summaryrefslogtreecommitdiffstats
path: root/linux-2.6-v4l-dvb-fixes.patch
diff options
context:
space:
mode:
authorJesse Keating <jkeating@redhat.com>2010-07-29 17:18:45 -0700
committerJesse Keating <jkeating@redhat.com>2010-07-29 17:18:45 -0700
commit2f82dda4a9bf41e64e864889bf06564bdf826e25 (patch)
tree118a7b483ae5de4dbf83d20001302f1404866ef0 /linux-2.6-v4l-dvb-fixes.patch
parent64ba2e5ffde5f2418eb26c700cb0ab62b04e5013 (diff)
downloaddom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.tar.gz
dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.tar.xz
dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.zip
initial srpm import
Diffstat (limited to 'linux-2.6-v4l-dvb-fixes.patch')
-rw-r--r--linux-2.6-v4l-dvb-fixes.patch113215
1 files changed, 113215 insertions, 0 deletions
diff --git a/linux-2.6-v4l-dvb-fixes.patch b/linux-2.6-v4l-dvb-fixes.patch
new file mode 100644
index 0000000..322148f
--- /dev/null
+++ b/linux-2.6-v4l-dvb-fixes.patch
@@ -0,0 +1,113215 @@
+Abylay Ospan (5):
+ V4L/DVB (10796): Add init code for NetUP Dual DVB-S2 CI card
+ V4L/DVB (10797): Add EEPROM code for NetUP Dual DVB-S2 CI card.
+ V4L/DVB (10798): Add CIMax(R) SP2 Common Interface code for NetUP Dual DVB-S2 CI card
+ V4L/DVB (11056): Bug fix in NetUP: restore high address lines in CI
+ V4L/DVB (11057): Fix CiMax stability in Netup Dual DVB-S2 CI
+
+Adam Baker (2):
+ V4L/DVB (10639): gspca - sq905: New subdriver.
+ V4L/DVB (10829): Support alternate resolutions for sq905
+
+Alan Cox (2):
+ V4L/DVB (11243): cx88: Missing failure checks
+ V4L/DVB (11244): pluto2: silence spew of card hung up messages
+
+Alan McIvor (1):
+ V4L/DVB (11124): Add support for ProVideo PV-183 to bttv
+
+Alexey Klimov (18):
+ V4L/DVB (10316): v4l/dvb: use usb_make_path in usb-radio drivers
+ V4L/DVB (10324): em28xx: Correct mailing list
+ V4L/DVB (10335): gspca - all subdrivers: Fix CodingStyle in sd_mod_init function.
+ V4L/DVB (10336): gspca - all subdrivers: Return ret instead of -1 in sd_mod_init.
+ V4L/DVB (10455): radio-mr800: codingstyle cleanups
+ V4L/DVB (10456): radio-mr800: place dev_err instead of dev_warn
+ V4L/DVB (10457): radio-mr800: add more dev_err messages in probe
+ V4L/DVB (10458): radio-mr800: move radio start and stop in one function
+ V4L/DVB (10459): radio-mr800: fix amradio_set_freq
+ V4L/DVB (10460): radio-mr800: add stereo support
+ V4L/DVB (10461): radio-mr800: add few lost mutex locks
+ V4L/DVB (10462): radio-mr800: increase version and add comments
+ V4L/DVB (10463): radio-mr800: fix checking of retval after usb_bulk_msg
+ V4L/DVB (10464): radio-si470x: use usb_make_path in usb-radio drivers
+ V4L/DVB (10465): dsbr100: Add few lost mutex locks.
+ V4L/DVB (10522): em28xx-audio: replace printk with em28xx_errdev
+ V4L/DVB (10946): radio-rtrack2: fix double mutex_unlock
+ V4L/DVB (10961): radio-terratec: remove linux/delay.h which hadn't been used.
+
+Andy Walls (44):
+ V4L/DVB (10274): cx18: Fix a PLL divisor update for the I2S master clock
+ V4L/DVB (10275): cx18: Additional debug to display outgoing mailbox parameters
+ V4L/DVB (10276): cx18, cx2341x, ivtv: Add AC-3 audio encoding control to cx18
+ V4L/DVB (10277): cx18, cx2341x: Fix bugs in cx18 AC3 control and comply with V4L2 spec
+ V4L/DVB (10278): cx18: Fix bad audio in first analog capture.
+ V4L/DVB (10279): cx18: Print driver version number when logging status
+ V4L/DVB (10280): cx18: Rename structure members: dev to pci_dev and v4l2dev to video_dev
+ V4L/DVB (10281): cx18: Conversion to new V4L2 framework: use v4l2_device object
+ V4L/DVB (10283): cx18: Call request_module() with proper argument types.
+ V4L/DVB (10284): cx18: Add initial entry for a Leadtek DVR3100 H hybrid card
+ V4L/DVB (10433): cx18: Defer A/V core initialization until a valid cx18_av_cmd arrives
+ V4L/DVB (10434): cx18: Smarter verification of CX18_AUDIO_ENABLE register writes
+ V4L/DVB (10435): cx18: Normalize APU after second APU firmware load
+ V4L/DVB (10436): cx18: Fix coding style of a switch statement per checkpatch.pl
+ V4L/DVB (10437): cx18: Remove an unused spinlock
+ V4L/DVB (10439): cx18: Clean-up and enable sliced VBI handling
+ V4L/DVB (10440): cx18: Fix presentation timestamp (PTS) for VBI buffers
+ V4L/DVB (10441): cx18: Fix VBI ioctl() handling and Raw/Sliced VBI state management
+ V4L/DVB (10442): cx18: Fixes for enforcing when Encoder Raw VBI params can be set
+ V4L/DVB (10443): cx18: Use correct line counts per field in firmware API call
+ V4L/DVB (10444): cx18: Fix sliced VBI PTS and fix artifacts in last raw line of field
+ V4L/DVB (10445): cx18: Process Raw VBI on a whole frame basis; fix VBI buffer size
+ V4L/DVB (10446): cx18: Finally get sliced VBI working - for 525 line 60 Hz systems at least
+ V4L/DVB (10755): cx18: Convert the integrated A/V decoder core interface to a v4l2_subdev
+ V4L/DVB (10756): cx18: Slim down instance handling, build names from v4l2_device.name
+ V4L/DVB (10757): cx18, v4l2-chip-ident: Finish conversion of AV decoder core to v4l2_subdev
+ V4L/DVB (10758): cx18: Convert I2C devices to v4l2_subdevices
+ V4L/DVB (10759): cx18: Convert GPIO connected functions to act as v4l2_subdevices
+ V4L/DVB (10760): cx18: Fix a memory leak of buffers used for sliced VBI insertion
+ V4L/DVB (10761): cx18: Change log lines for internal subdevs and fix tveeprom reads
+ V4L/DVB (10762): cx18: Get rid of unused variables related to video output
+ V4L/DVB (10763): cx18: Increment version number due to significant changes for v4l2_subdevs
+ V4L/DVB (10764): cx18: Disable AC3 controls as the firmware doesn't support AC3
+ V4L/DVB (10850): cx18: Use strlcpy() instead of strncpy() for temp eeprom i2c_client setup
+ V4L/DVB (10851): cx18: Fix a video scaling check problem introduced by sliced VBI changes
+ V4L/DVB (10852): cx18: Include cx18-audio.h in cx18-audio.c to eliminate s-parse warning
+ V4L/DVB (10853): cx18: Fix s-parse warnings and a logic error about extracting the VBI PTS
+ V4L/DVB (10854): cx18: Correct comments about vertical and horizontal blanking timings
+ V4L/DVB (10855): cx18: Fix VPS service register codes
+ V4L/DVB (10856): cx18: Add interlock so sliced VBI insertion only happens for an MPEG PS
+ V4L/DVB (11042): v4l2-api: Add definitions for V4L2_MPEG_STREAM_VBI_FMT_IVTV payloads
+ V4L/DVB (11091): cx18, ivtv: Ensure endianess for linemasks in VBI embedded in MPEG stream
+ V4L/DVB (11092): cx18: Optimize processing of VBI buffers from the capture unit
+ V4L/DVB (11233): mxl5005s: Switch in mxl5005s_set_params should operate on correct values
+
+Antoine Jacquet (1):
+ V4L/DVB (10263): zr364xx: add support for Aiptek DV T300
+
+Antonio Ospite (2):
+ V4L/DVB (10344): gspca - ov534: Disable the Hercules webcams.
+ V4L/DVB (10676): mt9m111: Call icl->reset() on mt9m111_reset().
+
+Antti Palosaari (4):
+ V4L/DVB (10286): af9015: add new USB ID for KWorld DVB-T 395U
+ V4L/DVB (10329): af9015: remove dual_mode module param
+ V4L/DVB (11215): zl10353: add support for Intel CE6230 and Intel CE6231
+ V4L/DVB (11216): Add driver for Intel CE6230 DVB-T USB2.0
+
+Arne Luehrs (1):
+ V4L/DVB (10319): dib0700: enable IR receiver in Nova TD usb stick (52009)
+
+Artem Makhutov (1):
+ V4L/DVB (11248): Remove debug output from stb6100_cfg.h
+
+Bruno Christo (1):
+ V4L/DVB (10827): Add support for GeoVision GV-800(S)
+
+Daniel Glöckner (1):
+ V4L/DVB (11242): allow v4l2 drivers to provide a get_unmapped_area handler
+
+Devin Heitmueller (36):
+ V4L/DVB (10320): dib0700: fix i2c error message to make data type clear
+ V4L/DVB (10321): dib0700: Report dib0700_i2c_enumeration failures
+ V4L/DVB (11059): xc5000: fix bug for hybrid xc5000 devices with IF other than 5380
+ V4L/DVB (11060): au8522: rename the au8522.c source file
+ V4L/DVB (11061): au8522: move shared state and common functions into a separate header files
+ V4L/DVB (11062): au8522: fix register read/write high bits
+ V4L/DVB (11063): au8522: power down the digital demod when not in use
+ V4L/DVB (11064): au8522: make use of hybrid framework so analog/digital demod can share state
+ V4L/DVB (11065): au8522: add support for analog side of demodulator
+ V4L/DVB (11066): au0828: add support for analog functionality in bridge
+ V4L/DVB (11067): au0828: workaround a bug in the au0828 i2c handling
+ V4L/DVB (11068): au0828: add analog profile for the HVR-850
+ V4L/DVB (11069): au8522: add mutex protecting use of hybrid state
+ V4L/DVB (11070): au0828: Rework the way the analog video binding occurs
+ V4L/DVB (11071): tveeprom: add the xc5000 tuner to the tveeprom definition
+ V4L/DVB (11072): au0828: advertise only NTSC-M (as opposed to all NTSC standards)
+ V4L/DVB (11073): au0828: disable VBI code since it doesn't yet work
+ V4L/DVB (11074): au0828: fix i2c enumeration bug
+ V4L/DVB (11075): au0828: make register debug lines easier to read
+ V4L/DVB (11076): au0828: make g_chip_ident call work properly
+ V4L/DVB (11077): au0828: properly handle missing analog USB endpoint
+ V4L/DVB (11078): au0828: properly handle non-existent analog inputs
+ V4L/DVB (11079): au0828: fix panic on disconnect if analog initialization failed
+ V4L/DVB (11080): au0828: Convert to use v4l2_device/subdev framework
+ V4L/DVB (11081): au0828: make sure v4l2_device name is unique
+ V4L/DVB (11082): au0828: remove memset calls in v4l2 routines.
+ V4L/DVB (11083): au0828: remove some unneeded braces
+ V4L/DVB (11084): au0828: add entry for undefined input type
+ V4L/DVB (11085): au0828/au8522: Codingstyle fixes
+ V4L/DVB (11086): au0828: rename macro for currently non-function VBI support
+ V4L/DVB (11088): au0828: finish videodev/subdev conversion
+ V4L/DVB (11089): au8522: finish conversion to v4l2_device/subdev
+ V4L/DVB (11139): em28xx: add remote control definition for HVR-900 (both versions)
+ V4L/DVB (11140): usbvision: fix oops on ARM platform when allocating transfer buffers
+ V4L/DVB (11141): em28xx: fix oops on ARM platform when allocating transfer buffers
+ V4L/DVB (11142): au0828: fix oops on ARM platform when allocating transfer buffers
+
+Douglas Kosovic (1):
+ V4L/DVB (10299): bttv: Add support for IVCE-8784 support for V4L2 bttv driver
+
+Douglas Schilling Landgraf (13):
+ V4L/DVB (10323): em28xx: Add entry for GADMEI TVR200
+ V4L/DVB (10326): em28xx: Cleanup: fix bad whitespacing
+ V4L/DVB (10327): em28xx: Add check before call em28xx_isoc_audio_deinit()
+ V4L/DVB (10517): em28xx: remove bad check (changeset a31c595188af)
+ V4L/DVB (10520): em28xx-audio: Add spinlock for trigger
+ V4L/DVB (10521): em28xx-audio: Add lock for users
+ V4L/DVB (10523): em28xx-audio: Add macros EM28XX_START_AUDIO / EM28XX_STOP_AUDIO
+ V4L/DVB (10524): em28xx: Add DVC 101 model to Pinnacle Dazzle description
+ V4L/DVB (10556): em28xx-cards: Add Pinnacle Dazzle Video Creator Plus DVC107 description
+ V4L/DVB (10739): em28xx-cards: remove incorrect entry
+ V4L/DVB (10740): em28xx-cards: Add SIIG AVTuner-PVR board
+ V4L/DVB (10741): em28xx: Add Kaiser Baas Video to DVD maker support
+ V4L/DVB (11222): gspca - zc3xx: The webcam DLink DSB - C320 has the sensor pas106.
+
+Erik Andren (3):
+ V4L/DVB (10334): gspca - stv06xx: Rework control description.
+ V4L/DVB (10341): gspca - stv06xx: Plug a memory leak in the pb0100 sensor driver.
+ V4L/DVB (10342): gspca - stv06xx: Add ctrl caching to the vv6410.
+
+Erik S. Beiser (1):
+ V4L/DVB (10826): cx88: Add IR support to pcHDTV HD3000 & HD5500
+
+Guennadi Liakhovetski (9):
+ V4L/DVB (10665): soc-camera: add data signal polarity flags to drivers
+ V4L/DVB (10672): sh_mobile_ceu_camera: include NV* formats into the format list only once.
+ V4L/DVB (10673): mt9t031: fix gain and hflip controls, register update, and scaling
+ V4L/DVB (10674): soc-camera: camera host driver for i.MX3x SoCs
+ V4L/DVB (10675): soc-camera: extend soc_camera_bus_param_compatible with more tests
+ V4L/DVB (11024): soc-camera: separate S_FMT and S_CROP operations
+ V4L/DVB (11025): soc-camera: configure drivers with a default format on open
+ V4L/DVB (11026): sh-mobile-ceu-camera: set field to the value, configured at open()
+ V4L/DVB (11027): soc-camera: configure drivers with a default format at probe time
+
+Hans Verkuil (171):
+ V4L/DVB (10231): v4l2-subdev: add v4l2_ext_controls support
+ V4L/DVB (10244): v4l2: replace a few snprintfs with strlcpy
+ V4L/DVB (10246): saa6752hs: convert to v4l2_subdev.
+ V4L/DVB (10247): saa7134: convert to the new v4l2 framework.
+ V4L/DVB (10249): v4l2-common: added v4l2_i2c_tuner_addrs()
+ V4L/DVB (10251): cx25840: add comments explaining what the init() does.
+ V4L/DVB (10252): v4l2 doc: explain why v4l2_device_unregister_subdev() has to be called.
+ V4L/DVB (10271): saa7146: convert to video_ioctl2.
+ V4L/DVB (10272): av7110: test type field in VIDIOC_G_SLICED_VBI_CAP
+ V4L/DVB (10291): em28xx: fix VIDIOC_G_CTRL when there is no msp34xx device.
+ V4L/DVB (10313): saa7146: fix VIDIOC_ENUMSTD.
+ V4L/DVB (10406): gspca: fix compiler warning
+ V4L/DVB (10408): v4l2: fix incorrect hue range check
+ V4L/DVB (10409): v4l: remove unused I2C_DRIVERIDs.
+ V4L/DVB (10486): ivtv/cx18: fix g_fmt and try_fmt for raw video
+ V4L/DVB (10487): doc: update hm12 documentation.
+ V4L/DVB (10488): ivtv: cleanup naming conventions
+ V4L/DVB (10489): doc: use consistent naming conventions for vdev and v4l2_dev.
+ V4L/DVB (10490): v4l2: prefill ident and revision from v4l2_dbg_chip_ident.
+ V4L/DVB (10496): saa7146: implement v4l2_device support.
+ V4L/DVB (10497): saa7146: i2c adapdata now points to v4l2_device.
+ V4L/DVB (10498): saa7146: the adapter class will be NULL when v4l2_subdev is used.
+ V4L/DVB (10499): saa7146: convert saa7146 and mxb in particular to v4l2_subdev.
+ V4L/DVB (10500): saa7146: setting control while capturing should return EBUSY, not EINVAL.
+ V4L/DVB (10501): saa7146: prevent unnecessary loading of v4l2-common.
+ V4L/DVB (10502): saa7146: move v4l2 device registration to saa7146_vv.
+ V4L/DVB (10536): saa6588: convert to v4l2-i2c-drv-legacy.h
+ V4L/DVB (10537): saa6588: convert to v4l2_subdev.
+ V4L/DVB (10538): saa6588: add g_chip_ident support.
+ V4L/DVB (10539): saa6588: remove legacy_class, not needed for saa6588
+ V4L/DVB (10540): cx2341x: fixed bug causing several audio controls to be no longer listed
+ V4L/DVB (10542): v4l2-subdev: add querystd and g_input_status
+ V4L/DVB (10544): v4l2-common: add comments warning that about the sort order
+ V4L/DVB (10641): v4l2-dev: remove limit of 32 devices per driver in get_index()
+ V4L/DVB (10642): vivi: update comment to reflect that vivi can now create more than 32 devs.
+ V4L/DVB (10643): v4l2-device: allow a NULL parent device when registering.
+ V4L/DVB (10644): v4l2-subdev: rename dev field to v4l2_dev
+ V4L/DVB (10645): vivi: introduce v4l2_device and do several cleanups
+ V4L/DVB (10646): vivi: controls are per-device, not global.
+ V4L/DVB (10647): vivi: add slider flag to controls.
+ V4L/DVB (10685): v4l2: add colorfx support to v4l2-common.c, and add to 'Changes' in spec.
+ V4L/DVB (10686): v4l2: add V4L2_CTRL_FLAG_WRITE_ONLY flag.
+ V4L/DVB (10687): v4l2-common/v4l2-spec: support/document write-only and button controls
+ V4L/DVB (10691): v4l2-common: add v4l2_i2c_subdev_addr()
+ V4L/DVB (10692): usbvision: convert to v4l2_device/v4l2_subdev.
+ V4L/DVB (10698): v4l2-common: remove v4l2_ctrl_query_fill_std
+ V4L/DVB (10700): saa7115: don't access reg 0x87 if it is not present.
+ V4L/DVB (10701): saa7185: add colorbar support.
+ V4L/DVB (10702): saa7115: add querystd and g_input_status support for zoran.
+ V4L/DVB (10703): zoran: convert to video_ioctl2 and remove 'ready_to_be_freed' hack.
+ V4L/DVB (10704): zoran: remove broken BIGPHYS_AREA and BUZ_HIMEM code, and allow for kmallocs > 128 kB
+ V4L/DVB (10705): zoran: use slider flag with volume etc. controls.
+ V4L/DVB (10706): zoran: fix field typo.
+ V4L/DVB (10707): zoran: set bytesperline to 0 when using MJPEG.
+ V4L/DVB (10708): zoran: remove old V4L1 ioctls, use v4l1-compat instead.
+ V4L/DVB (10709): zoran: set correct parent of the video device.
+ V4L/DVB (10710): zoran: cleanups in an attempt to make the source a bit more readable.
+ V4L/DVB (10711): zoran: fix TRY_FMT support
+ V4L/DVB (10712): zoran: fix G_FMT
+ V4L/DVB (10713): zoran: if reqbufs is called with count == 0, do a streamoff.
+ V4L/DVB (10714): zoran et al: convert zoran i2c modules to V4L2.
+ V4L/DVB (10715): zoran: clean up some old V4L1 left-overs and remove the MAP_NR macro.
+ V4L/DVB (10716): zoran: change buffer defaults to something that works with tvtime
+ V4L/DVB (10717): zoran: TRY_FMT and S_FMT now do the same parameter checks.
+ V4L/DVB (10718): bt866: convert to v4l2_subdev.
+ V4L/DVB (10719): bt819: convert to v4l2_subdev.
+ V4L/DVB (10720): bt819: that delay include is needed after all.
+ V4L/DVB (10721): bt856: convert to v4l2_subdev.
+ V4L/DVB (10722): ks0127: convert to v4l2_subdev.
+ V4L/DVB (10723): ks0127: add supported ks0127 variants to the i2c device list.
+ V4L/DVB (10724): saa7110: convert to v4l2_subdev.
+ V4L/DVB (10725): saa7185: convert to v4l2_subdev.
+ V4L/DVB (10726): vpx3220: convert to v4l2_subdev.
+ V4L/DVB (10727): adv7170: convert to v4l2_subdev.
+ V4L/DVB (10728): adv7175: convert to v4l2-subdev.
+ V4L/DVB (10729): zoran: convert to v4l2_device/v4l2_subdev.
+ V4L/DVB (10730): v4l-dvb: cleanup obsolete references to v4l1 headers.
+ V4L/DVB (10731): zoran i2c modules: remove i2c autoprobing support.
+ V4L/DVB (10732): zoran: s_jpegcomp should return a proper result, not 0.
+ V4L/DVB (10733): zoran: increase bufsize to a value suitable for 768x576.
+ V4L/DVB (10858): vino: convert to video_ioctl2.
+ V4L/DVB (10859): vino: minor renames
+ V4L/DVB (10860): saa7191: convert to v4l2-i2c-drv-legacy.h
+ V4L/DVB (10861): vino/indycam/saa7191: convert to i2c modules to V4L2.
+ V4L/DVB (10862): indycam: convert to v4l2_subdev
+ V4L/DVB (10863): saa7191: convert to v4l2_subdev.
+ V4L/DVB (10864): vino: introduce v4l2_device.
+ V4L/DVB (10865): vino: convert to v4l2_subdev.
+ V4L/DVB (10866): saa7191, indycam: remove compat code.
+ V4L/DVB (10868): vino: add note that this conversion is untested.
+ V4L/DVB (10873): w9968cf: add v4l2_device.
+ V4L/DVB (10874): w9968cf/ovcamchip: convert to v4l2_subdev.
+ V4L/DVB (10880): radio-aimslab: convert to v4l2_device.
+ V4L/DVB (10881): radio-aztech: convert to v4l2_device.
+ V4L/DVB (10882): radio-cadet: convert to v4l2_device.
+ V4L/DVB (10883): radio-gemtek-pci: convert to v4l2_device.
+ V4L/DVB (10884): radio-gemtek: convert to v4l2_device.
+ V4L/DVB (10885): radio-maestro: convert to v4l2_device.
+ V4L/DVB (10886): radio-maxiradio: convert to v4l2_device.
+ V4L/DVB (10887): radio-rtrack2: convert to v4l2_device.
+ V4L/DVB (10888): radio-sf16fmi: convert to v4l2_device.
+ V4L/DVB (10889): radio-sf16fmr2: convert to v4l2_device.
+ V4L/DVB (10890): radio-terratec: convert to v4l2_device.
+ V4L/DVB (10891): radio-trust: convert to v4l2_device.
+ V4L/DVB (10892): radio-typhoon: convert to v4l2_device.
+ V4L/DVB (10893): radio-zoltrix: convert to v4l2_device.
+ V4L/DVB (10894): ISA radio drivers: improve kernel log message
+ V4L/DVB (10909): tvmixer: remove last remaining references to this deleted module.
+ V4L/DVB (10910): videodev2.h: remove deprecated VIDIOC_G_CHIP_IDENT_OLD
+ V4L/DVB (10912): vivi: fix compile warning.
+ V4L/DVB (10914): v4l2: fix compile warnings when printing u64 value.
+ V4L/DVB (10919): tlv320aic23b: use v4l2-i2c-drv.h instead of drv-legacy.h
+ V4L/DVB (10920): v4l2-ioctl: fix partial-copy code.
+ V4L/DVB (10921): msp3400: remove obsolete V4L1 code
+ V4L/DVB (10959): radio: remove uaccess include
+ V4L/DVB (10960): omap24xxcam: don't set vfl_type.
+ V4L/DVB (10962): fired-avc: fix printk formatting warning.
+ V4L/DVB (10965): ivtv: bump version
+ V4L/DVB (10980): doc: improve the v4l2-framework documentation.
+ V4L/DVB (10983): v4l2-common: add missing i2c_unregister_device.
+ V4L/DVB (10987): cx23885: fix crash on non-netup cards
+ V4L/DVB (10988): v4l2-dev: use parent field if the v4l2_device has no parent set.
+ V4L/DVB (11021): v4l2-device: add a notify callback.
+ V4L/DVB (11022): zoran/bt819: use new notify functionality.
+ V4L/DVB (11044): v4l2-device: add v4l2_device_disconnect
+ V4L/DVB (11045): v4l2: call v4l2_device_disconnect in USB drivers.
+ V4L/DVB (11046): bttv: convert to v4l2_device.
+ V4L/DVB (11047): cx88: convert to v4l2_device.
+ V4L/DVB (11048): zoran: fix incorrect return type of notify function.
+ V4L/DVB (11051): v4l-dvb: replace remaining references to the old mailinglist.
+ V4L/DVB (11052): bt819: remove an unused header
+ V4L/DVB (11053): saa7134: set v4l2_dev field of video_device
+ V4L/DVB (11098): v4l2-common: remove incorrect MODULE test
+ V4L/DVB (11100): au8522: fix compilation warning.
+ V4L/DVB (11112): v4l2-subdev: add support for TRY_FMT, ENUM_FMT and G/S_PARM.
+ V4L/DVB (11113): ov7670: convert to v4l2_subdev
+ V4L/DVB (11114): cafe_ccic: convert to v4l2_device.
+ V4L/DVB (11115): cafe_ccic: use v4l2_subdev to talk to the ov7670 sensor.
+ V4L/DVB (11116): ov7670: cleanup and remove legacy code.
+ V4L/DVB (11117): ov7670: add support to get/set registers
+ V4L/DVB (11118): cafe_ccic: replace debugfs with g/s_register ioctls.
+ V4L/DVB (11120): cafe_ccic: stick in a comment with a request for test results
+ V4L/DVB (11253): saa7134: fix RTD Embedded Technologies VFG7350 support.
+ V4L/DVB (11254): cs53l32a: remove legacy support.
+ V4L/DVB (11255): dst_ca: fix compile warning.
+ V4L/DVB (11256): dabusb: fix compile warning.
+ V4L/DVB (11275): tvaudio: fix mute and s/g_tuner handling
+ V4L/DVB (11276): tvaudio: add tda9875 support.
+ V4L/DVB (11277): tvaudio: always call init_timer to prevent rmmod crash.
+ V4L/DVB (11278): bttv: convert to v4l2_subdev since i2c autoprobing will disappear.
+ V4L/DVB (11279): bttv: tda9875 is no longer used by bttv, so remove from bt8xx/Kconfig.
+ V4L/DVB (11281): bttv: move saa6588 config to the helper chip config
+ V4L/DVB (11282): saa7134: add RDS support.
+ V4L/DVB (11283): saa6588: remove legacy code.
+ V4L/DVB (11295): cx23885: convert to v4l2_device.
+ V4L/DVB (11297): cx23885: convert to v4l2_subdev.
+ V4L/DVB (11298): cx25840: remove legacy code for old-style i2c API
+ V4L/DVB (11300): cx88: convert to v4l2_subdev.
+ V4L/DVB (11301): wm8775: remove legacy code for old-style i2c API
+ V4L/DVB (11302): tda9875: remove legacy code for old-style i2c API
+ V4L/DVB (11303): tda7432: remove legacy code for old-style i2c API
+ V4L/DVB (11304): v4l2: remove v4l2_subdev_command calls where they are no longer needed.
+ V4L/DVB (11305): cx88: prevent probing rtc and ir devices
+ V4L/DVB (11309): cx25840: cleanup: remove intermediate 'ioctl' step
+ V4L/DVB (11310): cx18: remove intermediate 'ioctl' step
+ V4L/DVB (11311): v4l: replace 'ioctl' references in v4l i2c drivers
+ V4L/DVB (11312): tuner: remove V4L1 code from this driver.
+ V4L/DVB (11313): v4l2-subdev: add enum_framesizes and enum_frameintervals.
+ V4L/DVB (11314): au8522: remove unused I2C_DRIVERID
+ V4L/DVB (11315): cx25840: fix 'unused variable' warning.
+ V4L/DVB (11316): saa7191: tuner ops wasn't set.
+
+Hans Werner (1):
+ V4L/DVB (10392): lnbp21: documentation about the system register
+
+Hans de Goede (1):
+ V4L/DVB (11221): gspca - sonixj: Prefer sonixj instead of sn9c102 for 0471:0327.
+
+Igor M. Liplianin (18):
+ V4L/DVB (10266): Add support for TurboSight TBS6920 DVB-S2 PCI-e card.
+ V4L/DVB (10267): Add support for TeVii S470 DVB-S2 PCI-e card.
+ V4L/DVB (10268): Proper implement set_voltage in cx24116.
+ V4L/DVB (10269): Add support for DVBWorld DVBS2 PCI-e 2005.
+ V4L/DVB (10413): Bug fix: Restore HVR-4000 tuning.
+ V4L/DVB (10743): dm1105: not demuxing from interrupt context.
+ V4L/DVB (10744): dm1105: infrared remote code is remaked.
+ V4L/DVB (10799): Add support for ST STV6110 silicon tuner.
+ V4L/DVB (10800): Add support for ST LNBH24 LNB power controller.
+ V4L/DVB (10801): Add headers for ST STV0900 dual demodulator.
+ V4L/DVB (10802): Add more headers for ST STV0900 dual demodulator.
+ V4L/DVB (10803): Add core code for ST STV0900 dual demodulator.
+ V4L/DVB (10804): Add support for ST STV0900 dual demodulator.
+ V4L/DVB (10805): Add support for NetUP Dual DVB-S2 CI card
+ V4L/DVB (10808): Fix typo in lnbp21.c
+ V4L/DVB (10871): stv0900: delete debug messages not related to stv0900 tuning algorythm
+ V4L/DVB (11054): Shorten some lines in stv0900 to less then 81 characters
+ V4L/DVB (11055): Fix typo in stv0900
+
+Indika Katugampala (1):
+ V4L/DVB (10528): em28xx: support added for IO-DATA GV/MVP SZ - EMPIA-2820 chipset
+
+Jan Engelhardt (1):
+ V4L/DVB (10391): dvb: constify VFTs
+
+Janne Grunau (12):
+ V4L/DVB (11095): adds V4L2_CID_SHARPNESS to v4l2_ctrl_query_fill()
+ V4L/DVB (11096): V4L2 Driver for the Hauppauge HD PVR usb capture device
+ V4L/DVB (11097): use video_ioctl2 as ioctl handler directly
+ V4L/DVB (11125): fix mispelled Hauppauge in HD PVR and PVR USB2 driver comments
+ V4L/DVB (11152): hdpvr: Fix build with Config_I2C not set
+ V4L/DVB (11228): hdpvr: use debugging macro for buffer status
+ V4L/DVB (11229): hdpvr: set usb interface dev as parent in struct video_device
+ V4L/DVB (11230): hdpvr: return immediately from hdpvr_poll if data is available
+ V4L/DVB (11231): hdpvr: locking fixes
+ V4L/DVB (11245): hdpvr: add struct v4l2_device
+ V4L/DVB (11246): hdpvr: convert printing macros to v4l2_* with struct v4l2_device
+ V4L/DVB (11247): hdpvr: empty internal device buffer after stopping streaming
+
+Jean Delvare (8):
+ V4L/DVB (10867): vino: fold i2c-algo-sgi code into vino.
+ V4L/DVB (10931): zoran: Drop the lock_norm module parameter
+ V4L/DVB (10932): zoran: Don't frighten users with failed buffer allocation
+ V4L/DVB (10938): em28xx: Prevent general protection fault on rmmod
+ V4L/DVB (10939): ir-kbd-i2c: Prevent general protection fault on rmmod
+ V4L/DVB (10940): saa6588: Prevent general protection fault on rmmod
+ V4L/DVB (10943): cx88: Prevent general protection fault on rmmod
+ V4L/DVB (11111a): MAINTAINERS: Drop references to deprecated video4linux list
+
+Jean-Francois Moine (75):
+ V4L/DVB (10332): gspca - main: Version change.
+ V4L/DVB (10333): gspca - main and many subdrivers: Remove the epaddr variable.
+ V4L/DVB (10337): gspca - common: Simplify the debug macros.
+ V4L/DVB (10343): gspca - zc3xx / zc0301: Handle the 0ac8:303b instead of zc0301.
+ V4L/DVB (10345): gspca - jpeg subdrivers: One quantization table per subdriver.
+ V4L/DVB (10346): gspca - zc3xx: Fix bad variable type with i2c read.
+ V4L/DVB (10347): gspca - mars: Optimize, rewrite initialization and add controls.
+ V4L/DVB (10348): gspca - mars: Bad isoc packet scanning.
+ V4L/DVB (10350): gspca - tv8532: Cleanup code.
+ V4L/DVB (10352): gspca - spca508: Cleanup code.
+ V4L/DVB (10353): gspca - some subdrivers: Don't get the control values from the webcam.
+ V4L/DVB (10354): gspca - tv8532: Change the max brightness.
+ V4L/DVB (10356): gspca - sonixj: Cleanup code.
+ V4L/DVB (10357): gspca - main: Cleanup code.
+ V4L/DVB (10360): gspca - mars: Bad interface/altsetting since 0a10a0e906be.
+ V4L/DVB (10361): gspca - sonixj: Gamma control added.
+ V4L/DVB (10363): gspca - spca500: Abnormal error message when starting ClickSmart310.
+ V4L/DVB (10367): gspca - spca561: Optimize the isoc scanning function.
+ V4L/DVB (10368): gspca - spca561: Fix bugs and rewrite the init/start of the rev72a.
+ V4L/DVB (10370): gspca - main: Have 3 URBs instead of 2 for ISOC transfers.
+ V4L/DVB (10371): gspca - spca561: Fix image problem in the 352x288 mode of rev72a.
+ V4L/DVB (10372): gspca - sonixj: Cleanup code.
+ V4L/DVB (10373): gspca - zc3xx: Sensor adcm2700 added.
+ V4L/DVB (10374): gspca - zc3xx: Bad probe of the sensor adcm2700.
+ V4L/DVB (10375): gspca - zc3xx: Remove duplicated sequence of sensor cs2102k.
+ V4L/DVB (10376): gspca - zc3xx: Remove some useless tables of sensor adcm2700.
+ V4L/DVB (10378): gspca - main: Avoid error on set interface on disconnection.
+ V4L/DVB (10380): gspca - t613: Cleanup and optimize code.
+ V4L/DVB (10381): gspca - t613: New unknown sensor added.
+ V4L/DVB (10382): gspca - t613: Bad returned value when no known sensor found.
+ V4L/DVB (10383): gspca - spca505: Cleanup and optimize code.
+ V4L/DVB (10384): gspca - spca505: Simplify and add the brightness in start.
+ V4L/DVB (10387): gspca - spca505: Move some sequences from probe to streamon.
+ V4L/DVB (10389): gspca - zc3xx: Do work the sensor adcm2700.
+ V4L/DVB (10419): gspca - sonixj: Sensor mt9v111 added.
+ V4L/DVB (10420): gspca - vc032x: Webcam 041e:405b added and mi1310_soc updated.
+ V4L/DVB (10421): gspca - documentation: Add the webcam 041e:405b.
+ V4L/DVB (10423): gspca - sonixj: Bad sensor definition of the webcams 0c45:60c0.
+ V4L/DVB (10424): gspca - vc032x: Add resolution 1280x1024 for sensor mi1310_soc.
+ V4L/DVB (10425): gspca - sonixj: Bad initialization of sensor mt9v111.
+ V4L/DVB (10427): gspca - sonixj: Sensor sp80708 added for webcam 0c45:6143.
+ V4L/DVB (10428): gspca - sonixj: Specific gamma tables per sensor.
+ V4L/DVB (10429): gspca - sonixj: Simplify the probe of the sensors mi0360/mt9v111.
+ V4L/DVB (10430): gspca - sonixj: Adjust some exchanges with the sensor mt9v111.
+ V4L/DVB (10431): gspca - vc032x: Bad revision for the webcam 041e:405b.
+ V4L/DVB (10432): gspca - vc032x: Cleanup source, optimize and check i2c_write.
+ V4L/DVB (10617): gspca - vc032x: Remove the vc0321 reset.
+ V4L/DVB (10618): gspca - some drivers: Fix compilation warnings.
+ V4L/DVB (10620): gspca - main: More checks of the device disconnection.
+ V4L/DVB (10635): gspca - sonixj: No vertical flip control for mt9v111.
+ V4L/DVB (10636): gspca - sonixj: Add autogain for ov7630/48 and vflip for ov7648.
+ V4L/DVB (10637): gspca - t613: Bad sensor name in kernel trace when 'other' sensor.
+ V4L/DVB (10638): gspca - t613: Bad debug level when displaying the sensor type.
+ V4L/DVB (10679): gspca - sonixj: Handle the webcam 0c45:613c instead of sn9c102.
+ V4L/DVB (10680): gspca - zc3xx: Bad probe of the ov7xxx sensors.
+ V4L/DVB (10681): gspca - zc3xx: Bad probe of the ov7630c sensor.
+ V4L/DVB (10787): gspca - mars: Bad webcam register values tied to saturation.
+ V4L/DVB (10788): gspca - vc032x: Bad matrix for sensor mi1310_soc.
+ V4L/DVB (11039): gspca - most jpeg subdrivers: Change the JPEG header creation.
+ V4L/DVB (11040): gspca - most jpeg subdrivers: Have the JPEG quality settable.
+ V4L/DVB (11103): gspca - main: May have isochronous transfers on altsetting 0
+ V4L/DVB (11104): gspca - ov534: Bad frame pointer after adding the last packet
+ V4L/DVB (11105): gspca - ov534: Adjust the packet scan function
+ V4L/DVB (11106): gspca - ov534: New sensor ov965x and re-enable the webcam 06f8:3003
+ V4L/DVB (11143): gspca - t613: Bad sensor detection.
+ V4L/DVB (11144): gspca - t613: Don't re-read the ID registers at probe time.
+ V4L/DVB (11145): gspca - t613: Greater delay after om6802 reset.
+ V4L/DVB (11146): gspca - vc032x: Change the probe sequence.
+ V4L/DVB (11209): gspca - vc032x: New sensor mi1320_soc and webcam 15b8:6001 added.
+ V4L/DVB (11211): gspca - vc032x: Simplify the i2c write function.
+ V4L/DVB (11212): gspca - vc032x: Use YVYU format for sensor mi1320_soc.
+ V4L/DVB (11218): gspca - sq905: Update the frame pointer after adding the last packet.
+ V4L/DVB (11219): gspca - sq905: Optimize the resolution setting.
+ V4L/DVB (11220): gspca - finepix: Use a workqueue for streaming.
+ V4L/DVB (11223): gspca - doc: Add the 15b8:6001 webcam to the Documentation.
+
+Jochen Friedrich (2):
+ V4L/DVB (10452): Add Freescale MC44S803 tuner driver
+ V4L/DVB (10453): af9015: add MC44S803 support
+
+Jose Alberto Reguero (1):
+ V4L/DVB (10330): af9015: New remote RM-KS for Avermedia Volar-X
+
+Kay Sievers (1):
+ V4L/DVB (10395): struct device - replace bus_id with dev_name(), dev_set_name()
+
+Klaus Flittner (1):
+ V4L/DVB (11290): Add Elgato EyeTV DTT to dibcom driver
+
+Kuninori Morimoto (8):
+ V4L/DVB (10616): tw9910: color format check is added on set_fmt
+ V4L/DVB (10666): ov772x: move configuration from start_capture() to set_fmt()
+ V4L/DVB (10667): ov772x: setting method to register is changed.
+ V4L/DVB (10668): ov772x: bit mask operation fix on ov772x_mask_set.
+ V4L/DVB (10669): ov772x: Add image flip support
+ V4L/DVB (10670): tw9910: bit mask operation fix on tw9910_mask_set.
+ V4L/DVB (10671): sh_mobile_ceu: SOCAM flags are not platform dependent
+ V4L/DVB (11028): ov772x: use soft sleep mode in stop_capture
+
+Kyle Guinn (3):
+ V4L/DVB (10365): Add Mars-Semi MR97310A format
+ V4L/DVB (10366): gspca - mr97310a: New subdriver.
+ V4L/DVB (10369): gspca - mr97310a: Fix camera initialization copy/paste bugs.
+
+Laurent Pinchart (8):
+ V4L/DVB (10293): uvcvideo: replace strn{cpy,cat} with strl{cpy,cat}.
+ V4L/DVB (10294): uvcvideo: Add support for the Alcor Micro AU3820 chipset.
+ V4L/DVB (10295): uvcvideo: Retry URB buffers allocation when the system is low on memory.
+ V4L/DVB (10296): uvcvideo: Fix memory leak in input device handling
+ V4L/DVB (10650): uvcvideo: Initialize streaming parameters with the probe control value
+ V4L/DVB (10651): uvcvideo: Ignore empty bulk URBs
+ V4L/DVB (10652): uvcvideo: Add quirk to override wrong bandwidth value for Vimicro devices
+ V4L/DVB (11292): uvcvideo: Add support for Syntek cameras found in JAOtech Smart Terminals
+
+Lierdakil (1):
+ V4L/DVB (10388): gspca - pac207: Webcam 093a:2474 added.
+
+Magnus Damm (2):
+ V4L/DVB (10304): buf-dma-contig: fix USERPTR free handling
+ V4L/DVB (11029): video: use videobuf_waiton() in sh_mobile_ceu free_buffer()
+
+Martin Fuzzey (1):
+ V4L/DVB (10945): pwc : fix LED and power setup for first open
+
+Matthias Schwarzott (4):
+ V4L/DVB (10662): remove redundant memset after kzalloc
+ V4L/DVB (10822): Add support for Zarlink ZL10036 DVB-S tuner.
+ V4L/DVB (10823): saa7134: add DVB support for Avermedia A700 cards
+ V4L/DVB (10948): flexcop-pci: Print a message in case the new stream watchdog detects a problem
+
+Mauro Carvalho Chehab (49):
+ V4L/DVB (10211): vivi: Implements 4 inputs on vivi
+ V4L/DVB (10298): remove err macro from few usb devices
+ V4L/DVB (10305): videobuf-vmalloc: Fix: videobuf memory were never freed
+ V4L/DVB (10394): KWorld ATSC 115 all static
+ V4L/DVB (10404): saa7134-core: remove oss option, since saa7134-oss doesn't exist anymore
+ V4L/DVB (10405): saa7134-core: loading saa7134-alsa is now the default
+ V4L/DVB (10504): tda827x: Be sure that gate will be open/closed at the proper time
+ V4L/DVB (10505): tda8290: Print an error if i2c_gate is not provided
+ V4L/DVB (10506): saa7134: move tuner init code to saa7134-cards
+ V4L/DVB (10507): saa7134: Fix analog mode on devices that need to open an i2c gate
+ V4L/DVB (10508): saa7134: Cleanup: remove unused waitqueue from struct
+ V4L/DVB (10509): saa7134-video: two int controls lack a step
+ V4L/DVB (10511): saa7134: get rid of KBL
+ V4L/DVB (10512): tda1004x: Fix eeprom firmware load on boards with 16MHz Xtal
+ V4L/DVB (10514): em28xx: Add support for Kaiomy TVnPC U2 stick
+ V4L/DVB (10515): Adds IR table for the IR provided with this board and includes it at
+ V4L/DVB (10516): em28xx: Add support for Easy Cap Capture DC-60
+ V4L/DVB (10570): v4l2-framework: documments videobuf usage on drivers
+ V4L/DVB (10571): v4l2-framework.txt: Fixes the videobuf init functions
+ V4L/DVB (10654): em28xx: VideoMate For You USB TV box requires tvaudio
+ V4L/DVB (10738): Get rid of video_decoder.h header were uneeded
+ V4L/DVB(10738a): remove include/linux/video_encoder.h
+ V4L/DVB (10769): Update dependencies of the modules converted to V4L2
+ V4L/DVB (10771): tea575x-tuner: convert it to V4L2 API
+ V4L/DVB (10835): Kconfig: Add some missing selects for a required frontends
+ V4L/DVB (10836): Kconfig: replace DVB_FE_CUSTOMIZE to DVB_FE_CUSTOMISE
+ V4L/DVB (10837): Kconfig: only open the customise menu if selected
+ V4L/DVB (10838): get rid of the other occurrences of DVB_FE_CUSTOMIZE typo
+ V4L/DVB (10840): em28xx-dvb: Remove an unused header
+ V4L/DVB (10842): Adds some missing frontend selects for saa7134 and dvb-usb
+ V4L/DVB (10870): v4l2-ioctl: get rid of video_decoder.h
+ V4L/DVB (10896): /frontends/Kconfig: Move af9013 Kconfig option to its proper place
+ V4L/DVB (10897): Fix Kbuild MEDIA_TUNER_CUSTOMIZE dependencies
+ V4L/DVB (10870a): remove all references for video_decoder.h
+ V4L/DVB (10907): avoid loading the entire videodev.h header on V4L2 drivers
+ V4L/DVB (10951): xc5000: Fix CodingStyle errors introduced by the last patch
+ V4L/DVB (10908): videobuf-core: also needs a minimal subset of V4L1 header
+ V4L/DVB (11108): get_dvb_firmware: Add option to download firmware for cx231xx
+ V4L/DVB (11109): au0828: Fix compilation when VIDEO_ADV_DEBUG = n
+ V4L/DVB (11110): au8522/au0828: Fix Kconfig dependencies
+ V4L/DVB (11111): dvb_dummy_fe: Fix compilation breakage
+ V4L/DVB (11127): Kconfig: replace all occurrences of CUSTOMIZE to CUSTOMISE
+ V4L/DVB (11136): get_dvb_firmware: Add download code for cx18 firmwares
+ V4L/DVB (11137): get_dvb_firmware: add cx23885 firmwares
+ V4L/DVB (11138): get_dvb_firmware: add support for downloading the cx2584x firmware for pvrusb2
+ V4L/DVB (11225): v4lgrab: fix compilation warnings
+ V4L/DVB (11226): avoid warnings for request_ihex_firmware on dabusb and vicam
+ V4L/DVB (11227): ce6230: avoid using unitialized var
+ V4L/DVB (11308): msp3400: use the V4L2 header since no V4L1 code is there
+
+Michael Krufky (36):
+ V4L/DVB (10415): dib0700: add data debug to dib0700_i2c_xfer_new
+ V4L/DVB (10416): tveeprom: update to include Hauppauge tuners 151-155
+ V4L/DVB (10417): sms1xxx: add missing usb id 2040:2011
+ V4L/DVB (10746): sms1xxx: enable rf switch on Hauppauge Tiger devices
+ V4L/DVB (10747): sms1xxx: move definition of struct smsdvb_client_t into smsdvb.c
+ V4L/DVB (10749): sms1xxx: move smsusb_id_table into smsusb.c
+ V4L/DVB (10751): sms1xxx: fix checkpatch.pl violations introduced by previous changeset
+ V4L/DVB (10752): sms1xxx: load smsdvb module automatically based on device id
+ V4L/DVB (10753): siano: convert EXPORT_SYMBOL to EXPORT_SYMBOL_GPL
+ V4L/DVB (10772): siano: prevent duplicate variable declaration
+ V4L/DVB (10779): mxl5007t: remove analog tuning code
+ V4L/DVB (10780): mxl5007t: remove function mxl5007t_check_rf_input_power
+ V4L/DVB (10781): mxl5007t: mxl5007t_get_status should report if tuner is locked
+ V4L/DVB (10782): mxl5007t: warn when unknown revisions are detected
+ V4L/DVB (10783): mxl5007t: fix devname for hybrid_tuner_request_state
+ V4L/DVB (10784): mxl5007t: update driver for MxL 5007T V4
+ V4L/DVB (10876): tda18271: add support for AGC configuration via tuner callback
+ V4L/DVB (10877): saa7134: add analog support for Hauppauge HVR1110r3 boards
+ V4L/DVB (10898): remove build-time dependencies on dib7000m
+ V4L/DVB (10899): remove build-time dependencies on dib7000p
+ V4L/DVB (10900): remove build-time dependencies on dib3000mc
+ V4L/DVB (10901): cleanup linewraps in dib7000p.h
+ V4L/DVB (10902): cleanup linewraps in dib7000m.h
+ V4L/DVB (10903): cleanup linewraps in dib3000mc.h
+ V4L/DVB (10904): remove dib0070_ctrl_agc_filter from dib0070.h
+ V4L/DVB (10905): dib0700: enable DVB_FE_CUSTOMISE for dibcom frontends
+ V4L/DVB (10923): saa7134: fix typo in product name
+ V4L/DVB (10924): saa7134: enable serial transport streaming interface
+ V4L/DVB (10925): add support for LG Electronics LGDT3305 ATSC/QAM-B Demodulator
+ V4L/DVB (10926): saa7134: enable digital tv support for Hauppauge WinTV-HVR1120
+ V4L/DVB (10927): dib0700: add support for Hauppauge ATSC MiniCard
+ V4L/DVB (10968): lgdt3305: add email address to MODULE_AUTHOR
+ V4L/DVB (10969): lgdt3305: add missing space in comment
+ V4L/DVB (10970): lgdt3305: add MODULE_VERSION
+ V4L/DVB (10984): lgdt3305: avoid OOPS in error path of lgdt3305_attach
+ V4L/DVB (11251): tuner: prevent invalid initialization of t->config in set_type
+
+Mike Isely (62):
+ V4L/DVB (10236): pvrusb2: Stop advertising VBI capability - it isn't there
+ V4L/DVB (10237): pvrusb2: Generate a device-unique identifier
+ V4L/DVB (10238): pvrusb2: Change sysfs serial number handling
+ V4L/DVB (10239): pvrusb2: Fix misleading comment caused by earlier commit
+ V4L/DVB (10258): pvrusb2: Issue VIDIOC_INT_INIT to v4l2 modules when they first attach
+ V4L/DVB (10259): pvrusb2: Code module name directly in printk
+ V4L/DVB (10303): pvrusb2: Use usb_make_path() to determine device bus location
+ V4L/DVB (11154): pvrusb2: Split i2c module handling from i2c adapter
+ V4L/DVB (11155): pvrusb2: Set up v4l2_device instance
+ V4L/DVB (11156): pvrusb2: Changes to further isolate old i2c layer
+ V4L/DVB (11157): pvrusb2: whitespace trivial tweaks
+ V4L/DVB (11158): pvrusb2: New device attribute mechanism to specify sub-devices
+ V4L/DVB (11159): pvrusb2: Providing means to stop tracking an old i2c module
+ V4L/DVB (11160): pvrusb2: whitespace tweaks
+ V4L/DVB (11161): pvrusb2: Set i2c autoprobing to be off by default
+ V4L/DVB (11162): pvrusb2: Tie up loose ends with v4l2-subdev setup
+ V4L/DVB (11163): pvrusb2: Lay foundation for triggering sub-device updates
+ V4L/DVB (11164): pvrusb2: Tie-in sub-device log requests
+ V4L/DVB (11165): pvrusb2: Tie in debug register access to sub-devices
+ V4L/DVB (11166): pvrusb2: Implement status fetching from sub-devices
+ V4L/DVB (11167): pvrusb2: Tie in various v4l2 operations into the sub-device mechanism
+ V4L/DVB (11168): pvrusb2: Define value for a null sub-device ID
+ V4L/DVB (11169): pvrusb2: Note who our video decoder sub-device is, and set it up
+ V4L/DVB (11170): pvrusb2: Clean-up / placeholders inserted for additional development
+ V4L/DVB (11171): pvrusb2: Tie in sub-device decoder start/stop
+ V4L/DVB (11172): pvrusb2: Cause overall initialization to fail if sub-driver(s) fail
+ V4L/DVB (11173): pvrusb2: Fix backwards function header comments
+ V4L/DVB (11174): pvrusb2: Implement reporting of connected sub-devices
+ V4L/DVB (11175): pvrusb2: Implement sub-device specific update framework
+ V4L/DVB (11176): pvrusb2: Tie in wm8775 sub-device handling
+ V4L/DVB (11177): pvrusb2: Tie in saa7115 sub-device handling
+ V4L/DVB (11178): pvrusb2: Make audio sample rate update into a sub-device broadcast
+ V4L/DVB (11179): pvrusb2: make sub-device specific update function names uniform
+ V4L/DVB (11180): pvrusb2: Tie in msp3400 sub-device support
+ V4L/DVB (11181): pvrusb2: Fix silly 80 column issue
+ V4L/DVB (11182): pvrusb2: Tie in cx25840 sub-device support
+ V4L/DVB (11183): pvrusb2: Implement more sub-device loading trace and improve error handling
+ V4L/DVB (11184): pvrusb2: Define default i2c address for wm8775 sub-device
+ V4L/DVB (11185): pvrusb2: Fix uninitialized counter
+ V4L/DVB (11186): pvrusb2: Fix bugs involved in listing of sub-devices
+ V4L/DVB (11187): pvrusb2: Allow sub-devices to insert correctly
+ V4L/DVB (11188): pvrusb2: Sub-device update must happen BEFORE state dirty bits are cleared
+ V4L/DVB (11189): pvrusb2: Deal with space-after-comma coding style idiocy
+ V4L/DVB (11190): pvrusb2: Broadcast tuner type change to sub-devices
+ V4L/DVB (11191): pvrusb2: Define default I2C address for cx25840 sub-device
+ V4L/DVB (11192): pvrusb2: Implement trace print for stream on / off action
+ V4L/DVB (11193): pvrusb2: Correct some trace print inaccuracies
+ V4L/DVB (11194): pvrusb2: Implement mechanism to force a full sub-device update
+ V4L/DVB (11195): pvrusb2: Issue required core init broadcast to all sub-devices
+ V4L/DVB (11196): pvrusb2: Define default I2C addresses for msp3400 and saa7115 sub-devices
+ V4L/DVB (11197): pvrusb2: Fix incorrectly named sub-device ID
+ V4L/DVB (11198): pvrusb2: Define default I2C address for CS53L32A sub-device
+ V4L/DVB (11199): pvrusb2: Convert all device definitions to use new sub-device declarations
+ V4L/DVB (11200): pvrusb2: Make a bunch of dvb config structures const (trivial)
+ V4L/DVB (11201): pvrusb2: Fix space-after-comma idiocy
+ V4L/DVB (11202): pvrusb2: Fix slightly mis-leading header in debug interface output
+ V4L/DVB (11203): pvrusb2: Implement better reporting on attached sub-devices
+ V4L/DVB (11204): pvrusb2: Remove old i2c layer; we use v4l2-subdev now
+ V4L/DVB (11205): pvrusb2: Remove ancient IVTV specific ioctl functions
+ V4L/DVB (11206): pvrusb2: Add sub-device for demod
+ V4L/DVB (11207): pvrusb2: Add composite and s-video input support for OnAir devices
+ V4L/DVB (11208): pvrusb2: Use v4l2_device_disconnect()
+
+Márton Németh (2):
+ V4L/DVB (10633): DAB: fix typo
+ V4L/DVB (11293): uvcvideo: Add zero fill for VIDIOC_ENUM_FMT
+
+Nam Phạm Thành (1):
+ V4L/DVB (10242): pwc: add support for webcam snapshot button
+
+Nicola Soranzo (2):
+ V4L/DVB (10525): em28xx: Coding style fixes and a typo correction
+ V4L/DVB (10555): em28xx: CodingStyle fixes
+
+Oldřich Jedlička (1):
+ V4L/DVB (10632): Added support for AVerMedia Cardbus Hybrid remote control
+
+Oliver Endriss (1):
+ V4L/DVB (10843): saa7146: Clean-up i2c error handling
+
+Pascal Terjan (1):
+ V4L/DVB (10825): Add ids for Yuan PD378S DVB adapter
+
+Patrick Boettcher (2):
+ V4L/DVB (11284): Fix i2c code of flexcop-driver for rare revisions
+ V4L/DVB (11285): Remove unecessary udelay
+
+Philippe Rétornaz (1):
+ V4L/DVB (11035): mt9t031 bugfix
+
+Randy Dunlap (4):
+ V4L/DVB (10631): zoran: fix printk format
+ V4L/DVB (10830): dm1105: uses ir_* functions, select VIDEO_IR
+ V4L/DVB (10846): dvb/frontends: fix duplicate 'debug' symbol
+ V4L/DVB (11237): media/zoran: fix printk format
+
+Robert Krakora (3):
+ V4L/DVB (10255): em28xx: Clock (XCLK) Cleanup
+ V4L/DVB (10518): em28xx: Fix for em28xx memory leak and function rename
+ V4L/DVB (10519): em28xx: Fix for em28xx audio startup
+
+Robert Millan (1):
+ V4L/DVB (10944): Conceptronic CTVFMI2 PCI Id
+
+Roel Kluin (3):
+ V4L/DVB (10629): tvp514x: try_count reaches 0, not -1
+ V4L/DVB: calibration still successful at 10
+ V4L/DVB (10657): [PATCH] V4L: missing parentheses?
+
+Sascha Hauer (5):
+ V4L/DVB (11030): soc-camera: add board hook to specify the buswidth for camera sensors
+ V4L/DVB (11031): pcm990 baseboard: add camera bus width switch setting
+ V4L/DVB (11032): mt9m001: allow setting of bus width from board code
+ V4L/DVB (11033): mt9v022: allow setting of bus width from board code
+ V4L/DVB (11034): soc-camera: remove now unused gpio member of struct soc_camera_link
+
+Scott James Remnant (1):
+ V4L/DVB (10947): Auto-load videodev module when device opened.
+
+Sebastian Andrzej Siewior (1):
+ V4L/DVB (10655): tvp514x: make the module aware of rich people
+
+Sergio Aguirre (1):
+ V4L/DVB (10575): V4L2: Add COLORFX user control
+
+Sri Deevi (1):
+ V4L/DVB (10950): xc5000: prepare it to be used by cx231xx module
+
+Stephan Wienczny (1):
+ V4L/DVB (10949): Add support for Terratec Cinergy HT PCI MKII
+
+Steven Toth (1):
+ V4L/DVB (11296): cx23885: bugfix error message if firmware is not found
+
+Stoyan Gaydarov (1):
+ V4L/DVB (11235): changed ioctls to unlocked
+
+Theodore Kilgore (2):
+ V4L/DVB (10986): mr97310a: don't discard frame headers on stream output
+ V4L/DVB (11213): gspca - sq905c: New subdriver.
+
+Thierry MERLE (5):
+ V4L/DVB (10306): usbvision: use usb_make_path to report bus info
+ V4L/DVB (10307): em28xx: use usb_make_path to report bus info
+ V4L/DVB (10308): uvcvideo: use usb_make_path to report bus info
+ V4L/DVB (10309): s2255drv: use usb_make_path to report bus info
+ V4L/DVB (10379): gspca - main: Use usb_make_path() for VIDIOC_QUERYCAP.
+
+Tim Farrington (1):
+ V4L/DVB (10574): saa7134: fix Avermedia E506R composite input
+
+Tobias Klauser (1):
+ V4L/DVB (10628): V4L: Storage class should be before const qualifier
+
+Tobias Lorenz (3):
+ V4L/DVB (10530): Documentation and code cleanups
+ V4L/DVB (10531): Code rearrangements in preparation for other report types
+ V4L/DVB (10534): Output HW/SW version from scratchpad
+
+Trent Piepho (41):
+ V4L/DVB (10558): bttv: norm value should be unsigned
+ V4L/DVB (10559): bttv: Fix TDA9880 norm setting code
+ V4L/DVB (10560): bttv: make tuner card info more consistent
+ V4L/DVB (10561): bttv: store card database more efficiently
+ V4L/DVB (10562): bttv: rework the way digital inputs are indicated
+ V4L/DVB (10563): bttv: clean up mux code for IVC-120G
+ V4L/DVB (10564): bttv: fix external mux for PHYTEC VD-009
+ V4L/DVB (10565): bttv: fix external mux for RemoteVision MX
+ V4L/DVB (10566): bttv: clean up mux code for IDS Eagle
+ V4L/DVB (10567): bttv: shrink muxsel data in card database
+ V4L/DVB (10568): bttv: dynamically allocate device data
+ V4L/DVB (10791): videodev: not possible to register NULL video_device
+ V4L/DVB (10792): cx88: remove unnecessary forward declaration of cx88_core
+ V4L/DVB (10794): v4l2: Move code to zero querybuf output struct to v4l2_ioctl
+ V4L/DVB (10811): videodev: only copy needed part of RW ioctl's parameter
+ V4L/DVB (10812): v4l2: Zero out read-only ioctls in one place
+ V4L/DVB (10813): v4l2: New function v4l2_video_std_frame_period
+ V4L/DVB (10814): saa7146: some small fixes
+ V4L/DVB (10815): bttv: Don't need to zero ioctl parameter fields
+ V4L/DVB (10816): cx88: Don't need to zero ioctl parameter fields
+ V4L/DVB (10817): stkwebcam: Don't need to zero ioctl parameter fields
+ V4L/DVB (10818): usbvision: Don't need to zero ioctl parameter fields
+ V4L/DVB (10819): gspca: Don't need to zero ioctl parameter fields
+ V4L/DVB (10820): meye: Don't need to zero ioctl parameter fields
+ V4L/DVB (10848): zoran: Change first argument to zoran_v4l2_buffer_status
+ V4L/DVB (10930): zoran: Unify buffer descriptors
+ V4L/DVB (10933): zoran: Pass zoran_fh pointers instead of file pointers
+ V4L/DVB (10934): zoran: replace functions names in strings with __func__
+ V4L/DVB (11260): v4l2-ioctl: Check format for S_PARM and G_PARM
+ V4L/DVB (11261): saa7146: Remove buffer type check from vidioc_g_parm
+ V4L/DVB (11262): bttv: Remove buffer type check from vidioc_g_parm
+ V4L/DVB (11263): gspca: Stop setting buffer type, and avoid memset in querycap
+ V4L/DVB (11264): omap24xxcam: Remove buffer type check from vidioc_s/g_parm
+ V4L/DVB (11265): stkwebcam: Remove buffer type check from g_parm and q/dq/reqbufs
+ V4L/DVB (11266): vino: Remove code for things already done by video_ioctl2
+ V4L/DVB (11267): cafe_ccic: Remove buffer type check from XXXbuf
+ V4L/DVB (11268): cx23885-417: Don't need to zero ioctl parameter fields
+ V4L/DVB (11269): cx88-blackbird: Stop setting buffer type in XXX_fmt_vid_cap
+ V4L/DVB (11270): meye: Remove buffer type checks from XXX_fmt_vid_cap, XXXbuf
+ V4L/DVB (11271): usbvision: Remove buffer type checks from enum_fmt_vid_cap, XXXbuf
+ V4L/DVB (11272): zr364xx: Remove code for things already done by video_ioctl2
+
+Uri Shkolnik (2):
+ V4L/DVB (10748): sms1xxx: restore smsusb_driver.name to smsusb
+ V4L/DVB (10750): import changes from Siano
+
+Uwe Bugla (2):
+ V4L/DVB (11287): Code cleanup (passes checkpatch now) of the b2c2-flexcop-drivers 1/2
+ V4L/DVB (11288): Code cleanup (passes checkpatch now) of the b2c2-flexcop-drivers 2/2
+
+Vitaly Wool (1):
+ V4L/DVB (10833): em28xx: enable Compro VideoMate ForYou sound
+
+Xoan Loureiro (1):
+ V4L/DVB (11289): Patch for Yuan MC770 DVB-T (1164:0871)
+
+klaas de waal (1):
+ V4L/DVB (11236): tda827x: fix locking issues with DVB-C
+
+sebastian.blanes@gmail.com (1):
+ V4L/DVB (10824): Add "Sony PlayTV" to dibcom driver
+
+diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
+index f2e908d..2f21ecd 100644
+--- a/Documentation/dvb/get_dvb_firmware
++++ b/Documentation/dvb/get_dvb_firmware
+@@ -25,7 +25,7 @@ use IO::Handle;
+ "tda10046lifeview", "av7110", "dec2000t", "dec2540t",
+ "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
+ "or51211", "or51132_qam", "or51132_vsb", "bluebird",
+- "opera1");
++ "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2" );
+
+ # Check args
+ syntax() if (scalar(@ARGV) != 1);
+@@ -37,8 +37,8 @@ for ($i=0; $i < scalar(@components); $i++) {
+ $outfile = eval($cid);
+ die $@ if $@;
+ print STDERR <<EOF;
+-Firmware $outfile extracted successfully.
+-Now copy it to either /usr/lib/hotplug/firmware or /lib/firmware
++Firmware(s) $outfile extracted successfully.
++Now copy it(they) to either /usr/lib/hotplug/firmware or /lib/firmware
+ (depending on configuration of firmware hotplug).
+ EOF
+ exit(0);
+@@ -345,6 +345,85 @@ sub or51211 {
+ $fwfile;
+ }
+
++sub cx231xx {
++ my $fwfile = "v4l-cx231xx-avcore-01.fw";
++ my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
++ my $hash = "7d3bb956dc9df0eafded2b56ba57cc42";
++
++ checkstandard();
++
++ wgetfile($fwfile, $url);
++ verify($fwfile, $hash);
++
++ $fwfile;
++}
++
++sub cx18 {
++ my $url = "http://linuxtv.org/downloads/firmware/";
++
++ my %files = (
++ 'v4l-cx23418-apu.fw' => '588f081b562f5c653a3db1ad8f65939a',
++ 'v4l-cx23418-cpu.fw' => 'b6c7ed64bc44b1a6e0840adaeac39d79',
++ 'v4l-cx23418-dig.fw' => '95bc688d3e7599fd5800161e9971cc55',
++ );
++
++ checkstandard();
++
++ my $allfiles;
++ foreach my $fwfile (keys %files) {
++ wgetfile($fwfile, "$url/$fwfile");
++ verify($fwfile, $files{$fwfile});
++ $allfiles .= " $fwfile";
++ }
++
++ $allfiles =~ s/^\s//;
++
++ $allfiles;
++}
++
++sub cx23885 {
++ my $url = "http://linuxtv.org/downloads/firmware/";
++
++ my %files = (
++ 'v4l-cx23885-avcore-01.fw' => 'a9f8f5d901a7fb42f552e1ee6384f3bb',
++ 'v4l-cx23885-enc.fw' => 'a9f8f5d901a7fb42f552e1ee6384f3bb',
++ );
++
++ checkstandard();
++
++ my $allfiles;
++ foreach my $fwfile (keys %files) {
++ wgetfile($fwfile, "$url/$fwfile");
++ verify($fwfile, $files{$fwfile});
++ $allfiles .= " $fwfile";
++ }
++
++ $allfiles =~ s/^\s//;
++
++ $allfiles;
++}
++
++sub pvrusb2 {
++ my $url = "http://linuxtv.org/downloads/firmware/";
++
++ my %files = (
++ 'v4l-cx25840.fw' => 'dadb79e9904fc8af96e8111d9cb59320',
++ );
++
++ checkstandard();
++
++ my $allfiles;
++ foreach my $fwfile (keys %files) {
++ wgetfile($fwfile, "$url/$fwfile");
++ verify($fwfile, $files{$fwfile});
++ $allfiles .= " $fwfile";
++ }
++
++ $allfiles =~ s/^\s//;
++
++ $allfiles;
++}
++
+ sub or51132_qam {
+ my $fwfile = "dvb-fe-or51132-qam.fw";
+ my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
+index 20d3b94..6e5b914 100644
+--- a/Documentation/feature-removal-schedule.txt
++++ b/Documentation/feature-removal-schedule.txt
+@@ -37,10 +37,10 @@ Who: Pavel Machek <pavel@suse.cz>
+
+ ---------------------------
+
+-What: Video4Linux API 1 ioctls and video_decoder.h from Video devices.
+-When: December 2008
+-Files: include/linux/video_decoder.h include/linux/videodev.h
+-Check: include/linux/video_decoder.h include/linux/videodev.h
++What: Video4Linux API 1 ioctls and from Video devices.
++When: July 2009
++Files: include/linux/videodev.h
++Check: include/linux/videodev.h
+ Why: V4L1 AP1 was replaced by V4L2 API during migration from 2.4 to 2.6
+ series. The old API have lots of drawbacks and don't provide enough
+ means to work with all video and audio standards. The newer API is
+diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
+index f1d6399..1f779a2 100644
+--- a/Documentation/ioctl/ioctl-number.txt
++++ b/Documentation/ioctl/ioctl-number.txt
+@@ -122,10 +122,8 @@ Code Seq# Include File Comments
+ 'c' 00-7F linux/coda.h conflict!
+ 'c' 80-9F arch/s390/include/asm/chsc.h
+ 'd' 00-FF linux/char/drm/drm/h conflict!
+-'d' 00-DF linux/video_decoder.h conflict!
+ 'd' F0-FF linux/digi1.h
+ 'e' all linux/digi1.h conflict!
+-'e' 00-1F linux/video_encoder.h conflict!
+ 'e' 00-1F net/irda/irtty.h conflict!
+ 'f' 00-1F linux/ext2_fs.h
+ 'h' 00-7F Charon filesystem
+diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
+index 0d93fa1..f11c583 100644
+--- a/Documentation/video4linux/CARDLIST.bttv
++++ b/Documentation/video4linux/CARDLIST.bttv
+@@ -135,7 +135,7 @@
+ 134 -> Adlink RTV24
+ 135 -> DViCO FusionHDTV 5 Lite [18ac:d500]
+ 136 -> Acorp Y878F [9511:1540]
+-137 -> Conceptronic CTVFMi v2
++137 -> Conceptronic CTVFMi v2 [036e:109e]
+ 138 -> Prolink Pixelview PV-BT878P+ (Rev.2E)
+ 139 -> Prolink PixelView PlayTV MPEG2 PV-M4900
+ 140 -> Osprey 440 [0070:ff07]
+@@ -154,3 +154,7 @@
+ 153 -> PHYTEC VD-012 (bt878)
+ 154 -> PHYTEC VD-012-X1 (bt878)
+ 155 -> PHYTEC VD-012-X2 (bt878)
++156 -> IVCE-8784 [0000:f050,0001:f050,0002:f050,0003:f050]
++157 -> Geovision GV-800(S) (master) [800a:763d]
++158 -> Geovision GV-800(S) (slave) [800b:763d,800c:763d,800d:763d]
++159 -> ProVideo PV183 [1830:1540,1831:1540,1832:1540,1833:1540,1834:1540,1835:1540,1836:1540,1837:1540]
+diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
+index 35ea130..91aa3c0 100644
+--- a/Documentation/video4linux/CARDLIST.cx23885
++++ b/Documentation/video4linux/CARDLIST.cx23885
+@@ -12,3 +12,7 @@
+ 11 -> DViCO FusionHDTV DVB-T Dual Express [18ac:db78]
+ 12 -> Leadtek Winfast PxDVR3200 H [107d:6681]
+ 13 -> Compro VideoMate E650F [185b:e800]
++ 14 -> TurboSight TBS 6920 [6920:8888]
++ 15 -> TeVii S470 [d470:9022]
++ 16 -> DVBWorld DVB-S2 2005 [0001:2005]
++ 17 -> NetUP Dual DVB-S2 CI [1b55:2a2c]
+diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
+index 0d08f1e..71e9db0 100644
+--- a/Documentation/video4linux/CARDLIST.cx88
++++ b/Documentation/video4linux/CARDLIST.cx88
+@@ -77,3 +77,4 @@
+ 76 -> SATTRADE ST4200 DVB-S/S2 [b200:4200]
+ 77 -> TBS 8910 DVB-S [8910:8888]
+ 78 -> Prof 6200 DVB-S [b022:3022]
++ 79 -> Terratec Cinergy HT PCI MKII [153b:1177]
+diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
+index 75bded8..78d0a6e 100644
+--- a/Documentation/video4linux/CARDLIST.em28xx
++++ b/Documentation/video4linux/CARDLIST.em28xx
+@@ -7,12 +7,12 @@
+ 6 -> Terratec Cinergy 200 USB (em2800)
+ 7 -> Leadtek Winfast USB II (em2800) [0413:6023]
+ 8 -> Kworld USB2800 (em2800)
+- 9 -> Pinnacle Dazzle DVC 90/DVC 100 (em2820/em2840) [2304:0207,2304:021a]
++ 9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker (em2820/em2840) [1b80:e302,2304:0207,2304:021a]
+ 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500]
+ 11 -> Terratec Hybrid XS (em2880) [0ccd:0042]
+ 12 -> Kworld PVR TV 2800 RF (em2820/em2840)
+ 13 -> Terratec Prodigy XS (em2880) [0ccd:0047]
+- 14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840)
++ 14 -> SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0 (em2820/em2840)
+ 15 -> V-Gear PocketTV (em2800)
+ 16 -> Hauppauge WinTV HVR 950 (em2883) [2040:6513,2040:6517,2040:651b]
+ 17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227]
+@@ -30,7 +30,6 @@
+ 30 -> Videology 20K14XUSB USB2.0 (em2820/em2840)
+ 31 -> Usbgear VD204v9 (em2821)
+ 32 -> Supercomp USB 2.0 TV (em2821)
+- 33 -> SIIG AVTuner-PVR/Prolink PlayTV USB 2.0 (em2821)
+ 34 -> Terratec Cinergy A Hybrid XS (em2860) [0ccd:004f]
+ 35 -> Typhoon DVD Maker (em2860)
+ 36 -> NetGMBH Cam (em2860)
+@@ -58,3 +57,7 @@
+ 58 -> Compro VideoMate ForYou/Stereo (em2820/em2840) [185b:2041]
+ 60 -> Hauppauge WinTV HVR 850 (em2883) [2040:651f]
+ 61 -> Pixelview PlayTV Box 4 USB 2.0 (em2820/em2840)
++ 62 -> Gadmei TVR200 (em2820/em2840)
++ 63 -> Kaiomy TVnPC U2 (em2860) [eb1a:e303]
++ 64 -> Easy Cap Capture DC-60 (em2860)
++ 65 -> IO-DATA GV-MVP/SZ (em2820/em2840) [04bb:0515]
+diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
+index b8d4705..6dacf28 100644
+--- a/Documentation/video4linux/CARDLIST.saa7134
++++ b/Documentation/video4linux/CARDLIST.saa7134
+@@ -153,3 +153,5 @@
+ 152 -> Asus Tiger Rev:1.00 [1043:4857]
+ 153 -> Kworld Plus TV Analog Lite PCI [17de:7128]
+ 154 -> Avermedia AVerTV GO 007 FM Plus [1461:f31d]
++155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid [0070:6706,0070:6708]
++156 -> Hauppauge WinTV-HVR1110r3 [0070:6707,0070:6709,0070:670a]
+diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
+index 295462b..0e89e76 100644
+--- a/Documentation/video4linux/Zoran
++++ b/Documentation/video4linux/Zoran
+@@ -401,8 +401,7 @@ Additional notes for software developers:
+ first set the correct norm. Well, it seems logically correct: TV
+ standard is "more constant" for current country than geometry
+ 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.
++ square pixel format.
+ --
+ Please note that lavplay/lavrec are also included in the MJPEG-tools
+ (http://mjpeg.sf.net/).
+diff --git a/Documentation/video4linux/bttv/Insmod-options b/Documentation/video4linux/bttv/Insmod-options
+index 5ef7578..bbe3ed6 100644
+--- a/Documentation/video4linux/bttv/Insmod-options
++++ b/Documentation/video4linux/bttv/Insmod-options
+@@ -81,16 +81,6 @@ tuner.o
+ pal=[bdgil] select PAL variant (used for some tuners
+ only, important for the audio carrier).
+
+-tvmixer.o
+- registers a mixer device for the TV card's volume/bass/treble
+- controls (requires a i2c audio control chip like the msp3400).
+-
+- insmod args:
+- debug=1 print some debug info to the syslog.
+- devnr=n allocate device #n (0 == /dev/mixer,
+- 1 = /dev/mixer1, ...), default is to
+- use the first free one.
+-
+ tvaudio.o
+ new, experimental module which is supported to provide a single
+ driver for all simple i2c audio control chips (tda/tea*).
+diff --git a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README
+index 7ca2154..3a367cd 100644
+--- a/Documentation/video4linux/bttv/README
++++ b/Documentation/video4linux/bttv/README
+@@ -63,8 +63,8 @@ If you have some knowledge and spare time, please try to fix this
+ yourself (patches very welcome of course...) You know: The linux
+ slogan is "Do it yourself".
+
+-There is a mailing list: video4linux-list@redhat.com.
+-https://listman.redhat.com/mailman/listinfo/video4linux-list
++There is a mailing list: linux-media@vger.kernel.org
++http://vger.kernel.org/vger-lists.html#linux-media
+
+ If you have trouble with some specific TV card, try to ask there
+ instead of mailing me directly. The chance that someone with the
+diff --git a/Documentation/video4linux/cx2341x/README.hm12 b/Documentation/video4linux/cx2341x/README.hm12
+index 0e213ed..b36148e 100644
+--- a/Documentation/video4linux/cx2341x/README.hm12
++++ b/Documentation/video4linux/cx2341x/README.hm12
+@@ -32,6 +32,10 @@ Y, U and V planes. This code assumes frames of 720x576 (PAL) pixels.
+ The width of a frame is always 720 pixels, regardless of the actual specified
+ width.
+
++If the height is not a multiple of 32 lines, then the captured video is
++missing macroblocks at the end and is unusable. So the height must be a
++multiple of 32.
++
+ --------------------------------------------------------------------------
+
+ #include <stdio.h>
+diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
+index 1c58a76..98529e0 100644
+--- a/Documentation/video4linux/gspca.txt
++++ b/Documentation/video4linux/gspca.txt
+@@ -32,6 +32,7 @@ spca561 041e:403b Creative Webcam Vista (VF0010)
+ zc3xx 041e:4051 Creative Live!Cam Notebook Pro (VF0250)
+ ov519 041e:4052 Creative Live! VISTA IM
+ zc3xx 041e:4053 Creative Live!Cam Video IM
++vc032x 041e:405b Creative Live! Cam Notebook Ultra (VC0130)
+ ov519 041e:405f Creative Live! VISTA VF0330
+ ov519 041e:4060 Creative Live! VISTA VF0350
+ ov519 041e:4061 Creative Live! VISTA VF0400
+@@ -193,6 +194,7 @@ spca500 084d:0003 D-Link DSC-350
+ spca500 08ca:0103 Aiptek PocketDV
+ sunplus 08ca:0104 Aiptek PocketDVII 1.3
+ sunplus 08ca:0106 Aiptek Pocket DV3100+
++mr97310a 08ca:0111 Aiptek PenCam VGA+
+ sunplus 08ca:2008 Aiptek Mini PenCam 2 M
+ sunplus 08ca:2010 Aiptek PocketCam 3M
+ sunplus 08ca:2016 Aiptek PocketCam 2 Mega
+@@ -215,6 +217,7 @@ pac207 093a:2468 PAC207
+ pac207 093a:2470 Genius GF112
+ pac207 093a:2471 Genius VideoCam ge111
+ pac207 093a:2472 Genius VideoCam ge110
++pac207 093a:2474 Genius iLook 111
+ pac207 093a:2476 Genius e-Messenger 112
+ pac7311 093a:2600 PAC7311 Typhoon
+ pac7311 093a:2601 Philips SPC 610 NC
+@@ -279,6 +282,7 @@ spca561 10fd:7e50 FlyCam Usb 100
+ zc3xx 10fd:8050 Typhoon Webshot II USB 300k
+ ov534 1415:2000 Sony HD Eye for PS3 (SLEH 00201)
+ pac207 145f:013a Trust WB-1300N
++vc032x 15b8:6001 HP 2.0 Megapixel
+ vc032x 15b8:6002 HP 2.0 Megapixel rz406aa
+ spca501 1776:501c Arowana 300K CMOS Camera
+ t613 17a1:0128 TASCORP JPEG Webcam, NGS Cyclops
+diff --git a/Documentation/video4linux/si470x.txt b/Documentation/video4linux/si470x.txt
+index 49679e6..3a7823e 100644
+--- a/Documentation/video4linux/si470x.txt
++++ b/Documentation/video4linux/si470x.txt
+@@ -1,6 +1,6 @@
+ Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers
+
+-Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net>
++Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
+
+
+ Information from Silicon Labs
+@@ -41,7 +41,7 @@ chips are known to work:
+ - 10c4:818a: Silicon Labs USB FM Radio Reference Design
+ - 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
+ - 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
+-- 10c5:819a: DealExtreme USB Radio
++- 10c5:819a: Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear)
+
+
+ Software
+@@ -52,6 +52,7 @@ Testing is usually done with most application under Debian/testing:
+ - gradio - GTK FM radio tuner
+ - kradio - Comfortable Radio Application for KDE
+ - radio - ncurses-based radio application
++- mplayer - The Ultimate Movie Player For Linux
+
+ There is also a library libv4l, which can be used. It's going to have a function
+ for frequency seeking, either by using hardware functionality as in radio-si470x
+@@ -69,7 +70,7 @@ Audio Listing
+ USB Audio is provided by the ALSA snd_usb_audio module. It is recommended to
+ also select SND_USB_AUDIO, as this is required to get sound from the radio. For
+ listing you have to redirect the sound, for example using one of the following
+-commands.
++commands. Please adjust the audio devices to your needs (/dev/dsp* and hw:x,x).
+
+ If you just want to test audio (very poor quality):
+ cat /dev/dsp1 > /dev/dsp
+@@ -80,6 +81,10 @@ sox -2 --endian little -r 96000 -t oss /dev/dsp1 -t oss /dev/dsp
+ If you use arts try:
+ arecord -D hw:1,0 -r96000 -c2 -f S16_LE | artsdsp aplay -B -
+
++If you use mplayer try:
++mplayer -radio adevice=hw=1.0:arate=96000 \
++ -rawaudio rate=96000 \
++ radio://<frequency>/capture
+
+ Module Parameters
+ =================
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index ff12437..a311773 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -47,7 +47,9 @@ All drivers have the following structure:
+ 3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX, /dev/radioX and
+ /dev/vtxX) and keeping track of device-node specific data.
+
+-4) Filehandle-specific structs containing per-filehandle data.
++4) Filehandle-specific structs containing per-filehandle data;
++
++5) video buffer handling.
+
+ This is a rough schematic of how it all relates:
+
+@@ -82,12 +84,20 @@ You must register the device instance:
+ v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+
+ Registration will initialize the v4l2_device struct and link dev->driver_data
+-to v4l2_dev. Registration will also set v4l2_dev->name to a value derived from
+-dev (driver name followed by the bus_id, to be precise). You may change the
+-name after registration if you want.
++to v4l2_dev. If v4l2_dev->name is empty then it will be set to a value derived
++from dev (driver name followed by the bus_id, to be precise). If you set it
++up before calling v4l2_device_register then it will be untouched. If dev is
++NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
+
+ The first 'dev' argument is normally the struct device pointer of a pci_dev,
+-usb_device or platform_device.
++usb_device or platform_device. It is rare for dev to be NULL, but it happens
++with ISA devices or when one device creates multiple PCI devices, thus making
++it impossible to associate v4l2_dev with a particular parent.
++
++You can also supply a notify() callback that can be called by sub-devices to
++notify you of events. Whether you need to set this depends on the sub-device.
++Any notifications a sub-device supports must be defined in a header in
++include/media/<subdevice>.h.
+
+ You unregister with:
+
+@@ -95,6 +105,17 @@ You unregister with:
+
+ Unregistering will also automatically unregister all subdevs from the device.
+
++If you have a hotpluggable device (e.g. a USB device), then when a disconnect
++happens the parent device becomes invalid. Since v4l2_device has a pointer to
++that parent device it has to be cleared as well to mark that the parent is
++gone. To do this call:
++
++ v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
++
++This does *not* unregister the subdevs, so you still need to call the
++v4l2_device_unregister() function for that. If your driver is not hotpluggable,
++then there is no need to call v4l2_device_disconnect().
++
+ Sometimes you need to iterate over all devices registered by a specific
+ driver. This is usually the case if multiple device drivers use the same
+ hardware. E.g. the ivtvfb driver is a framebuffer driver that uses the ivtv
+@@ -134,7 +155,7 @@ The recommended approach is as follows:
+
+ static atomic_t drv_instance = ATOMIC_INIT(0);
+
+-static int __devinit drv_probe(struct pci_dev *dev,
++static int __devinit drv_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+ {
+ ...
+@@ -218,7 +239,7 @@ to add new ops and categories.
+
+ A sub-device driver initializes the v4l2_subdev struct using:
+
+- v4l2_subdev_init(subdev, &ops);
++ v4l2_subdev_init(sd, &ops);
+
+ Afterwards you need to initialize subdev->name with a unique name and set the
+ module owner. This is done for you if you use the i2c helper functions.
+@@ -226,7 +247,7 @@ module owner. This is done for you if you use the i2c helper functions.
+ A device (bridge) driver needs to register the v4l2_subdev with the
+ v4l2_device:
+
+- int err = v4l2_device_register_subdev(device, subdev);
++ int err = v4l2_device_register_subdev(v4l2_dev, sd);
+
+ This can fail if the subdev module disappeared before it could be registered.
+ After this function was called successfully the subdev->dev field points to
+@@ -234,17 +255,17 @@ the v4l2_device.
+
+ You can unregister a sub-device using:
+
+- v4l2_device_unregister_subdev(subdev);
++ v4l2_device_unregister_subdev(sd);
+
+-Afterwards the subdev module can be unloaded and subdev->dev == NULL.
++Afterwards the subdev module can be unloaded and sd->dev == NULL.
+
+ You can call an ops function either directly:
+
+- err = subdev->ops->core->g_chip_ident(subdev, &chip);
++ err = sd->ops->core->g_chip_ident(sd, &chip);
+
+ but it is better and easier to use this macro:
+
+- err = v4l2_subdev_call(subdev, core, g_chip_ident, &chip);
++ err = v4l2_subdev_call(sd, core, g_chip_ident, &chip);
+
+ The macro will to the right NULL pointer checks and returns -ENODEV if subdev
+ is NULL, -ENOIOCTLCMD if either subdev->core or subdev->core->g_chip_ident is
+@@ -252,19 +273,19 @@ NULL, or the actual result of the subdev->ops->core->g_chip_ident ops.
+
+ It is also possible to call all or a subset of the sub-devices:
+
+- v4l2_device_call_all(dev, 0, core, g_chip_ident, &chip);
++ v4l2_device_call_all(v4l2_dev, 0, core, g_chip_ident, &chip);
+
+ Any subdev that does not support this ops is skipped and error results are
+ ignored. If you want to check for errors use this:
+
+- err = v4l2_device_call_until_err(dev, 0, core, g_chip_ident, &chip);
++ err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_chip_ident, &chip);
+
+ Any error except -ENOIOCTLCMD will exit the loop with that error. If no
+ errors (except -ENOIOCTLCMD) occured, then 0 is returned.
+
+ The second argument to both calls is a group ID. If 0, then all subdevs are
+ called. If non-zero, then only those whose group ID match that value will
+-be called. Before a bridge driver registers a subdev it can set subdev->grp_id
++be called. Before a bridge driver registers a subdev it can set sd->grp_id
+ to whatever value it wants (it's 0 by default). This value is owned by the
+ bridge driver and the sub-device driver will never modify or use it.
+
+@@ -276,6 +297,11 @@ e.g. AUDIO_CONTROLLER and specify that as the group ID value when calling
+ v4l2_device_call_all(). That ensures that it will only go to the subdev
+ that needs it.
+
++If the sub-device needs to notify its v4l2_device parent of an event, then
++it can call v4l2_subdev_notify(sd, notification, arg). This macro checks
++whether there is a notify() callback defined and returns -ENODEV if not.
++Otherwise the result of the notify() call is returned.
++
+ The advantage of using v4l2_subdev is that it is a generic struct and does
+ not contain any knowledge about the underlying hardware. So a driver might
+ contain several subdevs that use an I2C bus, but also a subdev that is
+@@ -340,6 +366,12 @@ Make sure to call v4l2_device_unregister_subdev(sd) when the remove() callback
+ is called. This will unregister the sub-device from the bridge driver. It is
+ safe to call this even if the sub-device was never registered.
+
++You need to do this because when the bridge driver destroys the i2c adapter
++the remove() callbacks are called of the i2c devices on that adapter.
++After that the corresponding v4l2_subdev structures are invalid, so they
++have to be unregistered first. Calling v4l2_device_unregister_subdev(sd)
++from the remove() callback ensures that this is always done correctly.
++
+
+ The bridge driver also has some helper functions it can use:
+
+@@ -349,8 +381,8 @@ This loads the given module (can be NULL if no module needs to be loaded) and
+ calls i2c_new_device() with the given i2c_adapter and chip/address arguments.
+ If all goes well, then it registers the subdev with the v4l2_device. It gets
+ the v4l2_device by calling i2c_get_adapdata(adapter), so you should make sure
+-that adapdata is set to v4l2_device when you setup the i2c_adapter in your
+-driver.
++to call i2c_set_adapdata(adapter, v4l2_device) when you setup the i2c_adapter
++in your driver.
+
+ You can also use v4l2_i2c_new_probed_subdev() which is very similar to
+ v4l2_i2c_new_subdev(), except that it has an array of possible I2C addresses
+@@ -358,6 +390,14 @@ that it should probe. Internally it calls i2c_new_probed_device().
+
+ Both functions return NULL if something went wrong.
+
++Note that the chipid you pass to v4l2_i2c_new_(probed_)subdev() is usually
++the same as the module name. It allows you to specify a chip variant, e.g.
++"saa7114" or "saa7115". In general though the i2c driver autodetects this.
++The use of chipid is something that needs to be looked at more closely at a
++later date. It differs between i2c drivers and as such can be confusing.
++To see which chip variants are supported you can look in the i2c driver code
++for the i2c_device_id table. This lists all the possibilities.
++
+
+ struct video_device
+ -------------------
+@@ -396,6 +436,15 @@ You should also set these fields:
+ - ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
+ (highly recommended to use this and it might become compulsory in the
+ future!), then set this to your v4l2_ioctl_ops struct.
++- parent: you only set this if v4l2_device was registered with NULL as
++ the parent device struct. This only happens in cases where one hardware
++ device has multiple PCI devices that all share the same v4l2_device core.
++
++ The cx88 driver is an example of this: one core v4l2_device struct, but
++ it is used by both an raw video PCI device (cx8800) and a MPEG PCI device
++ (cx8802). Since the v4l2_device cannot be associated with a particular
++ PCI device it is setup without a parent device. But when the struct
++ video_device is setup you do know which parent PCI device to use.
+
+ If you use v4l2_ioctl_ops, then you should set either .unlocked_ioctl or
+ .ioctl to video_ioctl2 in your v4l2_file_operations struct.
+@@ -499,8 +548,8 @@ There are a few useful helper functions:
+
+ You can set/get driver private data in the video_device struct using:
+
+-void *video_get_drvdata(struct video_device *dev);
+-void video_set_drvdata(struct video_device *dev, void *data);
++void *video_get_drvdata(struct video_device *vdev);
++void video_set_drvdata(struct video_device *vdev, void *data);
+
+ Note that you can safely call video_set_drvdata() before calling
+ video_register_device().
+@@ -519,3 +568,103 @@ void *video_drvdata(struct file *file);
+ You can go from a video_device struct to the v4l2_device struct using:
+
+ struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
++
++video buffer helper functions
++-----------------------------
++
++The v4l2 core API provides a standard method for dealing with video
++buffers. Those methods allow a driver to implement read(), mmap() and
++overlay() on a consistent way.
++
++There are currently methods for using video buffers on devices that
++supports DMA with scatter/gather method (videobuf-dma-sg), DMA with
++linear access (videobuf-dma-contig), and vmalloced buffers, mostly
++used on USB drivers (videobuf-vmalloc).
++
++Any driver using videobuf should provide operations (callbacks) for
++four handlers:
++
++ops->buf_setup - calculates the size of the video buffers and avoid they
++ to waste more than some maximum limit of RAM;
++ops->buf_prepare - fills the video buffer structs and calls
++ videobuf_iolock() to alloc and prepare mmaped memory;
++ops->buf_queue - advices the driver that another buffer were
++ requested (by read() or by QBUF);
++ops->buf_release - frees any buffer that were allocated.
++
++In order to use it, the driver need to have a code (generally called at
++interrupt context) that will properly handle the buffer request lists,
++announcing that a new buffer were filled.
++
++The irq handling code should handle the videobuf task lists, in order
++to advice videobuf that a new frame were filled, in order to honor to a
++request. The code is generally like this one:
++ if (list_empty(&dma_q->active))
++ return;
++
++ buf = list_entry(dma_q->active.next, struct vbuffer, vb.queue);
++
++ if (!waitqueue_active(&buf->vb.done))
++ return;
++
++ /* Some logic to handle the buf may be needed here */
++
++ list_del(&buf->vb.queue);
++ do_gettimeofday(&buf->vb.ts);
++ wake_up(&buf->vb.done);
++
++Those are the videobuffer functions used on drivers, implemented on
++videobuf-core:
++
++- Videobuf init functions
++ videobuf_queue_sg_init()
++ Initializes the videobuf infrastructure. This function should be
++ called before any other videobuf function on drivers that uses DMA
++ Scatter/Gather buffers.
++
++ videobuf_queue_dma_contig_init
++ Initializes the videobuf infrastructure. This function should be
++ called before any other videobuf function on drivers that need DMA
++ contiguous buffers.
++
++ videobuf_queue_vmalloc_init()
++ Initializes the videobuf infrastructure. This function should be
++ called before any other videobuf function on USB (and other drivers)
++ that need a vmalloced type of videobuf.
++
++- videobuf_iolock()
++ Prepares the videobuf memory for the proper method (read, mmap, overlay).
++
++- videobuf_queue_is_busy()
++ Checks if a videobuf is streaming.
++
++- videobuf_queue_cancel()
++ Stops video handling.
++
++- videobuf_mmap_free()
++ frees mmap buffers.
++
++- videobuf_stop()
++ Stops video handling, ends mmap and frees mmap and other buffers.
++
++- V4L2 api functions. Those functions correspond to VIDIOC_foo ioctls:
++ videobuf_reqbufs(), videobuf_querybuf(), videobuf_qbuf(),
++ videobuf_dqbuf(), videobuf_streamon(), videobuf_streamoff().
++
++- V4L1 api function (corresponds to VIDIOCMBUF ioctl):
++ videobuf_cgmbuf()
++ This function is used to provide backward compatibility with V4L1
++ API.
++
++- Some help functions for read()/poll() operations:
++ videobuf_read_stream()
++ For continuous stream read()
++ videobuf_read_one()
++ For snapshot read()
++ videobuf_poll_stream()
++ polling help function
++
++The better way to understand it is to take a look at vivi driver. One
++of the main reasons for vivi is to be a videobuf usage example. the
++vivi_thread_tick() does the task that the IRQ callback would do on PCI
++drivers (or the irq callback on USB).
+diff --git a/Documentation/video4linux/v4lgrab.c b/Documentation/video4linux/v4lgrab.c
+index d6e70be..05769cf 100644
+--- a/Documentation/video4linux/v4lgrab.c
++++ b/Documentation/video4linux/v4lgrab.c
+@@ -105,8 +105,8 @@ int main(int argc, char ** argv)
+ struct video_picture vpic;
+
+ unsigned char *buffer, *src;
+- int bpp = 24, r, g, b;
+- unsigned int i, src_depth;
++ int bpp = 24, r = 0, g = 0, b = 0;
++ unsigned int i, src_depth = 16;
+
+ if (fd < 0) {
+ perror(VIDEO_DEV);
+diff --git a/Documentation/video4linux/zr364xx.txt b/Documentation/video4linux/zr364xx.txt
+index 5c81e3a..7f3d195 100644
+--- a/Documentation/video4linux/zr364xx.txt
++++ b/Documentation/video4linux/zr364xx.txt
+@@ -65,3 +65,4 @@ Vendor Product Distributor Model
+ 0x06d6 0x003b Trust Powerc@m 970Z
+ 0x0a17 0x004e Pentax Optio 50
+ 0x041e 0x405d Creative DiVi CAM 516
++0x08ca 0x2102 Aiptek DV T300
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 5d460c9..b41a4dc 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1040,7 +1040,6 @@ BTTV VIDEO4LINUX DRIVER
+ P: Mauro Carvalho Chehab
+ M: mchehab@infradead.org
+ L: linux-media@vger.kernel.org
+-L: video4linux-list@redhat.com
+ W: http://linuxtv.org
+ T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+ S: Maintained
+@@ -4746,7 +4745,6 @@ VIDEO FOR LINUX (V4L)
+ P: Mauro Carvalho Chehab
+ M: mchehab@infradead.org
+ L: linux-media@vger.kernel.org
+-L: video4linux-list@redhat.com
+ W: http://linuxtv.org
+ T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+ S: Maintained
+diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
+index 34841c7..fd8f786 100644
+--- a/arch/arm/mach-pxa/pcm990-baseboard.c
++++ b/arch/arm/mach-pxa/pcm990-baseboard.c
+@@ -381,14 +381,49 @@ static struct pca953x_platform_data pca9536_data = {
+ .gpio_base = NR_BUILTIN_GPIO + 1,
+ };
+
+-static struct soc_camera_link iclink[] = {
+- {
+- .bus_id = 0, /* Must match with the camera ID above */
+- .gpio = NR_BUILTIN_GPIO + 1,
+- }, {
+- .bus_id = 0, /* Must match with the camera ID above */
+- .gpio = -ENXIO,
++static int gpio_bus_switch;
++
++static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
++ unsigned long flags)
++{
++ if (gpio_bus_switch <= 0) {
++ if (flags == SOCAM_DATAWIDTH_10)
++ return 0;
++ else
++ return -EINVAL;
++ }
++
++ if (flags & SOCAM_DATAWIDTH_8)
++ gpio_set_value(gpio_bus_switch, 1);
++ else
++ gpio_set_value(gpio_bus_switch, 0);
++
++ return 0;
++}
++
++static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link)
++{
++ int ret;
++
++ if (!gpio_bus_switch) {
++ ret = gpio_request(NR_BUILTIN_GPIO + 1, "camera");
++ if (!ret) {
++ gpio_bus_switch = NR_BUILTIN_GPIO + 1;
++ gpio_direction_output(gpio_bus_switch, 0);
++ } else
++ gpio_bus_switch = -EINVAL;
+ }
++
++ if (gpio_bus_switch > 0)
++ return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
++ else
++ return SOCAM_DATAWIDTH_10;
++}
++
++static struct soc_camera_link iclink = {
++ .bus_id = 0, /* Must match with the camera ID above */
++ .query_bus_param = pcm990_camera_query_bus_param,
++ .set_bus_param = pcm990_camera_set_bus_param,
+ };
+
+ /* Board I2C devices. */
+@@ -399,10 +434,10 @@ static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
+ .platform_data = &pca9536_data,
+ }, {
+ I2C_BOARD_INFO("mt9v022", 0x48),
+- .platform_data = &iclink[0], /* With extender */
++ .platform_data = &iclink, /* With extender */
+ }, {
+ I2C_BOARD_INFO("mt9m001", 0x5d),
+- .platform_data = &iclink[0], /* With extender */
++ .platform_data = &iclink, /* With extender */
+ },
+ };
+ #endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
+diff --git a/arch/arm/plat-mxc/include/mach/mx3_camera.h b/arch/arm/plat-mxc/include/mach/mx3_camera.h
+new file mode 100644
+index 0000000..36d7ff2
+--- /dev/null
++++ b/arch/arm/plat-mxc/include/mach/mx3_camera.h
+@@ -0,0 +1,52 @@
++/*
++ * mx3_camera.h - i.MX3x camera driver header file
++ *
++ * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.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 _MX3_CAMERA_H_
++#define _MX3_CAMERA_H_
++
++#include <linux/device.h>
++
++#define MX3_CAMERA_CLK_SRC 1
++#define MX3_CAMERA_EXT_VSYNC 2
++#define MX3_CAMERA_DP 4
++#define MX3_CAMERA_PCP 8
++#define MX3_CAMERA_HSP 0x10
++#define MX3_CAMERA_VSP 0x20
++#define MX3_CAMERA_DATAWIDTH_4 0x40
++#define MX3_CAMERA_DATAWIDTH_8 0x80
++#define MX3_CAMERA_DATAWIDTH_10 0x100
++#define MX3_CAMERA_DATAWIDTH_15 0x200
++
++#define MX3_CAMERA_DATAWIDTH_MASK (MX3_CAMERA_DATAWIDTH_4 | MX3_CAMERA_DATAWIDTH_8 | \
++ MX3_CAMERA_DATAWIDTH_10 | MX3_CAMERA_DATAWIDTH_15)
++
++/**
++ * struct mx3_camera_pdata - i.MX3x camera platform data
++ * @flags: MX3_CAMERA_* flags
++ * @mclk_10khz: master clock frequency in 10kHz units
++ * @dma_dev: IPU DMA device to match against in channel allocation
++ */
++struct mx3_camera_pdata {
++ unsigned long flags;
++ unsigned long mclk_10khz;
++ struct device *dma_dev;
++};
++
++#endif
+diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c
+index 15b6d45..5188adc 100644
+--- a/arch/sh/boards/board-ap325rxa.c
++++ b/arch/sh/boards/board-ap325rxa.c
+@@ -299,7 +299,8 @@ static struct platform_device camera_device = {
+
+ static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
+ .flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
+- SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8,
++ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER |
++ SOCAM_DATAWIDTH_8,
+ };
+
+ static struct resource ceu_resources[] = {
+diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
+index 28e56c5..6d63959 100644
+--- a/arch/sh/boards/mach-migor/setup.c
++++ b/arch/sh/boards/mach-migor/setup.c
+@@ -352,8 +352,9 @@ static int tw9910_power(struct device *dev, int mode)
+ }
+
+ static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
+- .flags = SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_PCLK_SAMPLE_RISING \
+- | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH,
++ .flags = SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_PCLK_SAMPLE_RISING
++ | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH
++ | SOCAM_DATA_ACTIVE_HIGH,
+ };
+
+ static struct resource migor_ceu_resources[] = {
+diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
+index 93ea201..223c36e 100644
+--- a/drivers/media/Kconfig
++++ b/drivers/media/Kconfig
+@@ -117,7 +117,7 @@ source "drivers/media/dvb/Kconfig"
+ config DAB
+ boolean "DAB adapters"
+ ---help---
+- Allow selecting support for for Digital Audio Broadcasting (DAB)
++ Allow selecting support for Digital Audio Broadcasting (DAB)
+ Receiver adapters.
+
+ if DAB
+diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
+index d8229a0..3fe158a 100644
+--- a/drivers/media/common/ir-keymaps.c
++++ b/drivers/media/common/ir-keymaps.c
+@@ -153,6 +153,65 @@ IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE] = {
+ };
+ EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a);
+
++/* Oldrich Jedlicka <oldium.pro@seznam.cz> */
++IR_KEYTAB_TYPE ir_codes_avermedia_cardbus[IR_KEYTAB_SIZE] = {
++ [0x00] = KEY_POWER,
++ [0x01] = KEY_TUNER, /* TV/FM */
++ [0x03] = KEY_TEXT, /* Teletext */
++ [0x04] = KEY_EPG,
++ [0x05] = KEY_1,
++ [0x06] = KEY_2,
++ [0x07] = KEY_3,
++ [0x08] = KEY_AUDIO,
++ [0x09] = KEY_4,
++ [0x0a] = KEY_5,
++ [0x0b] = KEY_6,
++ [0x0c] = KEY_ZOOM, /* Full screen */
++ [0x0d] = KEY_7,
++ [0x0e] = KEY_8,
++ [0x0f] = KEY_9,
++ [0x10] = KEY_PAGEUP, /* 16-CH PREV */
++ [0x11] = KEY_0,
++ [0x12] = KEY_INFO,
++ [0x13] = KEY_AGAIN, /* CH RTN - channel return */
++ [0x14] = KEY_MUTE,
++ [0x15] = KEY_EDIT, /* Autoscan */
++ [0x17] = KEY_SAVE, /* Screenshot */
++ [0x18] = KEY_PLAYPAUSE,
++ [0x19] = KEY_RECORD,
++ [0x1a] = KEY_PLAY,
++ [0x1b] = KEY_STOP,
++ [0x1c] = KEY_FASTFORWARD,
++ [0x1d] = KEY_REWIND,
++ [0x1e] = KEY_VOLUMEDOWN,
++ [0x1f] = KEY_VOLUMEUP,
++ [0x22] = KEY_SLEEP, /* Sleep */
++ [0x23] = KEY_ZOOM, /* Aspect */
++ [0x26] = KEY_SCREEN, /* Pos */
++ [0x27] = KEY_ANGLE, /* Size */
++ [0x28] = KEY_SELECT, /* Select */
++ [0x29] = KEY_BLUE, /* Blue/Picture */
++ [0x2a] = KEY_BACKSPACE, /* Back */
++ [0x2b] = KEY_MEDIA, /* PIP (Picture-in-picture) */
++ [0x2c] = KEY_DOWN,
++ [0x2e] = KEY_DOT,
++ [0x2f] = KEY_TV, /* Live TV */
++ [0x32] = KEY_LEFT,
++ [0x33] = KEY_CLEAR, /* Clear */
++ [0x35] = KEY_RED, /* Red/TV */
++ [0x36] = KEY_UP,
++ [0x37] = KEY_HOME, /* Home */
++ [0x39] = KEY_GREEN, /* Green/Video */
++ [0x3d] = KEY_YELLOW, /* Yellow/Music */
++ [0x3e] = KEY_OK, /* Ok */
++ [0x3f] = KEY_RIGHT,
++ [0x40] = KEY_NEXT, /* Next */
++ [0x41] = KEY_PREVIOUS, /* Previous */
++ [0x42] = KEY_CHANNELDOWN, /* Channel down */
++ [0x43] = KEY_CHANNELUP /* Channel up */
++};
++EXPORT_SYMBOL_GPL(ir_codes_avermedia_cardbus);
++
+ /* Attila Kondoros <attila.kondoros@chello.hu> */
+ IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
+
+@@ -2452,6 +2511,55 @@ IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
+ };
+ EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog);
+
++/* Kaiomy TVnPC U2
++ Mauro Carvalho Chehab <mchehab@infradead.org>
++ */
++IR_KEYTAB_TYPE ir_codes_kaiomy[IR_KEYTAB_SIZE] = {
++ [0x43] = KEY_POWER2,
++ [0x01] = KEY_LIST,
++ [0x0b] = KEY_ZOOM,
++ [0x03] = KEY_POWER,
++
++ [0x04] = KEY_1,
++ [0x08] = KEY_2,
++ [0x02] = KEY_3,
++
++ [0x0f] = KEY_4,
++ [0x05] = KEY_5,
++ [0x06] = KEY_6,
++
++ [0x0c] = KEY_7,
++ [0x0d] = KEY_8,
++ [0x0a] = KEY_9,
++
++ [0x11] = KEY_0,
++
++ [0x09] = KEY_CHANNELUP,
++ [0x07] = KEY_CHANNELDOWN,
++
++ [0x0e] = KEY_VOLUMEUP,
++ [0x13] = KEY_VOLUMEDOWN,
++
++ [0x10] = KEY_HOME,
++ [0x12] = KEY_ENTER,
++
++ [0x14] = KEY_RECORD,
++ [0x15] = KEY_STOP,
++ [0x16] = KEY_PLAY,
++ [0x17] = KEY_MUTE,
++
++ [0x18] = KEY_UP,
++ [0x19] = KEY_DOWN,
++ [0x1a] = KEY_LEFT,
++ [0x1b] = KEY_RIGHT,
++
++ [0x1c] = KEY_RED,
++ [0x1d] = KEY_GREEN,
++ [0x1e] = KEY_YELLOW,
++ [0x1f] = KEY_BLUE,
++};
++EXPORT_SYMBOL_GPL(ir_codes_kaiomy);
++
+ IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
+ [0x20] = KEY_LIST,
+ [0x00] = KEY_POWER,
+@@ -2604,3 +2712,41 @@ IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE] = {
+ };
+
+ EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600);
++
++/* DVBWorld remotes
++ Igor M. Liplianin <liplianin@me.by>
++ */
++IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE] = {
++ [0x0a] = KEY_Q, /*power*/
++ [0x0c] = KEY_M, /*mute*/
++ [0x11] = KEY_1,
++ [0x12] = KEY_2,
++ [0x13] = KEY_3,
++ [0x14] = KEY_4,
++ [0x15] = KEY_5,
++ [0x16] = KEY_6,
++ [0x17] = KEY_7,
++ [0x18] = KEY_8,
++ [0x19] = KEY_9,
++ [0x10] = KEY_0,
++ [0x1c] = KEY_PAGEUP, /*ch+*/
++ [0x0f] = KEY_PAGEDOWN, /*ch-*/
++ [0x1a] = KEY_O, /*vol+*/
++ [0x0e] = KEY_Z, /*vol-*/
++ [0x04] = KEY_R, /*rec*/
++ [0x09] = KEY_D, /*fav*/
++ [0x08] = KEY_BACKSPACE, /*rewind*/
++ [0x07] = KEY_A, /*fast*/
++ [0x0b] = KEY_P, /*pause*/
++ [0x02] = KEY_ESC, /*cancel*/
++ [0x03] = KEY_G, /*tab*/
++ [0x00] = KEY_UP, /*up*/
++ [0x1f] = KEY_ENTER, /*ok*/
++ [0x01] = KEY_DOWN, /*down*/
++ [0x05] = KEY_C, /*cap*/
++ [0x06] = KEY_S, /*stop*/
++ [0x40] = KEY_F, /*full*/
++ [0x1e] = KEY_W, /*tvmode*/
++ [0x1b] = KEY_B, /*recall*/
++};
++EXPORT_SYMBOL_GPL(ir_codes_dm1105_nec);
+diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
+index d599d36..982f000 100644
+--- a/drivers/media/common/saa7146_core.c
++++ b/drivers/media/common/saa7146_core.c
+@@ -452,8 +452,6 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
+ INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
+ dev->ext = ext;
+
+- pci_set_drvdata(pci, dev);
+-
+ mutex_init(&dev->lock);
+ spin_lock_init(&dev->int_slock);
+ spin_lock_init(&dev->slock);
+@@ -477,8 +475,12 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
+
+ if (ext->attach(dev, pci_ext)) {
+ DEB_D(("ext->attach() failed for %p. skipping device.\n",dev));
+- goto err_unprobe;
++ goto err_free_i2c;
+ }
++ /* V4L extensions will set the pci drvdata to the v4l2_device in the
++ attach() above. So for those cards that do not use V4L we have to
++ set it explicitly. */
++ pci_set_drvdata(pci, &dev->v4l2_dev);
+
+ INIT_LIST_HEAD(&dev->item);
+ list_add_tail(&dev->item,&saa7146_devices);
+@@ -488,8 +490,6 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
+ out:
+ return err;
+
+-err_unprobe:
+- pci_set_drvdata(pci, NULL);
+ err_free_i2c:
+ pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
+ dev->d_i2c.dma_handle);
+@@ -514,7 +514,8 @@ err_free:
+
+ static void saa7146_remove_one(struct pci_dev *pdev)
+ {
+- struct saa7146_dev* dev = pci_get_drvdata(pdev);
++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
++ struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
+ struct {
+ void *addr;
+ dma_addr_t dma;
+@@ -528,6 +529,8 @@ static void saa7146_remove_one(struct pci_dev *pdev)
+ DEB_EE(("dev:%p\n",dev));
+
+ dev->ext->detach(dev);
++ /* Zero the PCI drvdata after use. */
++ pci_set_drvdata(pdev, NULL);
+
+ /* shut down all video dma transfers */
+ saa7146_write(dev, MC1, 0x00ff0000);
+diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
+index cf06f4d..620f655 100644
+--- a/drivers/media/common/saa7146_fops.c
++++ b/drivers/media/common/saa7146_fops.c
+@@ -308,14 +308,6 @@ static int fops_release(struct file *file)
+ return 0;
+ }
+
+-static long fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+-{
+-/*
+- DEB_EE(("file:%p, cmd:%d, arg:%li\n", file, cmd, arg));
+-*/
+- return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl);
+-}
+-
+ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
+ {
+ struct saa7146_fh *fh = file->private_data;
+@@ -425,7 +417,7 @@ static const struct v4l2_file_operations video_fops =
+ .write = fops_write,
+ .poll = fops_poll,
+ .mmap = fops_mmap,
+- .ioctl = fops_ioctl,
++ .ioctl = video_ioctl2,
+ };
+
+ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
+@@ -452,19 +444,22 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
+ }
+ }
+
+-static struct video_device device_template =
+-{
+- .fops = &video_fops,
+- .minor = -1,
+-};
+-
+ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
+ {
+- struct saa7146_vv *vv = kzalloc (sizeof(struct saa7146_vv),GFP_KERNEL);
+- if( NULL == vv ) {
++ struct saa7146_vv *vv;
++ int err;
++
++ err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
++ if (err)
++ return err;
++
++ vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
++ if (vv == NULL) {
+ ERR(("out of memory. aborting.\n"));
+- return -1;
++ return -ENOMEM;
+ }
++ ext_vv->ops = saa7146_video_ioctl_ops;
++ ext_vv->core_ops = &saa7146_video_ioctl_ops;
+
+ DEB_EE(("dev:%p\n",dev));
+
+@@ -507,6 +502,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
+
+ DEB_EE(("dev:%p\n",dev));
+
++ v4l2_device_unregister(&dev->v4l2_dev);
+ pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
+ kfree(vv);
+ dev->vv_data = NULL;
+@@ -521,6 +517,8 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
+ {
+ struct saa7146_vv *vv = dev->vv_data;
+ struct video_device *vfd;
++ int err;
++ int i;
+
+ DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
+
+@@ -529,16 +527,20 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
+ if (vfd == NULL)
+ return -ENOMEM;
+
+- memcpy(vfd, &device_template, sizeof(struct video_device));
+- strlcpy(vfd->name, name, sizeof(vfd->name));
++ vfd->fops = &video_fops;
++ vfd->ioctl_ops = &dev->ext_vv_data->ops;
+ vfd->release = video_device_release;
++ vfd->tvnorms = 0;
++ for (i = 0; i < dev->ext_vv_data->num_stds; i++)
++ vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
++ strlcpy(vfd->name, name, sizeof(vfd->name));
+ video_set_drvdata(vfd, dev);
+
+- // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
+- if (video_register_device(vfd, type, -1) < 0) {
++ err = video_register_device(vfd, type, -1);
++ if (err < 0) {
+ ERR(("cannot register v4l2 device. skipping.\n"));
+ video_device_release(vfd);
+- return -1;
++ return err;
+ }
+
+ if( VFL_TYPE_GRABBER == type ) {
+diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
+index c11da4d..7e8f568 100644
+--- a/drivers/media/common/saa7146_i2c.c
++++ b/drivers/media/common/saa7146_i2c.c
+@@ -293,7 +293,6 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
+ int i = 0, count = 0;
+ __le32 *buffer = dev->d_i2c.cpu_addr;
+ int err = 0;
+- int address_err = 0;
+ int short_delay = 0;
+
+ if (mutex_lock_interruptible(&dev->i2c_lock))
+@@ -333,17 +332,10 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
+ i2c address probing, however, and address errors indicate that a
+ device is really *not* there. retrying in that case
+ increases the time the device needs to probe greatly, so
+- it should be avoided. because of the fact, that only
+- analog based cards use irq based i2c transactions (for dvb
+- cards, this screwes up other interrupt sources), we bail out
+- completely for analog cards after an address error and trust
+- the saa7146 address error detection. */
+- if ( -EREMOTEIO == err ) {
+- if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
+- goto out;
+- }
+- address_err++;
+- }
++ it should be avoided. So we bail out in irq mode after an
++ address error and trust the saa7146 address error detection. */
++ if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags))
++ goto out;
+ DEB_I2C(("error while sending message(s). starting again.\n"));
+ break;
+ }
+@@ -358,10 +350,9 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
+
+ } while (err != num && retries--);
+
+- /* if every retry had an address error, exit right away */
+- if (address_err == retries) {
++ /* quit if any error occurred */
++ if (err != num)
+ goto out;
+- }
+
+ /* if any things had to be read, get the results */
+ if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
+@@ -390,7 +381,8 @@ out:
+ /* utility functions */
+ static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
+ {
+- struct saa7146_dev* dev = i2c_get_adapdata(adapter);
++ struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
++ struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
+
+ /* use helper function to transfer data */
+ return saa7146_i2c_transfer(dev, msg, num, adapter->retries);
+@@ -417,9 +409,8 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
+ dev->i2c_bitrate = bitrate;
+ saa7146_i2c_reset(dev);
+
+- if( NULL != i2c_adapter ) {
+- BUG_ON(!i2c_adapter->class);
+- i2c_set_adapdata(i2c_adapter,dev);
++ if (i2c_adapter) {
++ i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev);
+ i2c_adapter->dev.parent = &dev->pci->dev;
+ i2c_adapter->algo = &saa7146_algo;
+ i2c_adapter->algo_data = NULL;
+diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
+index 47fee05..552dab4 100644
+--- a/drivers/media/common/saa7146_video.c
++++ b/drivers/media/common/saa7146_video.c
+@@ -1,4 +1,5 @@
+ #include <media/saa7146_vv.h>
++#include <media/v4l2-chip-ident.h>
+
+ static int max_memory = 32;
+
+@@ -97,172 +98,13 @@ struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc)
+ return NULL;
+ }
+
+-static int g_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
+-{
+- struct saa7146_dev *dev = fh->dev;
+- DEB_EE(("dev:%p, fh:%p\n",dev,fh));
+-
+- switch (f->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- f->fmt.pix = fh->video_fmt;
+- return 0;
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- f->fmt.win = fh->ov.win;
+- return 0;
+- case V4L2_BUF_TYPE_VBI_CAPTURE:
+- {
+- f->fmt.vbi = fh->vbi_fmt;
+- return 0;
+- }
+- default:
+- DEB_D(("invalid format type '%d'.\n",f->type));
+- return -EINVAL;
+- }
+-}
+-
+-static int try_win(struct saa7146_dev *dev, struct v4l2_window *win)
+-{
+- struct saa7146_vv *vv = dev->vv_data;
+- enum v4l2_field field;
+- int maxw, maxh;
+-
+- DEB_EE(("dev:%p\n",dev));
+-
+- if (NULL == vv->ov_fb.base) {
+- DEB_D(("no fb base set.\n"));
+- return -EINVAL;
+- }
+- if (NULL == vv->ov_fmt) {
+- DEB_D(("no fb fmt set.\n"));
+- return -EINVAL;
+- }
+- if (win->w.width < 48 || win->w.height < 32) {
+- DEB_D(("min width/height. (%d,%d)\n",win->w.width,win->w.height));
+- return -EINVAL;
+- }
+- if (win->clipcount > 16) {
+- DEB_D(("clipcount too big.\n"));
+- return -EINVAL;
+- }
+-
+- field = win->field;
+- maxw = vv->standard->h_max_out;
+- maxh = vv->standard->v_max_out;
+-
+- if (V4L2_FIELD_ANY == field) {
+- field = (win->w.height > maxh/2)
+- ? V4L2_FIELD_INTERLACED
+- : V4L2_FIELD_TOP;
+- }
+- switch (field) {
+- case V4L2_FIELD_TOP:
+- case V4L2_FIELD_BOTTOM:
+- case V4L2_FIELD_ALTERNATE:
+- maxh = maxh / 2;
+- break;
+- case V4L2_FIELD_INTERLACED:
+- break;
+- default: {
+- DEB_D(("no known field mode '%d'.\n",field));
+- return -EINVAL;
+- }
+- }
+-
+- win->field = field;
+- if (win->w.width > maxw)
+- win->w.width = maxw;
+- if (win->w.height > maxh)
+- win->w.height = maxh;
+-
+- return 0;
+-}
+-
+-static int try_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
+-{
+- struct saa7146_dev *dev = fh->dev;
+- struct saa7146_vv *vv = dev->vv_data;
+- int err;
+-
+- switch (f->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- {
+- struct saa7146_format *fmt;
+- enum v4l2_field field;
+- int maxw, maxh;
+- int calc_bpl;
+-
+- DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
+-
+- fmt = format_by_fourcc(dev,f->fmt.pix.pixelformat);
+- if (NULL == fmt) {
+- return -EINVAL;
+- }
+-
+- field = f->fmt.pix.field;
+- maxw = vv->standard->h_max_out;
+- maxh = vv->standard->v_max_out;
+-
+- if (V4L2_FIELD_ANY == field) {
+- field = (f->fmt.pix.height > maxh/2)
+- ? V4L2_FIELD_INTERLACED
+- : V4L2_FIELD_BOTTOM;
+- }
+- switch (field) {
+- case V4L2_FIELD_ALTERNATE: {
+- vv->last_field = V4L2_FIELD_TOP;
+- maxh = maxh / 2;
+- break;
+- }
+- case V4L2_FIELD_TOP:
+- case V4L2_FIELD_BOTTOM:
+- vv->last_field = V4L2_FIELD_INTERLACED;
+- maxh = maxh / 2;
+- break;
+- case V4L2_FIELD_INTERLACED:
+- vv->last_field = V4L2_FIELD_INTERLACED;
+- break;
+- default: {
+- DEB_D(("no known field mode '%d'.\n",field));
+- return -EINVAL;
+- }
+- }
+-
+- f->fmt.pix.field = field;
+- if (f->fmt.pix.width > maxw)
+- f->fmt.pix.width = maxw;
+- if (f->fmt.pix.height > maxh)
+- f->fmt.pix.height = maxh;
+-
+- calc_bpl = (f->fmt.pix.width * fmt->depth)/8;
+-
+- if (f->fmt.pix.bytesperline < calc_bpl)
+- f->fmt.pix.bytesperline = calc_bpl;
+-
+- if (f->fmt.pix.bytesperline > (2*PAGE_SIZE * fmt->depth)/8) /* arbitrary constraint */
+- f->fmt.pix.bytesperline = calc_bpl;
+-
+- f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
+- DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",f->fmt.pix.width,f->fmt.pix.height,f->fmt.pix.bytesperline,f->fmt.pix.sizeimage));
+-
+- return 0;
+- }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));
+- err = try_win(dev,&f->fmt.win);
+- if (0 != err) {
+- return err;
+- }
+- return 0;
+- default:
+- DEB_EE(("unknown format type '%d'\n",f->type));
+- return -EINVAL;
+- }
+-}
++static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f);
+
+ int saa7146_start_preview(struct saa7146_fh *fh)
+ {
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
++ struct v4l2_format fmt;
+ int ret = 0, err = 0;
+
+ DEB_EE(("dev:%p, fh:%p\n",dev,fh));
+@@ -294,12 +136,13 @@ int saa7146_start_preview(struct saa7146_fh *fh)
+ return -EBUSY;
+ }
+
+- err = try_win(dev,&fh->ov.win);
++ fmt.fmt.win = fh->ov.win;
++ err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
+ if (0 != err) {
+ saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
+ return -EBUSY;
+ }
+-
++ fh->ov.win = fmt.fmt.win;
+ vv->ov_data = &fh->ov;
+
+ DEB_D(("%dx%d+%d+%d %s field=%s\n",
+@@ -355,58 +198,6 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
+ }
+ EXPORT_SYMBOL_GPL(saa7146_stop_preview);
+
+-static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
+-{
+- struct saa7146_dev *dev = fh->dev;
+- struct saa7146_vv *vv = dev->vv_data;
+-
+- int err;
+-
+- switch (f->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
+- if (IS_CAPTURE_ACTIVE(fh) != 0) {
+- DEB_EE(("streaming capture is active\n"));
+- return -EBUSY;
+- }
+- err = try_fmt(fh,f);
+- if (0 != err)
+- return err;
+- fh->video_fmt = f->fmt.pix;
+- DEB_EE(("set to pixelformat '%4.4s'\n",(char *)&fh->video_fmt.pixelformat));
+- return 0;
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));
+- err = try_win(dev,&f->fmt.win);
+- if (0 != err)
+- return err;
+- mutex_lock(&dev->lock);
+- fh->ov.win = f->fmt.win;
+- fh->ov.nclips = f->fmt.win.clipcount;
+- if (fh->ov.nclips > 16)
+- fh->ov.nclips = 16;
+- if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) {
+- mutex_unlock(&dev->lock);
+- return -EFAULT;
+- }
+-
+- /* fh->ov.fh is used to indicate that we have valid overlay informations, too */
+- fh->ov.fh = fh;
+-
+- mutex_unlock(&dev->lock);
+-
+- /* check if our current overlay is active */
+- if (IS_OVERLAY_ACTIVE(fh) != 0) {
+- saa7146_stop_preview(fh);
+- saa7146_start_preview(fh);
+- }
+- return 0;
+- default:
+- DEB_D(("unknown format type '%d'\n",f->type));
+- return -EINVAL;
+- }
+-}
+-
+ /********************************************************************************/
+ /* device controls */
+
+@@ -419,6 +210,7 @@ static struct v4l2_queryctrl controls[] = {
+ .step = 1,
+ .default_value = 128,
+ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },{
+ .id = V4L2_CID_CONTRAST,
+ .name = "Contrast",
+@@ -427,6 +219,7 @@ static struct v4l2_queryctrl controls[] = {
+ .step = 1,
+ .default_value = 64,
+ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },{
+ .id = V4L2_CID_SATURATION,
+ .name = "Saturation",
+@@ -435,15 +228,16 @@ static struct v4l2_queryctrl controls[] = {
+ .step = 1,
+ .default_value = 64,
+ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },{
+ .id = V4L2_CID_VFLIP,
+- .name = "Vertical flip",
++ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_HFLIP,
+- .name = "Horizontal flip",
++ .name = "Horizontal Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+@@ -463,132 +257,6 @@ static struct v4l2_queryctrl* ctrl_by_id(int id)
+ return NULL;
+ }
+
+-static int get_control(struct saa7146_fh *fh, struct v4l2_control *c)
+-{
+- struct saa7146_dev *dev = fh->dev;
+- struct saa7146_vv *vv = dev->vv_data;
+-
+- const struct v4l2_queryctrl* ctrl;
+- u32 value = 0;
+-
+- ctrl = ctrl_by_id(c->id);
+- if (NULL == ctrl)
+- return -EINVAL;
+- switch (c->id) {
+- case V4L2_CID_BRIGHTNESS:
+- value = saa7146_read(dev, BCS_CTRL);
+- c->value = 0xff & (value >> 24);
+- DEB_D(("V4L2_CID_BRIGHTNESS: %d\n",c->value));
+- break;
+- case V4L2_CID_CONTRAST:
+- value = saa7146_read(dev, BCS_CTRL);
+- c->value = 0x7f & (value >> 16);
+- DEB_D(("V4L2_CID_CONTRAST: %d\n",c->value));
+- break;
+- case V4L2_CID_SATURATION:
+- value = saa7146_read(dev, BCS_CTRL);
+- c->value = 0x7f & (value >> 0);
+- DEB_D(("V4L2_CID_SATURATION: %d\n",c->value));
+- break;
+- case V4L2_CID_VFLIP:
+- c->value = vv->vflip;
+- DEB_D(("V4L2_CID_VFLIP: %d\n",c->value));
+- break;
+- case V4L2_CID_HFLIP:
+- c->value = vv->hflip;
+- DEB_D(("V4L2_CID_HFLIP: %d\n",c->value));
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- return 0;
+-}
+-
+-static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
+-{
+- struct saa7146_dev *dev = fh->dev;
+- struct saa7146_vv *vv = dev->vv_data;
+-
+- const struct v4l2_queryctrl* ctrl;
+-
+- ctrl = ctrl_by_id(c->id);
+- if (NULL == ctrl) {
+- DEB_D(("unknown control %d\n",c->id));
+- return -EINVAL;
+- }
+-
+- mutex_lock(&dev->lock);
+-
+- switch (ctrl->type) {
+- case V4L2_CTRL_TYPE_BOOLEAN:
+- case V4L2_CTRL_TYPE_MENU:
+- case V4L2_CTRL_TYPE_INTEGER:
+- if (c->value < ctrl->minimum)
+- c->value = ctrl->minimum;
+- if (c->value > ctrl->maximum)
+- c->value = ctrl->maximum;
+- break;
+- default:
+- /* nothing */;
+- };
+-
+- switch (c->id) {
+- case V4L2_CID_BRIGHTNESS: {
+- u32 value = saa7146_read(dev, BCS_CTRL);
+- value &= 0x00ffffff;
+- value |= (c->value << 24);
+- saa7146_write(dev, BCS_CTRL, value);
+- saa7146_write(dev, MC2, MASK_22 | MASK_06 );
+- break;
+- }
+- case V4L2_CID_CONTRAST: {
+- u32 value = saa7146_read(dev, BCS_CTRL);
+- value &= 0xff00ffff;
+- value |= (c->value << 16);
+- saa7146_write(dev, BCS_CTRL, value);
+- saa7146_write(dev, MC2, MASK_22 | MASK_06 );
+- break;
+- }
+- case V4L2_CID_SATURATION: {
+- u32 value = saa7146_read(dev, BCS_CTRL);
+- value &= 0xffffff00;
+- value |= (c->value << 0);
+- saa7146_write(dev, BCS_CTRL, value);
+- saa7146_write(dev, MC2, MASK_22 | MASK_06 );
+- break;
+- }
+- case V4L2_CID_HFLIP:
+- /* fixme: we can support changing VFLIP and HFLIP here... */
+- if (IS_CAPTURE_ACTIVE(fh) != 0) {
+- DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
+- mutex_unlock(&dev->lock);
+- return -EINVAL;
+- }
+- vv->hflip = c->value;
+- break;
+- case V4L2_CID_VFLIP:
+- if (IS_CAPTURE_ACTIVE(fh) != 0) {
+- DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
+- mutex_unlock(&dev->lock);
+- return -EINVAL;
+- }
+- vv->vflip = c->value;
+- break;
+- default: {
+- mutex_unlock(&dev->lock);
+- return -EINVAL;
+- }
+- }
+- mutex_unlock(&dev->lock);
+-
+- if (IS_OVERLAY_ACTIVE(fh) != 0) {
+- saa7146_stop_preview(fh);
+- saa7146_start_preview(fh);
+- }
+- return 0;
+-}
+-
+ /********************************************************************************/
+ /* common pagetable functions */
+
+@@ -829,231 +497,446 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
+ return 0;
+ }
+
+-/*
+- * This function is _not_ called directly, but from
+- * video_generic_ioctl (and maybe others). userspace
+- * copying is done already, arg is a kernel pointer.
+- */
++static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++
++ strcpy((char *)cap->driver, "saa7146 v4l2");
++ strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
++ sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
++ cap->version = SAA7146_VERSION_CODE;
++ cap->capabilities =
++ V4L2_CAP_VIDEO_CAPTURE |
++ V4L2_CAP_VIDEO_OVERLAY |
++ V4L2_CAP_READWRITE |
++ V4L2_CAP_STREAMING;
++ cap->capabilities |= dev->ext_vv_data->capabilities;
++ return 0;
++}
+
+-long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
++static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+ {
+- struct saa7146_fh *fh = file->private_data;
+- struct saa7146_dev *dev = fh->dev;
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++
++ *fb = vv->ov_fb;
++ fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
++ return 0;
++}
++
++static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
++ struct saa7146_format *fmt;
+
+- long err = 0;
+- int result = 0, ee = 0;
++ DEB_EE(("VIDIOC_S_FBUF\n"));
+
+- struct saa7146_use_ops *ops;
+- struct videobuf_queue *q;
++ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
++ return -EPERM;
+
+- /* check if extension handles the command */
+- for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) {
+- if( cmd == dev->ext_vv_data->ioctls[ee].cmd )
+- break;
++ /* check args */
++ fmt = format_by_fourcc(dev, fb->fmt.pixelformat);
++ if (NULL == fmt)
++ return -EINVAL;
++
++ /* planar formats are not allowed for overlay video, clipping and video dma would clash */
++ if (fmt->flags & FORMAT_IS_PLANAR)
++ DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",
++ (char *)&fmt->pixelformat));
++
++ /* check if overlay is running */
++ if (IS_OVERLAY_ACTIVE(fh) != 0) {
++ if (vv->video_fh != fh) {
++ DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));
++ return -EBUSY;
++ }
+ }
+
+- if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) {
+- DEB_D(("extension handles ioctl exclusive.\n"));
+- result = dev->ext_vv_data->ioctl(fh, cmd, arg);
+- return result;
++ mutex_lock(&dev->lock);
++
++ /* ok, accept it */
++ vv->ov_fb = *fb;
++ vv->ov_fmt = fmt;
++ if (0 == vv->ov_fb.fmt.bytesperline)
++ vv->ov_fb.fmt.bytesperline =
++ vv->ov_fb.fmt.width * fmt->depth / 8;
++
++ mutex_unlock(&dev->lock);
++ return 0;
++}
++
++static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
++{
++ if (f->index >= NUM_FORMATS)
++ return -EINVAL;
++ strlcpy((char *)f->description, formats[f->index].name,
++ sizeof(f->description));
++ f->pixelformat = formats[f->index].pixelformat;
++ return 0;
++}
++
++static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
++{
++ const struct v4l2_queryctrl *ctrl;
++
++ if ((c->id < V4L2_CID_BASE ||
++ c->id >= V4L2_CID_LASTP1) &&
++ (c->id < V4L2_CID_PRIVATE_BASE ||
++ c->id >= V4L2_CID_PRIVATE_LASTP1))
++ return -EINVAL;
++
++ ctrl = ctrl_by_id(c->id);
++ if (ctrl == NULL)
++ return -EINVAL;
++
++ DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id));
++ *c = *ctrl;
++ return 0;
++}
++
++static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++ const struct v4l2_queryctrl *ctrl;
++ u32 value = 0;
++
++ ctrl = ctrl_by_id(c->id);
++ if (NULL == ctrl)
++ return -EINVAL;
++ switch (c->id) {
++ case V4L2_CID_BRIGHTNESS:
++ value = saa7146_read(dev, BCS_CTRL);
++ c->value = 0xff & (value >> 24);
++ DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value));
++ break;
++ case V4L2_CID_CONTRAST:
++ value = saa7146_read(dev, BCS_CTRL);
++ c->value = 0x7f & (value >> 16);
++ DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value));
++ break;
++ case V4L2_CID_SATURATION:
++ value = saa7146_read(dev, BCS_CTRL);
++ c->value = 0x7f & (value >> 0);
++ DEB_D(("V4L2_CID_SATURATION: %d\n", c->value));
++ break;
++ case V4L2_CID_VFLIP:
++ c->value = vv->vflip;
++ DEB_D(("V4L2_CID_VFLIP: %d\n", c->value));
++ break;
++ case V4L2_CID_HFLIP:
++ c->value = vv->hflip;
++ DEB_D(("V4L2_CID_HFLIP: %d\n", c->value));
++ break;
++ default:
++ return -EINVAL;
+ }
+- if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) {
+- DEB_D(("extension handles ioctl before.\n"));
+- result = dev->ext_vv_data->ioctl(fh, cmd, arg);
+- if( -EAGAIN != result ) {
+- return result;
+- }
++ return 0;
++}
++
++static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++ const struct v4l2_queryctrl *ctrl;
++
++ ctrl = ctrl_by_id(c->id);
++ if (NULL == ctrl) {
++ DEB_D(("unknown control %d\n", c->id));
++ return -EINVAL;
+ }
+
+- /* fixme: add handle "after" case (is it still needed?) */
++ mutex_lock(&dev->lock);
+
+- switch (fh->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- ops = &saa7146_video_uops;
+- q = &fh->video_q;
++ switch (ctrl->type) {
++ case V4L2_CTRL_TYPE_BOOLEAN:
++ case V4L2_CTRL_TYPE_MENU:
++ case V4L2_CTRL_TYPE_INTEGER:
++ if (c->value < ctrl->minimum)
++ c->value = ctrl->minimum;
++ if (c->value > ctrl->maximum)
++ c->value = ctrl->maximum;
+ break;
++ default:
++ /* nothing */;
++ }
++
++ switch (c->id) {
++ case V4L2_CID_BRIGHTNESS: {
++ u32 value = saa7146_read(dev, BCS_CTRL);
++ value &= 0x00ffffff;
++ value |= (c->value << 24);
++ saa7146_write(dev, BCS_CTRL, value);
++ saa7146_write(dev, MC2, MASK_22 | MASK_06);
++ break;
++ }
++ case V4L2_CID_CONTRAST: {
++ u32 value = saa7146_read(dev, BCS_CTRL);
++ value &= 0xff00ffff;
++ value |= (c->value << 16);
++ saa7146_write(dev, BCS_CTRL, value);
++ saa7146_write(dev, MC2, MASK_22 | MASK_06);
++ break;
++ }
++ case V4L2_CID_SATURATION: {
++ u32 value = saa7146_read(dev, BCS_CTRL);
++ value &= 0xffffff00;
++ value |= (c->value << 0);
++ saa7146_write(dev, BCS_CTRL, value);
++ saa7146_write(dev, MC2, MASK_22 | MASK_06);
++ break;
++ }
++ case V4L2_CID_HFLIP:
++ /* fixme: we can support changing VFLIP and HFLIP here... */
++ if (IS_CAPTURE_ACTIVE(fh) != 0) {
++ DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
++ mutex_unlock(&dev->lock);
++ return -EBUSY;
+ }
+- case V4L2_BUF_TYPE_VBI_CAPTURE: {
+- ops = &saa7146_vbi_uops;
+- q = &fh->vbi_q;
++ vv->hflip = c->value;
+ break;
++ case V4L2_CID_VFLIP:
++ if (IS_CAPTURE_ACTIVE(fh) != 0) {
++ DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
++ mutex_unlock(&dev->lock);
++ return -EBUSY;
+ }
++ vv->vflip = c->value;
++ break;
+ default:
+- BUG();
+- return 0;
++ mutex_unlock(&dev->lock);
++ return -EINVAL;
+ }
++ mutex_unlock(&dev->lock);
+
+- switch (cmd) {
+- case VIDIOC_QUERYCAP:
+- {
+- struct v4l2_capability *cap = arg;
+- memset(cap,0,sizeof(*cap));
+-
+- DEB_EE(("VIDIOC_QUERYCAP\n"));
+-
+- strcpy((char *)cap->driver, "saa7146 v4l2");
+- strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+- sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
+- cap->version = SAA7146_VERSION_CODE;
+- cap->capabilities =
+- V4L2_CAP_VIDEO_CAPTURE |
+- V4L2_CAP_VIDEO_OVERLAY |
+- V4L2_CAP_READWRITE |
+- V4L2_CAP_STREAMING;
+- cap->capabilities |= dev->ext_vv_data->capabilities;
+- return 0;
++ if (IS_OVERLAY_ACTIVE(fh) != 0) {
++ saa7146_stop_preview(fh);
++ saa7146_start_preview(fh);
+ }
+- case VIDIOC_G_FBUF:
+- {
+- struct v4l2_framebuffer *fb = arg;
+-
+- DEB_EE(("VIDIOC_G_FBUF\n"));
++ return 0;
++}
+
+- *fb = vv->ov_fb;
+- fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+- return 0;
+- }
+- case VIDIOC_S_FBUF:
+- {
+- struct v4l2_framebuffer *fb = arg;
+- struct saa7146_format *fmt;
++static int vidioc_g_parm(struct file *file, void *fh,
++ struct v4l2_streamparm *parm)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct saa7146_vv *vv = dev->vv_data;
+
+- DEB_EE(("VIDIOC_S_FBUF\n"));
++ parm->parm.capture.readbuffers = 1;
++ v4l2_video_std_frame_period(vv->standard->id,
++ &parm->parm.capture.timeperframe);
++ return 0;
++}
+
+- if(!capable(CAP_SYS_ADMIN) &&
+- !capable(CAP_SYS_RAWIO))
+- return -EPERM;
++static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
++{
++ f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt;
++ return 0;
++}
+
+- /* check args */
+- fmt = format_by_fourcc(dev,fb->fmt.pixelformat);
+- if (NULL == fmt) {
+- return -EINVAL;
+- }
++static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
++{
++ f->fmt.win = ((struct saa7146_fh *)fh)->ov.win;
++ return 0;
++}
+
+- /* planar formats are not allowed for overlay video, clipping and video dma would clash */
+- if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
+- DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat));
+- }
++static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
++{
++ f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt;
++ return 0;
++}
+
+- /* check if overlay is running */
+- if (IS_OVERLAY_ACTIVE(fh) != 0) {
+- if (vv->video_fh != fh) {
+- DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));
+- return -EBUSY;
+- }
+- }
++static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++ struct saa7146_format *fmt;
++ enum v4l2_field field;
++ int maxw, maxh;
++ int calc_bpl;
+
+- mutex_lock(&dev->lock);
++ DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
+
+- /* ok, accept it */
+- vv->ov_fb = *fb;
+- vv->ov_fmt = fmt;
+- if (0 == vv->ov_fb.fmt.bytesperline)
+- vv->ov_fb.fmt.bytesperline =
+- vv->ov_fb.fmt.width*fmt->depth/8;
++ fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat);
++ if (NULL == fmt)
++ return -EINVAL;
+
+- mutex_unlock(&dev->lock);
++ field = f->fmt.pix.field;
++ maxw = vv->standard->h_max_out;
++ maxh = vv->standard->v_max_out;
+
+- return 0;
++ if (V4L2_FIELD_ANY == field) {
++ field = (f->fmt.pix.height > maxh / 2)
++ ? V4L2_FIELD_INTERLACED
++ : V4L2_FIELD_BOTTOM;
+ }
+- case VIDIOC_ENUM_FMT:
+- {
+- struct v4l2_fmtdesc *f = arg;
+-
+- switch (f->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- if (f->index >= NUM_FORMATS)
+- return -EINVAL;
+- strlcpy((char *)f->description, formats[f->index].name,
+- sizeof(f->description));
+- f->pixelformat = formats[f->index].pixelformat;
+- f->flags = 0;
+- memset(f->reserved, 0, sizeof(f->reserved));
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index));
+- return 0;
++ switch (field) {
++ case V4L2_FIELD_ALTERNATE:
++ vv->last_field = V4L2_FIELD_TOP;
++ maxh = maxh / 2;
++ break;
++ case V4L2_FIELD_TOP:
++ case V4L2_FIELD_BOTTOM:
++ vv->last_field = V4L2_FIELD_INTERLACED;
++ maxh = maxh / 2;
++ break;
++ case V4L2_FIELD_INTERLACED:
++ vv->last_field = V4L2_FIELD_INTERLACED;
++ break;
++ default:
++ DEB_D(("no known field mode '%d'.\n", field));
++ return -EINVAL;
+ }
+- case VIDIOC_QUERYCTRL:
+- {
+- const struct v4l2_queryctrl *ctrl;
+- struct v4l2_queryctrl *c = arg;
+
+- if ((c->id < V4L2_CID_BASE ||
+- c->id >= V4L2_CID_LASTP1) &&
+- (c->id < V4L2_CID_PRIVATE_BASE ||
+- c->id >= V4L2_CID_PRIVATE_LASTP1))
+- return -EINVAL;
++ f->fmt.pix.field = field;
++ if (f->fmt.pix.width > maxw)
++ f->fmt.pix.width = maxw;
++ if (f->fmt.pix.height > maxh)
++ f->fmt.pix.height = maxh;
+
+- ctrl = ctrl_by_id(c->id);
+- if( NULL == ctrl ) {
+- return -EINVAL;
+-/*
+- c->flags = V4L2_CTRL_FLAG_DISABLED;
+- return 0;
+-*/
+- }
++ calc_bpl = (f->fmt.pix.width * fmt->depth) / 8;
+
+- DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n",c->id));
+- *c = *ctrl;
+- return 0;
++ if (f->fmt.pix.bytesperline < calc_bpl)
++ f->fmt.pix.bytesperline = calc_bpl;
++
++ if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */
++ f->fmt.pix.bytesperline = calc_bpl;
++
++ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
++ DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width,
++ f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage));
++
++ return 0;
++}
++
++
++static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++ struct v4l2_window *win = &f->fmt.win;
++ enum v4l2_field field;
++ int maxw, maxh;
++
++ DEB_EE(("dev:%p\n", dev));
++
++ if (NULL == vv->ov_fb.base) {
++ DEB_D(("no fb base set.\n"));
++ return -EINVAL;
+ }
+- case VIDIOC_G_CTRL: {
+- DEB_EE(("VIDIOC_G_CTRL\n"));
+- return get_control(fh,arg);
++ if (NULL == vv->ov_fmt) {
++ DEB_D(("no fb fmt set.\n"));
++ return -EINVAL;
+ }
+- case VIDIOC_S_CTRL:
+- {
+- DEB_EE(("VIDIOC_S_CTRL\n"));
+- err = set_control(fh,arg);
+- return err;
++ if (win->w.width < 48 || win->w.height < 32) {
++ DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height));
++ return -EINVAL;
+ }
+- case VIDIOC_G_PARM:
+- {
+- struct v4l2_streamparm *parm = arg;
+- if( parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ) {
+- return -EINVAL;
+- }
+- memset(&parm->parm.capture,0,sizeof(struct v4l2_captureparm));
+- parm->parm.capture.readbuffers = 1;
+- // fixme: only for PAL!
+- parm->parm.capture.timeperframe.numerator = 1;
+- parm->parm.capture.timeperframe.denominator = 25;
+- return 0;
++ if (win->clipcount > 16) {
++ DEB_D(("clipcount too big.\n"));
++ return -EINVAL;
+ }
+- case VIDIOC_G_FMT:
+- {
+- struct v4l2_format *f = arg;
+- DEB_EE(("VIDIOC_G_FMT\n"));
+- return g_fmt(fh,f);
++
++ field = win->field;
++ maxw = vv->standard->h_max_out;
++ maxh = vv->standard->v_max_out;
++
++ if (V4L2_FIELD_ANY == field) {
++ field = (win->w.height > maxh / 2)
++ ? V4L2_FIELD_INTERLACED
++ : V4L2_FIELD_TOP;
++ }
++ switch (field) {
++ case V4L2_FIELD_TOP:
++ case V4L2_FIELD_BOTTOM:
++ case V4L2_FIELD_ALTERNATE:
++ maxh = maxh / 2;
++ break;
++ case V4L2_FIELD_INTERLACED:
++ break;
++ default:
++ DEB_D(("no known field mode '%d'.\n", field));
++ return -EINVAL;
+ }
+- case VIDIOC_S_FMT:
+- {
+- struct v4l2_format *f = arg;
+- DEB_EE(("VIDIOC_S_FMT\n"));
+- return s_fmt(fh,f);
++
++ win->field = field;
++ if (win->w.width > maxw)
++ win->w.width = maxw;
++ if (win->w.height > maxh)
++ win->w.height = maxh;
++
++ return 0;
++}
++
++static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f)
++{
++ struct saa7146_fh *fh = __fh;
++ struct saa7146_dev *dev = fh->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++ int err;
++
++ DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
++ if (IS_CAPTURE_ACTIVE(fh) != 0) {
++ DEB_EE(("streaming capture is active\n"));
++ return -EBUSY;
+ }
+- case VIDIOC_TRY_FMT:
+- {
+- struct v4l2_format *f = arg;
+- DEB_EE(("VIDIOC_TRY_FMT\n"));
+- return try_fmt(fh,f);
++ err = vidioc_try_fmt_vid_cap(file, fh, f);
++ if (0 != err)
++ return err;
++ fh->video_fmt = f->fmt.pix;
++ DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat));
++ return 0;
++}
++
++static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f)
++{
++ struct saa7146_fh *fh = __fh;
++ struct saa7146_dev *dev = fh->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++ int err;
++
++ DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh));
++ err = vidioc_try_fmt_vid_overlay(file, fh, f);
++ if (0 != err)
++ return err;
++ mutex_lock(&dev->lock);
++ fh->ov.win = f->fmt.win;
++ fh->ov.nclips = f->fmt.win.clipcount;
++ if (fh->ov.nclips > 16)
++ fh->ov.nclips = 16;
++ if (copy_from_user(fh->ov.clips, f->fmt.win.clips,
++ sizeof(struct v4l2_clip) * fh->ov.nclips)) {
++ mutex_unlock(&dev->lock);
++ return -EFAULT;
+ }
+- case VIDIOC_G_STD:
+- {
+- v4l2_std_id *id = arg;
+- DEB_EE(("VIDIOC_G_STD\n"));
+- *id = vv->standard->id;
+- return 0;
++
++ /* fh->ov.fh is used to indicate that we have valid overlay informations, too */
++ fh->ov.fh = fh;
++
++ mutex_unlock(&dev->lock);
++
++ /* check if our current overlay is active */
++ if (IS_OVERLAY_ACTIVE(fh) != 0) {
++ saa7146_stop_preview(fh);
++ saa7146_start_preview(fh);
+ }
++ return 0;
++}
++
++static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++
++ *norm = vv->standard->id;
++ return 0;
++}
++
+ /* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
+ PAL / NTSC / SECAM. if your hardware does not (or does more)
+ -- override this function in your extension */
++/*
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *e = arg;
+@@ -1066,162 +949,245 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ }
+ return -EINVAL;
+ }
+- case VIDIOC_S_STD:
+- {
+- v4l2_std_id *id = arg;
+- int found = 0;
+- int i;
+-
+- DEB_EE(("VIDIOC_S_STD\n"));
++ */
+
+- if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
+- DEB_D(("cannot change video standard while streaming capture is active\n"));
+- return -EBUSY;
+- }
++static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++ int found = 0;
++ int err, i;
+
+- if ((vv->video_status & STATUS_OVERLAY) != 0) {
+- vv->ov_suspend = vv->video_fh;
+- err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
+- if (0 != err) {
+- DEB_D(("suspending video failed. aborting\n"));
+- return err;
+- }
+- }
++ DEB_EE(("VIDIOC_S_STD\n"));
+
+- mutex_lock(&dev->lock);
++ if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
++ DEB_D(("cannot change video standard while streaming capture is active\n"));
++ return -EBUSY;
++ }
+
+- for(i = 0; i < dev->ext_vv_data->num_stds; i++)
+- if (*id & dev->ext_vv_data->stds[i].id)
+- break;
+- if (i != dev->ext_vv_data->num_stds) {
+- vv->standard = &dev->ext_vv_data->stds[i];
+- if( NULL != dev->ext_vv_data->std_callback )
+- dev->ext_vv_data->std_callback(dev, vv->standard);
+- found = 1;
++ if ((vv->video_status & STATUS_OVERLAY) != 0) {
++ vv->ov_suspend = vv->video_fh;
++ err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
++ if (0 != err) {
++ DEB_D(("suspending video failed. aborting\n"));
++ return err;
+ }
++ }
+
+- mutex_unlock(&dev->lock);
++ mutex_lock(&dev->lock);
+
+- if (vv->ov_suspend != NULL) {
+- saa7146_start_preview(vv->ov_suspend);
+- vv->ov_suspend = NULL;
+- }
++ for (i = 0; i < dev->ext_vv_data->num_stds; i++)
++ if (*id & dev->ext_vv_data->stds[i].id)
++ break;
++ if (i != dev->ext_vv_data->num_stds) {
++ vv->standard = &dev->ext_vv_data->stds[i];
++ if (NULL != dev->ext_vv_data->std_callback)
++ dev->ext_vv_data->std_callback(dev, vv->standard);
++ found = 1;
++ }
+
+- if( 0 == found ) {
+- DEB_EE(("VIDIOC_S_STD: standard not found.\n"));
+- return -EINVAL;
+- }
++ mutex_unlock(&dev->lock);
+
+- DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n",vv->standard->name));
+- return 0;
++ if (vv->ov_suspend != NULL) {
++ saa7146_start_preview(vv->ov_suspend);
++ vv->ov_suspend = NULL;
+ }
+- case VIDIOC_OVERLAY:
+- {
+- int on = *(int *)arg;
+
+- DEB_D(("VIDIOC_OVERLAY on:%d\n",on));
+- if (on != 0) {
+- err = saa7146_start_preview(fh);
+- } else {
+- err = saa7146_stop_preview(fh);
+- }
+- return err;
+- }
+- case VIDIOC_REQBUFS: {
+- struct v4l2_requestbuffers *req = arg;
+- DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type));
+- return videobuf_reqbufs(q,req);
+- }
+- case VIDIOC_QUERYBUF: {
+- struct v4l2_buffer *buf = arg;
+- DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset));
+- return videobuf_querybuf(q,buf);
+- }
+- case VIDIOC_QBUF: {
+- struct v4l2_buffer *buf = arg;
+- int ret = 0;
+- ret = videobuf_qbuf(q,buf);
+- DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index));
+- return ret;
+- }
+- case VIDIOC_DQBUF: {
+- struct v4l2_buffer *buf = arg;
+- int ret = 0;
+- ret = videobuf_dqbuf(q,buf,file->f_flags & O_NONBLOCK);
+- DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index));
+- return ret;
++ if (!found) {
++ DEB_EE(("VIDIOC_S_STD: standard not found.\n"));
++ return -EINVAL;
+ }
+- case VIDIOC_STREAMON: {
+- int *type = arg;
+- DEB_D(("VIDIOC_STREAMON, type:%d\n",*type));
+
+- err = video_begin(fh);
+- if( 0 != err) {
+- return err;
+- }
+- err = videobuf_streamon(q);
+- return err;
+- }
+- case VIDIOC_STREAMOFF: {
+- int *type = arg;
++ DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name));
++ return 0;
++}
+
+- DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type));
++static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
++{
++ int err;
+
+- /* ugly: we need to copy some checks from video_end(),
+- because videobuf_streamoff() relies on the capture running.
+- check and fix this */
+- if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
+- DEB_S(("not capturing.\n"));
+- return 0;
+- }
++ DEB_D(("VIDIOC_OVERLAY on:%d\n", on));
++ if (on)
++ err = saa7146_start_preview(fh);
++ else
++ err = saa7146_stop_preview(fh);
++ return err;
++}
+
+- if (vv->video_fh != fh) {
+- DEB_S(("capturing, but in another open.\n"));
+- return -EBUSY;
+- }
++static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b)
++{
++ struct saa7146_fh *fh = __fh;
+
+- err = videobuf_streamoff(q);
+- if (0 != err) {
+- DEB_D(("warning: videobuf_streamoff() failed.\n"));
+- video_end(fh, file);
+- } else {
+- err = video_end(fh, file);
+- }
++ if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return videobuf_reqbufs(&fh->video_q, b);
++ if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE)
++ return videobuf_reqbufs(&fh->vbi_q, b);
++ return -EINVAL;
++}
++
++static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
++{
++ struct saa7146_fh *fh = __fh;
++
++ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return videobuf_querybuf(&fh->video_q, buf);
++ if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
++ return videobuf_querybuf(&fh->vbi_q, buf);
++ return -EINVAL;
++}
++
++static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
++{
++ struct saa7146_fh *fh = __fh;
++
++ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return videobuf_qbuf(&fh->video_q, buf);
++ if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
++ return videobuf_qbuf(&fh->vbi_q, buf);
++ return -EINVAL;
++}
++
++static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
++{
++ struct saa7146_fh *fh = __fh;
++
++ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK);
++ if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
++ return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK);
++ return -EINVAL;
++}
++
++static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
++{
++ struct saa7146_fh *fh = __fh;
++ int err;
++
++ DEB_D(("VIDIOC_STREAMON, type:%d\n", type));
++
++ err = video_begin(fh);
++ if (err)
+ return err;
++ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return videobuf_streamon(&fh->video_q);
++ if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
++ return videobuf_streamon(&fh->vbi_q);
++ return -EINVAL;
++}
++
++static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
++{
++ struct saa7146_fh *fh = __fh;
++ struct saa7146_dev *dev = fh->dev;
++ struct saa7146_vv *vv = dev->vv_data;
++ int err;
++
++ DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type));
++
++ /* ugly: we need to copy some checks from video_end(),
++ because videobuf_streamoff() relies on the capture running.
++ check and fix this */
++ if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
++ DEB_S(("not capturing.\n"));
++ return 0;
+ }
+-#ifdef CONFIG_VIDEO_V4L1_COMPAT
+- case VIDIOCGMBUF:
+- {
+- struct video_mbuf *mbuf = arg;
+- int i;
+
+- /* fixme: number of capture buffers and sizes for v4l apps */
+- int gbuffers = 2;
+- int gbufsize = 768*576*4;
++ if (vv->video_fh != fh) {
++ DEB_S(("capturing, but in another open.\n"));
++ return -EBUSY;
++ }
+
+- DEB_D(("VIDIOCGMBUF \n"));
++ err = -EINVAL;
++ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ err = videobuf_streamoff(&fh->video_q);
++ else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
++ err = videobuf_streamoff(&fh->vbi_q);
++ if (0 != err) {
++ DEB_D(("warning: videobuf_streamoff() failed.\n"));
++ video_end(fh, file);
++ } else {
++ err = video_end(fh, file);
++ }
++ return err;
++}
+
+- q = &fh->video_q;
+- err = videobuf_mmap_setup(q,gbuffers,gbufsize,
+- V4L2_MEMORY_MMAP);
+- if (err < 0)
+- return err;
++static int vidioc_g_chip_ident(struct file *file, void *__fh,
++ struct v4l2_dbg_chip_ident *chip)
++{
++ struct saa7146_fh *fh = __fh;
++ struct saa7146_dev *dev = fh->dev;
+
+- gbuffers = err;
+- memset(mbuf,0,sizeof(*mbuf));
+- mbuf->frames = gbuffers;
+- mbuf->size = gbuffers * gbufsize;
+- for (i = 0; i < gbuffers; i++)
+- mbuf->offsets[i] = i * gbufsize;
++ chip->ident = V4L2_IDENT_NONE;
++ chip->revision = 0;
++ if (chip->match.type == V4L2_CHIP_MATCH_HOST && !chip->match.addr) {
++ chip->ident = V4L2_IDENT_SAA7146;
+ return 0;
+ }
+-#endif
+- default:
+- return v4l_compat_translate_ioctl(file, cmd, arg,
+- saa7146_video_do_ioctl);
+- }
++ return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
++ core, g_chip_ident, chip);
++}
++
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf)
++{
++ struct saa7146_fh *fh = __fh;
++ struct videobuf_queue *q = &fh->video_q;
++ int err, i;
++
++ /* fixme: number of capture buffers and sizes for v4l apps */
++ int gbuffers = 2;
++ int gbufsize = 768 * 576 * 4;
++
++ DEB_D(("VIDIOCGMBUF \n"));
++
++ q = &fh->video_q;
++ err = videobuf_mmap_setup(q, gbuffers, gbufsize,
++ V4L2_MEMORY_MMAP);
++ if (err < 0)
++ return err;
++
++ gbuffers = err;
++ memset(mbuf, 0, sizeof(*mbuf));
++ mbuf->frames = gbuffers;
++ mbuf->size = gbuffers * gbufsize;
++ for (i = 0; i < gbuffers; i++)
++ mbuf->offsets[i] = i * gbufsize;
+ return 0;
+ }
++#endif
++
++const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
++ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
++ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
++ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
++ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
++ .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
++ .vidioc_g_chip_ident = vidioc_g_chip_ident,
++
++ .vidioc_overlay = vidioc_overlay,
++ .vidioc_g_fbuf = vidioc_g_fbuf,
++ .vidioc_s_fbuf = vidioc_s_fbuf,
++ .vidioc_reqbufs = vidioc_reqbufs,
++ .vidioc_querybuf = vidioc_querybuf,
++ .vidioc_qbuf = vidioc_qbuf,
++ .vidioc_dqbuf = vidioc_dqbuf,
++ .vidioc_g_std = vidioc_g_std,
++ .vidioc_s_std = vidioc_s_std,
++ .vidioc_queryctrl = vidioc_queryctrl,
++ .vidioc_g_ctrl = vidioc_g_ctrl,
++ .vidioc_s_ctrl = vidioc_s_ctrl,
++ .vidioc_streamon = vidioc_streamon,
++ .vidioc_streamoff = vidioc_streamoff,
++ .vidioc_g_parm = vidioc_g_parm,
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++ .vidiocgmbuf = vidiocgmbuf,
++#endif
++};
+
+ /*********************************************************************************/
+ /* buffer handling functions */
+diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
+index 6f92bea..52c3f65 100644
+--- a/drivers/media/common/tuners/Kconfig
++++ b/drivers/media/common/tuners/Kconfig
+@@ -21,16 +21,17 @@ config MEDIA_TUNER
+ tristate
+ default VIDEO_MEDIA && I2C
+ depends on VIDEO_MEDIA && I2C
+- select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE
+-
+-menuconfig MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
++
++menuconfig MEDIA_TUNER_CUSTOMISE
+ bool "Customize analog and hybrid tuner modules to build"
+ depends on MEDIA_TUNER
+ default n
+@@ -43,13 +44,13 @@ menuconfig MEDIA_TUNER_CUSTOMIZE
+
+ If unsure say N.
+
+-if MEDIA_TUNER_CUSTOMIZE
++if MEDIA_TUNER_CUSTOMISE
+
+ config MEDIA_TUNER_SIMPLE
+ tristate "Simple tuner support"
+ depends on VIDEO_MEDIA && I2C
+ select MEDIA_TUNER_TDA9887
+- default m if MEDIA_TUNER_CUSTOMIZE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to include support for various simple tuners.
+
+@@ -58,28 +59,28 @@ config MEDIA_TUNER_TDA8290
+ depends on VIDEO_MEDIA && I2C
+ select MEDIA_TUNER_TDA827X
+ select MEDIA_TUNER_TDA18271
+- default m if MEDIA_TUNER_CUSTOMIZE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to include support for Philips TDA8290+8275(a) tuner.
+
+ config MEDIA_TUNER_TDA827X
+ tristate "Philips TDA827X silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if DVB_FE_CUSTOMISE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A DVB-T silicon tuner module. Say Y when you want to support this tuner.
+
+ config MEDIA_TUNER_TDA18271
+ tristate "NXP TDA18271 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if DVB_FE_CUSTOMISE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A silicon tuner module. Say Y when you want to support this tuner.
+
+ config MEDIA_TUNER_TDA9887
+ tristate "TDA 9885/6/7 analog IF demodulator"
+ depends on VIDEO_MEDIA && I2C
+- default m if MEDIA_TUNER_CUSTOMIZE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to include support for Philips TDA9885/6/7
+ analog IF demodulator.
+@@ -88,63 +89,63 @@ config MEDIA_TUNER_TEA5761
+ tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
+ depends on VIDEO_MEDIA && I2C
+ depends on EXPERIMENTAL
+- default m if MEDIA_TUNER_CUSTOMIZE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to include support for the Philips TEA5761 radio tuner.
+
+ config MEDIA_TUNER_TEA5767
+ tristate "TEA 5767 radio tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if MEDIA_TUNER_CUSTOMIZE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to include support for the Philips TEA5767 radio tuner.
+
+ config MEDIA_TUNER_MT20XX
+ tristate "Microtune 2032 / 2050 tuners"
+ depends on VIDEO_MEDIA && I2C
+- default m if MEDIA_TUNER_CUSTOMIZE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to include support for the MT2032 / MT2050 tuner.
+
+ config MEDIA_TUNER_MT2060
+ tristate "Microtune MT2060 silicon IF tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if DVB_FE_CUSTOMISE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A driver for the silicon IF tuner MT2060 from Microtune.
+
+ config MEDIA_TUNER_MT2266
+ tristate "Microtune MT2266 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if DVB_FE_CUSTOMISE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner MT2266 from Microtune.
+
+ config MEDIA_TUNER_MT2131
+ tristate "Microtune MT2131 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if DVB_FE_CUSTOMISE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner MT2131 from Microtune.
+
+ config MEDIA_TUNER_QT1010
+ tristate "Quantek QT1010 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if DVB_FE_CUSTOMISE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A driver for the silicon tuner QT1010 from Quantek.
+
+ config MEDIA_TUNER_XC2028
+ tristate "XCeive xc2028/xc3028 tuners"
+ depends on VIDEO_MEDIA && I2C
+- default m if MEDIA_TUNER_CUSTOMIZE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to include support for the xc2028/xc3028 tuners.
+
+ config MEDIA_TUNER_XC5000
+ tristate "Xceive XC5000 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if DVB_FE_CUSTOMISE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A driver for the silicon tuner XC5000 from Xceive.
+ This device is only used inside a SiP called togther with a
+@@ -153,15 +154,22 @@ config MEDIA_TUNER_XC5000
+ config MEDIA_TUNER_MXL5005S
+ tristate "MaxLinear MSL5005S silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if DVB_FE_CUSTOMISE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A driver for the silicon tuner MXL5005S from MaxLinear.
+
+ config MEDIA_TUNER_MXL5007T
+ tristate "MaxLinear MxL5007T silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+- default m if DVB_FE_CUSTOMISE
++ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A driver for the silicon tuner MxL5007T from MaxLinear.
+
+-endif # MEDIA_TUNER_CUSTOMIZE
++config MEDIA_TUNER_MC44S803
++ tristate "Freescale MC44S803 Low Power CMOS Broadband tuners"
++ depends on VIDEO_MEDIA && I2C
++ default m if MEDIA_TUNER_CUSTOMISE
++ help
++ Say Y here to support the Freescale MC44S803 based tuners
++
++endif # MEDIA_TUNER_CUSTOMISE
+diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
+index 4dfbe5b..4132b2b 100644
+--- a/drivers/media/common/tuners/Makefile
++++ b/drivers/media/common/tuners/Makefile
+@@ -22,6 +22,7 @@ obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
+ obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
+ obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
+ obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
++obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
+
+ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+ EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+diff --git a/drivers/media/common/tuners/mc44s803.c b/drivers/media/common/tuners/mc44s803.c
+new file mode 100644
+index 0000000..20c4485
+--- /dev/null
++++ b/drivers/media/common/tuners/mc44s803.c
+@@ -0,0 +1,371 @@
++/*
++ * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
++ *
++ * Copyright (c) 2009 Jochen Friedrich <jochen@scram.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/module.h>
++#include <linux/delay.h>
++#include <linux/dvb/frontend.h>
++#include <linux/i2c.h>
++
++#include "dvb_frontend.h"
++
++#include "mc44s803.h"
++#include "mc44s803_priv.h"
++
++#define mc_printk(level, format, arg...) \
++ printk(level "mc44s803: " format , ## arg)
++
++/* Writes a single register */
++static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val)
++{
++ u8 buf[3];
++ struct i2c_msg msg = {
++ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3
++ };
++
++ buf[0] = (val & 0xff0000) >> 16;
++ buf[1] = (val & 0xff00) >> 8;
++ buf[2] = (val & 0xff);
++
++ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
++ mc_printk(KERN_WARNING, "I2C write failed\n");
++ return -EREMOTEIO;
++ }
++ return 0;
++}
++
++/* Reads a single register */
++static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val)
++{
++ u32 wval;
++ u8 buf[3];
++ int ret;
++ struct i2c_msg msg[] = {
++ { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
++ .buf = buf, .len = 3 },
++ };
++
++ wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) |
++ MC44S803_REG_SM(reg, MC44S803_D);
++
++ ret = mc44s803_writereg(priv, wval);
++ if (ret)
++ return ret;
++
++ if (i2c_transfer(priv->i2c, msg, 1) != 1) {
++ mc_printk(KERN_WARNING, "I2C read failed\n");
++ return -EREMOTEIO;
++ }
++
++ *val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
++
++ return 0;
++}
++
++static int mc44s803_release(struct dvb_frontend *fe)
++{
++ struct mc44s803_priv *priv = fe->tuner_priv;
++
++ fe->tuner_priv = NULL;
++ kfree(priv);
++
++ return 0;
++}
++
++static int mc44s803_init(struct dvb_frontend *fe)
++{
++ struct mc44s803_priv *priv = fe->tuner_priv;
++ u32 val;
++ int err;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++
++/* Reset chip */
++ val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) |
++ MC44S803_REG_SM(1, MC44S803_RS);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++/* Power Up and Start Osc */
++
++ val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
++ MC44S803_REG_SM(0xC0, MC44S803_REFOSC) |
++ MC44S803_REG_SM(1, MC44S803_OSCSEL);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) |
++ MC44S803_REG_SM(0x200, MC44S803_POWER);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ msleep(10);
++
++ val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
++ MC44S803_REG_SM(0x40, MC44S803_REFOSC) |
++ MC44S803_REG_SM(1, MC44S803_OSCSEL);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ msleep(20);
++
++/* Setup Mixer */
++
++ val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) |
++ MC44S803_REG_SM(1, MC44S803_TRI_STATE) |
++ MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++/* Setup Cirquit Adjust */
++
++ val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
++ MC44S803_REG_SM(1, MC44S803_G1) |
++ MC44S803_REG_SM(1, MC44S803_G3) |
++ MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
++ MC44S803_REG_SM(1, MC44S803_G6) |
++ MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
++ MC44S803_REG_SM(0x3, MC44S803_LP) |
++ MC44S803_REG_SM(1, MC44S803_CLRF) |
++ MC44S803_REG_SM(1, MC44S803_CLIF);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
++ MC44S803_REG_SM(1, MC44S803_G1) |
++ MC44S803_REG_SM(1, MC44S803_G3) |
++ MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
++ MC44S803_REG_SM(1, MC44S803_G6) |
++ MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
++ MC44S803_REG_SM(0x3, MC44S803_LP);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++/* Setup Digtune */
++
++ val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
++ MC44S803_REG_SM(3, MC44S803_XOD);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++/* Setup AGC */
++
++ val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) |
++ MC44S803_REG_SM(1, MC44S803_AT1) |
++ MC44S803_REG_SM(1, MC44S803_AT2) |
++ MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) |
++ MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) |
++ MC44S803_REG_SM(1, MC44S803_LNA0);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++ return 0;
++
++exit:
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ mc_printk(KERN_WARNING, "I/O Error\n");
++ return err;
++}
++
++static int mc44s803_set_params(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *params)
++{
++ struct mc44s803_priv *priv = fe->tuner_priv;
++ u32 r1, r2, n1, n2, lo1, lo2, freq, val;
++ int err;
++
++ priv->frequency = params->frequency;
++
++ r1 = MC44S803_OSC / 1000000;
++ r2 = MC44S803_OSC / 100000;
++
++ n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000;
++ freq = MC44S803_OSC / r1 * n1;
++ lo1 = ((60 * n1) + (r1 / 2)) / r1;
++ freq = freq - params->frequency;
++
++ n2 = (freq - MC44S803_IF2 + 50000) / 100000;
++ lo2 = ((60 * n2) + (r2 / 2)) / r2;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++
++ val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) |
++ MC44S803_REG_SM(r1-1, MC44S803_R1) |
++ MC44S803_REG_SM(r2-1, MC44S803_R2) |
++ MC44S803_REG_SM(1, MC44S803_REFBUF_EN);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) |
++ MC44S803_REG_SM(n1-2, MC44S803_LO1);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) |
++ MC44S803_REG_SM(n2-2, MC44S803_LO2);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
++ MC44S803_REG_SM(1, MC44S803_DA) |
++ MC44S803_REG_SM(lo1, MC44S803_LO_REF) |
++ MC44S803_REG_SM(1, MC44S803_AT);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
++ MC44S803_REG_SM(2, MC44S803_DA) |
++ MC44S803_REG_SM(lo2, MC44S803_LO_REF) |
++ MC44S803_REG_SM(1, MC44S803_AT);
++
++ err = mc44s803_writereg(priv, val);
++ if (err)
++ goto exit;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ return 0;
++
++exit:
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ mc_printk(KERN_WARNING, "I/O Error\n");
++ return err;
++}
++
++static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency)
++{
++ struct mc44s803_priv *priv = fe->tuner_priv;
++ *frequency = priv->frequency;
++ return 0;
++}
++
++static const struct dvb_tuner_ops mc44s803_tuner_ops = {
++ .info = {
++ .name = "Freescale MC44S803",
++ .frequency_min = 48000000,
++ .frequency_max = 1000000000,
++ .frequency_step = 100000,
++ },
++
++ .release = mc44s803_release,
++ .init = mc44s803_init,
++ .set_params = mc44s803_set_params,
++ .get_frequency = mc44s803_get_frequency
++};
++
++/* This functions tries to identify a MC44S803 tuner by reading the ID
++ register. This is hasty. */
++struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, struct mc44s803_config *cfg)
++{
++ struct mc44s803_priv *priv;
++ u32 reg;
++ u8 id;
++ int ret;
++
++ reg = 0;
++
++ priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL);
++ if (priv == NULL)
++ return NULL;
++
++ priv->cfg = cfg;
++ priv->i2c = i2c;
++ priv->fe = fe;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
++
++ ret = mc44s803_readreg(priv, MC44S803_REG_ID, &reg);
++ if (ret)
++ goto error;
++
++ id = MC44S803_REG_MS(reg, MC44S803_ID);
++
++ if (id != 0x14) {
++ mc_printk(KERN_ERR, "unsupported ID "
++ "(%x should be 0x14)\n", id);
++ goto error;
++ }
++
++ mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id);
++ memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops,
++ sizeof(struct dvb_tuner_ops));
++
++ fe->tuner_priv = priv;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
++
++ return fe;
++
++error:
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
++
++ kfree(priv);
++ return NULL;
++}
++EXPORT_SYMBOL(mc44s803_attach);
++
++MODULE_AUTHOR("Jochen Friedrich");
++MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/common/tuners/mc44s803.h b/drivers/media/common/tuners/mc44s803.h
+new file mode 100644
+index 0000000..34f3892
+--- /dev/null
++++ b/drivers/media/common/tuners/mc44s803.h
+@@ -0,0 +1,46 @@
++/*
++ * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
++ *
++ * Copyright (c) 2009 Jochen Friedrich <jochen@scram.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 MC44S803_H
++#define MC44S803_H
++
++struct dvb_frontend;
++struct i2c_adapter;
++
++struct mc44s803_config {
++ u8 i2c_address;
++ u8 dig_out;
++};
++
++#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \
++ (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE))
++extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, struct mc44s803_config *cfg);
++#else
++static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, struct mc44s803_config *cfg)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif /* CONFIG_MEDIA_TUNER_MC44S803 */
++
++#endif
+diff --git a/drivers/media/common/tuners/mc44s803_priv.h b/drivers/media/common/tuners/mc44s803_priv.h
+new file mode 100644
+index 0000000..14a9278
+--- /dev/null
++++ b/drivers/media/common/tuners/mc44s803_priv.h
+@@ -0,0 +1,208 @@
++/*
++ * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
++ *
++ * Copyright (c) 2009 Jochen Friedrich <jochen@scram.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 MC44S803_PRIV_H
++#define MC44S803_PRIV_H
++
++/* This driver is based on the information available in the datasheet
++ http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf
++
++ SPI or I2C Address : 0xc0-0xc6
++
++ Reg.No | Function
++ -------------------------------------------
++ 00 | Power Down
++ 01 | Reference Oszillator
++ 02 | Reference Dividers
++ 03 | Mixer and Reference Buffer
++ 04 | Reset/Serial Out
++ 05 | LO 1
++ 06 | LO 2
++ 07 | Circuit Adjust
++ 08 | Test
++ 09 | Digital Tune
++ 0A | LNA AGC
++ 0B | Data Register Address
++ 0C | Regulator Test
++ 0D | VCO Test
++ 0E | LNA Gain/Input Power
++ 0F | ID Bits
++
++*/
++
++#define MC44S803_OSC 26000000 /* 26 MHz */
++#define MC44S803_IF1 1086000000 /* 1086 MHz */
++#define MC44S803_IF2 36125000 /* 36.125 MHz */
++
++#define MC44S803_REG_POWER 0
++#define MC44S803_REG_REFOSC 1
++#define MC44S803_REG_REFDIV 2
++#define MC44S803_REG_MIXER 3
++#define MC44S803_REG_RESET 4
++#define MC44S803_REG_LO1 5
++#define MC44S803_REG_LO2 6
++#define MC44S803_REG_CIRCADJ 7
++#define MC44S803_REG_TEST 8
++#define MC44S803_REG_DIGTUNE 9
++#define MC44S803_REG_LNAAGC 0x0A
++#define MC44S803_REG_DATAREG 0x0B
++#define MC44S803_REG_REGTEST 0x0C
++#define MC44S803_REG_VCOTEST 0x0D
++#define MC44S803_REG_LNAGAIN 0x0E
++#define MC44S803_REG_ID 0x0F
++
++/* Register definitions */
++#define MC44S803_ADDR 0x0F
++#define MC44S803_ADDR_S 0
++/* REG_POWER */
++#define MC44S803_POWER 0xFFFFF0
++#define MC44S803_POWER_S 4
++/* REG_REFOSC */
++#define MC44S803_REFOSC 0x1FF0
++#define MC44S803_REFOSC_S 4
++#define MC44S803_OSCSEL 0x2000
++#define MC44S803_OSCSEL_S 13
++/* REG_REFDIV */
++#define MC44S803_R2 0x1FF0
++#define MC44S803_R2_S 4
++#define MC44S803_REFBUF_EN 0x2000
++#define MC44S803_REFBUF_EN_S 13
++#define MC44S803_R1 0x7C000
++#define MC44S803_R1_S 14
++/* REG_MIXER */
++#define MC44S803_R3 0x70
++#define MC44S803_R3_S 4
++#define MC44S803_MUX3 0x80
++#define MC44S803_MUX3_S 7
++#define MC44S803_MUX4 0x100
++#define MC44S803_MUX4_S 8
++#define MC44S803_OSC_SCR 0x200
++#define MC44S803_OSC_SCR_S 9
++#define MC44S803_TRI_STATE 0x400
++#define MC44S803_TRI_STATE_S 10
++#define MC44S803_BUF_GAIN 0x800
++#define MC44S803_BUF_GAIN_S 11
++#define MC44S803_BUF_IO 0x1000
++#define MC44S803_BUF_IO_S 12
++#define MC44S803_MIXER_RES 0xFE000
++#define MC44S803_MIXER_RES_S 13
++/* REG_RESET */
++#define MC44S803_RS 0x10
++#define MC44S803_RS_S 4
++#define MC44S803_SO 0x20
++#define MC44S803_SO_S 5
++/* REG_LO1 */
++#define MC44S803_LO1 0xFFF0
++#define MC44S803_LO1_S 4
++/* REG_LO2 */
++#define MC44S803_LO2 0x7FFF0
++#define MC44S803_LO2_S 4
++/* REG_CIRCADJ */
++#define MC44S803_G1 0x20
++#define MC44S803_G1_S 5
++#define MC44S803_G3 0x80
++#define MC44S803_G3_S 7
++#define MC44S803_CIRCADJ_RES 0x300
++#define MC44S803_CIRCADJ_RES_S 8
++#define MC44S803_G6 0x400
++#define MC44S803_G6_S 10
++#define MC44S803_G7 0x800
++#define MC44S803_G7_S 11
++#define MC44S803_S1 0x1000
++#define MC44S803_S1_S 12
++#define MC44S803_LP 0x7E000
++#define MC44S803_LP_S 13
++#define MC44S803_CLRF 0x80000
++#define MC44S803_CLRF_S 19
++#define MC44S803_CLIF 0x100000
++#define MC44S803_CLIF_S 20
++/* REG_TEST */
++/* REG_DIGTUNE */
++#define MC44S803_DA 0xF0
++#define MC44S803_DA_S 4
++#define MC44S803_XOD 0x300
++#define MC44S803_XOD_S 8
++#define MC44S803_RST 0x10000
++#define MC44S803_RST_S 16
++#define MC44S803_LO_REF 0x1FFF00
++#define MC44S803_LO_REF_S 8
++#define MC44S803_AT 0x200000
++#define MC44S803_AT_S 21
++#define MC44S803_MT 0x400000
++#define MC44S803_MT_S 22
++/* REG_LNAAGC */
++#define MC44S803_G 0x3F0
++#define MC44S803_G_S 4
++#define MC44S803_AT1 0x400
++#define MC44S803_AT1_S 10
++#define MC44S803_AT2 0x800
++#define MC44S803_AT2_S 11
++#define MC44S803_HL_GR_EN 0x8000
++#define MC44S803_HL_GR_EN_S 15
++#define MC44S803_AGC_AN_DIG 0x10000
++#define MC44S803_AGC_AN_DIG_S 16
++#define MC44S803_ATTEN_EN 0x20000
++#define MC44S803_ATTEN_EN_S 17
++#define MC44S803_AGC_READ_EN 0x40000
++#define MC44S803_AGC_READ_EN_S 18
++#define MC44S803_LNA0 0x80000
++#define MC44S803_LNA0_S 19
++#define MC44S803_AGC_SEL 0x100000
++#define MC44S803_AGC_SEL_S 20
++#define MC44S803_AT0 0x200000
++#define MC44S803_AT0_S 21
++#define MC44S803_B 0xC00000
++#define MC44S803_B_S 22
++/* REG_DATAREG */
++#define MC44S803_D 0xF0
++#define MC44S803_D_S 4
++/* REG_REGTEST */
++/* REG_VCOTEST */
++/* REG_LNAGAIN */
++#define MC44S803_IF_PWR 0x700
++#define MC44S803_IF_PWR_S 8
++#define MC44S803_RF_PWR 0x3800
++#define MC44S803_RF_PWR_S 11
++#define MC44S803_LNA_GAIN 0xFC000
++#define MC44S803_LNA_GAIN_S 14
++/* REG_ID */
++#define MC44S803_ID 0x3E00
++#define MC44S803_ID_S 9
++
++/* Some macros to read/write fields */
++
++/* First shift, then mask */
++#define MC44S803_REG_SM(_val, _reg) \
++ (((_val) << _reg##_S) & (_reg))
++
++/* First mask, then shift */
++#define MC44S803_REG_MS(_val, _reg) \
++ (((_val) & (_reg)) >> _reg##_S)
++
++struct mc44s803_priv {
++ struct mc44s803_config *cfg;
++ struct i2c_adapter *i2c;
++ struct dvb_frontend *fe;
++
++ u32 frequency;
++};
++
++#endif
+diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c
+index 12206d7..c7abe3d 100644
+--- a/drivers/media/common/tuners/mt2060.c
++++ b/drivers/media/common/tuners/mt2060.c
+@@ -278,7 +278,7 @@ static void mt2060_calibrate(struct mt2060_priv *priv)
+ while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0)
+ msleep(20);
+
+- if (i < 10) {
++ if (i <= 10) {
+ mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :)
+ dprintk("calibration was successful: %d", (int)priv->fmfreq);
+ } else
+diff --git a/drivers/media/common/tuners/mt20xx.c b/drivers/media/common/tuners/mt20xx.c
+index 35b763a..44608ad 100644
+--- a/drivers/media/common/tuners/mt20xx.c
++++ b/drivers/media/common/tuners/mt20xx.c
+@@ -6,7 +6,7 @@
+ */
+ #include <linux/delay.h>
+ #include <linux/i2c.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include "tuner-i2c.h"
+ #include "mt20xx.h"
+
+diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
+index 31522d2..0803dab 100644
+--- a/drivers/media/common/tuners/mxl5005s.c
++++ b/drivers/media/common/tuners/mxl5005s.c
+@@ -4003,12 +4003,11 @@ static int mxl5005s_set_params(struct dvb_frontend *fe,
+ /* Change tuner for new modulation type if reqd */
+ if (req_mode != state->current_mode) {
+ switch (req_mode) {
+- case VSB_8:
+- case QAM_64:
+- case QAM_256:
+- case QAM_AUTO:
++ case MXL_ATSC:
++ case MXL_QAM:
+ req_bw = MXL5005S_BANDWIDTH_6MHZ;
+ break;
++ case MXL_DVBT:
+ default:
+ /* Assume DVB-T */
+ switch (params->u.ofdm.bandwidth) {
+diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c
+index 3ec2894..2d02698 100644
+--- a/drivers/media/common/tuners/mxl5007t.c
++++ b/drivers/media/common/tuners/mxl5007t.c
+@@ -1,7 +1,7 @@
+ /*
+ * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner
+ *
+- * Copyright (C) 2008 Michael Krufky <mkrufky@linuxtv.org>
++ * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * 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
+@@ -66,22 +66,17 @@ MODULE_PARM_DESC(debug, "set debug level");
+ #define MHz 1000000
+
+ enum mxl5007t_mode {
+- MxL_MODE_OTA_DVBT_ATSC = 0,
+- MxL_MODE_OTA_NTSC_PAL_GH = 1,
+- MxL_MODE_OTA_PAL_IB = 2,
+- MxL_MODE_OTA_PAL_D_SECAM_KL = 3,
+- MxL_MODE_OTA_ISDBT = 4,
+- MxL_MODE_CABLE_DIGITAL = 0x10,
+- MxL_MODE_CABLE_NTSC_PAL_GH = 0x11,
+- MxL_MODE_CABLE_PAL_IB = 0x12,
+- MxL_MODE_CABLE_PAL_D_SECAM_KL = 0x13,
+- MxL_MODE_CABLE_SCTE40 = 0x14,
++ MxL_MODE_ISDBT = 0,
++ MxL_MODE_DVBT = 1,
++ MxL_MODE_ATSC = 2,
++ MxL_MODE_CABLE = 0x10,
+ };
+
+ enum mxl5007t_chip_version {
+ MxL_UNKNOWN_ID = 0x00,
+ MxL_5007_V1_F1 = 0x11,
+ MxL_5007_V1_F2 = 0x12,
++ MxL_5007_V4 = 0x14,
+ MxL_5007_V2_100_F1 = 0x21,
+ MxL_5007_V2_100_F2 = 0x22,
+ MxL_5007_V2_200_F1 = 0x23,
+@@ -96,67 +91,61 @@ struct reg_pair_t {
+ /* ------------------------------------------------------------------------- */
+
+ static struct reg_pair_t init_tab[] = {
+- { 0x0b, 0x44 }, /* XTAL */
+- { 0x0c, 0x60 }, /* IF */
+- { 0x10, 0x00 }, /* MISC */
+- { 0x12, 0xca }, /* IDAC */
+- { 0x16, 0x90 }, /* MODE */
+- { 0x32, 0x38 }, /* MODE Analog/Digital */
+- { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */
+- { 0x2c, 0x34 }, /* OVERRIDE */
+- { 0x4d, 0x40 }, /* OVERRIDE */
+- { 0x7f, 0x02 }, /* OVERRIDE */
+- { 0x9a, 0x52 }, /* OVERRIDE */
+- { 0x48, 0x5a }, /* OVERRIDE */
+- { 0x76, 0x1a }, /* OVERRIDE */
+- { 0x6a, 0x48 }, /* OVERRIDE */
+- { 0x64, 0x28 }, /* OVERRIDE */
+- { 0x66, 0xe6 }, /* OVERRIDE */
+- { 0x35, 0x0e }, /* OVERRIDE */
+- { 0x7e, 0x01 }, /* OVERRIDE */
+- { 0x83, 0x00 }, /* OVERRIDE */
+- { 0x04, 0x0b }, /* OVERRIDE */
+- { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */
++ { 0x02, 0x06 },
++ { 0x03, 0x48 },
++ { 0x05, 0x04 },
++ { 0x06, 0x10 },
++ { 0x2e, 0x15 }, /* OVERRIDE */
++ { 0x30, 0x10 }, /* OVERRIDE */
++ { 0x45, 0x58 }, /* OVERRIDE */
++ { 0x48, 0x19 }, /* OVERRIDE */
++ { 0x52, 0x03 }, /* OVERRIDE */
++ { 0x53, 0x44 }, /* OVERRIDE */
++ { 0x6a, 0x4b }, /* OVERRIDE */
++ { 0x76, 0x00 }, /* OVERRIDE */
++ { 0x78, 0x18 }, /* OVERRIDE */
++ { 0x7a, 0x17 }, /* OVERRIDE */
++ { 0x85, 0x06 }, /* OVERRIDE */
++ { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
+ { 0, 0 }
+ };
+
+ static struct reg_pair_t init_tab_cable[] = {
+- { 0x0b, 0x44 }, /* XTAL */
+- { 0x0c, 0x60 }, /* IF */
+- { 0x10, 0x00 }, /* MISC */
+- { 0x12, 0xca }, /* IDAC */
+- { 0x16, 0x90 }, /* MODE */
+- { 0x32, 0x38 }, /* MODE A/D */
+- { 0x71, 0x3f }, /* TOP1 */
+- { 0x72, 0x3f }, /* TOP2 */
+- { 0x74, 0x3f }, /* TOP3 */
+- { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */
+- { 0x2c, 0x34 }, /* OVERRIDE */
+- { 0x4d, 0x40 }, /* OVERRIDE */
+- { 0x7f, 0x02 }, /* OVERRIDE */
+- { 0x9a, 0x52 }, /* OVERRIDE */
+- { 0x48, 0x5a }, /* OVERRIDE */
+- { 0x76, 0x1a }, /* OVERRIDE */
+- { 0x6a, 0x48 }, /* OVERRIDE */
+- { 0x64, 0x28 }, /* OVERRIDE */
+- { 0x66, 0xe6 }, /* OVERRIDE */
+- { 0x35, 0x0e }, /* OVERRIDE */
+- { 0x7e, 0x01 }, /* OVERRIDE */
+- { 0x04, 0x0b }, /* OVERRIDE */
+- { 0x68, 0xb4 }, /* OVERRIDE */
+- { 0x36, 0x00 }, /* OVERRIDE */
+- { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */
++ { 0x02, 0x06 },
++ { 0x03, 0x48 },
++ { 0x05, 0x04 },
++ { 0x06, 0x10 },
++ { 0x09, 0x3f },
++ { 0x0a, 0x3f },
++ { 0x0b, 0x3f },
++ { 0x2e, 0x15 }, /* OVERRIDE */
++ { 0x30, 0x10 }, /* OVERRIDE */
++ { 0x45, 0x58 }, /* OVERRIDE */
++ { 0x48, 0x19 }, /* OVERRIDE */
++ { 0x52, 0x03 }, /* OVERRIDE */
++ { 0x53, 0x44 }, /* OVERRIDE */
++ { 0x6a, 0x4b }, /* OVERRIDE */
++ { 0x76, 0x00 }, /* OVERRIDE */
++ { 0x78, 0x18 }, /* OVERRIDE */
++ { 0x7a, 0x17 }, /* OVERRIDE */
++ { 0x85, 0x06 }, /* OVERRIDE */
++ { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */
+ { 0, 0 }
+ };
+
+ /* ------------------------------------------------------------------------- */
+
+ static struct reg_pair_t reg_pair_rftune[] = {
+- { 0x11, 0x00 }, /* abort tune */
+- { 0x13, 0x15 },
+- { 0x14, 0x40 },
+- { 0x15, 0x0e },
+- { 0x11, 0x02 }, /* start tune */
++ { 0x0f, 0x00 }, /* abort tune */
++ { 0x0c, 0x15 },
++ { 0x0d, 0x40 },
++ { 0x0e, 0x0e },
++ { 0x1f, 0x87 }, /* OVERRIDE */
++ { 0x20, 0x1f }, /* OVERRIDE */
++ { 0x21, 0x87 }, /* OVERRIDE */
++ { 0x22, 0x1f }, /* OVERRIDE */
++ { 0x80, 0x01 }, /* freq dependent */
++ { 0x0f, 0x01 }, /* start tune */
+ { 0, 0 }
+ };
+
+@@ -227,63 +216,20 @@ static void mxl5007t_set_mode_bits(struct mxl5007t_state *state,
+ s32 if_diff_out_level)
+ {
+ switch (mode) {
+- case MxL_MODE_OTA_DVBT_ATSC:
+- set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06);
+- set_reg_bits(state->tab_init, 0x35, 0xff, 0x0e);
++ case MxL_MODE_ATSC:
++ set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12);
+ break;
+- case MxL_MODE_OTA_ISDBT:
+- set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06);
+- set_reg_bits(state->tab_init, 0x35, 0xff, 0x12);
++ case MxL_MODE_DVBT:
++ set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11);
+ break;
+- case MxL_MODE_OTA_NTSC_PAL_GH:
+- set_reg_bits(state->tab_init, 0x16, 0x70, 0x00);
+- set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
++ case MxL_MODE_ISDBT:
++ set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10);
+ break;
+- case MxL_MODE_OTA_PAL_IB:
+- set_reg_bits(state->tab_init, 0x16, 0x70, 0x10);
+- set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+- break;
+- case MxL_MODE_OTA_PAL_D_SECAM_KL:
+- set_reg_bits(state->tab_init, 0x16, 0x70, 0x20);
+- set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+- break;
+- case MxL_MODE_CABLE_DIGITAL:
+- set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+- set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+- 8 - if_diff_out_level);
+- set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+- break;
+- case MxL_MODE_CABLE_NTSC_PAL_GH:
+- set_reg_bits(state->tab_init, 0x16, 0x70, 0x00);
+- set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+- set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+- set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+- 8 - if_diff_out_level);
+- set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+- break;
+- case MxL_MODE_CABLE_PAL_IB:
+- set_reg_bits(state->tab_init, 0x16, 0x70, 0x10);
+- set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+- set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+- set_reg_bits(state->tab_init_cable, 0x72, 0xff,
++ case MxL_MODE_CABLE:
++ set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1);
++ set_reg_bits(state->tab_init_cable, 0x0a, 0xff,
+ 8 - if_diff_out_level);
+- set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+- break;
+- case MxL_MODE_CABLE_PAL_D_SECAM_KL:
+- set_reg_bits(state->tab_init, 0x16, 0x70, 0x20);
+- set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+- set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+- set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+- 8 - if_diff_out_level);
+- set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+- break;
+- case MxL_MODE_CABLE_SCTE40:
+- set_reg_bits(state->tab_init_cable, 0x36, 0xff, 0x08);
+- set_reg_bits(state->tab_init_cable, 0x68, 0xff, 0xbc);
+- set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+- set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+- 8 - if_diff_out_level);
+- set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
++ set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17);
+ break;
+ default:
+ mxl_fail(-EINVAL);
+@@ -302,43 +248,43 @@ static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state,
+ val = 0x00;
+ break;
+ case MxL_IF_4_5_MHZ:
+- val = 0x20;
++ val = 0x02;
+ break;
+ case MxL_IF_4_57_MHZ:
+- val = 0x30;
++ val = 0x03;
+ break;
+ case MxL_IF_5_MHZ:
+- val = 0x40;
++ val = 0x04;
+ break;
+ case MxL_IF_5_38_MHZ:
+- val = 0x50;
++ val = 0x05;
+ break;
+ case MxL_IF_6_MHZ:
+- val = 0x60;
++ val = 0x06;
+ break;
+ case MxL_IF_6_28_MHZ:
+- val = 0x70;
++ val = 0x07;
+ break;
+ case MxL_IF_9_1915_MHZ:
+- val = 0x80;
++ val = 0x08;
+ break;
+ case MxL_IF_35_25_MHZ:
+- val = 0x90;
++ val = 0x09;
+ break;
+ case MxL_IF_36_15_MHZ:
+- val = 0xa0;
++ val = 0x0a;
+ break;
+ case MxL_IF_44_MHZ:
+- val = 0xb0;
++ val = 0x0b;
+ break;
+ default:
+ mxl_fail(-EINVAL);
+ return;
+ }
+- set_reg_bits(state->tab_init, 0x0c, 0xf0, val);
++ set_reg_bits(state->tab_init, 0x02, 0x0f, val);
+
+ /* set inverted IF or normal IF */
+- set_reg_bits(state->tab_init, 0x0c, 0x08, invert_if ? 0x08 : 0x00);
++ set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00);
+
+ return;
+ }
+@@ -346,56 +292,68 @@ static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state,
+ static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state,
+ enum mxl5007t_xtal_freq xtal_freq)
+ {
+- u8 val;
+-
+ switch (xtal_freq) {
+ case MxL_XTAL_16_MHZ:
+- val = 0x00; /* select xtal freq & Ref Freq */
++ /* select xtal freq & ref freq */
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00);
+ break;
+ case MxL_XTAL_20_MHZ:
+- val = 0x11;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01);
+ break;
+ case MxL_XTAL_20_25_MHZ:
+- val = 0x22;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02);
+ break;
+ case MxL_XTAL_20_48_MHZ:
+- val = 0x33;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03);
+ break;
+ case MxL_XTAL_24_MHZ:
+- val = 0x44;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04);
+ break;
+ case MxL_XTAL_25_MHZ:
+- val = 0x55;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05);
+ break;
+ case MxL_XTAL_25_14_MHZ:
+- val = 0x66;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06);
+ break;
+ case MxL_XTAL_27_MHZ:
+- val = 0x77;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07);
+ break;
+ case MxL_XTAL_28_8_MHZ:
+- val = 0x88;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08);
+ break;
+ case MxL_XTAL_32_MHZ:
+- val = 0x99;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09);
+ break;
+ case MxL_XTAL_40_MHZ:
+- val = 0xaa;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a);
+ break;
+ case MxL_XTAL_44_MHZ:
+- val = 0xbb;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b);
+ break;
+ case MxL_XTAL_48_MHZ:
+- val = 0xcc;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c);
+ break;
+ case MxL_XTAL_49_3811_MHZ:
+- val = 0xdd;
++ set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0);
++ set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d);
+ break;
+ default:
+ mxl_fail(-EINVAL);
+ return;
+ }
+- set_reg_bits(state->tab_init, 0x0b, 0xff, val);
+
+ return;
+ }
+@@ -412,16 +370,11 @@ static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state,
+ mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if);
+ mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz);
+
+- set_reg_bits(state->tab_init, 0x10, 0x40, cfg->loop_thru_enable << 6);
+-
+- set_reg_bits(state->tab_init, 0xd8, 0x08, cfg->clk_out_enable << 3);
+-
+- set_reg_bits(state->tab_init, 0x10, 0x07, cfg->clk_out_amp);
++ set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable);
++ set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3);
++ set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp);
+
+- /* set IDAC to automatic mode control by AGC */
+- set_reg_bits(state->tab_init, 0x12, 0x80, 0x00);
+-
+- if (mode >= MxL_MODE_CABLE_DIGITAL) {
++ if (mode >= MxL_MODE_CABLE) {
+ copy_reg_bits(state->tab_init, state->tab_init_cable);
+ return state->tab_init_cable;
+ } else
+@@ -447,7 +400,7 @@ static void mxl5007t_set_bw_bits(struct mxl5007t_state *state,
+ * and DIG_MODEINDEX_CSF */
+ break;
+ case MxL_BW_7MHz:
+- val = 0x21;
++ val = 0x2a;
+ break;
+ case MxL_BW_8MHz:
+ val = 0x3f;
+@@ -456,7 +409,7 @@ static void mxl5007t_set_bw_bits(struct mxl5007t_state *state,
+ mxl_fail(-EINVAL);
+ return;
+ }
+- set_reg_bits(state->tab_rftune, 0x13, 0x3f, val);
++ set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val);
+
+ return;
+ }
+@@ -493,8 +446,11 @@ reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state,
+ if (temp > 7812)
+ dig_rf_freq++;
+
+- set_reg_bits(state->tab_rftune, 0x14, 0xff, (u8)dig_rf_freq);
+- set_reg_bits(state->tab_rftune, 0x15, 0xff, (u8)(dig_rf_freq >> 8));
++ set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq);
++ set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8));
++
++ if (rf_freq >= 333000000)
++ set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40);
+
+ return state->tab_rftune;
+ }
+@@ -551,9 +507,10 @@ static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val)
+ static int mxl5007t_soft_reset(struct mxl5007t_state *state)
+ {
+ u8 d = 0xff;
+- struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0,
+- .buf = &d, .len = 1 };
+-
++ struct i2c_msg msg = {
++ .addr = state->i2c_props.addr, .flags = 0,
++ .buf = &d, .len = 1
++ };
+ int ret = i2c_transfer(state->i2c_props.adap, &msg, 1);
+
+ if (ret != 1) {
+@@ -580,9 +537,6 @@ static int mxl5007t_tuner_init(struct mxl5007t_state *state,
+ if (mxl_fail(ret))
+ goto fail;
+ mdelay(1);
+-
+- ret = mxl5007t_write_reg(state, 0x2c, 0x35);
+- mxl_fail(ret);
+ fail:
+ return ret;
+ }
+@@ -615,7 +569,7 @@ static int mxl5007t_synth_lock_status(struct mxl5007t_state *state,
+ *rf_locked = 0;
+ *ref_locked = 0;
+
+- ret = mxl5007t_read_reg(state, 0xcf, &d);
++ ret = mxl5007t_read_reg(state, 0xd8, &d);
+ if (mxl_fail(ret))
+ goto fail;
+
+@@ -628,37 +582,14 @@ fail:
+ return ret;
+ }
+
+-static int mxl5007t_check_rf_input_power(struct mxl5007t_state *state,
+- s32 *rf_input_level)
+-{
+- u8 d1, d2;
+- int ret;
+-
+- ret = mxl5007t_read_reg(state, 0xb7, &d1);
+- if (mxl_fail(ret))
+- goto fail;
+-
+- ret = mxl5007t_read_reg(state, 0xbf, &d2);
+- if (mxl_fail(ret))
+- goto fail;
+-
+- d2 = d2 >> 4;
+- if (d2 > 7)
+- d2 += 0xf0;
+-
+- *rf_input_level = (s32)(d1 + d2 - 113);
+-fail:
+- return ret;
+-}
+-
+ /* ------------------------------------------------------------------------- */
+
+ static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status)
+ {
+ struct mxl5007t_state *state = fe->tuner_priv;
+- int rf_locked, ref_locked;
+- s32 rf_input_level = 0;
+- int ret;
++ int rf_locked, ref_locked, ret;
++
++ *status = 0;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+@@ -669,10 +600,8 @@ static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status)
+ mxl_debug("%s%s", rf_locked ? "rf locked " : "",
+ ref_locked ? "ref locked" : "");
+
+- ret = mxl5007t_check_rf_input_power(state, &rf_input_level);
+- if (mxl_fail(ret))
+- goto fail;
+- mxl_debug("rf input power: %d", rf_input_level);
++ if ((rf_locked) || (ref_locked))
++ *status |= TUNER_STATUS_LOCKED;
+ fail:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+@@ -695,11 +624,11 @@ static int mxl5007t_set_params(struct dvb_frontend *fe,
+ switch (params->u.vsb.modulation) {
+ case VSB_8:
+ case VSB_16:
+- mode = MxL_MODE_OTA_DVBT_ATSC;
++ mode = MxL_MODE_ATSC;
+ break;
+ case QAM_64:
+ case QAM_256:
+- mode = MxL_MODE_CABLE_DIGITAL;
++ mode = MxL_MODE_CABLE;
+ break;
+ default:
+ mxl_err("modulation not set!");
+@@ -721,7 +650,7 @@ static int mxl5007t_set_params(struct dvb_frontend *fe,
+ mxl_err("bandwidth not set!");
+ return -EINVAL;
+ }
+- mode = MxL_MODE_OTA_DVBT_ATSC;
++ mode = MxL_MODE_DVBT;
+ } else {
+ mxl_err("modulation type not supported!");
+ return -EINVAL;
+@@ -752,96 +681,20 @@ fail:
+ return ret;
+ }
+
+-static int mxl5007t_set_analog_params(struct dvb_frontend *fe,
+- struct analog_parameters *params)
+-{
+- struct mxl5007t_state *state = fe->tuner_priv;
+- enum mxl5007t_bw_mhz bw = 0; /* FIXME */
+- enum mxl5007t_mode cbl_mode;
+- enum mxl5007t_mode ota_mode;
+- char *mode_name;
+- int ret;
+- u32 freq = params->frequency * 62500;
+-
+-#define cable 1
+- if (params->std & V4L2_STD_MN) {
+- cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH;
+- ota_mode = MxL_MODE_OTA_NTSC_PAL_GH;
+- mode_name = "MN";
+- } else if (params->std & V4L2_STD_B) {
+- cbl_mode = MxL_MODE_CABLE_PAL_IB;
+- ota_mode = MxL_MODE_OTA_PAL_IB;
+- mode_name = "B";
+- } else if (params->std & V4L2_STD_GH) {
+- cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH;
+- ota_mode = MxL_MODE_OTA_NTSC_PAL_GH;
+- mode_name = "GH";
+- } else if (params->std & V4L2_STD_PAL_I) {
+- cbl_mode = MxL_MODE_CABLE_PAL_IB;
+- ota_mode = MxL_MODE_OTA_PAL_IB;
+- mode_name = "I";
+- } else if (params->std & V4L2_STD_DK) {
+- cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL;
+- ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL;
+- mode_name = "DK";
+- } else if (params->std & V4L2_STD_SECAM_L) {
+- cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL;
+- ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL;
+- mode_name = "L";
+- } else if (params->std & V4L2_STD_SECAM_LC) {
+- cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL;
+- ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL;
+- mode_name = "L'";
+- } else {
+- mode_name = "xx";
+- /* FIXME */
+- cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH;
+- ota_mode = MxL_MODE_OTA_NTSC_PAL_GH;
+- }
+- mxl_debug("setting mxl5007 to system %s", mode_name);
+-
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+-
+- mutex_lock(&state->lock);
+-
+- ret = mxl5007t_tuner_init(state, cable ? cbl_mode : ota_mode);
+- if (mxl_fail(ret))
+- goto fail;
+-
+- ret = mxl5007t_tuner_rf_tune(state, freq, bw);
+- if (mxl_fail(ret))
+- goto fail;
+-
+- state->frequency = freq;
+- state->bandwidth = 0;
+-fail:
+- mutex_unlock(&state->lock);
+-
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 0);
+-
+- return ret;
+-}
+-
+ /* ------------------------------------------------------------------------- */
+
+ static int mxl5007t_init(struct dvb_frontend *fe)
+ {
+ struct mxl5007t_state *state = fe->tuner_priv;
+ int ret;
+- u8 d;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+- ret = mxl5007t_read_reg(state, 0x05, &d);
+- if (mxl_fail(ret))
+- goto fail;
+-
+- ret = mxl5007t_write_reg(state, 0x05, d | 0x01);
++ /* wake from standby */
++ ret = mxl5007t_write_reg(state, 0x01, 0x01);
+ mxl_fail(ret);
+-fail:
++
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+@@ -852,18 +705,16 @@ static int mxl5007t_sleep(struct dvb_frontend *fe)
+ {
+ struct mxl5007t_state *state = fe->tuner_priv;
+ int ret;
+- u8 d;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+- ret = mxl5007t_read_reg(state, 0x05, &d);
+- if (mxl_fail(ret))
+- goto fail;
+-
+- ret = mxl5007t_write_reg(state, 0x05, d & ~0x01);
++ /* enter standby mode */
++ ret = mxl5007t_write_reg(state, 0x01, 0x00);
+ mxl_fail(ret);
+-fail:
++ ret = mxl5007t_write_reg(state, 0x0f, 0x00);
++ mxl_fail(ret);
++
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+@@ -911,7 +762,6 @@ static struct dvb_tuner_ops mxl5007t_tuner_ops = {
+ .init = mxl5007t_init,
+ .sleep = mxl5007t_sleep,
+ .set_params = mxl5007t_set_params,
+- .set_analog_params = mxl5007t_set_analog_params,
+ .get_status = mxl5007t_get_status,
+ .get_frequency = mxl5007t_get_frequency,
+ .get_bandwidth = mxl5007t_get_bandwidth,
+@@ -924,7 +774,7 @@ static int mxl5007t_get_chip_id(struct mxl5007t_state *state)
+ int ret;
+ u8 id;
+
+- ret = mxl5007t_read_reg(state, 0xd3, &id);
++ ret = mxl5007t_read_reg(state, 0xd9, &id);
+ if (mxl_fail(ret))
+ goto fail;
+
+@@ -947,8 +797,12 @@ static int mxl5007t_get_chip_id(struct mxl5007t_state *state)
+ case MxL_5007_V2_200_F2:
+ name = "MxL5007.v2.200.f2";
+ break;
++ case MxL_5007_V4:
++ name = "MxL5007T.v4";
++ break;
+ default:
+ name = "MxL5007T";
++ printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id);
+ id = MxL_UNKNOWN_ID;
+ }
+ state->chip_id = id;
+@@ -975,7 +829,7 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
+ mutex_lock(&mxl5007t_list_mutex);
+ instance = hybrid_tuner_request_state(struct mxl5007t_state, state,
+ hybrid_tuner_instance_list,
+- i2c, addr, "mxl5007");
++ i2c, addr, "mxl5007t");
+ switch (instance) {
+ case 0:
+ goto fail;
+@@ -1018,7 +872,7 @@ EXPORT_SYMBOL_GPL(mxl5007t_attach);
+ MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver");
+ MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+ MODULE_LICENSE("GPL");
+-MODULE_VERSION("0.1");
++MODULE_VERSION("0.2");
+
+ /*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
+index 6fb5b45..fc76c30 100644
+--- a/drivers/media/common/tuners/tda18271-common.c
++++ b/drivers/media/common/tuners/tda18271-common.c
+@@ -490,9 +490,9 @@ int tda18271_set_standby_mode(struct dvb_frontend *fe,
+ tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
+
+ regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */
+- regs[R_EP3] |= sm ? (1 << 7) : 0 |
+- sm_lt ? (1 << 6) : 0 |
+- sm_xt ? (1 << 5) : 0;
++ regs[R_EP3] |= (sm ? (1 << 7) : 0) |
++ (sm_lt ? (1 << 6) : 0) |
++ (sm_xt ? (1 << 5) : 0);
+
+ return tda18271_write_regs(fe, R_EP3, 1);
+ }
+diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
+index 1b48b5d..b109356 100644
+--- a/drivers/media/common/tuners/tda18271-fe.c
++++ b/drivers/media/common/tuners/tda18271-fe.c
+@@ -818,6 +818,38 @@ fail:
+ return ret;
+ }
+
++/* ------------------------------------------------------------------ */
++
++static int tda18271_agc(struct dvb_frontend *fe)
++{
++ struct tda18271_priv *priv = fe->tuner_priv;
++ int ret = 0;
++
++ switch (priv->config) {
++ case 0:
++ /* no LNA */
++ tda_dbg("no agc configuration provided\n");
++ break;
++ case 3:
++ /* switch with GPIO of saa713x */
++ tda_dbg("invoking callback\n");
++ if (fe->callback)
++ ret = fe->callback(priv->i2c_props.adap->algo_data,
++ DVB_FRONTEND_COMPONENT_TUNER,
++ TDA18271_CALLBACK_CMD_AGC_ENABLE,
++ priv->mode);
++ break;
++ case 1:
++ case 2:
++ default:
++ /* n/a - currently not supported */
++ tda_err("unsupported configuration: %d\n", priv->config);
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
+ static int tda18271_tune(struct dvb_frontend *fe,
+ struct tda18271_std_map_item *map, u32 freq, u32 bw)
+ {
+@@ -827,6 +859,10 @@ static int tda18271_tune(struct dvb_frontend *fe,
+ tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
+ freq, map->if_freq, bw, map->agc_mode, map->std);
+
++ ret = tda18271_agc(fe);
++ if (tda_fail(ret))
++ tda_warn("failed to configure agc\n");
++
+ ret = tda18271_init(fe);
+ if (tda_fail(ret))
+ goto fail;
+@@ -1159,6 +1195,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
+ /* new tuner instance */
+ priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+ priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
++ priv->config = (cfg) ? cfg->config : 0;
+ priv->cal_initialized = false;
+ mutex_init(&priv->lock);
+
+diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h
+index 81a7393..74beb28 100644
+--- a/drivers/media/common/tuners/tda18271-priv.h
++++ b/drivers/media/common/tuners/tda18271-priv.h
+@@ -91,11 +91,6 @@ enum tda18271_pll {
+ TDA18271_CAL_PLL,
+ };
+
+-enum tda18271_mode {
+- TDA18271_ANALOG,
+- TDA18271_DIGITAL,
+-};
+-
+ struct tda18271_map_layout;
+
+ enum tda18271_ver {
+@@ -114,6 +109,7 @@ struct tda18271_priv {
+ enum tda18271_i2c_gate gate;
+ enum tda18271_ver id;
+
++ unsigned int config; /* interface to saa713x / tda829x */
+ unsigned int tm_rfcal;
+ unsigned int cal_initialized:1;
+ unsigned int small_i2c:1;
+diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h
+index 7db9831..53a9892 100644
+--- a/drivers/media/common/tuners/tda18271.h
++++ b/drivers/media/common/tuners/tda18271.h
+@@ -79,6 +79,16 @@ struct tda18271_config {
+
+ /* some i2c providers cant write all 39 registers at once */
+ unsigned int small_i2c:1;
++
++ /* interface to saa713x / tda829x */
++ unsigned int config;
++};
++
++#define TDA18271_CALLBACK_CMD_AGC_ENABLE 0
++
++enum tda18271_mode {
++ TDA18271_ANALOG = 0,
++ TDA18271_DIGITAL,
+ };
+
+ #if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE))
+diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c
+index f4d931f..36a7bc7 100644
+--- a/drivers/media/common/tuners/tda827x.c
++++ b/drivers/media/common/tuners/tda827x.c
+@@ -132,11 +132,31 @@ static const struct tda827x_data tda827x_table[] = {
+ { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
+ };
+
++static int tuner_transfer(struct dvb_frontend *fe,
++ struct i2c_msg *msg,
++ const int size)
++{
++ int rc;
++ struct tda827x_priv *priv = fe->tuner_priv;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ rc = i2c_transfer(priv->i2c_adap, msg, size);
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ if (rc >= 0 && rc != size)
++ return -EIO;
++
++ return rc;
++}
++
+ static int tda827xo_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+ {
+ struct tda827x_priv *priv = fe->tuner_priv;
+ u8 buf[14];
++ int rc;
+
+ struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+@@ -183,27 +203,29 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
+ buf[13] = 0x40;
+
+ msg.len = 14;
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
+- printk("%s: could not write to tuner at addr: 0x%02x\n",
+- __func__, priv->i2c_addr << 1);
+- return -EIO;
+- }
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
++
+ msleep(500);
+ /* correct CP value */
+ buf[0] = 0x30;
+ buf[1] = 0x50 + tda827x_table[i].cp;
+ msg.len = 2;
+
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+
+ priv->frequency = params->frequency;
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+
+ return 0;
++
++err:
++ printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
++ __func__, priv->i2c_addr << 1);
++ return rc;
+ }
+
+ static int tda827xo_sleep(struct dvb_frontend *fe)
+@@ -214,9 +236,7 @@ static int tda827xo_sleep(struct dvb_frontend *fe)
+ .buf = buf, .len = sizeof(buf) };
+
+ dprintk("%s:\n", __func__);
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ if (priv->cfg && priv->cfg->sleep)
+ priv->cfg->sleep(fe);
+@@ -266,44 +286,44 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe,
+
+ msg.buf = tuner_reg;
+ msg.len = 8;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ msg.buf = reg2;
+ msg.len = 2;
+ reg2[0] = 0x80;
+ reg2[1] = 0;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ reg2[0] = 0x60;
+ reg2[1] = 0xbf;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ reg2[0] = 0x30;
+ reg2[1] = tuner_reg[4] + 0x80;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ msleep(1);
+ reg2[0] = 0x30;
+ reg2[1] = tuner_reg[4] + 4;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ msleep(1);
+ reg2[0] = 0x30;
+ reg2[1] = tuner_reg[4];
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ msleep(550);
+ reg2[0] = 0x30;
+ reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ reg2[0] = 0x60;
+ reg2[1] = 0x3f;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ reg2[0] = 0x80;
+ reg2[1] = 0x08; /* Vsync en */
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ priv->frequency = params->frequency;
+
+@@ -317,7 +337,7 @@ static void tda827xo_agcf(struct dvb_frontend *fe)
+ struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+ .buf = data, .len = 2};
+
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+ }
+
+ /* ------------------------------------------------------------------ */
+@@ -331,7 +351,7 @@ struct tda827xa_data {
+ u8 gc3;
+ };
+
+-static const struct tda827xa_data tda827xa_dvbt[] = {
++static struct tda827xa_data tda827xa_dvbt[] = {
+ { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+@@ -361,6 +381,36 @@ static const struct tda827xa_data tda827xa_dvbt[] = {
+ { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+ };
+
++static struct tda827xa_data tda827xa_dvbc[] = {
++ { .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
++ { .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
++ { .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
++ { .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
++ { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
++ { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
++ { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
++ { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
++ { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
++ { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
++ { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1},
++ { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3},
++ { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3},
++ { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1},
++ { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
++ { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
++ { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1},
++ { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
++ { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1},
++ { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
++ { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
++ { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
++ { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
++ { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
++ { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
++ { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
++ { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
++};
++
+ static struct tda827xa_data tda827xa_analog[] = {
+ { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
+ { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+@@ -398,13 +448,8 @@ static int tda827xa_sleep(struct dvb_frontend *fe)
+ .buf = buf, .len = sizeof(buf) };
+
+ dprintk("%s:\n", __func__);
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+
+- i2c_transfer(priv->i2c_adap, &msg, 1);
+-
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 0);
++ tuner_transfer(fe, &msg, 1);
+
+ if (priv->cfg && priv->cfg->sleep)
+ priv->cfg->sleep(fe);
+@@ -455,7 +500,7 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+ buf[1] = high ? 0 : 1;
+ if (priv->cfg->config == 2)
+ buf[1] = high ? 1 : 0;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+ break;
+ case 3: /* switch with GPIO of saa713x */
+ if (fe->callback)
+@@ -469,12 +514,13 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+ {
+ struct tda827x_priv *priv = fe->tuner_priv;
++ struct tda827xa_data *frequency_map = tda827xa_dvbt;
+ u8 buf[11];
+
+ struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+
+- int i, tuner_freq, if_freq;
++ int i, tuner_freq, if_freq, rc;
+ u32 N;
+
+ dprintk("%s:\n", __func__);
+@@ -495,56 +541,58 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
+ }
+ tuner_freq = params->frequency + if_freq;
+
++ if (fe->ops.info.type == FE_QAM) {
++ dprintk("%s select tda827xa_dvbc\n", __func__);
++ frequency_map = tda827xa_dvbc;
++ }
++
+ i = 0;
+- while (tda827xa_dvbt[i].lomax < tuner_freq) {
+- if(tda827xa_dvbt[i + 1].lomax == 0)
++ while (frequency_map[i].lomax < tuner_freq) {
++ if (frequency_map[i + 1].lomax == 0)
+ break;
+ i++;
+ }
+
+- N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
++ N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd;
+ buf[0] = 0; // subaddress
+ buf[1] = N >> 8;
+ buf[2] = N & 0xff;
+ buf[3] = 0;
+ buf[4] = 0x16;
+- buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
+- tda827xa_dvbt[i].sbs;
+- buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
++ buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) +
++ frequency_map[i].sbs;
++ buf[6] = 0x4b + (frequency_map[i].gc3 << 4);
+ buf[7] = 0x1c;
+ buf[8] = 0x06;
+ buf[9] = 0x24;
+ buf[10] = 0x00;
+ msg.len = 11;
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
+- printk("%s: could not write to tuner at addr: 0x%02x\n",
+- __func__, priv->i2c_addr << 1);
+- return -EIO;
+- }
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
++
+ buf[0] = 0x90;
+ buf[1] = 0xff;
+ buf[2] = 0x60;
+ buf[3] = 0x00;
+ buf[4] = 0x59; // lpsel, for 6MHz + 2
+ msg.len = 5;
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+
+ buf[0] = 0xa0;
+ buf[1] = 0x40;
+ msg.len = 2;
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+
+ msleep(11);
+ msg.flags = I2C_M_RD;
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+ msg.flags = 0;
+
+ buf[1] >>= 4;
+@@ -553,49 +601,55 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
+ tda827xa_lna_gain(fe, 0, NULL);
+ buf[0] = 0x60;
+ buf[1] = 0x0c;
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+ }
+
+ buf[0] = 0xc0;
+ buf[1] = 0x99; // lpsel, for 6MHz + 2
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+
+ buf[0] = 0x60;
+ buf[1] = 0x3c;
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+
+ /* correct CP value */
+ buf[0] = 0x30;
+- buf[1] = 0x10 + tda827xa_dvbt[i].scr;
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ buf[1] = 0x10 + frequency_map[i].scr;
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+
+ msleep(163);
+ buf[0] = 0xc0;
+ buf[1] = 0x39; // lpsel, for 6MHz + 2
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+
+ msleep(3);
+ /* freeze AGC1 */
+ buf[0] = 0x50;
+- buf[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ buf[1] = 0x4f + (frequency_map[i].gc3 << 4);
++ rc = tuner_transfer(fe, &msg, 1);
++ if (rc < 0)
++ goto err;
+
+ priv->frequency = params->frequency;
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+
++
+ return 0;
++
++err:
++ printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
++ __func__, priv->i2c_addr << 1);
++ return rc;
+ }
+
+
+@@ -643,7 +697,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
+ tuner_reg[9] = 0x20;
+ tuner_reg[10] = 0x00;
+ msg.len = 11;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ tuner_reg[0] = 0x90;
+ tuner_reg[1] = 0xff;
+@@ -651,19 +705,19 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
+ tuner_reg[3] = 0;
+ tuner_reg[4] = 0x99 + (priv->lpsel << 1);
+ msg.len = 5;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ tuner_reg[0] = 0xa0;
+ tuner_reg[1] = 0xc0;
+ msg.len = 2;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ tuner_reg[0] = 0x30;
+ tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ msg.flags = I2C_M_RD;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+ msg.flags = 0;
+ tuner_reg[1] >>= 4;
+ dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
+@@ -673,24 +727,24 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
+ msleep(100);
+ tuner_reg[0] = 0x60;
+ tuner_reg[1] = 0x3c;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ msleep(163);
+ tuner_reg[0] = 0x50;
+ tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ tuner_reg[0] = 0x80;
+ tuner_reg[1] = 0x28;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ tuner_reg[0] = 0xb0;
+ tuner_reg[1] = 0x01;
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ tuner_reg[0] = 0xc0;
+ tuner_reg[1] = 0x19 + (priv->lpsel << 1);
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+
+ priv->frequency = params->frequency;
+
+@@ -703,7 +757,7 @@ static void tda827xa_agcf(struct dvb_frontend *fe)
+ unsigned char data[] = {0x80, 0x2c};
+ struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
+ .buf = data, .len = 2};
+- i2c_transfer(priv->i2c_adap, &msg, 1);
++ tuner_transfer(fe, &msg, 1);
+ }
+
+ /* ------------------------------------------------------------------ */
+@@ -792,16 +846,19 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = {
+ };
+
+ static int tda827x_probe_version(struct dvb_frontend *fe)
+-{ u8 data;
++{
++ u8 data;
++ int rc;
+ struct tda827x_priv *priv = fe->tuner_priv;
+ struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD,
+ .buf = &data, .len = 1 };
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
++
++ rc = tuner_transfer(fe, &msg, 1);
++
++ if (rc < 0) {
+ printk("%s: could not read from tuner at addr: 0x%02x\n",
+ __func__, msg.addr << 1);
+- return -EIO;
++ return rc;
+ }
+ if ((data & 0x3c) == 0) {
+ dprintk("tda827x tuner found\n");
+diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
+index 4b8662e..064d14c 100644
+--- a/drivers/media/common/tuners/tda8290.c
++++ b/drivers/media/common/tuners/tda8290.c
+@@ -22,7 +22,7 @@
+
+ #include <linux/i2c.h>
+ #include <linux/delay.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include "tuner-i2c.h"
+ #include "tda8290.h"
+ #include "tda827x.h"
+@@ -566,8 +566,11 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
+ u8 data;
+ struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
+
+- if (NULL == analog_ops->i2c_gate_ctrl)
++ if (!analog_ops->i2c_gate_ctrl) {
++ printk(KERN_ERR "tda8290: no gate control were provided!\n");
++
+ return -EINVAL;
++ }
+
+ analog_ops->i2c_gate_ctrl(fe, 1);
+
+@@ -615,11 +618,13 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
+
+ if (ret != 1) {
+ tuner_warn("tuner access failed!\n");
++ analog_ops->i2c_gate_ctrl(fe, 0);
+ return -EREMOTEIO;
+ }
+
+ if ((data == 0x83) || (data == 0x84)) {
+ priv->ver |= TDA18271;
++ tda829x_tda18271_config.config = priv->cfg.config;
+ dvb_attach(tda18271_attach, fe, priv->tda827x_addr,
+ priv->i2c_props.adap, &tda829x_tda18271_config);
+ } else {
+diff --git a/drivers/media/common/tuners/tea5761.c b/drivers/media/common/tuners/tea5761.c
+index b23dade..60ed872 100644
+--- a/drivers/media/common/tuners/tea5761.c
++++ b/drivers/media/common/tuners/tea5761.c
+@@ -9,7 +9,7 @@
+
+ #include <linux/i2c.h>
+ #include <linux/delay.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <media/tuner.h>
+ #include "tuner-i2c.h"
+ #include "tea5761.h"
+diff --git a/drivers/media/common/tuners/tea5767.c b/drivers/media/common/tuners/tea5767.c
+index 1f56463..223a226 100644
+--- a/drivers/media/common/tuners/tea5767.c
++++ b/drivers/media/common/tuners/tea5767.c
+@@ -12,7 +12,7 @@
+
+ #include <linux/i2c.h>
+ #include <linux/delay.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include "tuner-i2c.h"
+ #include "tea5767.h"
+
+diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
+index 493ce93..b545985 100644
+--- a/drivers/media/common/tuners/xc5000.c
++++ b/drivers/media/common/tuners/xc5000.c
+@@ -739,7 +739,10 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
+ dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+ __func__, params->frequency);
+
+- priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */
++ /* Fix me: it could be air. */
++ priv->rf_mode = params->mode;
++ if (params->mode > XC_RF_MODE_CABLE)
++ priv->rf_mode = XC_RF_MODE_CABLE;
+
+ /* params->frequency is in units of 62.5khz */
+ priv->freq_hz = params->frequency * 62500;
+@@ -970,8 +973,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+ case 1:
+ /* new tuner instance */
+ priv->bandwidth = BANDWIDTH_6_MHZ;
+- priv->if_khz = cfg->if_khz;
+-
+ fe->tuner_priv = priv;
+ break;
+ default:
+@@ -980,6 +981,13 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+ break;
+ }
+
++ if (priv->if_khz == 0) {
++ /* If the IF hasn't been set yet, use the value provided by
++ the caller (occurs in hybrid devices where the analog
++ call to xc5000_attach occurs before the digital side) */
++ priv->if_khz = cfg->if_khz;
++ }
++
+ /* Check if firmware has been loaded. It is possible that another
+ instance of the driver has loaded the firmware.
+ */
+diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
+index a8c6249..9e57814 100644
+--- a/drivers/media/dvb/b2c2/Kconfig
++++ b/drivers/media/dvb/b2c2/Kconfig
+@@ -13,7 +13,7 @@ config DVB_B2C2_FLEXCOP
+ select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
+ select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+ select DVB_CX24123 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+ select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
+ help
+ Support for the digital TV receiver chip made by B2C2 Inc. included in
+diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
+index d9db066..b97cf72 100644
+--- a/drivers/media/dvb/b2c2/Makefile
++++ b/drivers/media/dvb/b2c2/Makefile
+@@ -2,7 +2,6 @@ b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \
+ flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o
+ obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
+
+-
+ ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),)
+ b2c2-flexcop-objs += flexcop-dma.o
+ endif
+diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
+index 8ce0633..3e1c472 100644
+--- a/drivers/media/dvb/b2c2/flexcop-common.h
++++ b/drivers/media/dvb/b2c2/flexcop-common.h
+@@ -28,11 +28,14 @@
+
+ /* Steal from usb.h */
+ #undef err
+-#define err(format, arg...) printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg)
++#define err(format, arg...) \
++ printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg)
+ #undef info
+-#define info(format, arg...) printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg)
++#define info(format, arg...) \
++ printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg)
+ #undef warn
+-#define warn(format, arg...) printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
++#define warn(format, arg...) \
++ printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
+
+ struct flexcop_dma {
+ struct pci_dev *pdev;
+@@ -91,16 +94,14 @@ struct flexcop_device {
+ int fullts_streaming_state;
+
+ /* bus specific callbacks */
+- flexcop_ibi_value (*read_ibi_reg) (struct flexcop_device *, flexcop_ibi_register);
+- int (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value);
+-
+-
+- int (*i2c_request) (struct flexcop_i2c_adapter*,
++ flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *,
++ flexcop_ibi_register);
++ int (*write_ibi_reg) (struct flexcop_device *,
++ flexcop_ibi_register, flexcop_ibi_value);
++ int (*i2c_request) (struct flexcop_i2c_adapter *,
+ flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+- int (*stream_control) (struct flexcop_device*, int);
+-
++ int (*stream_control) (struct flexcop_device *, int);
+ int (*get_mac_addr) (struct flexcop_device *fc, int extended);
+-
+ void *bus_specific;
+ };
+
+@@ -111,22 +112,28 @@ void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
+ void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
+
+ struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
+-void flexcop_device_kfree(struct flexcop_device*);
++void flexcop_device_kfree(struct flexcop_device *);
+
+-int flexcop_device_initialize(struct flexcop_device*);
++int flexcop_device_initialize(struct flexcop_device *);
+ void flexcop_device_exit(struct flexcop_device *fc);
+-
+ void flexcop_reset_block_300(struct flexcop_device *fc);
+
+ /* from flexcop-dma.c */
+-int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size);
++int flexcop_dma_allocate(struct pci_dev *pdev,
++ struct flexcop_dma *dma, u32 size);
+ void flexcop_dma_free(struct flexcop_dma *dma);
+
+-int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
+-int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
+-int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx);
+-int flexcop_dma_xfer_control(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, int onoff);
+-int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
++int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
++ flexcop_dma_index_t no, int onoff);
++int flexcop_dma_control_size_irq(struct flexcop_device *fc,
++ flexcop_dma_index_t no, int onoff);
++int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma,
++ flexcop_dma_index_t dma_idx);
++int flexcop_dma_xfer_control(struct flexcop_device *fc,
++ flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index,
++ int onoff);
++int flexcop_dma_config_timer(struct flexcop_device *fc,
++ flexcop_dma_index_t dma_idx, u8 cycles);
+
+ /* from flexcop-eeprom.c */
+ /* the PCI part uses this call to get the MAC address, the USB part has its own */
+@@ -141,13 +148,15 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t,
+ u8 chipaddr, u8 addr, u8 *buf, u16 len);
+
+ /* from flexcop-sram.c */
+-int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target);
++int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
++ flexcop_sram_dest_target_t target);
+ void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
+-void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill);
++void flexcop_sram_ctrl(struct flexcop_device *fc,
++ int usb_wan, int sramdma, int maximumfill);
+
+ /* global prototypes for the flexcop-chip */
+ /* from flexcop-fe-tuner.c */
+-int flexcop_frontend_init(struct flexcop_device *card);
++int flexcop_frontend_init(struct flexcop_device *fc);
+ void flexcop_frontend_exit(struct flexcop_device *fc);
+
+ /* from flexcop-i2c.c */
+@@ -159,11 +168,14 @@ int flexcop_sram_init(struct flexcop_device *fc);
+
+ /* from flexcop-misc.c */
+ void flexcop_determine_revision(struct flexcop_device *fc);
+-void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
+-void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num);
++void flexcop_device_name(struct flexcop_device *fc,
++ const char *prefix, const char *suffix);
++void flexcop_dump_reg(struct flexcop_device *fc,
++ flexcop_ibi_register reg, int num);
+
+ /* from flexcop-hw-filter.c */
+-int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff);
++int flexcop_pid_feed_control(struct flexcop_device *fc,
++ struct dvb_demux_feed *dvbdmxfeed, int onoff);
+ void flexcop_hw_filter_init(struct flexcop_device *fc);
+
+ void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
+diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
+index 26f0011..2881e0d 100644
+--- a/drivers/media/dvb/b2c2/flexcop-dma.c
++++ b/drivers/media/dvb/b2c2/flexcop-dma.c
+@@ -1,13 +1,12 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
+- * flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop.
+- *
+- * see flexcop.c for copyright information.
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-dma.c - configuring and controlling the DMA of the FlexCop
++ * see flexcop.c for copyright information
+ */
+ #include "flexcop.h"
+
+-int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
++int flexcop_dma_allocate(struct pci_dev *pdev,
++ struct flexcop_dma *dma, u32 size)
+ {
+ u8 *tcpu;
+ dma_addr_t tdma = 0;
+@@ -32,7 +31,8 @@ EXPORT_SYMBOL(flexcop_dma_allocate);
+
+ void flexcop_dma_free(struct flexcop_dma *dma)
+ {
+- pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0);
++ pci_free_consistent(dma->pdev, dma->size*2,
++ dma->cpu_addr0, dma->dma_addr0);
+ memset(dma,0,sizeof(struct flexcop_dma));
+ }
+ EXPORT_SYMBOL(flexcop_dma_free);
+@@ -44,8 +44,8 @@ int flexcop_dma_config(struct flexcop_device *fc,
+ flexcop_ibi_value v0x0,v0x4,v0xc;
+ v0x0.raw = v0x4.raw = v0xc.raw = 0;
+
+- v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
+- v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
++ v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
++ v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
+ v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
+
+ if ((dma_idx & FC_DMA_1) == dma_idx) {
+@@ -57,7 +57,8 @@ int flexcop_dma_config(struct flexcop_device *fc,
+ fc->write_ibi_reg(fc,dma2_014,v0x4);
+ fc->write_ibi_reg(fc,dma2_01c,v0xc);
+ } else {
+- err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call.");
++ err("either DMA1 or DMA2 can be configured within one "
++ "flexcop_dma_config call.");
+ return -EINVAL;
+ }
+
+@@ -81,7 +82,8 @@ int flexcop_dma_xfer_control(struct flexcop_device *fc,
+ r0x0 = dma2_010;
+ r0xc = dma2_01c;
+ } else {
+- err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call.");
++ err("either transfer DMA1 or DMA2 can be started within one "
++ "flexcop_dma_xfer_control call.");
+ return -EINVAL;
+ }
+
+@@ -154,8 +156,7 @@ EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+
+ /* 1 cycles = 1.97 msec */
+ int flexcop_dma_config_timer(struct flexcop_device *fc,
+- flexcop_dma_index_t dma_idx,
+- u8 cycles)
++ flexcop_dma_index_t dma_idx, u8 cycles)
+ {
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c
+index 8a8ae8a..a25373a 100644
+--- a/drivers/media/dvb/b2c2/flexcop-eeprom.c
++++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c
+@@ -1,9 +1,7 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
+- * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used)
+- *
+- * see flexcop.c for copyright information.
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading)
++ * see flexcop.c for copyright information
+ */
+ #include "flexcop.h"
+
+@@ -14,17 +12,17 @@ static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
+ return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
+ }
+
+-static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
++static int eeprom_lrc_write(struct adapter *adapter, u32 addr,
++ u32 len, u8 *wbuf, u8 *rbuf, int retries)
+ {
+- int i;
++int i;
+
+- for (i = 0; i < retries; i++) {
+- if (eeprom_write(adapter, addr, wbuf, len) == len) {
+- if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
+- return 1;
++for (i = 0; i < retries; i++) {
++ if (eeprom_write(adapter, addr, wbuf, len) == len) {
++ if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
++ return 1;
+ }
+ }
+-
+ return 0;
+ }
+
+@@ -39,12 +37,10 @@ static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
+ return 0;
+
+ memcpy(wbuf, key, len);
+-
+ wbuf[16] = 0;
+ wbuf[17] = 0;
+ wbuf[18] = 0;
+ wbuf[19] = calc_lrc(wbuf, 19);
+-
+ return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
+ }
+
+@@ -59,7 +55,6 @@ static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
+ return 0;
+
+ memcpy(key, buf, len);
+-
+ return 1;
+ }
+
+@@ -74,9 +69,7 @@ static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
+ tmp[3] = mac[5];
+ tmp[4] = mac[6];
+ tmp[5] = mac[7];
+-
+ } else {
+-
+ tmp[0] = mac[0];
+ tmp[1] = mac[1];
+ tmp[2] = mac[2];
+@@ -90,11 +83,11 @@ static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
+
+ if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
+ return 1;
+-
+ return 0;
+ }
+
+-static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len)
++static int flexcop_eeprom_read(struct flexcop_device *fc,
++ u16 addr, u8 *buf, u16 len)
+ {
+ return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
+ }
+@@ -110,7 +103,8 @@ static u8 calc_lrc(u8 *buf, int len)
+ return sum;
+ }
+
+-static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
++static int flexcop_eeprom_request(struct flexcop_device *fc,
++ flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
+ {
+ int i,ret = 0;
+ u8 chipaddr = 0x50 | ((addr >> 8) & 3);
+@@ -123,7 +117,8 @@ static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t
+ return ret;
+ }
+
+-static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries)
++static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr,
++ u8 *buf, u16 len, int retries)
+ {
+ int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries);
+ if (ret == 0)
+@@ -133,8 +128,7 @@ static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf,
+ }
+
+ /* JJ's comment about extended == 1: it is not presently used anywhere but was
+- * added to the low-level functions for possible support of EUI64
+- */
++ * added to the low-level functions for possible support of EUI64 */
+ int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
+ {
+ u8 buf[8];
+@@ -142,12 +136,9 @@ int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
+
+ if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
+ if (extended != 0) {
+- err("TODO: extended (EUI64) MAC addresses aren't completely supported yet");
++ err("TODO: extended (EUI64) MAC addresses aren't "
++ "completely supported yet");
+ ret = -EINVAL;
+-/* memcpy(fc->dvb_adapter.proposed_mac,buf,3);
+- mac[3] = 0xfe;
+- mac[4] = 0xff;
+- memcpy(&fc->dvb_adapter.proposed_mac[3],&buf[5],3); */
+ } else
+ memcpy(fc->dvb_adapter.proposed_mac,buf,6);
+ }
+diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+index 5cded37..f7afab5 100644
+--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
++++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+@@ -592,14 +592,14 @@ int flexcop_frontend_init(struct flexcop_device *fc)
+ fc->fe_sleep = ops->sleep;
+ ops->sleep = flexcop_sleep;
+
+- fc->dev_type = FC_SKY;
++ fc->dev_type = FC_SKY_REV26;
+ goto fe_found;
+ }
+
+ /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
+ fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
+ if (fc->fe != NULL) {
+- fc->dev_type = FC_AIR_DVB;
++ fc->dev_type = FC_AIR_DVBT;
+ fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
+ goto fe_found;
+ }
+@@ -653,7 +653,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
+ fc->fe_sleep = ops->sleep;
+ ops->sleep = flexcop_sleep;
+
+- fc->dev_type = FC_SKY_OLD;
++ fc->dev_type = FC_SKY_REV23;
+ goto fe_found;
+ }
+
+diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
+index 451974b..77e4547 100644
+--- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c
++++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
+@@ -1,33 +1,30 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
+- * flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions.
+- *
+- * see flexcop.c for copyright information.
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-hw-filter.c - pid and mac address filtering and control functions
++ * see flexcop.c for copyright information
+ */
+ #include "flexcop.h"
+
+ static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
+ {
+- flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
+-
+- deb_ts("rcv_data is now: '%s'\n",onoff ? "on" : "off");
++ flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff);
++ deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off");
+ }
+
+ void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
+ {
+- flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff);
++ flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff);
+ }
+
+ static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
+ {
+- flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff);
++ flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff);
+ }
+
+ void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
+ {
+- flexcop_ibi_value v418,v41c;
+- v41c = fc->read_ibi_reg(fc,mac_address_41c);
++ flexcop_ibi_value v418, v41c;
++ v41c = fc->read_ibi_reg(fc, mac_address_41c);
+
+ v418.mac_address_418.MAC1 = mac[0];
+ v418.mac_address_418.MAC2 = mac[1];
+@@ -36,27 +33,28 @@ void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
+ v41c.mac_address_41c.MAC7 = mac[4];
+ v41c.mac_address_41c.MAC8 = mac[5];
+
+- fc->write_ibi_reg(fc,mac_address_418,v418);
+- fc->write_ibi_reg(fc,mac_address_41c,v41c);
++ fc->write_ibi_reg(fc, mac_address_418, v418);
++ fc->write_ibi_reg(fc, mac_address_41c, v41c);
+ }
+
+ void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
+ {
+- flexcop_set_ibi_value(ctrl_208,MAC_filter_Mode_sig,onoff);
++ flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff);
+ }
+
+-static void flexcop_pid_group_filter(struct flexcop_device *fc, u16 pid, u16 mask)
++static void flexcop_pid_group_filter(struct flexcop_device *fc,
++ u16 pid, u16 mask)
+ {
+ /* index_reg_310.extra_index_reg need to 0 or 7 to work */
+ flexcop_ibi_value v30c;
+ v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
+ v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
+- fc->write_ibi_reg(fc,pid_filter_30c,v30c);
++ fc->write_ibi_reg(fc, pid_filter_30c, v30c);
+ }
+
+ static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
+ {
+- flexcop_set_ibi_value(ctrl_208,Mask_filter_sig,onoff);
++ flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff);
+ }
+
+ /* this fancy define reduces the code size of the quite similar PID controlling of
+@@ -65,91 +63,112 @@ static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
+
+ #define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
+ flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
+- v208 = fc->read_ibi_reg(fc, ctrl_208); \
+-\
+- vpid.vregname.field = onoff ? pid : 0x1fff; \
+- vpid.vregname.trans_field = transval; \
+- v208.ctrl_208.enablefield = onoff; \
+-\
+- fc->write_ibi_reg(fc,vregname,vpid); \
+- fc->write_ibi_reg(fc,ctrl_208,v208);
++v208 = fc->read_ibi_reg(fc, ctrl_208); \
++vpid.vregname.field = onoff ? pid : 0x1fff; \
++vpid.vregname.trans_field = transval; \
++v208.ctrl_208.enablefield = onoff; \
++fc->write_ibi_reg(fc, vregname, vpid); \
++fc->write_ibi_reg(fc, ctrl_208, v208);
+
+-static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
++static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc,
++ u16 pid, int onoff)
+ {
+- pid_ctrl(pid_filter_300,Stream1_PID,Stream1_filter_sig,Stream1_trans,0);
++ pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig,
++ Stream1_trans, 0);
+ }
+
+-static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
++static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc,
++ u16 pid, int onoff)
+ {
+- pid_ctrl(pid_filter_300,Stream2_PID,Stream2_filter_sig,Stream2_trans,0);
++ pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig,
++ Stream2_trans, 0);
+ }
+
+-static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
++static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc,
++ u16 pid, int onoff)
+ {
+- pid_ctrl(pid_filter_304,PCR_PID,PCR_filter_sig,PCR_trans,0);
++ pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0);
+ }
+
+-static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
++static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc,
++ u16 pid, int onoff)
+ {
+- pid_ctrl(pid_filter_304,PMT_PID,PMT_filter_sig,PMT_trans,0);
++ pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0);
+ }
+
+-static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
++static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc,
++ u16 pid, int onoff)
+ {
+- pid_ctrl(pid_filter_308,EMM_PID,EMM_filter_sig,EMM_trans,0);
++ pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0);
+ }
+
+-static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
++static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc,
++ u16 pid, int onoff)
+ {
+- pid_ctrl(pid_filter_308,ECM_PID,ECM_filter_sig,ECM_trans,0);
++ pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0);
+ }
+
+-static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff)
++static void flexcop_pid_control(struct flexcop_device *fc,
++ int index, u16 pid, int onoff)
+ {
+ if (pid == 0x2000)
+ return;
+
+- deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off");
++ deb_ts("setting pid: %5d %04x at index %d '%s'\n",
++ pid, pid, index, onoff ? "on" : "off");
+
+ /* We could use bit magic here to reduce source code size.
+ * I decided against it, but to use the real register names */
+ switch (index) {
+- case 0: flexcop_pid_Stream1_PID_ctrl(fc,pid,onoff); break;
+- case 1: flexcop_pid_Stream2_PID_ctrl(fc,pid,onoff); break;
+- case 2: flexcop_pid_PCR_PID_ctrl(fc,pid,onoff); break;
+- case 3: flexcop_pid_PMT_PID_ctrl(fc,pid,onoff); break;
+- case 4: flexcop_pid_EMM_PID_ctrl(fc,pid,onoff); break;
+- case 5: flexcop_pid_ECM_PID_ctrl(fc,pid,onoff); break;
+- default:
+- if (fc->has_32_hw_pid_filter && index < 38) {
+- flexcop_ibi_value vpid,vid;
+-
+- /* set the index */
+- vid = fc->read_ibi_reg(fc,index_reg_310);
+- vid.index_reg_310.index_reg = index - 6;
+- fc->write_ibi_reg(fc,index_reg_310, vid);
+-
+- vpid = fc->read_ibi_reg(fc,pid_n_reg_314);
+- vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
+- vpid.pid_n_reg_314.PID_enable_bit = onoff;
+- fc->write_ibi_reg(fc,pid_n_reg_314, vpid);
+- }
+- break;
++ case 0:
++ flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff);
++ break;
++ case 1:
++ flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff);
++ break;
++ case 2:
++ flexcop_pid_PCR_PID_ctrl(fc, pid, onoff);
++ break;
++ case 3:
++ flexcop_pid_PMT_PID_ctrl(fc, pid, onoff);
++ break;
++ case 4:
++ flexcop_pid_EMM_PID_ctrl(fc, pid, onoff);
++ break;
++ case 5:
++ flexcop_pid_ECM_PID_ctrl(fc, pid, onoff);
++ break;
++ default:
++ if (fc->has_32_hw_pid_filter && index < 38) {
++ flexcop_ibi_value vpid, vid;
++
++ /* set the index */
++ vid = fc->read_ibi_reg(fc, index_reg_310);
++ vid.index_reg_310.index_reg = index - 6;
++ fc->write_ibi_reg(fc, index_reg_310, vid);
++
++ vpid = fc->read_ibi_reg(fc, pid_n_reg_314);
++ vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
++ vpid.pid_n_reg_314.PID_enable_bit = onoff;
++ fc->write_ibi_reg(fc, pid_n_reg_314, vpid);
++ }
++ break;
+ }
+ }
+
+-static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc,int onoff)
++static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff)
+ {
+ if (fc->fullts_streaming_state != onoff) {
+ deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
+ flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
+- flexcop_pid_group_filter_ctrl(fc,onoff);
++ flexcop_pid_group_filter_ctrl(fc, onoff);
+ fc->fullts_streaming_state = onoff;
+ }
+ return 0;
+ }
+
+-int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff)
++int flexcop_pid_feed_control(struct flexcop_device *fc,
++ struct dvb_demux_feed *dvbdmxfeed, int onoff)
+ {
+ int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
+
+@@ -164,24 +183,25 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
+ * - or the requested pid is 0x2000 */
+
+ if (!fc->pid_filtering && fc->feedcount == onoff)
+- flexcop_toggle_fullts_streaming(fc,onoff);
++ flexcop_toggle_fullts_streaming(fc, onoff);
+
+ if (fc->pid_filtering) {
+- flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
++ flexcop_pid_control \
++ (fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
+
+ if (fc->extra_feedcount > 0)
+- flexcop_toggle_fullts_streaming(fc,1);
++ flexcop_toggle_fullts_streaming(fc, 1);
+ else if (dvbdmxfeed->pid == 0x2000)
+- flexcop_toggle_fullts_streaming(fc,onoff);
++ flexcop_toggle_fullts_streaming(fc, onoff);
+ else
+- flexcop_toggle_fullts_streaming(fc,0);
++ flexcop_toggle_fullts_streaming(fc, 0);
+ }
+
+ /* if it was the first or last feed request change the stream-status */
+ if (fc->feedcount == onoff) {
+- flexcop_rcv_data_ctrl(fc,onoff);
++ flexcop_rcv_data_ctrl(fc, onoff);
+ if (fc->stream_control) /* device specific stream control */
+- fc->stream_control(fc,onoff);
++ fc->stream_control(fc, onoff);
+
+ /* feeding stopped -> reset the flexcop filter*/
+ if (onoff == 0) {
+@@ -189,7 +209,6 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
+ flexcop_hw_filter_init(fc);
+ }
+ }
+-
+ return 0;
+ }
+ EXPORT_SYMBOL(flexcop_pid_feed_control);
+@@ -199,15 +218,15 @@ void flexcop_hw_filter_init(struct flexcop_device *fc)
+ int i;
+ flexcop_ibi_value v;
+ for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
+- flexcop_pid_control(fc,i,0x1fff,0);
++ flexcop_pid_control(fc, i, 0x1fff, 0);
+
+ flexcop_pid_group_filter(fc, 0, 0x1fe0);
+- flexcop_pid_group_filter_ctrl(fc,0);
++ flexcop_pid_group_filter_ctrl(fc, 0);
+
+- v = fc->read_ibi_reg(fc,pid_filter_308);
++ v = fc->read_ibi_reg(fc, pid_filter_308);
+ v.pid_filter_308.EMM_filter_4 = 1;
+ v.pid_filter_308.EMM_filter_6 = 0;
+- fc->write_ibi_reg(fc,pid_filter_308,v);
++ fc->write_ibi_reg(fc, pid_filter_308, v);
+
+ flexcop_null_filter_ctrl(fc, 1);
+ }
+diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
+index f13783f..e2bed50 100644
+--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
++++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
+@@ -1,17 +1,14 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
+- *
+- * see flexcop.c for copyright information.
++ * see flexcop.c for copyright information
+ */
+ #include "flexcop.h"
+
+ #define FC_MAX_I2C_RETRIES 100000
+
+-/* #define DUMP_I2C_MESSAGES */
+-
+-static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100)
++static int flexcop_i2c_operation(struct flexcop_device *fc,
++ flexcop_ibi_value *r100)
+ {
+ int i;
+ flexcop_ibi_value r;
+@@ -26,7 +23,7 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r
+ r = fc->read_ibi_reg(fc, tw_sm_c_100);
+
+ if (!r.tw_sm_c_100.no_base_addr_ack_error) {
+- if (r.tw_sm_c_100.st_done) { /* && !r.tw_sm_c_100.working_start */
++ if (r.tw_sm_c_100.st_done) {
+ *r100 = r;
+ deb_i2c("i2c success\n");
+ return 0;
+@@ -36,17 +33,31 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r
+ return -EREMOTEIO;
+ }
+ }
+- deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i);
++ deb_i2c("tried %d times i2c operation, "
++ "never finished or too many ack errors.\n", i);
+ return -EREMOTEIO;
+ }
+
+ static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
+- flexcop_ibi_value r100, u8 *buf)
++ flexcop_ibi_value r100, u8 *buf)
+ {
+ flexcop_ibi_value r104;
+- int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
++ int len = r100.tw_sm_c_100.total_bytes,
++ /* remember total_bytes is buflen-1 */
+ ret;
+
++ /* work-around to have CableStar2 and SkyStar2 rev 2.7 work
++ * correctly:
++ *
++ * the ITD1000 is behind an i2c-gate which closes automatically
++ * after an i2c-transaction the STV0297 needs 2 consecutive reads
++ * one with no_base_addr = 0 and one with 1
++ *
++ * those two work-arounds are conflictin: we check for the card
++ * type, it is set when probing the ITD1000 */
++ if (i2c->fc->dev_type == FC_SKY_REV27)
++ r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
++
+ ret = flexcop_i2c_operation(i2c->fc, &r100);
+ if (ret != 0) {
+ deb_i2c("Retrying operation\n");
+@@ -69,11 +80,11 @@ static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
+ if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg;
+ if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg;
+ }
+-
+ return 0;
+ }
+
+-static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
++static int flexcop_i2c_write4(struct flexcop_device *fc,
++ flexcop_ibi_value r100, u8 *buf)
+ {
+ flexcop_ibi_value r104;
+ int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */
+@@ -81,7 +92,6 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100,
+
+ /* there is at least one byte, otherwise we wouldn't be here */
+ r100.tw_sm_c_100.data1_reg = buf[0];
+-
+ r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0;
+ r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
+ r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
+@@ -94,7 +104,7 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100,
+ }
+
+ int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
+- flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
++ flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+ {
+ int ret;
+
+@@ -117,7 +127,6 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
+ printk("rd(");
+ else
+ printk("wr(");
+-
+ printk("%02x): %02x ", chipaddr, addr);
+ #endif
+
+@@ -163,7 +172,8 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
+ EXPORT_SYMBOL(flexcop_i2c_request);
+
+ /* master xfer callback for demodulator */
+-static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
++static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
++ struct i2c_msg msgs[], int num)
+ {
+ struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
+ int i, ret = 0;
+@@ -182,12 +192,13 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs
+ /* reading */
+ if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
+ ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
+- msgs[i].buf[0], msgs[i+1].buf, msgs[i+1].len);
++ msgs[i].buf[0], msgs[i+1].buf,
++ msgs[i+1].len);
+ i++; /* skip the following message */
+ } else /* writing */
+ ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
+- msgs[i].buf[0], &msgs[i].buf[1],
+- msgs[i].len - 1);
++ msgs[i].buf[0], &msgs[i].buf[1],
++ msgs[i].len - 1);
+ if (ret < 0) {
+ err("i2c master_xfer failed");
+ break;
+@@ -214,23 +225,21 @@ static struct i2c_algorithm flexcop_algo = {
+ int flexcop_i2c_init(struct flexcop_device *fc)
+ {
+ int ret;
+-
+ mutex_init(&fc->i2c_mutex);
+
+ fc->fc_i2c_adap[0].fc = fc;
+ fc->fc_i2c_adap[1].fc = fc;
+ fc->fc_i2c_adap[2].fc = fc;
+-
+ fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
+ fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
+ fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
+
+ strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
+- sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
++ sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
+ strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
+- sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
++ sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
+ strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
+- sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
++ sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
+
+ i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
+ i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
+@@ -268,7 +277,6 @@ adap_2_failed:
+ i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+ adap_1_failed:
+ i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+-
+ return ret;
+ }
+
+@@ -279,6 +287,5 @@ void flexcop_i2c_exit(struct flexcop_device *fc)
+ i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+ i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+ }
+-
+ fc->init_state &= ~FC_STATE_I2C_INIT;
+ }
+diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c
+index 93d20e5..e56627d 100644
+--- a/drivers/media/dvb/b2c2/flexcop-misc.c
++++ b/drivers/media/dvb/b2c2/flexcop-misc.c
+@@ -1,9 +1,7 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
+- * flexcop-misc.c - miscellaneous functions.
+- *
+- * see flexcop.c for copyright information.
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-misc.c - miscellaneous functions
++ * see flexcop.c for copyright information
+ */
+ #include "flexcop.h"
+
+@@ -12,39 +10,43 @@ void flexcop_determine_revision(struct flexcop_device *fc)
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
+
+ switch (v.misc_204.Rev_N_sig_revision_hi) {
+- case 0x2:
+- deb_info("found a FlexCopII.\n");
+- fc->rev = FLEXCOP_II;
+- break;
+- case 0x3:
+- deb_info("found a FlexCopIIb.\n");
+- fc->rev = FLEXCOP_IIB;
+- break;
+- case 0x0:
+- deb_info("found a FlexCopIII.\n");
+- fc->rev = FLEXCOP_III;
+- break;
+- default:
+- err("unkown FlexCop Revision: %x. Please report the linux-dvb@linuxtv.org.",v.misc_204.Rev_N_sig_revision_hi);
+- break;
++ case 0x2:
++ deb_info("found a FlexCopII.\n");
++ fc->rev = FLEXCOP_II;
++ break;
++ case 0x3:
++ deb_info("found a FlexCopIIb.\n");
++ fc->rev = FLEXCOP_IIB;
++ break;
++ case 0x0:
++ deb_info("found a FlexCopIII.\n");
++ fc->rev = FLEXCOP_III;
++ break;
++ default:
++ err("unknown FlexCop Revision: %x. Please report this to "
++ "linux-dvb@linuxtv.org.",
++ v.misc_204.Rev_N_sig_revision_hi);
++ break;
+ }
+
+ if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
+- deb_info("this FlexCop has the additional 32 hardware pid filter.\n");
++ deb_info("this FlexCop has "
++ "the additional 32 hardware pid filter.\n");
+ else
+- deb_info("this FlexCop has only the 6 basic main hardware pid filter.\n");
++ deb_info("this FlexCop has "
++ "the 6 basic main hardware pid filter.\n");
+ /* bus parts have to decide if hw pid filtering is used or not. */
+ }
+
+ static const char *flexcop_revision_names[] = {
+- "Unkown chip",
++ "Unknown chip",
+ "FlexCopII",
+ "FlexCopIIb",
+ "FlexCopIII",
+ };
+
+ static const char *flexcop_device_names[] = {
+- "Unkown device",
++ "Unknown device",
+ "Air2PC/AirStar 2 DVB-T",
+ "Air2PC/AirStar 2 ATSC 1st generation",
+ "Air2PC/AirStar 2 ATSC 2nd generation",
+@@ -61,21 +63,23 @@ static const char *flexcop_bus_names[] = {
+ "PCI",
+ };
+
+-void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const
+- char *suffix)
++void flexcop_device_name(struct flexcop_device *fc,
++ const char *prefix, const char *suffix)
+ {
+- info("%s '%s' at the '%s' bus controlled by a '%s' %s",prefix,
+- flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type],
+- flexcop_revision_names[fc->rev],suffix);
++ info("%s '%s' at the '%s' bus controlled by a '%s' %s",
++ prefix, flexcop_device_names[fc->dev_type],
++ flexcop_bus_names[fc->bus_type],
++ flexcop_revision_names[fc->rev], suffix);
+ }
+
+-void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num)
++void flexcop_dump_reg(struct flexcop_device *fc,
++ flexcop_ibi_register reg, int num)
+ {
+ flexcop_ibi_value v;
+ int i;
+ for (i = 0; i < num; i++) {
+- v = fc->read_ibi_reg(fc,reg+4*i);
+- deb_rdump("0x%03x: %08x, ",reg+4*i, v.raw);
++ v = fc->read_ibi_reg(fc, reg+4*i);
++ deb_rdump("0x%03x: %08x, ", reg+4*i, v.raw);
+ }
+ deb_rdump("\n");
+ }
+diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
+index 76e37fd..227c020 100644
+--- a/drivers/media/dvb/b2c2/flexcop-pci.c
++++ b/drivers/media/dvb/b2c2/flexcop-pci.c
+@@ -1,9 +1,7 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
+- * flexcop-pci.c - covers the PCI part including DMA transfers.
+- *
+- * see flexcop.c for copyright information.
++ * Linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-pci.c - covers the PCI part including DMA transfers
++ * see flexcop.c for copyright information
+ */
+
+ #define FC_LOG_PREFIX "flexcop-pci"
+@@ -11,7 +9,8 @@
+
+ static int enable_pid_filtering = 1;
+ module_param(enable_pid_filtering, int, 0444);
+-MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
++MODULE_PARM_DESC(enable_pid_filtering,
++ "enable hardware pid filtering: supported values: 0 (fullts), 1");
+
+ static int irq_chk_intv = 100;
+ module_param(irq_chk_intv, int, 0644);
+@@ -26,17 +25,17 @@ MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog.");
+ #define DEBSTATUS " (debugging is not enabled)"
+ #endif
+
+-#define deb_info(args...) dprintk(0x01,args)
+-#define deb_reg(args...) dprintk(0x02,args)
+-#define deb_ts(args...) dprintk(0x04,args)
+-#define deb_irq(args...) dprintk(0x08,args)
+-#define deb_chk(args...) dprintk(0x10,args)
++#define deb_info(args...) dprintk(0x01, args)
++#define deb_reg(args...) dprintk(0x02, args)
++#define deb_ts(args...) dprintk(0x04, args)
++#define deb_irq(args...) dprintk(0x08, args)
++#define deb_chk(args...) dprintk(0x10, args)
+
+ static int debug;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug,
+ "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))."
+- DEBSTATUS);
++ DEBSTATUS);
+
+ #define DRIVER_VERSION "0.1"
+ #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
+@@ -51,30 +50,30 @@ struct flexcop_pci {
+
+ void __iomem *io_mem;
+ u32 irq;
+-/* buffersize (at least for DMA1, need to be % 188 == 0,
+- * this logic is required */
++ /* buffersize (at least for DMA1, need to be % 188 == 0,
++ * this logic is required */
+ #define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188)
+ #define FC_DEFAULT_DMA2_BUFSIZE (10 * 188)
+ struct flexcop_dma dma[2];
+
+ int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
+- u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */
++ u32 last_dma1_cur_pos;
++ /* position of the pointer last time the timer/packet irq occured */
+ int count;
+ int count_prev;
+ int stream_problem;
+
+ spinlock_t irq_lock;
+-
+ unsigned long last_irq;
+
+ struct delayed_work irq_check_work;
+-
+ struct flexcop_device *fc_dev;
+ };
+
+-static int lastwreg,lastwval,lastrreg,lastrval;
++static int lastwreg, lastwval, lastrreg, lastrval;
+
+-static flexcop_ibi_value flexcop_pci_read_ibi_reg (struct flexcop_device *fc, flexcop_ibi_register r)
++static flexcop_ibi_value flexcop_pci_read_ibi_reg(struct flexcop_device *fc,
++ flexcop_ibi_register r)
+ {
+ struct flexcop_pci *fc_pci = fc->bus_specific;
+ flexcop_ibi_value v;
+@@ -82,19 +81,20 @@ static flexcop_ibi_value flexcop_pci_read_ibi_reg (struct flexcop_device *fc, fl
+
+ if (lastrreg != r || lastrval != v.raw) {
+ lastrreg = r; lastrval = v.raw;
+- deb_reg("new rd: %3x: %08x\n",r,v.raw);
++ deb_reg("new rd: %3x: %08x\n", r, v.raw);
+ }
+
+ return v;
+ }
+
+-static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register r, flexcop_ibi_value v)
++static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc,
++ flexcop_ibi_register r, flexcop_ibi_value v)
+ {
+ struct flexcop_pci *fc_pci = fc->bus_specific;
+
+ if (lastwreg != r || lastwval != v.raw) {
+ lastwreg = r; lastwval = v.raw;
+- deb_reg("new wr: %3x: %08x\n",r,v.raw);
++ deb_reg("new wr: %3x: %08x\n", r, v.raw);
+ }
+
+ writel(v.raw, fc_pci->io_mem + r);
+@@ -113,15 +113,16 @@ static void flexcop_pci_irq_check_work(struct work_struct *work)
+ deb_chk("no IRQ since the last check\n");
+ if (fc_pci->stream_problem++ == 3) {
+ struct dvb_demux_feed *feed;
++ deb_info("flexcop-pci: stream problem, resetting pid filter\n");
+
+ spin_lock_irq(&fc->demux.lock);
+ list_for_each_entry(feed, &fc->demux.feed_list,
+- list_head) {
++ list_head) {
+ flexcop_pid_feed_control(fc, feed, 0);
+ }
+
+ list_for_each_entry(feed, &fc->demux.feed_list,
+- list_head) {
++ list_head) {
+ flexcop_pid_feed_control(fc, feed, 1);
+ }
+ spin_unlock_irq(&fc->demux.lock);
+@@ -149,11 +150,10 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
+ flexcop_ibi_value v;
+ irqreturn_t ret = IRQ_HANDLED;
+
+- spin_lock_irqsave(&fc_pci->irq_lock,flags);
+-
+- v = fc->read_ibi_reg(fc,irq_20c);
++ spin_lock_irqsave(&fc_pci->irq_lock, flags);
++ v = fc->read_ibi_reg(fc, irq_20c);
+
+- /* errors */
++ /* errors */
+ if (v.irq_20c.Data_receiver_error)
+ deb_chk("data receiver error\n");
+ if (v.irq_20c.Continuity_error_flag)
+@@ -164,24 +164,29 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
+ deb_chk("Transport error\n");
+
+ if ((fc_pci->count % 1000) == 0)
+- deb_chk("%d valid irq took place so far\n",fc_pci->count);
++ deb_chk("%d valid irq took place so far\n", fc_pci->count);
+
+ if (v.irq_20c.DMA1_IRQ_Status == 1) {
+ if (fc_pci->active_dma1_addr == 0)
+- flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188);
++ flexcop_pass_dmx_packets(fc_pci->fc_dev,
++ fc_pci->dma[0].cpu_addr0,
++ fc_pci->dma[0].size / 188);
+ else
+- flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr1,fc_pci->dma[0].size / 188);
++ flexcop_pass_dmx_packets(fc_pci->fc_dev,
++ fc_pci->dma[0].cpu_addr1,
++ fc_pci->dma[0].size / 188);
+
+ deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr);
+ fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr;
+- } else if (v.irq_20c.DMA1_Timer_Status == 1) {
+ /* for the timer IRQ we only can use buffer dmx feeding, because we don't have
+ * complete TS packets when reading from the DMA memory */
++ } else if (v.irq_20c.DMA1_Timer_Status == 1) {
+ dma_addr_t cur_addr =
+ fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
+ u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
+
+- deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, last_cur_pos: %08x ",
++ deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, "
++ "last_cur_pos: %08x ",
+ jiffies_to_usecs(jiffies - fc_pci->last_irq),
+ v.raw, (unsigned long long)cur_addr, cur_pos,
+ fc_pci->last_dma1_cur_pos);
+@@ -191,30 +196,36 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
+ * pass the data from last_cur_pos to the buffer end to the demux
+ */
+ if (cur_pos < fc_pci->last_dma1_cur_pos) {
+- deb_irq(" end was reached: passing %d bytes ",(fc_pci->dma[0].size*2 - 1) - fc_pci->last_dma1_cur_pos);
++ deb_irq(" end was reached: passing %d bytes ",
++ (fc_pci->dma[0].size*2 - 1) -
++ fc_pci->last_dma1_cur_pos);
+ flexcop_pass_dmx_data(fc_pci->fc_dev,
+- fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
+- (fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos);
++ fc_pci->dma[0].cpu_addr0 +
++ fc_pci->last_dma1_cur_pos,
++ (fc_pci->dma[0].size*2) -
++ fc_pci->last_dma1_cur_pos);
+ fc_pci->last_dma1_cur_pos = 0;
+ }
+
+ if (cur_pos > fc_pci->last_dma1_cur_pos) {
+- deb_irq(" passing %d bytes ",cur_pos - fc_pci->last_dma1_cur_pos);
++ deb_irq(" passing %d bytes ",
++ cur_pos - fc_pci->last_dma1_cur_pos);
+ flexcop_pass_dmx_data(fc_pci->fc_dev,
+- fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
+- cur_pos - fc_pci->last_dma1_cur_pos);
++ fc_pci->dma[0].cpu_addr0 +
++ fc_pci->last_dma1_cur_pos,
++ cur_pos - fc_pci->last_dma1_cur_pos);
+ }
+ deb_irq("\n");
+
+ fc_pci->last_dma1_cur_pos = cur_pos;
+ fc_pci->count++;
+ } else {
+- deb_irq("isr for flexcop called, apparently without reason (%08x)\n",v.raw);
++ deb_irq("isr for flexcop called, "
++ "apparently without reason (%08x)\n", v.raw);
+ ret = IRQ_NONE;
+ }
+
+- spin_unlock_irqrestore(&fc_pci->irq_lock,flags);
+-
++ spin_unlock_irqrestore(&fc_pci->irq_lock, flags);
+ return ret;
+ }
+
+@@ -222,52 +233,48 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
+ {
+ struct flexcop_pci *fc_pci = fc->bus_specific;
+ if (onoff) {
+- flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1);
+- flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2);
+-
+- flexcop_dma_config_timer(fc,FC_DMA_1,0);
+-
+- flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,1);
++ flexcop_dma_config(fc, &fc_pci->dma[0], FC_DMA_1);
++ flexcop_dma_config(fc, &fc_pci->dma[1], FC_DMA_2);
++ flexcop_dma_config_timer(fc, FC_DMA_1, 0);
++ flexcop_dma_xfer_control(fc, FC_DMA_1,
++ FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 1);
+ deb_irq("DMA xfer enabled\n");
+
+ fc_pci->last_dma1_cur_pos = 0;
+- flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
++ flexcop_dma_control_timer_irq(fc, FC_DMA_1, 1);
+ deb_irq("IRQ enabled\n");
+-
+ fc_pci->count_prev = fc_pci->count;
+-
+-// fc_pci->active_dma1_addr = 0;
+-// flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
+-
+ } else {
+- flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
++ flexcop_dma_control_timer_irq(fc, FC_DMA_1, 0);
+ deb_irq("IRQ disabled\n");
+
+-// flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
+-
+- flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,0);
++ flexcop_dma_xfer_control(fc, FC_DMA_1,
++ FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 0);
+ deb_irq("DMA xfer disabled\n");
+ }
+-
+ return 0;
+ }
+
+ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
+ {
+ int ret;
+- if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
++ ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[0],
++ FC_DEFAULT_DMA1_BUFSIZE);
++ if (ret != 0)
+ return ret;
+
+- if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) {
++ ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[1],
++ FC_DEFAULT_DMA2_BUFSIZE);
++ if (ret != 0) {
+ flexcop_dma_free(&fc_pci->dma[0]);
+ return ret;
+ }
+
+- flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
+- flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
+-
++ flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_MEDIA |
++ FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
++ flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_CAO |
++ FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
+ fc_pci->init_state |= FC_PCI_DMA_INIT;
+-
+ return ret;
+ }
+
+@@ -290,12 +297,8 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
+
+ if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
+ return ret;
+-
+ pci_set_master(fc_pci->pdev);
+
+- /* enable interrupts */
+- // pci_write_config_dword(pdev, 0x6c, 0x8000);
+-
+ if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0)
+ goto err_pci_disable_device;
+
+@@ -338,8 +341,8 @@ static void flexcop_pci_exit(struct flexcop_pci *fc_pci)
+ fc_pci->init_state &= ~FC_PCI_INIT;
+ }
+
+-
+-static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
++static int flexcop_pci_probe(struct pci_dev *pdev,
++ const struct pci_device_id *ent)
+ {
+ struct flexcop_device *fc;
+ struct flexcop_pci *fc_pci;
+@@ -350,7 +353,7 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
+ return -ENOMEM;
+ }
+
+-/* general flexcop init */
++ /* general flexcop init */
+ fc_pci = fc->bus_specific;
+ fc_pci->fc_dev = fc;
+
+@@ -358,7 +361,6 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
+ fc->write_ibi_reg = flexcop_pci_write_ibi_reg;
+ fc->i2c_request = flexcop_i2c_request;
+ fc->get_mac_addr = flexcop_eeprom_check_mac_addr;
+-
+ fc->stream_control = flexcop_pci_stream_control;
+
+ if (enable_pid_filtering)
+@@ -368,29 +370,29 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
+
+ fc->pid_filtering = enable_pid_filtering;
+ fc->bus_type = FC_PCI;
+-
+ fc->dev = &pdev->dev;
+ fc->owner = THIS_MODULE;
+
+-/* bus specific part */
++ /* bus specific part */
+ fc_pci->pdev = pdev;
+ if ((ret = flexcop_pci_init(fc_pci)) != 0)
+ goto err_kfree;
+
+-/* init flexcop */
++ /* init flexcop */
+ if ((ret = flexcop_device_initialize(fc)) != 0)
+ goto err_pci_exit;
+
+-/* init dma */
++ /* init dma */
+ if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
+ goto err_fc_exit;
+
+ INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work);
+
+- if (irq_chk_intv > 0)
+- schedule_delayed_work(&fc_pci->irq_check_work,
+- msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
+-
++ if (irq_chk_intv > 0)
++ schedule_delayed_work(&fc_pci->irq_check_work,
++ msecs_to_jiffies(irq_chk_intv < 100 ?
++ 100 :
++ irq_chk_intv));
+ return ret;
+
+ err_fc_exit:
+@@ -420,7 +422,6 @@ static void flexcop_pci_remove(struct pci_dev *pdev)
+
+ static struct pci_device_id flexcop_pci_tbl[] = {
+ { PCI_DEVICE(0x13d0, 0x2103) },
+-/* { PCI_DEVICE(0x13d0, 0x2200) }, ? */
+ { },
+ };
+
+diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
+index 7599fcc..dc4528d 100644
+--- a/drivers/media/dvb/b2c2/flexcop-reg.h
++++ b/drivers/media/dvb/b2c2/flexcop-reg.h
+@@ -1,14 +1,11 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
+- *
+- * see flexcop.c for copyright information.
++ * see flexcop.c for copyright information
+ */
+ #ifndef __FLEXCOP_REG_H__
+ #define __FLEXCOP_REG_H__
+
+-
+ typedef enum {
+ FLEXCOP_UNK = 0,
+ FLEXCOP_II,
+@@ -18,13 +15,13 @@ typedef enum {
+
+ typedef enum {
+ FC_UNK = 0,
+- FC_AIR_DVB,
++ FC_CABLE,
++ FC_AIR_DVBT,
+ FC_AIR_ATSC1,
+ FC_AIR_ATSC2,
+- FC_SKY,
+- FC_SKY_OLD,
+- FC_CABLE,
+ FC_AIR_ATSC3,
++ FC_SKY_REV23,
++ FC_SKY_REV26,
+ FC_SKY_REV27,
+ FC_SKY_REV28,
+ } flexcop_device_type_t;
+@@ -36,12 +33,12 @@ typedef enum {
+
+ /* FlexCop IBI Registers */
+ #if defined(__LITTLE_ENDIAN)
+- #include "flexcop_ibi_value_le.h"
++#include "flexcop_ibi_value_le.h"
+ #else
+ #if defined(__BIG_ENDIAN)
+- #include "flexcop_ibi_value_be.h"
++#include "flexcop_ibi_value_be.h"
+ #else
+- #error no endian defined
++#error no endian defined
+ #endif
+ #endif
+
+diff --git a/drivers/media/dvb/b2c2/flexcop-sram.c b/drivers/media/dvb/b2c2/flexcop-sram.c
+index cda6952..f2199e4 100644
+--- a/drivers/media/dvb/b2c2/flexcop-sram.c
++++ b/drivers/media/dvb/b2c2/flexcop-sram.c
+@@ -1,45 +1,43 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
+- * flexcop-sram.c - functions for controlling the SRAM.
+- *
+- * see flexcop.c for copyright information.
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-sram.c - functions for controlling the SRAM
++ * see flexcop.c for copyright information
+ */
+ #include "flexcop.h"
+
+-static void flexcop_sram_set_chip (struct flexcop_device *fc, flexcop_sram_type_t type)
++static void flexcop_sram_set_chip(struct flexcop_device *fc,
++ flexcop_sram_type_t type)
+ {
+- flexcop_set_ibi_value(wan_ctrl_reg_71c,sram_chip,type);
++ flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type);
+ }
+
+ int flexcop_sram_init(struct flexcop_device *fc)
+ {
+ switch (fc->rev) {
+- case FLEXCOP_II:
+- case FLEXCOP_IIB:
+- flexcop_sram_set_chip(fc,FC_SRAM_1_32KB);
+- break;
+- case FLEXCOP_III:
+- flexcop_sram_set_chip(fc,FC_SRAM_1_48KB);
+- break;
+- default:
+- return -EINVAL;
++ case FLEXCOP_II:
++ case FLEXCOP_IIB:
++ flexcop_sram_set_chip(fc, FC_SRAM_1_32KB);
++ break;
++ case FLEXCOP_III:
++ flexcop_sram_set_chip(fc, FC_SRAM_1_48KB);
++ break;
++ default:
++ return -EINVAL;
+ }
+ return 0;
+ }
+
+-int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target)
++int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
++ flexcop_sram_dest_target_t target)
+ {
+ flexcop_ibi_value v;
+-
+- v = fc->read_ibi_reg(fc,sram_dest_reg_714);
++ v = fc->read_ibi_reg(fc, sram_dest_reg_714);
+
+ if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
+ err("SRAM destination target to available on FlexCopII(b)\n");
+ return -EINVAL;
+ }
+-
+- deb_sram("sram dest: %x target: %x\n",dest, target);
++ deb_sram("sram dest: %x target: %x\n", dest, target);
+
+ if (dest & FC_SRAM_DEST_NET)
+ v.sram_dest_reg_714.NET_Dest = target;
+@@ -154,14 +152,12 @@ static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len
+ else
+ bank = 0x10000000;
+ }
+-
+ flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
+ }
+
+ static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
+ {
+ u32 bank;
+-
+ bank = 0;
+
+ if (adapter->dw_sram_type == 0x20000) {
+@@ -174,26 +170,22 @@ static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
+ else
+ bank = 0x10000000;
+ }
+-
+ flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
+ }
+
+ static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+ {
+ u32 length;
+-
+ while (len != 0) {
+ length = len;
+-
+- // check if the address range belongs to the same
+- // 32K memory chip. If not, the data is read from
+- // one chip at a time.
++ /* check if the address range belongs to the same
++ * 32K memory chip. If not, the data is read
++ * from one chip at a time */
+ if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
+ length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
+ }
+
+ sram_read_chunk(adapter, addr, buf, length);
+-
+ addr = addr + length;
+ buf = buf + length;
+ len = len - length;
+@@ -203,19 +195,17 @@ static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+ static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+ {
+ u32 length;
+-
+ while (len != 0) {
+ length = len;
+
+- // check if the address range belongs to the same
+- // 32K memory chip. If not, the data is written to
+- // one chip at a time.
++ /* check if the address range belongs to the same
++ * 32K memory chip. If not, the data is
++ * written to one chip at a time */
+ if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
+ length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
+ }
+
+ sram_write_chunk(adapter, addr, buf, length);
+-
+ addr = addr + length;
+ buf = buf + length;
+ len = len - length;
+@@ -224,39 +214,29 @@ static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+
+ static void sram_set_size(struct adapter *adapter, u32 mask)
+ {
+- write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
++ write_reg_dw(adapter, 0x71c,
++ (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
+ }
+
+ static void sram_init(struct adapter *adapter)
+ {
+ u32 tmp;
+-
+ tmp = read_reg_dw(adapter, 0x71c);
+-
+ write_reg_dw(adapter, 0x71c, 1);
+
+ if (read_reg_dw(adapter, 0x71c) != 0) {
+ write_reg_dw(adapter, 0x71c, tmp);
+-
+ adapter->dw_sram_type = tmp & 0x30000;
+-
+ ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
+-
+ } else {
+-
+ adapter->dw_sram_type = 0x10000;
+-
+ ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
+ }
+-
+- /* return value is never used? */
+-/* return adapter->dw_sram_type; */
+ }
+
+ static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
+ {
+ u8 tmp1, tmp2;
+-
+ dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr);
+
+ sram_set_size(adapter, mask);
+@@ -269,7 +249,6 @@ static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
+ sram_write(adapter, addr + 4, &tmp1, 1);
+
+ tmp2 = 0;
+-
+ mdelay(20);
+
+ sram_read(adapter, addr, &tmp2, 1);
+@@ -287,7 +266,6 @@ static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
+ sram_write(adapter, addr + 4, &tmp1, 1);
+
+ tmp2 = 0;
+-
+ mdelay(20);
+
+ sram_read(adapter, addr, &tmp2, 1);
+@@ -297,26 +275,24 @@ static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
+
+ if (tmp2 != 0x5a)
+ return 0;
+-
+ return 1;
+ }
+
+ static u32 sram_length(struct adapter *adapter)
+ {
+ if (adapter->dw_sram_type == 0x10000)
+- return 32768; // 32K
++ return 32768; /* 32K */
+ if (adapter->dw_sram_type == 0x00000)
+- return 65536; // 64K
++ return 65536; /* 64K */
+ if (adapter->dw_sram_type == 0x20000)
+- return 131072; // 128K
+-
+- return 32768; // 32K
++ return 131072; /* 128K */
++ return 32768; /* 32K */
+ }
+
+ /* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
+- - for 128K there are 4x32K chips at bank 0,1,2,3.
+- - for 64K there are 2x32K chips at bank 1,2.
+- - for 32K there is one 32K chip at bank 0.
++ - for 128K there are 4x32K chips at bank 0,1,2,3.
++ - for 64K there are 2x32K chips at bank 1,2.
++ - for 32K there is one 32K chip at bank 0.
+
+ FlexCop works only with one bank at a time. The bank is selected
+ by bits 28-29 of the 0x700 register.
+@@ -324,24 +300,18 @@ static u32 sram_length(struct adapter *adapter)
+ bank 0 covers addresses 0x00000-0x07fff
+ bank 1 covers addresses 0x08000-0x0ffff
+ bank 2 covers addresses 0x10000-0x17fff
+- bank 3 covers addresses 0x18000-0x1ffff
+-*/
++ bank 3 covers addresses 0x18000-0x1ffff */
+
+ static int flexcop_sram_detect(struct flexcop_device *fc)
+ {
+- flexcop_ibi_value r208,r71c_0,vr71c_1;
+-
++ flexcop_ibi_value r208, r71c_0, vr71c_1;
+ r208 = fc->read_ibi_reg(fc, ctrl_208);
+ fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
+
+ r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
+-
+ write_reg_dw(adapter, 0x71c, 1);
+-
+ tmp3 = read_reg_dw(adapter, 0x71c);
+-
+ dprintk("%s: tmp3 = %x\n", __func__, tmp3);
+-
+ write_reg_dw(adapter, 0x71c, tmp2);
+
+ // check for internal SRAM ???
+@@ -350,9 +320,7 @@ static int flexcop_sram_detect(struct flexcop_device *fc)
+ sram_set_size(adapter, 0x10000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+-
+ dprintk("%s: sram size = 32K\n", __func__);
+-
+ return 32;
+ }
+
+@@ -360,9 +328,7 @@ static int flexcop_sram_detect(struct flexcop_device *fc)
+ sram_set_size(adapter, 0x20000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+-
+ dprintk("%s: sram size = 128K\n", __func__);
+-
+ return 128;
+ }
+
+@@ -370,9 +336,7 @@ static int flexcop_sram_detect(struct flexcop_device *fc)
+ sram_set_size(adapter, 0x00000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+-
+ dprintk("%s: sram size = 64K\n", __func__);
+-
+ return 64;
+ }
+
+@@ -380,18 +344,14 @@ static int flexcop_sram_detect(struct flexcop_device *fc)
+ sram_set_size(adapter, 0x10000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+-
+ dprintk("%s: sram size = 32K\n", __func__);
+-
+ return 32;
+ }
+
+ sram_set_size(adapter, 0x10000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+-
+ dprintk("%s: SRAM detection failed. Set to 32K \n", __func__);
+-
+ return 0;
+ }
+
+diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
+index ae0d76a..bedcfb6 100644
+--- a/drivers/media/dvb/b2c2/flexcop-usb.c
++++ b/drivers/media/dvb/b2c2/flexcop-usb.c
+@@ -1,11 +1,8 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
+- * flexcop-usb.c - covers the USB part.
+- *
+- * see flexcop.c for copyright information.
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-usb.c - covers the USB part
++ * see flexcop.c for copyright information
+ */
+-
+ #define FC_LOG_PREFIX "flexcop_usb"
+ #include "flexcop-usb.h"
+ #include "flexcop-common.h"
+@@ -18,42 +15,47 @@
+ /* debug */
+ #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+ #define dprintk(level,args...) \
+- do { if ((debug & level)) { printk(args); } } while (0)
+-#define debug_dump(b,l,method) {\
++ do { if ((debug & level)) printk(args); } while (0)
++
++#define debug_dump(b, l, method) do {\
+ int i; \
+- for (i = 0; i < l; i++) method("%02x ", b[i]); \
+- method("\n");\
+-}
++ for (i = 0; i < l; i++) \
++ method("%02x ", b[i]); \
++ method("\n"); \
++} while (0)
+
+ #define DEBSTATUS ""
+ #else
+-#define dprintk(level,args...)
+-#define debug_dump(b,l,method)
++#define dprintk(level, args...)
++#define debug_dump(b, l, method)
+ #define DEBSTATUS " (debugging is not enabled)"
+ #endif
+
+ static int debug;
+ module_param(debug, int, 0644);
+-MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
++MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
++ "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
+ #undef DEBSTATUS
+
+-#define deb_info(args...) dprintk(0x01,args)
+-#define deb_ts(args...) dprintk(0x02,args)
+-#define deb_ctrl(args...) dprintk(0x04,args)
+-#define deb_i2c(args...) dprintk(0x08,args)
+-#define deb_v8(args...) dprintk(0x10,args)
++#define deb_info(args...) dprintk(0x01, args)
++#define deb_ts(args...) dprintk(0x02, args)
++#define deb_ctrl(args...) dprintk(0x04, args)
++#define deb_i2c(args...) dprintk(0x08, args)
++#define deb_v8(args...) dprintk(0x10, args)
+
+ /* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
+ * in the IBI address, to make the V8 code simpler.
+- * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
++ * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used)
+ * in general: 0000 0HHH 000L LL00
+ * IBI ADDRESS FORMAT: RHHH BLLL
+ *
+ * where R is the read(1)/write(0) bit, B is the busy bit
+ * and HHH and LLL are the two sets of three bits from the PCI address.
+ */
+-#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
+-#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
++#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \
++ (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
++#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \
++ (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
+
+ /*
+ * DKT 020228
+@@ -69,12 +71,13 @@ static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI,
+ struct flexcop_usb *fc_usb = fc->bus_specific;
+ u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
+ u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
+- u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | (read ? 0x80 : 0);
++ u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
++ (read ? 0x80 : 0);
+
+ int len = usb_control_msg(fc_usb->udev,
+ read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
+ request,
+- request_type, /* 0xc0 read or 0x40 write*/
++ request_type, /* 0xc0 read or 0x40 write */
+ wAddress,
+ 0,
+ val,
+@@ -82,55 +85,49 @@ static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI,
+ B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+
+ if (len != sizeof(u32)) {
+- err("error while %s dword from %d (%d).",read ? "reading" : "writing",
+- wAddress,wRegOffsPCI);
++ err("error while %s dword from %d (%d).", read ? "reading" :
++ "writing", wAddress, wRegOffsPCI);
+ return -EIO;
+ }
+ return 0;
+ }
+-
+ /*
+ * DKT 010817 - add support for V8 memory read/write and flash update
+ */
+ static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
+ flexcop_usb_request_t req, u8 page, u16 wAddress,
+- u8 *pbBuffer,u32 buflen)
++ u8 *pbBuffer, u32 buflen)
+ {
+-// u8 dwRequestType;
+ u8 request_type = USB_TYPE_VENDOR;
+ u16 wIndex;
+- int nWaitTime,pipe,len;
+-
++ int nWaitTime, pipe, len;
+ wIndex = page << 8;
+
+ switch (req) {
+- case B2C2_USB_READ_V8_MEM:
+- nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
+- request_type |= USB_DIR_IN;
+-// dwRequestType = (u8) RTYPE_READ_V8_MEMORY;
+- pipe = B2C2_USB_CTRL_PIPE_IN;
++ case B2C2_USB_READ_V8_MEM:
++ nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
++ request_type |= USB_DIR_IN;
++ pipe = B2C2_USB_CTRL_PIPE_IN;
+ break;
+- case B2C2_USB_WRITE_V8_MEM:
+- wIndex |= pbBuffer[0];
+- request_type |= USB_DIR_OUT;
+- nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
+-// dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY;
+- pipe = B2C2_USB_CTRL_PIPE_OUT;
++ case B2C2_USB_WRITE_V8_MEM:
++ wIndex |= pbBuffer[0];
++ request_type |= USB_DIR_OUT;
++ nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
++ pipe = B2C2_USB_CTRL_PIPE_OUT;
+ break;
+- case B2C2_USB_FLASH_BLOCK:
+- request_type |= USB_DIR_OUT;
+- nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
+-// dwRequestType = (u8) RTYPE_WRITE_V8_FLASH;
+- pipe = B2C2_USB_CTRL_PIPE_OUT;
++ case B2C2_USB_FLASH_BLOCK:
++ request_type |= USB_DIR_OUT;
++ nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
++ pipe = B2C2_USB_CTRL_PIPE_OUT;
+ break;
+- default:
+- deb_info("unsupported request for v8_mem_req %x.\n",req);
++ default:
++ deb_info("unsupported request for v8_mem_req %x.\n", req);
+ return -EINVAL;
+ }
+- deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n",request_type,req,
+- wAddress,wIndex,buflen);
++ deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
++ wAddress, wIndex, buflen);
+
+- len = usb_control_msg(fc_usb->udev,pipe,
++ len = usb_control_msg(fc_usb->udev, pipe,
+ req,
+ request_type,
+ wAddress,
+@@ -139,39 +136,53 @@ static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
+ buflen,
+ nWaitTime * HZ);
+
+- debug_dump(pbBuffer,len,deb_v8);
+-
++ debug_dump(pbBuffer, len, deb_v8);
+ return len == buflen ? 0 : -EIO;
+ }
+
+ #define bytes_left_to_read_on_page(paddr,buflen) \
+- ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
+- ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
++ ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
++ ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
+
+-static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request_t req,
+- flexcop_usb_mem_page_t page_start, u32 addr, int extended, u8 *buf, u32 len)
++static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
++ flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
++ u32 addr, int extended, u8 *buf, u32 len)
+ {
+ int i,ret = 0;
+ u16 wMax;
+ u32 pagechunk = 0;
+
+ switch(req) {
+- case B2C2_USB_READ_V8_MEM: wMax = USB_MEM_READ_MAX; break;
+- case B2C2_USB_WRITE_V8_MEM: wMax = USB_MEM_WRITE_MAX; break;
+- case B2C2_USB_FLASH_BLOCK: wMax = USB_FLASH_MAX; break;
+- default:
+- return -EINVAL;
++ case B2C2_USB_READ_V8_MEM:
++ wMax = USB_MEM_READ_MAX;
++ break;
++ case B2C2_USB_WRITE_V8_MEM:
++ wMax = USB_MEM_WRITE_MAX;
++ break;
++ case B2C2_USB_FLASH_BLOCK:
++ wMax = USB_FLASH_MAX;
++ break;
++ default:
++ return -EINVAL;
+ break;
+ }
+ for (i = 0; i < len;) {
+- pagechunk = wMax < bytes_left_to_read_on_page(addr,len) ? wMax : bytes_left_to_read_on_page(addr,len);
+- deb_info("%x\n",(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended));
+- if ((ret = flexcop_usb_v8_memory_req(fc_usb,req,
+- page_start + (addr / V8_MEMORY_PAGE_SIZE), /* actual page */
+- (addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended),
+- &buf[i],pagechunk)) < 0)
++ pagechunk =
++ wMax < bytes_left_to_read_on_page(addr, len) ?
++ wMax :
++ bytes_left_to_read_on_page(addr, len);
++ deb_info("%x\n",
++ (addr & V8_MEMORY_PAGE_MASK) |
++ (V8_MEMORY_EXTENDED*extended));
++
++ ret = flexcop_usb_v8_memory_req(fc_usb, req,
++ page_start + (addr / V8_MEMORY_PAGE_SIZE),
++ (addr & V8_MEMORY_PAGE_MASK) |
++ (V8_MEMORY_EXTENDED*extended),
++ &buf[i], pagechunk);
++
++ if (ret < 0)
+ return ret;
+-
+ addr += pagechunk;
+ len -= pagechunk;
+ }
+@@ -180,8 +191,9 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request
+
+ static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
+ {
+- return flexcop_usb_memory_req(fc->bus_specific,B2C2_USB_READ_V8_MEM,
+- V8_MEMORY_PAGE_FLASH,0x1f010,1,fc->dvb_adapter.proposed_mac,6);
++ return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM,
++ V8_MEMORY_PAGE_FLASH, 0x1f010, 1,
++ fc->dvb_adapter.proposed_mac, 6);
+ }
+
+ #if 0
+@@ -191,11 +203,8 @@ static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
+ {
+ u16 wValue;
+ u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
+-// u8 dwRequestType = (u8) RTYPE_GENERIC,
+ int nWaitTime = 2,
+- pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN,
+- len;
+-
++ pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
+ wValue = (func << 8) | extra;
+
+ len = usb_control_msg(fc_usb->udev,pipe,
+@@ -218,36 +227,35 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
+ struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
+ u16 wValue, wIndex;
+ int nWaitTime,pipe,len;
+-// u8 dwRequestType;
+ u8 request_type = USB_TYPE_VENDOR;
+
+ switch (func) {
+- case USB_FUNC_I2C_WRITE:
+- case USB_FUNC_I2C_MULTIWRITE:
+- case USB_FUNC_I2C_REPEATWRITE:
++ case USB_FUNC_I2C_WRITE:
++ case USB_FUNC_I2C_MULTIWRITE:
++ case USB_FUNC_I2C_REPEATWRITE:
+ /* DKT 020208 - add this to support special case of DiSEqC */
+- case USB_FUNC_I2C_CHECKWRITE:
+- pipe = B2C2_USB_CTRL_PIPE_OUT;
+- nWaitTime = 2;
+-// dwRequestType = (u8) RTYPE_GENERIC;
+- request_type |= USB_DIR_OUT;
++ case USB_FUNC_I2C_CHECKWRITE:
++ pipe = B2C2_USB_CTRL_PIPE_OUT;
++ nWaitTime = 2;
++ request_type |= USB_DIR_OUT;
+ break;
+- case USB_FUNC_I2C_READ:
+- case USB_FUNC_I2C_REPEATREAD:
+- pipe = B2C2_USB_CTRL_PIPE_IN;
+- nWaitTime = 2;
+-// dwRequestType = (u8) RTYPE_GENERIC;
+- request_type |= USB_DIR_IN;
++ case USB_FUNC_I2C_READ:
++ case USB_FUNC_I2C_REPEATREAD:
++ pipe = B2C2_USB_CTRL_PIPE_IN;
++ nWaitTime = 2;
++ request_type |= USB_DIR_IN;
+ break;
+- default:
+- deb_info("unsupported function for i2c_req %x\n",func);
+- return -EINVAL;
++ default:
++ deb_info("unsupported function for i2c_req %x\n", func);
++ return -EINVAL;
+ }
+ wValue = (func << 8) | (i2c->port << 4);
+ wIndex = (chipaddr << 8 ) | addr;
+
+- deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req,
+- wValue & 0xff, wValue >> 8, wIndex & 0xff, wIndex >> 8);
++ deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",
++ func, request_type, req,
++ wValue & 0xff, wValue >> 8,
++ wIndex & 0xff, wIndex >> 8);
+
+ len = usb_control_msg(fc_usb->udev,pipe,
+ req,
+@@ -257,44 +265,49 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
+ buf,
+ buflen,
+ nWaitTime * HZ);
+-
+ return len == buflen ? 0 : -EREMOTEIO;
+ }
+
+-/* actual bus specific access functions, make sure prototype are/will be equal to pci */
+-static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg)
++/* actual bus specific access functions,
++ make sure prototype are/will be equal to pci */
++static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc,
++ flexcop_ibi_register reg)
+ {
+ flexcop_ibi_value val;
+ val.raw = 0;
+- flexcop_usb_readwrite_dw(fc,reg, &val.raw, 1);
++ flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1);
+ return val;
+ }
+
+-static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg, flexcop_ibi_value val)
++static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
++ flexcop_ibi_register reg, flexcop_ibi_value val)
+ {
+- return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0);
++ return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0);
+ }
+
+ static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
+- flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
++ flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+ {
+ if (op == FC_READ)
+ return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+- USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
++ USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
+ else
+ return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+- USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
++ USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
+ }
+
+-static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, int buffer_length)
++static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
++ u8 *buffer, int buffer_length)
+ {
+ u8 *b;
+ int l;
+
+- deb_ts("tmp_buffer_length=%d, buffer_length=%d\n", fc_usb->tmp_buffer_length, buffer_length);
++ deb_ts("tmp_buffer_length=%d, buffer_length=%d\n",
++ fc_usb->tmp_buffer_length, buffer_length);
+
+ if (fc_usb->tmp_buffer_length > 0) {
+- memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer, buffer_length);
++ memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer,
++ buffer_length);
+ fc_usb->tmp_buffer_length += buffer_length;
+ b = fc_usb->tmp_buffer;
+ l = fc_usb->tmp_buffer_length;
+@@ -304,23 +317,26 @@ static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, in
+ }
+
+ while (l >= 190) {
+- if (*b == 0xff)
++ if (*b == 0xff) {
+ switch (*(b+1) & 0x03) {
+- case 0x01: /* media packet */
+- if ( *(b+2) == 0x47 )
+- flexcop_pass_dmx_packets(fc_usb->fc_dev, b+2, 1);
+- else
+- deb_ts("not ts packet %02x %02x %02x %02x \n", *(b+2), *(b+3), *(b+4), *(b+5) );
+-
+- b += 190;
+- l -= 190;
++ case 0x01: /* media packet */
++ if (*(b+2) == 0x47)
++ flexcop_pass_dmx_packets(
++ fc_usb->fc_dev, b+2, 1);
++ else
++ deb_ts(
++ "not ts packet %02x %02x %02x %02x \n",
++ *(b+2), *(b+3),
++ *(b+4), *(b+5));
++ b += 190;
++ l -= 190;
+ break;
+- default:
+- deb_ts("wrong packet type\n");
+- l = 0;
++ default:
++ deb_ts("wrong packet type\n");
++ l = 0;
+ break;
+ }
+- else {
++ } else {
+ deb_ts("wrong header\n");
+ l = 0;
+ }
+@@ -337,23 +353,26 @@ static void flexcop_usb_urb_complete(struct urb *urb)
+ int i;
+
+ if (urb->actual_length > 0)
+- deb_ts("urb completed, bufsize: %d actlen; %d\n",urb->transfer_buffer_length, urb->actual_length);
++ deb_ts("urb completed, bufsize: %d actlen; %d\n",
++ urb->transfer_buffer_length, urb->actual_length);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (urb->iso_frame_desc[i].status < 0) {
+- err("iso frame descriptor %d has an error: %d\n",i,urb->iso_frame_desc[i].status);
++ err("iso frame descriptor %d has an error: %d\n", i,
++ urb->iso_frame_desc[i].status);
+ } else
+ if (urb->iso_frame_desc[i].actual_length > 0) {
+- deb_ts("passed %d bytes to the demux\n",urb->iso_frame_desc[i].actual_length);
++ deb_ts("passed %d bytes to the demux\n",
++ urb->iso_frame_desc[i].actual_length);
+
+ flexcop_usb_process_frame(fc_usb,
+- urb->transfer_buffer + urb->iso_frame_desc[i].offset,
++ urb->transfer_buffer +
++ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+- }
++ }
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+-
+ usb_submit_urb(urb,GFP_ATOMIC);
+ }
+
+@@ -374,35 +393,47 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
+ }
+
+ if (fc_usb->iso_buffer != NULL)
+- pci_free_consistent(NULL,fc_usb->buffer_size, fc_usb->iso_buffer, fc_usb->dma_addr);
++ pci_free_consistent(NULL,
++ fc_usb->buffer_size, fc_usb->iso_buffer,
++ fc_usb->dma_addr);
+ }
+
+ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
+ {
+- u16 frame_size = le16_to_cpu(fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
+- int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
++ u16 frame_size = le16_to_cpu(
++ fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
++ int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
++ frame_size, i, j, ret;
+ int buffer_offset = 0;
+
+- deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
+- B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize);
++ deb_ts("creating %d iso-urbs with %d frames "
++ "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
++ B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
+
+- fc_usb->iso_buffer = pci_alloc_consistent(NULL,bufsize,&fc_usb->dma_addr);
++ fc_usb->iso_buffer = pci_alloc_consistent(NULL,
++ bufsize, &fc_usb->dma_addr);
+ if (fc_usb->iso_buffer == NULL)
+ return -ENOMEM;
++
+ memset(fc_usb->iso_buffer, 0, bufsize);
+ fc_usb->buffer_size = bufsize;
+
+ /* creating iso urbs */
+- for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
+- if (!(fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) {
++ for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
++ fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
++ GFP_ATOMIC);
++ if (fc_usb->iso_urb[i] == NULL) {
+ ret = -ENOMEM;
+ goto urb_error;
+ }
++ }
++
+ /* initialising and submitting iso urbs */
+ for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
+ int frame_offset = 0;
+ struct urb *urb = fc_usb->iso_urb[i];
+- deb_ts("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
++ deb_ts("initializing and submitting urb no. %d "
++ "(buf_offset: %d).\n", i, buffer_offset);
+
+ urb->dev = fc_usb->udev;
+ urb->context = fc_usb;
+@@ -416,26 +447,26 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
+
+ buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
+ for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
+- deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset);
++ deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",
++ i, j, frame_offset);
+ urb->iso_frame_desc[j].offset = frame_offset;
+ urb->iso_frame_desc[j].length = frame_size;
+ frame_offset += frame_size;
+ }
+
+ if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
+- err("submitting urb %d failed with %d.",i,ret);
++ err("submitting urb %d failed with %d.", i, ret);
+ goto urb_error;
+ }
+ deb_ts("submitted urb no. %d.\n",i);
+ }
+
+-/* SRAM */
+-
+- flexcop_sram_set_dest(fc_usb->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET |
+- FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_WAN_USB);
+- flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
+- flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
+-
++ /* SRAM */
++ flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA |
++ FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI,
++ FC_SRAM_DEST_TARGET_WAN_USB);
++ flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS);
++ flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1);
+ return 0;
+
+ urb_error:
+@@ -448,20 +479,20 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb)
+ /* use the alternate setting with the larges buffer */
+ usb_set_interface(fc_usb->udev,0,1);
+ switch (fc_usb->udev->speed) {
+- case USB_SPEED_LOW:
+- err("cannot handle USB speed because it is to sLOW.");
+- return -ENODEV;
+- break;
+- case USB_SPEED_FULL:
+- info("running at FULL speed.");
+- break;
+- case USB_SPEED_HIGH:
+- info("running at HIGH speed.");
+- break;
+- case USB_SPEED_UNKNOWN: /* fall through */
+- default:
+- err("cannot handle USB speed because it is unkown.");
+- return -ENODEV;
++ case USB_SPEED_LOW:
++ err("cannot handle USB speed because it is too slow.");
++ return -ENODEV;
++ break;
++ case USB_SPEED_FULL:
++ info("running at FULL speed.");
++ break;
++ case USB_SPEED_HIGH:
++ info("running at HIGH speed.");
++ break;
++ case USB_SPEED_UNKNOWN: /* fall through */
++ default:
++ err("cannot handle USB speed because it is unknown.");
++ return -ENODEV;
+ }
+ usb_set_intfdata(fc_usb->uintf, fc_usb);
+ return 0;
+@@ -485,7 +516,7 @@ static int flexcop_usb_probe(struct usb_interface *intf,
+ return -ENOMEM;
+ }
+
+-/* general flexcop init */
++ /* general flexcop init */
+ fc_usb = fc->bus_specific;
+ fc_usb->fc_dev = fc;
+
+@@ -502,21 +533,21 @@ static int flexcop_usb_probe(struct usb_interface *intf,
+ fc->dev = &udev->dev;
+ fc->owner = THIS_MODULE;
+
+-/* bus specific part */
++ /* bus specific part */
+ fc_usb->udev = udev;
+ fc_usb->uintf = intf;
+ if ((ret = flexcop_usb_init(fc_usb)) != 0)
+ goto err_kfree;
+
+-/* init flexcop */
++ /* init flexcop */
+ if ((ret = flexcop_device_initialize(fc)) != 0)
+ goto err_usb_exit;
+
+-/* xfer init */
++ /* xfer init */
+ if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
+ goto err_fc_exit;
+
+- info("%s successfully initialized and connected.",DRIVER_NAME);
++ info("%s successfully initialized and connected.", DRIVER_NAME);
+ return 0;
+
+ err_fc_exit:
+@@ -535,12 +566,12 @@ static void flexcop_usb_disconnect(struct usb_interface *intf)
+ flexcop_device_exit(fc_usb->fc_dev);
+ flexcop_usb_exit(fc_usb);
+ flexcop_device_kfree(fc_usb->fc_dev);
+- info("%s successfully deinitialized and disconnected.",DRIVER_NAME);
++ info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
+ }
+
+ static struct usb_device_id flexcop_usb_table [] = {
+- { USB_DEVICE(0x0af7, 0x0101) },
+- { }
++ { USB_DEVICE(0x0af7, 0x0101) },
++ { }
+ };
+ MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
+
+@@ -557,10 +588,9 @@ static int __init flexcop_usb_module_init(void)
+ {
+ int result;
+ if ((result = usb_register(&flexcop_usb_driver))) {
+- err("usb_register failed. (%d)",result);
++ err("usb_register failed. (%d)", result);
+ return result;
+ }
+-
+ return 0;
+ }
+
+diff --git a/drivers/media/dvb/b2c2/flexcop-usb.h b/drivers/media/dvb/b2c2/flexcop-usb.h
+index 630e647..92529a9 100644
+--- a/drivers/media/dvb/b2c2/flexcop-usb.h
++++ b/drivers/media/dvb/b2c2/flexcop-usb.h
+@@ -1,15 +1,20 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-usb.h - header file for the USB part
++ * see flexcop.c for copyright information
++ */
+ #ifndef __FLEXCOP_USB_H_INCLUDED__
+ #define __FLEXCOP_USB_H_INCLUDED__
+
+ #include <linux/usb.h>
+
+ /* transfer parameters */
+-#define B2C2_USB_FRAMES_PER_ISO 4
+-#define B2C2_USB_NUM_ISO_URB 4
++#define B2C2_USB_FRAMES_PER_ISO 4
++#define B2C2_USB_NUM_ISO_URB 4
+
+-#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev,0)
+-#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev,0)
+-#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev,0x81)
++#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev, 0)
++#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev, 0)
++#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 0x81)
+
+ struct flexcop_usb {
+ struct usb_device *udev;
+@@ -18,8 +23,8 @@ struct flexcop_usb {
+ u8 *iso_buffer;
+ int buffer_size;
+ dma_addr_t dma_addr;
+- struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
+
++ struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
+ struct flexcop_device *fc_dev;
+
+ u8 tmp_buffer[1023+190];
+@@ -30,14 +35,6 @@ struct flexcop_usb {
+ /* request types TODO What is its use?*/
+ typedef enum {
+
+-/* something is wrong with this part
+- RTYPE_READ_DW = (1 << 6),
+- RTYPE_WRITE_DW_1 = (3 << 6),
+- RTYPE_READ_V8_MEMORY = (6 << 6),
+- RTYPE_WRITE_V8_MEMORY = (7 << 6),
+- RTYPE_WRITE_V8_FLASH = (8 << 6),
+- RTYPE_GENERIC = (9 << 6),
+-*/
+ } flexcop_usb_request_type_t;
+ #endif
+
+@@ -47,7 +44,6 @@ typedef enum {
+ B2C2_USB_READ_V8_MEM = 0x05,
+ B2C2_USB_READ_REG = 0x08,
+ B2C2_USB_WRITE_REG = 0x0A,
+-/* B2C2_USB_WRITEREGLO = 0x0A, */
+ B2C2_USB_WRITEREGHI = 0x0B,
+ B2C2_USB_FLASH_BLOCK = 0x10,
+ B2C2_USB_I2C_REQUEST = 0x11,
+@@ -62,15 +58,13 @@ typedef enum {
+ USB_FUNC_I2C_REPEATWRITE = 0x04,
+ USB_FUNC_GET_DESCRIPTOR = 0x05,
+ USB_FUNC_I2C_REPEATREAD = 0x06,
+-/* DKT 020208 - add this to support special case of DiSEqC */
++ /* DKT 020208 - add this to support special case of DiSEqC */
+ USB_FUNC_I2C_CHECKWRITE = 0x07,
+ USB_FUNC_I2C_CHECKRESULT = 0x08,
+ } flexcop_usb_i2c_function_t;
+
+-/*
+- * function definition for UTILITY request 0x12
+- * DKT 020304 - new utility function
+- */
++/* function definition for UTILITY request 0x12
++ * DKT 020304 - new utility function */
+ typedef enum {
+ UTILITY_SET_FILTER = 0x01,
+ UTILITY_DATA_ENABLE = 0x02,
+@@ -84,7 +78,7 @@ typedef enum {
+ UTILITY_DATA_RESET = 0x0A,
+ UTILITY_GET_DATA_STATUS = 0x10,
+ UTILITY_GET_V8_REG = 0x11,
+-/* DKT 020326 - add function for v1.14 */
++ /* DKT 020326 - add function for v1.14 */
+ UTILITY_SRAM_WRITE = 0x12,
+ UTILITY_SRAM_READ = 0x13,
+ UTILITY_SRAM_TESTFILL = 0x14,
+@@ -92,13 +86,13 @@ typedef enum {
+ UTILITY_SRAM_TESTVERIFY = 0x16,
+ } flexcop_usb_utility_function_t;
+
+-#define B2C2_WAIT_FOR_OPERATION_RW 1*HZ /* 1 s */
+-#define B2C2_WAIT_FOR_OPERATION_RDW 3*HZ /* 3 s */
+-#define B2C2_WAIT_FOR_OPERATION_WDW 1*HZ /* 1 s */
++#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ)
++#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ)
++#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ)
+
+-#define B2C2_WAIT_FOR_OPERATION_V8READ 3*HZ /* 3 s */
+-#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3*HZ /* 3 s */
+-#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3*HZ /* 3 s */
++#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ)
++#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ)
++#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ)
+
+ typedef enum {
+ V8_MEMORY_PAGE_DVB_CI = 0x20,
+@@ -107,13 +101,11 @@ typedef enum {
+ V8_MEMORY_PAGE_FLASH = 0x80
+ } flexcop_usb_mem_page_t;
+
+-#define V8_MEMORY_EXTENDED (1 << 15)
+-
+-#define USB_MEM_READ_MAX 32
+-#define USB_MEM_WRITE_MAX 1
+-#define USB_FLASH_MAX 8
+-
+-#define V8_MEMORY_PAGE_SIZE 0x8000 // 32K
+-#define V8_MEMORY_PAGE_MASK 0x7FFF
++#define V8_MEMORY_EXTENDED (1 << 15)
++#define USB_MEM_READ_MAX 32
++#define USB_MEM_WRITE_MAX 1
++#define USB_FLASH_MAX 8
++#define V8_MEMORY_PAGE_SIZE 0x8000 /* 32K */
++#define V8_MEMORY_PAGE_MASK 0x7FFF
+
+ #endif
+diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
+index 9106895..2df1b02 100644
+--- a/drivers/media/dvb/b2c2/flexcop.c
++++ b/drivers/media/dvb/b2c2/flexcop.c
+@@ -1,22 +1,20 @@
+ /*
+- * flexcop.c - driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
+- * Copyright (C) 2004-5 Patrick Boettcher <patrick.boettcher@desy.de>
+- *
+- * based on the skystar2-driver
+- * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop.c - main module part
++ * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
++ * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
+ *
+ * Acknowledgements:
+- * John Jurrius from BBTI, Inc. for extensive support with
+- * code examples and data books
+- *
+- * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
++ * John Jurrius from BBTI, Inc. for extensive support
++ * with code examples and data books
++ * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
+ *
+ * Contributions to the skystar2-driver have been done by
+- * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
+- * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
+- * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac filtering)
+- *
++ * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
++ * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
++ * Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
++ * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac
++ * filtering)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+@@ -46,7 +44,10 @@
+
+ int b2c2_flexcop_debug;
+ module_param_named(debug, b2c2_flexcop_debug, int, 0644);
+-MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS);
++MODULE_PARM_DESC(debug,
++ "set debug level (1=info,2=tuner,4=i2c,8=ts,"
++ "16=sram,32=reg (|-able))."
++ DEBSTATUS);
+ #undef DEBSTATUS
+
+ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+@@ -57,37 +58,36 @@ flexcop_ibi_value ibi_zero;
+ static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+ {
+ struct flexcop_device *fc = dvbdmxfeed->demux->priv;
+- return flexcop_pid_feed_control(fc,dvbdmxfeed,1);
++ return flexcop_pid_feed_control(fc, dvbdmxfeed, 1);
+ }
+
+ static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+ {
+ struct flexcop_device *fc = dvbdmxfeed->demux->priv;
+- return flexcop_pid_feed_control(fc,dvbdmxfeed,0);
++ return flexcop_pid_feed_control(fc, dvbdmxfeed, 0);
+ }
+
+ static int flexcop_dvb_init(struct flexcop_device *fc)
+ {
+ int ret = dvb_register_adapter(&fc->dvb_adapter,
+- "FlexCop Digital TV device", fc->owner,
+- fc->dev, adapter_nr);
++ "FlexCop Digital TV device", fc->owner,
++ fc->dev, adapter_nr);
+ if (ret < 0) {
+ err("error registering DVB adapter");
+ return ret;
+ }
+ fc->dvb_adapter.priv = fc;
+
+- fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
++ fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING
++ | DMX_MEMORY_BASED_FILTERING);
+ fc->demux.priv = fc;
+-
+ fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
+-
+ fc->demux.start_feed = flexcop_dvb_start_feed;
+ fc->demux.stop_feed = flexcop_dvb_stop_feed;
+ fc->demux.write_to_decoder = NULL;
+
+ if ((ret = dvb_dmx_init(&fc->demux)) < 0) {
+- err("dvb_dmx failed: error %d",ret);
++ err("dvb_dmx failed: error %d", ret);
+ goto err_dmx;
+ }
+
+@@ -97,23 +97,23 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
+ fc->dmxdev.demux = &fc->demux.dmx;
+ fc->dmxdev.capabilities = 0;
+ if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) {
+- err("dvb_dmxdev_init failed: error %d",ret);
++ err("dvb_dmxdev_init failed: error %d", ret);
+ goto err_dmx_dev;
+ }
+
+ if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
+- err("adding hw_frontend to dmx failed: error %d",ret);
++ err("adding hw_frontend to dmx failed: error %d", ret);
+ goto err_dmx_add_hw_frontend;
+ }
+
+ fc->mem_frontend.source = DMX_MEMORY_FE;
+ if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) {
+- err("adding mem_frontend to dmx failed: error %d",ret);
++ err("adding mem_frontend to dmx failed: error %d", ret);
+ goto err_dmx_add_mem_frontend;
+ }
+
+ if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
+- err("connect frontend failed: error %d",ret);
++ err("connect frontend failed: error %d", ret);
+ goto err_connect_frontend;
+ }
+
+@@ -123,9 +123,9 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
+ return 0;
+
+ err_connect_frontend:
+- fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
++ fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend);
+ err_dmx_add_mem_frontend:
+- fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend);
++ fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend);
+ err_dmx_add_hw_frontend:
+ dvb_dmxdev_release(&fc->dmxdev);
+ err_dmx_dev:
+@@ -141,12 +141,13 @@ static void flexcop_dvb_exit(struct flexcop_device *fc)
+ dvb_net_release(&fc->dvbnet);
+
+ fc->demux.dmx.close(&fc->demux.dmx);
+- fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
+- fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend);
++ fc->demux.dmx.remove_frontend(&fc->demux.dmx,
++ &fc->mem_frontend);
++ fc->demux.dmx.remove_frontend(&fc->demux.dmx,
++ &fc->hw_frontend);
+ dvb_dmxdev_release(&fc->dmxdev);
+ dvb_dmx_release(&fc->demux);
+ dvb_unregister_adapter(&fc->dvb_adapter);
+-
+ deb_info("deinitialized dvb stuff\n");
+ }
+ fc->init_state &= ~FC_STATE_DVB_INIT;
+@@ -168,9 +169,9 @@ EXPORT_SYMBOL(flexcop_pass_dmx_packets);
+
+ static void flexcop_reset(struct flexcop_device *fc)
+ {
+- flexcop_ibi_value v210,v204;
++ flexcop_ibi_value v210, v204;
+
+-/* reset the flexcop itself */
++ /* reset the flexcop itself */
+ fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+ v210.raw = 0;
+@@ -183,13 +184,11 @@ static void flexcop_reset(struct flexcop_device *fc)
+ v210.sw_reset_210.reset_block_600 = 1;
+ v210.sw_reset_210.reset_block_700 = 1;
+ v210.sw_reset_210.Block_reset_enable = 0xb2;
+-
+ v210.sw_reset_210.Special_controls = 0xc259;
+-
+ fc->write_ibi_reg(fc,sw_reset_210,v210);
+ msleep(1);
+
+-/* reset the periphical devices */
++ /* reset the periphical devices */
+
+ v204 = fc->read_ibi_reg(fc,misc_204);
+ v204.misc_204.Per_reset_sig = 0;
+@@ -201,25 +200,24 @@ static void flexcop_reset(struct flexcop_device *fc)
+
+ void flexcop_reset_block_300(struct flexcop_device *fc)
+ {
+- flexcop_ibi_value v208_save = fc->read_ibi_reg(fc,ctrl_208),
+- v210 = fc->read_ibi_reg(fc,sw_reset_210);
+-
+- deb_rdump("208: %08x, 210: %08x\n",v208_save.raw,v210.raw);
++ flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208),
++ v210 = fc->read_ibi_reg(fc, sw_reset_210);
+
++ deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw);
+ fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+ v210.sw_reset_210.reset_block_300 = 1;
+ v210.sw_reset_210.Block_reset_enable = 0xb2;
+
+ fc->write_ibi_reg(fc,sw_reset_210,v210);
+- udelay(1000);
+ fc->write_ibi_reg(fc,ctrl_208,v208_save);
+ }
+
+ struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
+ {
+ void *bus;
+- struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device), GFP_KERNEL);
++ struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device),
++ GFP_KERNEL);
+ if (!fc) {
+ err("no memory");
+ return NULL;
+@@ -254,7 +252,6 @@ int flexcop_device_initialize(struct flexcop_device *fc)
+ flexcop_determine_revision(fc);
+ flexcop_sram_init(fc);
+ flexcop_hw_filter_init(fc);
+-
+ flexcop_smc_ctrl(fc, 0);
+
+ if ((ret = flexcop_dvb_init(fc)))
+@@ -279,7 +276,6 @@ int flexcop_device_initialize(struct flexcop_device *fc)
+ goto error;
+
+ flexcop_device_name(fc,"initialization of","complete");
+-
+ return 0;
+
+ error:
+diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h
+index 0cebe1d..897b10c 100644
+--- a/drivers/media/dvb/b2c2/flexcop.h
++++ b/drivers/media/dvb/b2c2/flexcop.h
+@@ -1,9 +1,7 @@
+ /*
+- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
+- * flexcop.h - private header file for all flexcop-chip-source files.
+- *
+- * see flexcop.c for copyright information.
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop.h - private header file for all flexcop-chip-source files
++ * see flexcop.c for copyright information
+ */
+ #ifndef __FLEXCOP_H__
+ #define __FLEXCOP_H___
+@@ -21,11 +19,11 @@ extern int b2c2_flexcop_debug;
+ #define dprintk(level,args...)
+ #endif
+
+-#define deb_info(args...) dprintk(0x01,args)
+-#define deb_tuner(args...) dprintk(0x02,args)
+-#define deb_i2c(args...) dprintk(0x04,args)
+-#define deb_ts(args...) dprintk(0x08,args)
+-#define deb_sram(args...) dprintk(0x10,args)
+-#define deb_rdump(args...) dprintk(0x20,args)
++#define deb_info(args...) dprintk(0x01, args)
++#define deb_tuner(args...) dprintk(0x02, args)
++#define deb_i2c(args...) dprintk(0x04, args)
++#define deb_ts(args...) dprintk(0x08, args)
++#define deb_sram(args...) dprintk(0x10, args)
++#define deb_rdump(args...) dprintk(0x20, args)
+
+ #endif
+diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
+index ed9a675..8f64bdb 100644
+--- a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
++++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
+@@ -1,10 +1,7 @@
+-/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
++/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * register descriptions
+- *
+- * see flexcop.c for copyright information.
++ * see flexcop.c for copyright information
+ */
+-
+ /* This file is automatically generated, do not edit things here. */
+ #ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+ #define __FLEXCOP_IBI_VALUE_INCLUDED__
+diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
+index 49f2315..c75830d 100644
+--- a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
++++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
+@@ -1,10 +1,7 @@
+-/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+- *
++/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * register descriptions
+- *
+- * see flexcop.c for copyright information.
++ * see flexcop.c for copyright information
+ */
+-
+ /* This file is automatically generated, do not edit things here. */
+ #ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+ #define __FLEXCOP_IBI_VALUE_INCLUDED__
+diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
+index 27edb0e..8668e63 100644
+--- a/drivers/media/dvb/bt8xx/Kconfig
++++ b/drivers/media/dvb/bt8xx/Kconfig
+@@ -8,7 +8,7 @@ config DVB_BT8XX
+ select DVB_OR51211 if !DVB_FE_CUSTOMISE
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+ help
+ Support for PCI cards based on the Bt8xx PCI bridge. Examples are
+ the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
+diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
+index 0258451..4601b05 100644
+--- a/drivers/media/dvb/bt8xx/dst_ca.c
++++ b/drivers/media/dvb/bt8xx/dst_ca.c
+@@ -552,16 +552,19 @@ free_mem_and_exit:
+ return result;
+ }
+
+-static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ioctl_arg)
++static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg)
+ {
+- struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
+- struct dst_state* state = (struct dst_state*) dvbdev->priv;
++ struct dvb_device *dvbdev;
++ struct dst_state *state;
+ struct ca_slot_info *p_ca_slot_info;
+ struct ca_caps *p_ca_caps;
+ struct ca_msg *p_ca_message;
+ void __user *arg = (void __user *)ioctl_arg;
+ int result = 0;
+
++ lock_kernel();
++ dvbdev = (struct dvb_device *)file->private_data;
++ state = (struct dst_state *)dvbdev->priv;
+ p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
+ p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
+ p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
+@@ -647,6 +650,7 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
+ kfree (p_ca_slot_info);
+ kfree (p_ca_caps);
+
++ unlock_kernel();
+ return result;
+ }
+
+@@ -682,9 +686,9 @@ static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t
+ return 0;
+ }
+
+-static struct file_operations dst_ca_fops = {
++static const struct file_operations dst_ca_fops = {
+ .owner = THIS_MODULE,
+- .ioctl = dst_ca_ioctl,
++ .unlocked_ioctl = dst_ca_ioctl,
+ .open = dst_ca_open,
+ .release = dst_ca_release,
+ .read = dst_ca_read,
+diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+index 48762a2..b1857c1 100644
+--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
++++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+@@ -814,7 +814,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
+
+ mutex_init(&card->lock);
+ card->bttv_nr = sub->core->nr;
+- strncpy(card->card_name, sub->core->name, sizeof(sub->core->name));
++ strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name));
+ card->i2c_adapter = &sub->core->i2c_adap;
+
+ switch(sub->core->type) {
+diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
+index 43f4d44..de3eeb0 100644
+--- a/drivers/media/dvb/dm1105/Kconfig
++++ b/drivers/media/dvb/dm1105/Kconfig
+@@ -8,6 +8,7 @@ config DVB_DM1105
+ select DVB_STB6000 if !DVB_FE_CUSTOMISE
+ select DVB_CX24116 if !DVB_FE_CUSTOMISE
+ select DVB_SI21XX if !DVB_FE_CUSTOMISE
++ select VIDEO_IR
+ help
+ Support for cards based on the SDMC DM1105 PCI chip like
+ DvbWorld 2002
+diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
+index f48f73a..5b20cf5 100644
+--- a/drivers/media/dvb/dm1105/dm1105.c
++++ b/drivers/media/dvb/dm1105/dm1105.c
+@@ -156,46 +156,12 @@ MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
+
+ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+-static u16 ir_codes_dm1105_nec[128] = {
+- [0x0a] = KEY_Q, /*power*/
+- [0x0c] = KEY_M, /*mute*/
+- [0x11] = KEY_1,
+- [0x12] = KEY_2,
+- [0x13] = KEY_3,
+- [0x14] = KEY_4,
+- [0x15] = KEY_5,
+- [0x16] = KEY_6,
+- [0x17] = KEY_7,
+- [0x18] = KEY_8,
+- [0x19] = KEY_9,
+- [0x10] = KEY_0,
+- [0x1c] = KEY_PAGEUP, /*ch+*/
+- [0x0f] = KEY_PAGEDOWN, /*ch-*/
+- [0x1a] = KEY_O, /*vol+*/
+- [0x0e] = KEY_Z, /*vol-*/
+- [0x04] = KEY_R, /*rec*/
+- [0x09] = KEY_D, /*fav*/
+- [0x08] = KEY_BACKSPACE, /*rewind*/
+- [0x07] = KEY_A, /*fast*/
+- [0x0b] = KEY_P, /*pause*/
+- [0x02] = KEY_ESC, /*cancel*/
+- [0x03] = KEY_G, /*tab*/
+- [0x00] = KEY_UP, /*up*/
+- [0x1f] = KEY_ENTER, /*ok*/
+- [0x01] = KEY_DOWN, /*down*/
+- [0x05] = KEY_C, /*cap*/
+- [0x06] = KEY_S, /*stop*/
+- [0x40] = KEY_F, /*full*/
+- [0x1e] = KEY_W, /*tvmode*/
+- [0x1b] = KEY_B, /*recall*/
+-};
+-
+ /* infrared remote control */
+ struct infrared {
+- u16 key_map[128];
+ struct input_dev *input_dev;
++ struct ir_input_state ir;
+ char input_phys[32];
+- struct tasklet_struct ir_tasklet;
++ struct work_struct work;
+ u32 ir_command;
+ };
+
+@@ -220,10 +186,14 @@ struct dm1105dvb {
+ /* i2c */
+ struct i2c_adapter i2c_adap;
+
++ /* irq */
++ struct work_struct work;
++
+ /* dma */
+ dma_addr_t dma_addr;
+ unsigned char *ts_buf;
+ u32 wrp;
++ u32 nextwrp;
+ u32 buffer_size;
+ unsigned int PacketErrorCount;
+ unsigned int dmarst;
+@@ -233,8 +203,6 @@ struct dm1105dvb {
+
+ #define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
+
+-static struct dm1105dvb *dm1105dvb_local;
+-
+ static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+ {
+@@ -407,38 +375,61 @@ static int dm1105dvb_stop_feed(struct dvb_demux_feed *f)
+ return 0;
+ }
+
+-/* ir tasklet */
+-static void dm1105_emit_key(unsigned long parm)
++/* ir work handler */
++static void dm1105_emit_key(struct work_struct *work)
+ {
+- struct infrared *ir = (struct infrared *) parm;
++ struct infrared *ir = container_of(work, struct infrared, work);
+ u32 ircom = ir->ir_command;
+ u8 data;
+- u16 keycode;
++
++ if (ir_debug)
++ printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom);
+
+ data = (ircom >> 8) & 0x7f;
+
+- input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data);
+- input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
+- keycode = ir->key_map[data];
++ ir_input_keydown(ir->input_dev, &ir->ir, data, data);
++ ir_input_nokey(ir->input_dev, &ir->ir);
++}
+
+- if (!keycode)
+- return;
++/* work handler */
++static void dm1105_dmx_buffer(struct work_struct *work)
++{
++ struct dm1105dvb *dm1105dvb =
++ container_of(work, struct dm1105dvb, work);
++ unsigned int nbpackets;
++ u32 oldwrp = dm1105dvb->wrp;
++ u32 nextwrp = dm1105dvb->nextwrp;
++
++ if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
++ (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
++ (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
++ dm1105dvb->PacketErrorCount++;
++ /* bad packet found */
++ if ((dm1105dvb->PacketErrorCount >= 2) &&
++ (dm1105dvb->dmarst == 0)) {
++ outb(1, dm_io_mem(DM1105_RST));
++ dm1105dvb->wrp = 0;
++ dm1105dvb->PacketErrorCount = 0;
++ dm1105dvb->dmarst = 0;
++ return;
++ }
++ }
+
+- input_event(ir->input_dev, EV_KEY, keycode, 1);
+- input_sync(ir->input_dev);
+- input_event(ir->input_dev, EV_KEY, keycode, 0);
+- input_sync(ir->input_dev);
++ if (nextwrp < oldwrp) {
++ memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size,
++ dm1105dvb->ts_buf, nextwrp);
++ nbpackets = ((dm1105dvb->buffer_size - oldwrp) + nextwrp) / 188;
++ } else
++ nbpackets = (nextwrp - oldwrp) / 188;
+
++ dm1105dvb->wrp = nextwrp;
++ dvb_dmx_swfilter_packets(&dm1105dvb->demux,
++ &dm1105dvb->ts_buf[oldwrp], nbpackets);
+ }
+
+ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
+ {
+ struct dm1105dvb *dm1105dvb = dev_id;
+- unsigned int piece;
+- unsigned int nbpackets;
+- u32 command;
+- u32 nextwrp;
+- u32 oldwrp;
+
+ /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
+ unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
+@@ -447,71 +438,25 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
+ switch (intsts) {
+ case INTSTS_TSIRQ:
+ case (INTSTS_TSIRQ | INTSTS_IR):
+- nextwrp = inl(dm_io_mem(DM1105_WRP)) -
+- inl(dm_io_mem(DM1105_STADR)) ;
+- oldwrp = dm1105dvb->wrp;
+- spin_lock(&dm1105dvb->lock);
+- if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
+- (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
+- (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
+- dm1105dvb->PacketErrorCount++;
+- /* bad packet found */
+- if ((dm1105dvb->PacketErrorCount >= 2) &&
+- (dm1105dvb->dmarst == 0)) {
+- outb(1, dm_io_mem(DM1105_RST));
+- dm1105dvb->wrp = 0;
+- dm1105dvb->PacketErrorCount = 0;
+- dm1105dvb->dmarst = 0;
+- spin_unlock(&dm1105dvb->lock);
+- return IRQ_HANDLED;
+- }
+- }
+- if (nextwrp < oldwrp) {
+- piece = dm1105dvb->buffer_size - oldwrp;
+- memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp);
+- nbpackets = (piece + nextwrp)/188;
+- } else {
+- nbpackets = (nextwrp - oldwrp)/188;
+- }
+- dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets);
+- dm1105dvb->wrp = nextwrp;
+- spin_unlock(&dm1105dvb->lock);
++ dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
++ inl(dm_io_mem(DM1105_STADR));
++ schedule_work(&dm1105dvb->work);
+ break;
+ case INTSTS_IR:
+- command = inl(dm_io_mem(DM1105_IRCODE));
+- if (ir_debug)
+- printk("dm1105: received byte 0x%04x\n", command);
+-
+- dm1105dvb->ir.ir_command = command;
+- tasklet_schedule(&dm1105dvb->ir.ir_tasklet);
++ dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
++ schedule_work(&dm1105dvb->ir.work);
+ break;
+ }
+- return IRQ_HANDLED;
+-
+-
+-}
+-
+-/* register with input layer */
+-static void input_register_keys(struct infrared *ir)
+-{
+- int i;
+
+- memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
+-
+- for (i = 0; i < ARRAY_SIZE(ir->key_map); i++)
+- set_bit(ir->key_map[i], ir->input_dev->keybit);
+-
+- ir->input_dev->keycode = ir->key_map;
+- ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
+- ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
++ return IRQ_HANDLED;
+ }
+
+ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
+ {
+ struct input_dev *input_dev;
+- int err;
+-
+- dm1105dvb_local = dm1105;
++ IR_KEYTAB_TYPE *ir_codes = ir_codes_dm1105_nec;
++ int ir_type = IR_TYPE_OTHER;
++ int err = -ENOMEM;
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+@@ -521,12 +466,11 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
+ snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
+ "pci-%s/ir0", pci_name(dm1105->pdev));
+
+- input_dev->evbit[0] = BIT(EV_KEY);
++ ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes);
+ input_dev->name = "DVB on-card IR receiver";
+-
+ input_dev->phys = dm1105->ir.input_phys;
+ input_dev->id.bustype = BUS_PCI;
+- input_dev->id.version = 2;
++ input_dev->id.version = 1;
+ if (dm1105->pdev->subsystem_vendor) {
+ input_dev->id.vendor = dm1105->pdev->subsystem_vendor;
+ input_dev->id.product = dm1105->pdev->subsystem_device;
+@@ -534,25 +478,22 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
+ input_dev->id.vendor = dm1105->pdev->vendor;
+ input_dev->id.product = dm1105->pdev->device;
+ }
++
+ input_dev->dev.parent = &dm1105->pdev->dev;
+- /* initial keymap */
+- memcpy(dm1105->ir.key_map, ir_codes_dm1105_nec, sizeof dm1105->ir.key_map);
+- input_register_keys(&dm1105->ir);
++
++ INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
++
+ err = input_register_device(input_dev);
+ if (err) {
+ input_free_device(input_dev);
+ return err;
+ }
+
+- tasklet_init(&dm1105->ir.ir_tasklet, dm1105_emit_key, (unsigned long) &dm1105->ir);
+-
+ return 0;
+ }
+
+-
+ void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
+ {
+- tasklet_kill(&dm1105->ir.ir_tasklet);
+ input_unregister_device(dm1105->ir.input_dev);
+
+ }
+@@ -710,7 +651,7 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
+
+ dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
+ if (!dm1105dvb)
+- goto out;
++ return -ENOMEM;
+
+ dm1105dvb->pdev = pdev;
+ dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
+@@ -740,13 +681,9 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
+ spin_lock_init(&dm1105dvb->lock);
+ pci_set_drvdata(pdev, dm1105dvb);
+
+- ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb);
+- if (ret < 0)
+- goto err_pci_iounmap;
+-
+ ret = dm1105dvb_hw_init(dm1105dvb);
+ if (ret < 0)
+- goto err_free_irq;
++ goto err_pci_iounmap;
+
+ /* i2c */
+ i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
+@@ -813,8 +750,15 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
+
+ dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
+ dm1105_ir_init(dm1105dvb);
+-out:
+- return ret;
++
++ INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
++
++ ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
++ DRIVER_NAME, dm1105dvb);
++ if (ret < 0)
++ goto err_free_irq;
++
++ return 0;
+
+ err_disconnect_frontend:
+ dmx->disconnect_frontend(dmx);
+@@ -843,7 +787,7 @@ err_pci_disable_device:
+ err_kfree:
+ pci_set_drvdata(pdev, NULL);
+ kfree(dm1105dvb);
+- goto out;
++ return ret;
+ }
+
+ static void __devexit dm1105_remove(struct pci_dev *pdev)
+diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
+index 069d847..c35fbb8 100644
+--- a/drivers/media/dvb/dvb-core/dmxdev.c
++++ b/drivers/media/dvb/dvb-core/dmxdev.c
+@@ -1024,7 +1024,7 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
+ return ret;
+ }
+
+-static struct file_operations dvb_demux_fops = {
++static const struct file_operations dvb_demux_fops = {
+ .owner = THIS_MODULE,
+ .read = dvb_demux_read,
+ .ioctl = dvb_demux_ioctl,
+diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+index 7e3aeaa..cb22da5 100644
+--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
++++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+@@ -1607,7 +1607,7 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait)
+ EXPORT_SYMBOL(dvb_ca_en50221_init);
+
+
+-static struct file_operations dvb_ca_fops = {
++static const struct file_operations dvb_ca_fops = {
+ .owner = THIS_MODULE,
+ .read = dvb_ca_en50221_io_read,
+ .write = dvb_ca_en50221_io_write,
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
+index 8dcb3fb..ebc7815 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
+@@ -1875,7 +1875,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
+ return ret;
+ }
+
+-static struct file_operations dvb_frontend_fops = {
++static const struct file_operations dvb_frontend_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = dvb_generic_ioctl,
+ .poll = dvb_frontend_poll,
+diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
+index f6ba846..8280f8d 100644
+--- a/drivers/media/dvb/dvb-core/dvb_net.c
++++ b/drivers/media/dvb/dvb-core/dvb_net.c
+@@ -1459,7 +1459,7 @@ static int dvb_net_close(struct inode *inode, struct file *file)
+ }
+
+
+-static struct file_operations dvb_net_fops = {
++static const struct file_operations dvb_net_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = dvb_net_ioctl,
+ .open = dvb_generic_open,
+diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
+index 6a32680..a454ee8 100644
+--- a/drivers/media/dvb/dvb-core/dvbdev.c
++++ b/drivers/media/dvb/dvb-core/dvbdev.c
+@@ -228,8 +228,8 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
+ dvbdev->fops = dvbdevfops;
+ init_waitqueue_head (&dvbdev->wait_queue);
+
+- memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
+- dvbdev->fops->owner = adap->module;
++ memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
++ dvbdevfops->owner = adap->module;
+
+ list_add_tail (&dvbdev->list_head, &adap->device_list);
+
+diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
+index dca49cf..7992730 100644
+--- a/drivers/media/dvb/dvb-core/dvbdev.h
++++ b/drivers/media/dvb/dvb-core/dvbdev.h
+@@ -71,7 +71,7 @@ struct dvb_adapter {
+
+ struct dvb_device {
+ struct list_head list_head;
+- struct file_operations *fops;
++ const struct file_operations *fops;
+ struct dvb_adapter *adapter;
+ int type;
+ int minor;
+diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
+index 49f7b20..6103caa 100644
+--- a/drivers/media/dvb/dvb-usb/Kconfig
++++ b/drivers/media/dvb/dvb-usb/Kconfig
+@@ -25,7 +25,7 @@ config DVB_USB_A800
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ select DVB_PLL if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
+
+@@ -34,7 +34,7 @@ config DVB_USB_DIBUSB_MB
+ depends on DVB_USB
+ select DVB_PLL if !DVB_FE_CUSTOMISE
+ select DVB_DIB3000MB
+- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
+ DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
+@@ -55,7 +55,7 @@ config DVB_USB_DIBUSB_MC
+ tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
+ depends on DVB_USB
+ select DVB_DIB3000MC
+- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Support for USB2.0 DVB-T receivers based on reference designs made by
+ DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
+@@ -69,15 +69,17 @@ config DVB_USB_DIBUSB_MC
+ config DVB_USB_DIB0700
+ tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
+ depends on DVB_USB
+- select DVB_DIB7000P
+- select DVB_DIB7000M
+- select DVB_DIB3000MC
++ select DVB_DIB7000P if !DVB_FE_CUSTOMISE
++ select DVB_DIB7000M if !DVB_FE_CUSTOMISE
++ select DVB_DIB3000MC if !DVB_FE_CUSTOMISE
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+- select DVB_TUNER_DIB0070
+- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
++ select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
++ select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
++ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+ help
+ Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
+ USB bridge is also present in devices having the DiB7700 DVB-T-USB
+@@ -95,7 +97,8 @@ config DVB_USB_UMT_010
+ depends on DVB_USB
+ select DVB_PLL if !DVB_FE_CUSTOMISE
+ select DVB_DIB3000MC
+- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
++ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
+
+@@ -108,10 +111,11 @@ config DVB_USB_CXUSB
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_DIB7000P if !DVB_FE_CUSTOMISE
++ select DVB_LGS8GL5 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the Conexant USB2.0 hybrid reference design.
+ Currently, only DVB and ATSC modes are supported, analog mode
+@@ -125,8 +129,8 @@ config DVB_USB_M920X
+ depends on DVB_USB
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
+ Currently, only devices with a product id of
+@@ -137,7 +141,7 @@ config DVB_USB_GL861
+ tristate "Genesys Logic GL861 USB2.0 support"
+ depends on DVB_USB
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
+ receiver with USB ID 0db0:5581.
+@@ -146,7 +150,7 @@ config DVB_USB_AU6610
+ tristate "Alcor Micro AU6610 USB2.0 support"
+ depends on DVB_USB
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
+
+@@ -199,7 +203,7 @@ config DVB_USB_NOVA_T_USB2
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ select DVB_PLL if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
+
+@@ -235,8 +239,8 @@ config DVB_USB_OPERA1
+ config DVB_USB_AF9005
+ tristate "Afatech AF9005 DVB-T USB1.1 support"
+ depends on DVB_USB && EXPERIMENTAL
+- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
+ and the TerraTec Cinergy T USB XE (Rev.1)
+@@ -284,7 +288,7 @@ config DVB_USB_DTV5100
+ tristate "AME DTV-5100 USB2.0 DVB-T support"
+ depends on DVB_USB
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
+
+@@ -293,9 +297,18 @@ config DVB_USB_AF9015
+ depends on DVB_USB && EXPERIMENTAL
+ select DVB_AF9013
+ select DVB_PLL if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
++
++config DVB_USB_CE6230
++ tristate "Intel CE6230 DVB-T USB2.0 support"
++ depends on DVB_USB && EXPERIMENTAL
++ select DVB_ZL10353
++ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
++ help
++ Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
+diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
+index 3122b7c..f92734e 100644
+--- a/drivers/media/dvb/dvb-usb/Makefile
++++ b/drivers/media/dvb/dvb-usb/Makefile
+@@ -76,6 +76,8 @@ obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
+ dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
+ obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
+
++dvb-usb-ce6230-objs = ce6230.o
++obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
+
+ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ # due to tuner-xc3028
+diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
+index 6a97a40..f0ba8b0 100644
+--- a/drivers/media/dvb/dvb-usb/af9015.c
++++ b/drivers/media/dvb/dvb-usb/af9015.c
+@@ -27,9 +27,7 @@
+ #include "qt1010.h"
+ #include "tda18271.h"
+ #include "mxl5005s.h"
+-#if 0
+-#include "mc44s80x.h"
+-#endif
++#include "mc44s803.h"
+
+ static int dvb_usb_af9015_debug;
+ module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
+@@ -37,9 +35,6 @@ MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+ static int dvb_usb_af9015_remote;
+ module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
+ MODULE_PARM_DESC(remote, "select remote");
+-static int dvb_usb_af9015_dual_mode;
+-module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644);
+-MODULE_PARM_DESC(dual_mode, "enable dual mode");
+ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+ static DEFINE_MUTEX(af9015_usb_mutex);
+@@ -283,6 +278,21 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
+ req.data = &msg[i+1].buf[0];
+ ret = af9015_ctrl_msg(d, &req);
+ i += 2;
++ } else if (msg[i].flags & I2C_M_RD) {
++ ret = -EINVAL;
++ if (msg[i].addr ==
++ af9015_af9013_config[0].demod_address)
++ goto error;
++ else
++ req.cmd = READ_I2C;
++ req.i2c_addr = msg[i].addr;
++ req.addr = addr;
++ req.mbox = mbox;
++ req.addr_len = addr_len;
++ req.data_len = msg[i].len;
++ req.data = &msg[i].buf[0];
++ ret = af9015_ctrl_msg(d, &req);
++ i += 1;
+ } else {
+ if (msg[i].addr ==
+ af9015_af9013_config[0].demod_address)
+@@ -748,6 +758,16 @@ static int af9015_read_config(struct usb_device *udev)
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_digittrade);
+ break;
++ case AF9015_REMOTE_AVERMEDIA_KS:
++ af9015_properties[i].rc_key_map =
++ af9015_rc_keys_avermedia;
++ af9015_properties[i].rc_key_map_size =
++ ARRAY_SIZE(af9015_rc_keys_avermedia);
++ af9015_config.ir_table =
++ af9015_ir_table_avermedia_ks;
++ af9015_config.ir_table_size =
++ ARRAY_SIZE(af9015_ir_table_avermedia_ks);
++ break;
+ }
+ } else {
+ switch (le16_to_cpu(udev->descriptor.idVendor)) {
+@@ -836,9 +856,6 @@ static int af9015_read_config(struct usb_device *udev)
+ goto error;
+ af9015_config.dual_mode = val;
+ deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode);
+- /* disable dual mode by default because it is buggy */
+- if (!dvb_usb_af9015_dual_mode)
+- af9015_config.dual_mode = 0;
+
+ /* Set adapter0 buffer size according to USB port speed, adapter1 buffer
+ size can be static because it is enabled only USB2.0 */
+@@ -935,7 +952,6 @@ static int af9015_read_config(struct usb_device *udev)
+ switch (val) {
+ case AF9013_TUNER_ENV77H11D5:
+ case AF9013_TUNER_MT2060:
+- case AF9013_TUNER_MC44S803:
+ case AF9013_TUNER_QT1010:
+ case AF9013_TUNER_UNKNOWN:
+ case AF9013_TUNER_MT2060_2:
+@@ -948,6 +964,10 @@ static int af9015_read_config(struct usb_device *udev)
+ case AF9013_TUNER_MXL5005R:
+ af9015_af9013_config[i].rf_spec_inv = 0;
+ break;
++ case AF9013_TUNER_MC44S803:
++ af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
++ af9015_af9013_config[i].rf_spec_inv = 1;
++ break;
+ default:
+ warn("tuner id:%d not supported, please report!", val);
+ return -ENODEV;
+@@ -1135,6 +1155,11 @@ static struct mxl5005s_config af9015_mxl5005_config = {
+ .AgcMasterByte = 0x00,
+ };
+
++static struct mc44s803_config af9015_mc44s803_config = {
++ .i2c_address = 0xc0,
++ .dig_out = 1,
++};
++
+ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+ struct af9015_state *state = adap->dev->priv;
+@@ -1179,15 +1204,8 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
+ DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_MC44S803:
+-#if 0
+- ret = dvb_attach(mc44s80x_attach, adap->fe, i2c_adap)
+- == NULL ? -ENODEV : 0;
+-#else
+- ret = -ENODEV;
+- info("Freescale MC44S803 tuner found but no driver for that" \
+- "tuner. Look at the Linuxtv.org for tuner driver" \
+- "status.");
+-#endif
++ ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
++ &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
+ break;
+ case AF9013_TUNER_UNKNOWN:
+ default:
+@@ -1218,6 +1236,7 @@ static struct usb_device_id af9015_usb_table[] = {
+ {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
+ /* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
+ {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
++ {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
+ {0},
+ };
+ MODULE_DEVICE_TABLE(usb, af9015_usb_table);
+@@ -1417,7 +1436,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
+ {
+ .name = "KWorld USB DVB-T TV Stick II " \
+ "(VS-DVB-T 395U)",
+- .cold_ids = {&af9015_usb_table[16], NULL},
++ .cold_ids = {&af9015_usb_table[16],
++ &af9015_usb_table[17], NULL},
+ .warm_ids = {NULL},
+ },
+ }
+diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
+index 21c7782..00e2571 100644
+--- a/drivers/media/dvb/dvb-usb/af9015.h
++++ b/drivers/media/dvb/dvb-usb/af9015.h
+@@ -124,6 +124,7 @@ enum af9015_remote {
+ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+ AF9015_REMOTE_MYGICTV_U718,
+ AF9015_REMOTE_DIGITTRADE_DVB_T,
++ AF9015_REMOTE_AVERMEDIA_KS,
+ };
+
+ /* Leadtek WinFast DTV Dongle Gold */
+@@ -597,6 +598,36 @@ static u8 af9015_ir_table_avermedia[] = {
+ 0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
+ };
+
++static u8 af9015_ir_table_avermedia_ks[] = {
++ 0x05, 0xfa, 0x01, 0xfe, 0x12, 0x05, 0x00,
++ 0x05, 0xfa, 0x02, 0xfd, 0x0e, 0x05, 0x00,
++ 0x05, 0xfa, 0x03, 0xfc, 0x0d, 0x05, 0x00,
++ 0x05, 0xfa, 0x04, 0xfb, 0x2e, 0x05, 0x00,
++ 0x05, 0xfa, 0x05, 0xfa, 0x2d, 0x05, 0x00,
++ 0x05, 0xfa, 0x06, 0xf9, 0x10, 0x05, 0x00,
++ 0x05, 0xfa, 0x07, 0xf8, 0x0f, 0x05, 0x00,
++ 0x05, 0xfa, 0x08, 0xf7, 0x3d, 0x05, 0x00,
++ 0x05, 0xfa, 0x09, 0xf6, 0x1e, 0x05, 0x00,
++ 0x05, 0xfa, 0x0a, 0xf5, 0x1f, 0x05, 0x00,
++ 0x05, 0xfa, 0x0b, 0xf4, 0x20, 0x05, 0x00,
++ 0x05, 0xfa, 0x0c, 0xf3, 0x21, 0x05, 0x00,
++ 0x05, 0xfa, 0x0d, 0xf2, 0x22, 0x05, 0x00,
++ 0x05, 0xfa, 0x0e, 0xf1, 0x23, 0x05, 0x00,
++ 0x05, 0xfa, 0x0f, 0xf0, 0x24, 0x05, 0x00,
++ 0x05, 0xfa, 0x10, 0xef, 0x25, 0x05, 0x00,
++ 0x05, 0xfa, 0x11, 0xee, 0x26, 0x05, 0x00,
++ 0x05, 0xfa, 0x12, 0xed, 0x27, 0x05, 0x00,
++ 0x05, 0xfa, 0x13, 0xec, 0x04, 0x05, 0x00,
++ 0x05, 0xfa, 0x15, 0xea, 0x0a, 0x05, 0x00,
++ 0x05, 0xfa, 0x16, 0xe9, 0x11, 0x05, 0x00,
++ 0x05, 0xfa, 0x17, 0xe8, 0x15, 0x05, 0x00,
++ 0x05, 0xfa, 0x18, 0xe7, 0x16, 0x05, 0x00,
++ 0x05, 0xfa, 0x1c, 0xe3, 0x05, 0x05, 0x00,
++ 0x05, 0xfa, 0x1d, 0xe2, 0x09, 0x05, 0x00,
++ 0x05, 0xfa, 0x4d, 0xb2, 0x3f, 0x05, 0x00,
++ 0x05, 0xfa, 0x56, 0xa9, 0x3e, 0x05, 0x00
++};
++
+ /* Digittrade DVB-T USB Stick */
+ static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = {
+ { 0x01, 0x0f, KEY_LAST }, /* RETURN */
+diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c
+new file mode 100644
+index 0000000..5862820
+--- /dev/null
++++ b/drivers/media/dvb/dvb-usb/ce6230.c
+@@ -0,0 +1,328 @@
++/*
++ * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
++ *
++ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
++ *
++ * 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 "ce6230.h"
++#include "zl10353.h"
++#include "mxl5005s.h"
++
++/* debug */
++static int dvb_usb_ce6230_debug;
++module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);
++MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
++DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
++
++static struct zl10353_config ce6230_zl10353_config;
++
++static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
++{
++ int ret;
++ unsigned int pipe;
++ u8 request;
++ u8 requesttype;
++ u16 value;
++ u16 index;
++ u8 buf[req->data_len];
++
++ request = req->cmd;
++ value = req->value;
++ index = req->index;
++
++ switch (req->cmd) {
++ case I2C_READ:
++ case DEMOD_READ:
++ case REG_READ:
++ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
++ break;
++ case I2C_WRITE:
++ case DEMOD_WRITE:
++ case REG_WRITE:
++ requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
++ break;
++ default:
++ err("unknown command:%02x", req->cmd);
++ ret = -EPERM;
++ goto error;
++ }
++
++ if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
++ /* write */
++ memcpy(buf, req->data, req->data_len);
++ pipe = usb_sndctrlpipe(udev, 0);
++ } else {
++ /* read */
++ pipe = usb_rcvctrlpipe(udev, 0);
++ }
++
++ msleep(1); /* avoid I2C errors */
++
++ ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
++ buf, sizeof(buf), CE6230_USB_TIMEOUT);
++
++ ce6230_debug_dump(request, requesttype, value, index, buf,
++ req->data_len, deb_xfer);
++
++ if (ret < 0)
++ deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
++ else
++ ret = 0;
++
++ /* read request, copy returned data to return buf */
++ if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
++ memcpy(req->data, buf, req->data_len);
++
++error:
++ return ret;
++}
++
++static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
++{
++ return ce6230_rw_udev(d->udev, req);
++}
++
++/* I2C */
++static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
++ int num)
++{
++ struct dvb_usb_device *d = i2c_get_adapdata(adap);
++ int i = 0;
++ struct req_t req;
++ int ret = 0;
++ memset(&req, 0, sizeof(&req));
++
++ if (num > 2)
++ return -EINVAL;
++
++ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
++ return -EAGAIN;
++
++ while (i < num) {
++ if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
++ if (msg[i].addr ==
++ ce6230_zl10353_config.demod_address) {
++ req.cmd = DEMOD_READ;
++ req.value = msg[i].addr >> 1;
++ req.index = msg[i].buf[0];
++ req.data_len = msg[i+1].len;
++ req.data = &msg[i+1].buf[0];
++ ret = ce6230_ctrl_msg(d, &req);
++ } else {
++ err("i2c read not implemented");
++ ret = -EPERM;
++ }
++ i += 2;
++ } else {
++ if (msg[i].addr ==
++ ce6230_zl10353_config.demod_address) {
++ req.cmd = DEMOD_WRITE;
++ req.value = msg[i].addr >> 1;
++ req.index = msg[i].buf[0];
++ req.data_len = msg[i].len-1;
++ req.data = &msg[i].buf[1];
++ ret = ce6230_ctrl_msg(d, &req);
++ } else {
++ req.cmd = I2C_WRITE;
++ req.value = 0x2000 + (msg[i].addr >> 1);
++ req.index = 0x0000;
++ req.data_len = msg[i].len;
++ req.data = &msg[i].buf[0];
++ ret = ce6230_ctrl_msg(d, &req);
++ }
++ i += 1;
++ }
++ if (ret)
++ break;
++ }
++
++ mutex_unlock(&d->i2c_mutex);
++ return ret ? ret : i;
++}
++
++static u32 ce6230_i2c_func(struct i2c_adapter *adapter)
++{
++ return I2C_FUNC_I2C;
++}
++
++static struct i2c_algorithm ce6230_i2c_algo = {
++ .master_xfer = ce6230_i2c_xfer,
++ .functionality = ce6230_i2c_func,
++};
++
++/* Callbacks for DVB USB */
++static struct zl10353_config ce6230_zl10353_config = {
++ .demod_address = 0x1e,
++ .adc_clock = 450000,
++ .if2 = 45700,
++ .no_tuner = 1,
++ .parallel_ts = 1,
++ .clock_ctl_1 = 0x34,
++ .pll_0 = 0x0e,
++};
++
++static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
++{
++ deb_info("%s:\n", __func__);
++ adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
++ &adap->dev->i2c_adap);
++ if (adap->fe == NULL)
++ return -ENODEV;
++ return 0;
++}
++
++static struct mxl5005s_config ce6230_mxl5003s_config = {
++ .i2c_address = 0xc6,
++ .if_freq = IF_FREQ_4570000HZ,
++ .xtal_freq = CRYSTAL_FREQ_16000000HZ,
++ .agc_mode = MXL_SINGLE_AGC,
++ .tracking_filter = MXL_TF_DEFAULT,
++ .rssi_enable = MXL_RSSI_ENABLE,
++ .cap_select = MXL_CAP_SEL_ENABLE,
++ .div_out = MXL_DIV_OUT_4,
++ .clock_out = MXL_CLOCK_OUT_DISABLE,
++ .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
++ .top = MXL5005S_TOP_25P2,
++ .mod_mode = MXL_DIGITAL_MODE,
++ .if_mode = MXL_ZERO_IF,
++ .AgcMasterByte = 0x00,
++};
++
++static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
++{
++ int ret;
++ deb_info("%s:\n", __func__);
++ ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
++ &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
++ return ret;
++}
++
++static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
++{
++ int ret;
++ deb_info("%s: onoff:%d\n", __func__, onoff);
++
++ /* InterfaceNumber 1 / AlternateSetting 0 idle
++ InterfaceNumber 1 / AlternateSetting 1 streaming */
++ ret = usb_set_interface(d->udev, 1, onoff);
++ if (ret)
++ err("usb_set_interface failed with error:%d", ret);
++
++ return ret;
++}
++
++/* DVB USB Driver stuff */
++static struct dvb_usb_device_properties ce6230_properties;
++
++static int ce6230_probe(struct usb_interface *intf,
++ const struct usb_device_id *id)
++{
++ int ret = 0;
++ struct dvb_usb_device *d = NULL;
++
++ deb_info("%s: interface:%d\n", __func__,
++ intf->cur_altsetting->desc.bInterfaceNumber);
++
++ if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
++ ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,
++ &d, adapter_nr);
++ if (ret)
++ err("init failed with error:%d\n", ret);
++ }
++
++ return ret;
++}
++
++static struct usb_device_id ce6230_table[] = {
++ { USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
++ { } /* Terminating entry */
++};
++MODULE_DEVICE_TABLE(usb, ce6230_table);
++
++static struct dvb_usb_device_properties ce6230_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
++
++ .usb_ctrl = DEVICE_SPECIFIC,
++ .no_reconnect = 1,
++
++ .size_of_priv = 0,
++
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .frontend_attach = ce6230_zl10353_frontend_attach,
++ .tuner_attach = ce6230_mxl5003s_tuner_attach,
++ .stream = {
++ .type = USB_BULK,
++ .count = 6,
++ .endpoint = 0x82,
++ .u = {
++ .bulk = {
++ .buffersize = 512,
++ }
++ }
++ },
++ }
++ },
++
++ .power_ctrl = ce6230_power_ctrl,
++
++ .i2c_algo = &ce6230_i2c_algo,
++
++ .num_device_descs = 1,
++ .devices = {
++ {
++ .name = "Intel CE9500 reference design",
++ .cold_ids = {NULL},
++ .warm_ids = {&ce6230_table[0], NULL},
++ },
++ }
++};
++
++static struct usb_driver ce6230_driver = {
++ .name = "dvb_usb_ce6230",
++ .probe = ce6230_probe,
++ .disconnect = dvb_usb_device_exit,
++ .id_table = ce6230_table,
++};
++
++/* module stuff */
++static int __init ce6230_module_init(void)
++{
++ int ret;
++ deb_info("%s:\n", __func__);
++ ret = usb_register(&ce6230_driver);
++ if (ret)
++ err("usb_register failed with error:%d", ret);
++
++ return ret;
++}
++
++static void __exit ce6230_module_exit(void)
++{
++ deb_info("%s:\n", __func__);
++ /* deregister this driver from the USB subsystem */
++ usb_deregister(&ce6230_driver);
++}
++
++module_init(ce6230_module_init);
++module_exit(ce6230_module_exit);
++
++MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
++MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/dvb-usb/ce6230.h b/drivers/media/dvb/dvb-usb/ce6230.h
+new file mode 100644
+index 0000000..97c4248
+--- /dev/null
++++ b/drivers/media/dvb/dvb-usb/ce6230.h
+@@ -0,0 +1,69 @@
++/*
++ * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
++ *
++ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
++ *
++ * 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 _DVB_USB_CE6230_H_
++#define _DVB_USB_CE6230_H_
++
++#define DVB_USB_LOG_PREFIX "ce6230"
++#include "dvb-usb.h"
++
++#define deb_info(args...) dprintk(dvb_usb_ce6230_debug, 0x01, args)
++#define deb_rc(args...) dprintk(dvb_usb_ce6230_debug, 0x02, args)
++#define deb_xfer(args...) dprintk(dvb_usb_ce6230_debug, 0x04, args)
++#define deb_reg(args...) dprintk(dvb_usb_ce6230_debug, 0x08, args)
++#define deb_i2c(args...) dprintk(dvb_usb_ce6230_debug, 0x10, args)
++#define deb_fw(args...) dprintk(dvb_usb_ce6230_debug, 0x20, args)
++
++#define ce6230_debug_dump(r, t, v, i, b, l, func) { \
++ int loop_; \
++ func("%02x %02x %02x %02x %02x %02x %02x %02x", \
++ t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
++ if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
++ func(" >>> "); \
++ else \
++ func(" <<< "); \
++ for (loop_ = 0; loop_ < l; loop_++) \
++ func("%02x ", b[loop_]); \
++ func("\n");\
++}
++
++#define CE6230_USB_TIMEOUT 1000
++
++struct req_t {
++ u8 cmd; /* [1] */
++ u16 value; /* [2|3] */
++ u16 index; /* [4|5] */
++ u16 data_len; /* [6|7] */
++ u8 *data;
++};
++
++enum ce6230_cmd {
++ CONFIG_READ = 0xd0, /* rd 0 (unclear) */
++ UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */
++ I2C_READ = 0xd9, /* rd 9 (unclear) */
++ I2C_WRITE = 0xca, /* wr a */
++ DEMOD_READ = 0xdb, /* rd b */
++ DEMOD_WRITE = 0xcc, /* wr c */
++ REG_READ = 0xde, /* rd e */
++ REG_WRITE = 0xcf, /* wr f */
++};
++
++#endif
+diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
+index 200b215..db7f7f7 100644
+--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
+@@ -158,6 +158,10 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+ err("i2c read error (status = %d)\n", result);
+ break;
+ }
++
++ deb_data("<<< ");
++ debug_dump(msg[i].buf, msg[i].len, deb_data);
++
+ } else {
+ /* Write request */
+ buf[0] = REQUEST_NEW_I2C_WRITE;
+@@ -169,6 +173,9 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+ /* The Actual i2c payload */
+ memcpy(&buf[4], msg[i].buf, msg[i].len);
+
++ deb_data(">>> ");
++ debug_dump(buf, msg[i].len + 4, deb_data);
++
+ result = usb_control_msg(d->udev,
+ usb_sndctrlpipe(d->udev, 0),
+ REQUEST_NEW_I2C_WRITE,
+@@ -211,7 +218,8 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
+
+ /* special thing in the current firmware: when length is zero the read-failed */
+ if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) {
+- deb_info("I2C read failed on address %x\n", msg[i].addr);
++ deb_info("I2C read failed on address 0x%02x\n",
++ msg[i].addr);
+ break;
+ }
+
+diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
+index 635d30a..8ddbadf 100644
+--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
++++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
+@@ -17,6 +17,8 @@
+ #include "xc5000.h"
+ #include "s5h1411.h"
+ #include "dib0070.h"
++#include "lgdt3305.h"
++#include "mxl5007t.h"
+
+ static int force_lna_activation;
+ module_param(force_lna_activation, int, 0644);
+@@ -262,7 +264,12 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+- dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config);
++ if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
++ stk7700d_dib7000p_mt2266_config)
++ != 0) {
++ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__);
++ return -ENODEV;
++ }
+ }
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
+@@ -284,7 +291,12 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+- dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,18,stk7700d_dib7000p_mt2266_config);
++ if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
++ stk7700d_dib7000p_mt2266_config)
++ != 0) {
++ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__);
++ return -ENODEV;
++ }
+ }
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
+@@ -421,8 +433,12 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+ msleep(10);
+
+- dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+- &stk7700ph_dib7700_xc3028_config);
++ if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
++ &stk7700ph_dib7700_xc3028_config) != 0) {
++ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
++ __func__);
++ return -ENODEV;
++ }
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ &stk7700ph_dib7700_xc3028_config);
+@@ -1187,8 +1203,12 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+- dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+- &dib7070p_dib7000p_config);
++ if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
++ &dib7070p_dib7000p_config) != 0) {
++ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
++ __func__);
++ return -ENODEV;
++ }
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ &dib7070p_dib7000p_config);
+@@ -1244,7 +1264,12 @@ static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+- dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config);
++ if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
++ stk7070pd_dib7000p_config) != 0) {
++ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
++ __func__);
++ return -ENODEV;
++ }
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
+ return adap->fe == NULL ? -ENODEV : 0;
+@@ -1347,6 +1372,72 @@ static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
+ == NULL ? -ENODEV : 0;
+ }
+
++static struct lgdt3305_config hcw_lgdt3305_config = {
++ .i2c_addr = 0x0e,
++ .mpeg_mode = LGDT3305_MPEG_PARALLEL,
++ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
++ .tpvalid_polarity = LGDT3305_TP_VALID_LOW,
++ .deny_i2c_rptr = 0,
++ .spectral_inversion = 1,
++ .qam_if_khz = 6000,
++ .vsb_if_khz = 6000,
++ .usref_8vsb = 0x0500,
++};
++
++static struct mxl5007t_config hcw_mxl5007t_config = {
++ .xtal_freq_hz = MxL_XTAL_25_MHZ,
++ .if_freq_hz = MxL_IF_6_MHZ,
++ .invert_if = 1,
++};
++
++/* TIGER-ATSC map:
++ GPIO0 - LNA_CTR (H: LNA power enabled, L: LNA power disabled)
++ GPIO1 - ANT_SEL (H: VPA, L: MCX)
++ GPIO4 - SCL2
++ GPIO6 - EN_TUNER
++ GPIO7 - SDA2
++ GPIO10 - DEM_RST
++
++ MXL is behind LG's i2c repeater. LG is on SCL2/SDA2 gpios on the DIB
++ */
++static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
++{
++ struct dib0700_state *st = adap->dev->priv;
++
++ /* Make use of the new i2c functions from FW 1.20 */
++ st->fw_use_new_i2c_api = 1;
++
++ st->disable_streaming_master_mode = 1;
++
++ /* fe power enable */
++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
++ msleep(30);
++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
++ msleep(30);
++
++ /* demod reset */
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
++ msleep(30);
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
++ msleep(30);
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
++ msleep(30);
++
++ adap->fe = dvb_attach(lgdt3305_attach,
++ &hcw_lgdt3305_config,
++ &adap->dev->i2c_adap);
++
++ return adap->fe == NULL ? -ENODEV : 0;
++}
++
++static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap)
++{
++ return dvb_attach(mxl5007t_attach, adap->fe,
++ &adap->dev->i2c_adap, 0x60,
++ &hcw_mxl5007t_config) == NULL ? -ENODEV : 0;
++}
++
++
+ /* DVB-USB and USB stuff follows */
+ struct usb_device_id dib0700_usb_id_table[] = {
+ /* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
+@@ -1396,6 +1487,12 @@ struct usb_device_id dib0700_usb_id_table[] = {
+ { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_EXPRESS) },
+ { USB_DEVICE(USB_VID_TERRATEC,
+ USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) },
++ { USB_DEVICE(USB_VID_SONY, USB_PID_SONY_PLAYTV) },
++/* 45 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_PD378S) },
++ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) },
++ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) },
++ { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) },
++ { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) },
+ { 0 } /* Terminating entry */
+ };
+ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
+@@ -1595,7 +1692,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ },
+ },
+
+- .num_device_descs = 9,
++ .num_device_descs = 11,
+ .devices = {
+ { "DiBcom STK7070P reference design",
+ { &dib0700_usb_id_table[15], NULL },
+@@ -1633,6 +1730,14 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ { &dib0700_usb_id_table[33], NULL },
+ { NULL },
+ },
++ { "Elgato EyeTV DTT",
++ { &dib0700_usb_id_table[49], NULL },
++ { NULL },
++ },
++ { "Yuan PD378S",
++ { &dib0700_usb_id_table[45], NULL },
++ { NULL },
++ },
+ },
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+@@ -1661,7 +1766,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ }
+ },
+
+- .num_device_descs = 5,
++ .num_device_descs = 6,
+ .devices = {
+ { "DiBcom STK7070PD reference design",
+ { &dib0700_usb_id_table[17], NULL },
+@@ -1682,8 +1787,16 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ { "Terratec Cinergy DT USB XS Diversity",
+ { &dib0700_usb_id_table[43], NULL },
+ { NULL },
++ },
++ { "Sony PlayTV",
++ { &dib0700_usb_id_table[44], NULL },
++ { NULL },
+ }
+- }
++ },
++ .rc_interval = DEFAULT_RC_INTERVAL,
++ .rc_key_map = dib0700_rc_keys,
++ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
++ .rc_query = dib0700_rc_query
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+@@ -1699,7 +1812,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ },
+ },
+
+- .num_device_descs = 5,
++ .num_device_descs = 7,
+ .devices = {
+ { "Terratec Cinergy HT USB XE",
+ { &dib0700_usb_id_table[27], NULL },
+@@ -1725,6 +1838,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ { &dib0700_usb_id_table[39], NULL },
+ { NULL },
+ },
++ { "YUAN High-Tech MC770",
++ { &dib0700_usb_id_table[48], NULL },
++ { NULL },
++ },
+ },
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dib0700_rc_keys,
+@@ -1759,6 +1876,31 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
++ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
++ .num_adapters = 1,
++ .adapter = {
++ {
++ .frontend_attach = lgdt3305_frontend_attach,
++ .tuner_attach = mxl5007t_tuner_attach,
++
++ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
++
++ .size_of_priv = sizeof(struct
++ dib0700_adapter_state),
++ },
++ },
++
++ .num_device_descs = 2,
++ .devices = {
++ { "Hauppauge ATSC MiniCard (B200)",
++ { &dib0700_usb_id_table[46], NULL },
++ { NULL },
++ },
++ { "Hauppauge ATSC MiniCard (B210)",
++ { &dib0700_usb_id_table[47], NULL },
++ { NULL },
++ },
++ },
+ },
+ };
+
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+index 0db0c06..dc7ea21 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+@@ -27,12 +27,14 @@
+ #define USB_VID_DIBCOM 0x10b8
+ #define USB_VID_DPOSH 0x1498
+ #define USB_VID_DVICO 0x0fe9
++#define USB_VID_ELGATO 0x0fd9
+ #define USB_VID_EMPIA 0xeb1a
+ #define USB_VID_GENPIX 0x09c0
+ #define USB_VID_GRANDTEC 0x5032
+ #define USB_VID_HANFTEK 0x15f4
+ #define USB_VID_HAUPPAUGE 0x2040
+ #define USB_VID_HYPER_PALTEK 0x1025
++#define USB_VID_INTEL 0x8086
+ #define USB_VID_KWORLD 0xeb2a
+ #define USB_VID_KWORLD_2 0x1b80
+ #define USB_VID_KYE 0x0458
+@@ -48,6 +50,7 @@
+ #define USB_VID_TERRATEC 0x0ccd
+ #define USB_VID_TELESTAR 0x10b9
+ #define USB_VID_VISIONPLUS 0x13d3
++#define USB_VID_SONY 0x1415
+ #define USB_VID_TWINHAN 0x1822
+ #define USB_VID_ULTIMA_ELECTRONIC 0x05d8
+ #define USB_VID_UNIWILL 0x1584
+@@ -95,8 +98,10 @@
+ #define USB_PID_UNIWILL_STK7700P 0x6003
+ #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
+ #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
++#define USB_PID_INTEL_CE9500 0x9500
+ #define USB_PID_KWORLD_399U 0xe399
+ #define USB_PID_KWORLD_395U 0xe396
++#define USB_PID_KWORLD_395U_2 0xe39b
+ #define USB_PID_KWORLD_PC160_2T 0xc160
+ #define USB_PID_KWORLD_VSTREAM_COLD 0x17de
+ #define USB_PID_KWORLD_VSTREAM_WARM 0x17df
+@@ -149,6 +154,8 @@
+ #define USB_PID_HAUPPAUGE_MYTV_T 0x7080
+ #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580
+ #define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200
++#define USB_PID_HAUPPAUGE_TIGER_ATSC 0xb200
++#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210 0xb210
+ #define USB_PID_AVERMEDIA_EXPRESS 0xb568
+ #define USB_PID_AVERMEDIA_VOLAR 0xa807
+ #define USB_PID_AVERMEDIA_VOLAR_2 0xb808
+@@ -232,9 +239,13 @@
+ #define USB_PID_ASUS_U3100 0x173f
+ #define USB_PID_YUAN_EC372S 0x1edc
+ #define USB_PID_YUAN_STK7700PH 0x1f08
++#define USB_PID_YUAN_PD378S 0x2edc
++#define USB_PID_YUAN_MC770 0x0871
+ #define USB_PID_DW2102 0x2102
+ #define USB_PID_XTENSIONS_XD_380 0x0381
+ #define USB_PID_TELESTAR_STARSTICK_2 0x8000
+ #define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807
++#define USB_PID_SONY_PLAYTV 0x0003
++#define USB_PID_ELGATO_EYETV_DTT 0x0021
+
+ #endif
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
+index b1de0f7..2d5352e 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
++++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
+@@ -223,7 +223,7 @@ struct dvb_usb_device_properties {
+ int generic_bulk_ctrl_endpoint;
+
+ int num_device_descs;
+- struct dvb_usb_device_description devices[9];
++ struct dvb_usb_device_description devices[11];
+ };
+
+ /**
+diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
+index b55d9cc..af8fdf7 100644
+--- a/drivers/media/dvb/firewire/firedtv-avc.c
++++ b/drivers/media/dvb/firewire/firedtv-avc.c
+@@ -150,7 +150,7 @@ static void debug_fcp(const u8 *data, size_t length)
+ subunit_type = data[1] >> 3;
+ subunit_id = data[1] & 7;
+ op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
+- printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
++ printk(KERN_INFO "%ssu=%x.%x l=%zu: %-8s - %s\n",
+ prefix, subunit_type, subunit_id, length,
+ debug_fcp_ctype(data[0]),
+ debug_fcp_opcode(op, data, length));
+diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
+index 0026956..a206cee 100644
+--- a/drivers/media/dvb/frontends/Kconfig
++++ b/drivers/media/dvb/frontends/Kconfig
+@@ -1,17 +1,21 @@
+-menu "Customise DVB Frontends"
+- depends on DVB_CORE
+-
+ config DVB_FE_CUSTOMISE
+ bool "Customise the frontend modules to build"
++ depends on DVB_CORE
+ default N
+ help
+- This allows the user to deselect frontend drivers unnecessary
+- for their hardware from the build. Use this option with care
+- as deselecting frontends which are in fact necessary will result
+- in DVB devices which cannot be tuned due to lack of driver support.
++ This allows the user to select/deselect frontend drivers for their
++ hardware from the build.
++
++ Use this option with care as deselecting frontends which are in fact
++ necessary will result in DVB devices which cannot be tuned due to lack
++ of driver support.
+
+ If unsure say N.
+
++if DVB_FE_CUSTOMISE
++
++menu "Customise DVB Frontends"
++
+ comment "Multistandard (satellite) frontends"
+ depends on DVB_CORE
+
+@@ -55,6 +59,13 @@ config DVB_MT312
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
++config DVB_ZL10036
++ tristate "Zarlink ZL10036 silicon tuner"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ A DVB-S tuner module. Say Y when you want to support this frontend.
++
+ config DVB_S5H1420
+ tristate "Samsung S5H1420 based"
+ depends on DVB_CORE && I2C
+@@ -83,6 +94,20 @@ config DVB_STV0299
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
++config DVB_STV6110
++ tristate "ST STV6110 silicon tuner"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ A DVB-S silicon tuner module. Say Y when you want to support this tuner.
++
++config DVB_STV0900
++ tristate "ST STV0900 based"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ A DVB-S/S2 demodulator. Say Y when you want to support this frontend.
++
+ config DVB_TDA8083
+ tristate "Philips TDA8083 based"
+ depends on DVB_CORE && I2C
+@@ -288,6 +313,13 @@ config DVB_TDA10048
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
++config DVB_AF9013
++ tristate "Afatech AF9013 demodulator"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ Say Y when you want to support this frontend.
++
+ comment "DVB-C (cable) frontends"
+ depends on DVB_CORE
+
+@@ -387,6 +419,14 @@ config DVB_LGDT3304
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
++config DVB_LGDT3305
++ tristate "LG Electronics LGDT3305 based"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
++ to support this frontend.
++
+ config DVB_S5H1409
+ tristate "Samsung S5H1409 based"
+ depends on DVB_CORE && I2C
+@@ -397,7 +437,7 @@ config DVB_S5H1409
+
+ config DVB_AU8522
+ tristate "Auvitek AU8522 based"
+- depends on DVB_CORE && I2C
++ depends on DVB_CORE && I2C && VIDEO_V4L2
+ default m if DVB_FE_CUSTOMISE
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+@@ -446,11 +486,11 @@ comment "SEC control devices for DVB-S"
+ depends on DVB_CORE
+
+ config DVB_LNBP21
+- tristate "LNBP21 SEC controller"
++ tristate "LNBP21/LNBH24 SEC controllers"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+- An SEC control chip.
++ An SEC control chips.
+
+ config DVB_ISL6405
+ tristate "ISL6405 SEC controller"
+@@ -478,11 +518,6 @@ comment "Tools to develop new frontends"
+ config DVB_DUMMY_FE
+ tristate "Dummy frontend driver"
+ default n
+-
+-config DVB_AF9013
+- tristate "Afatech AF9013 demodulator"
+- depends on DVB_CORE && I2C
+- default m if DVB_FE_CUSTOMISE
+- help
+- Say Y when you want to support this frontend.
+ endmenu
++
++endif
+diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
+index af7bdf0..65a336a 100644
+--- a/drivers/media/dvb/frontends/Makefile
++++ b/drivers/media/dvb/frontends/Makefile
+@@ -7,6 +7,8 @@ EXTRA_CFLAGS += -Idrivers/media/common/tuners/
+
+ s921-objs := s921_module.o s921_core.o
+ stb0899-objs = stb0899_drv.o stb0899_algo.o
++stv0900-objs = stv0900_core.o stv0900_sw.o
++au8522-objs = au8522_dig.o au8522_decoder.o
+
+ obj-$(CONFIG_DVB_PLL) += dvb-pll.o
+ obj-$(CONFIG_DVB_STV0299) += stv0299.o
+@@ -28,6 +30,7 @@ obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
+ obj-$(CONFIG_DVB_SP887X) += sp887x.o
+ obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
+ obj-$(CONFIG_DVB_MT352) += mt352.o
++obj-$(CONFIG_DVB_ZL10036) += zl10036.o
+ obj-$(CONFIG_DVB_ZL10353) += zl10353.o
+ obj-$(CONFIG_DVB_CX22702) += cx22702.o
+ obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o
+@@ -41,6 +44,7 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
+ obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
+ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+ obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
++obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
+ obj-$(CONFIG_DVB_CX24123) += cx24123.o
+ obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+ obj-$(CONFIG_DVB_ISL6405) += isl6405.o
+@@ -64,4 +68,6 @@ obj-$(CONFIG_DVB_SI21XX) += si21xx.o
+ obj-$(CONFIG_DVB_STV0288) += stv0288.o
+ obj-$(CONFIG_DVB_STB6000) += stb6000.o
+ obj-$(CONFIG_DVB_S921) += s921.o
++obj-$(CONFIG_DVB_STV6110) += stv6110.o
++obj-$(CONFIG_DVB_STV0900) += stv0900.o
+
+diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
+deleted file mode 100644
+index eabf9a6..0000000
+--- a/drivers/media/dvb/frontends/au8522.c
++++ /dev/null
+@@ -1,874 +0,0 @@
+-/*
+- Auvitek AU8522 QAM/8VSB demodulator driver
+-
+- Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+-
+- This program is free software; you can redistribute it and/or modify
+- it under the terms of the GNU General Public License as published by
+- the Free Software Foundation; either version 2 of the License, or
+- (at your option) any later version.
+-
+- This program is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- GNU General Public License for more details.
+-
+- You should have received a copy of the GNU General Public License
+- along with this program; if not, write to the Free Software
+- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-*/
+-
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/string.h>
+-#include <linux/slab.h>
+-#include <linux/delay.h>
+-#include "dvb_frontend.h"
+-#include "au8522.h"
+-
+-struct au8522_state {
+-
+- struct i2c_adapter *i2c;
+-
+- /* configuration settings */
+- const struct au8522_config *config;
+-
+- struct dvb_frontend frontend;
+-
+- u32 current_frequency;
+- fe_modulation_t current_modulation;
+-
+- u32 fe_status;
+- unsigned int led_state;
+-};
+-
+-static int debug;
+-
+-#define dprintk(arg...) do { \
+- if (debug) \
+- printk(arg); \
+- } while (0)
+-
+-/* 16 bit registers, 8 bit values */
+-static int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
+-{
+- int ret;
+- u8 buf [] = { reg >> 8, reg & 0xff, data };
+-
+- struct i2c_msg msg = { .addr = state->config->demod_address,
+- .flags = 0, .buf = buf, .len = 3 };
+-
+- ret = i2c_transfer(state->i2c, &msg, 1);
+-
+- if (ret != 1)
+- printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+- "ret == %i)\n", __func__, reg, data, ret);
+-
+- return (ret != 1) ? -1 : 0;
+-}
+-
+-static u8 au8522_readreg(struct au8522_state *state, u16 reg)
+-{
+- int ret;
+- u8 b0 [] = { reg >> 8, reg & 0xff };
+- u8 b1 [] = { 0 };
+-
+- struct i2c_msg msg [] = {
+- { .addr = state->config->demod_address, .flags = 0,
+- .buf = b0, .len = 2 },
+- { .addr = state->config->demod_address, .flags = I2C_M_RD,
+- .buf = b1, .len = 1 } };
+-
+- ret = i2c_transfer(state->i2c, msg, 2);
+-
+- if (ret != 2)
+- printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+- __func__, ret);
+- return b1[0];
+-}
+-
+-static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+-
+- dprintk("%s(%d)\n", __func__, enable);
+-
+- if (enable)
+- return au8522_writereg(state, 0x106, 1);
+- else
+- return au8522_writereg(state, 0x106, 0);
+-}
+-
+-struct mse2snr_tab {
+- u16 val;
+- u16 data;
+-};
+-
+-/* VSB SNR lookup table */
+-static struct mse2snr_tab vsb_mse2snr_tab[] = {
+- { 0, 270 },
+- { 2, 250 },
+- { 3, 240 },
+- { 5, 230 },
+- { 7, 220 },
+- { 9, 210 },
+- { 12, 200 },
+- { 13, 195 },
+- { 15, 190 },
+- { 17, 185 },
+- { 19, 180 },
+- { 21, 175 },
+- { 24, 170 },
+- { 27, 165 },
+- { 31, 160 },
+- { 32, 158 },
+- { 33, 156 },
+- { 36, 152 },
+- { 37, 150 },
+- { 39, 148 },
+- { 40, 146 },
+- { 41, 144 },
+- { 43, 142 },
+- { 44, 140 },
+- { 48, 135 },
+- { 50, 130 },
+- { 43, 142 },
+- { 53, 125 },
+- { 56, 120 },
+- { 256, 115 },
+-};
+-
+-/* QAM64 SNR lookup table */
+-static struct mse2snr_tab qam64_mse2snr_tab[] = {
+- { 15, 0 },
+- { 16, 290 },
+- { 17, 288 },
+- { 18, 286 },
+- { 19, 284 },
+- { 20, 282 },
+- { 21, 281 },
+- { 22, 279 },
+- { 23, 277 },
+- { 24, 275 },
+- { 25, 273 },
+- { 26, 271 },
+- { 27, 269 },
+- { 28, 268 },
+- { 29, 266 },
+- { 30, 264 },
+- { 31, 262 },
+- { 32, 260 },
+- { 33, 259 },
+- { 34, 258 },
+- { 35, 256 },
+- { 36, 255 },
+- { 37, 254 },
+- { 38, 252 },
+- { 39, 251 },
+- { 40, 250 },
+- { 41, 249 },
+- { 42, 248 },
+- { 43, 246 },
+- { 44, 245 },
+- { 45, 244 },
+- { 46, 242 },
+- { 47, 241 },
+- { 48, 240 },
+- { 50, 239 },
+- { 51, 238 },
+- { 53, 237 },
+- { 54, 236 },
+- { 56, 235 },
+- { 57, 234 },
+- { 59, 233 },
+- { 60, 232 },
+- { 62, 231 },
+- { 63, 230 },
+- { 65, 229 },
+- { 67, 228 },
+- { 68, 227 },
+- { 70, 226 },
+- { 71, 225 },
+- { 73, 224 },
+- { 74, 223 },
+- { 76, 222 },
+- { 78, 221 },
+- { 80, 220 },
+- { 82, 219 },
+- { 85, 218 },
+- { 88, 217 },
+- { 90, 216 },
+- { 92, 215 },
+- { 93, 214 },
+- { 94, 212 },
+- { 95, 211 },
+- { 97, 210 },
+- { 99, 209 },
+- { 101, 208 },
+- { 102, 207 },
+- { 104, 206 },
+- { 107, 205 },
+- { 111, 204 },
+- { 114, 203 },
+- { 118, 202 },
+- { 122, 201 },
+- { 125, 200 },
+- { 128, 199 },
+- { 130, 198 },
+- { 132, 197 },
+- { 256, 190 },
+-};
+-
+-/* QAM256 SNR lookup table */
+-static struct mse2snr_tab qam256_mse2snr_tab[] = {
+- { 16, 0 },
+- { 17, 400 },
+- { 18, 398 },
+- { 19, 396 },
+- { 20, 394 },
+- { 21, 392 },
+- { 22, 390 },
+- { 23, 388 },
+- { 24, 386 },
+- { 25, 384 },
+- { 26, 382 },
+- { 27, 380 },
+- { 28, 379 },
+- { 29, 378 },
+- { 30, 377 },
+- { 31, 376 },
+- { 32, 375 },
+- { 33, 374 },
+- { 34, 373 },
+- { 35, 372 },
+- { 36, 371 },
+- { 37, 370 },
+- { 38, 362 },
+- { 39, 354 },
+- { 40, 346 },
+- { 41, 338 },
+- { 42, 330 },
+- { 43, 328 },
+- { 44, 326 },
+- { 45, 324 },
+- { 46, 322 },
+- { 47, 320 },
+- { 48, 319 },
+- { 49, 318 },
+- { 50, 317 },
+- { 51, 316 },
+- { 52, 315 },
+- { 53, 314 },
+- { 54, 313 },
+- { 55, 312 },
+- { 56, 311 },
+- { 57, 310 },
+- { 58, 308 },
+- { 59, 306 },
+- { 60, 304 },
+- { 61, 302 },
+- { 62, 300 },
+- { 63, 298 },
+- { 65, 295 },
+- { 68, 294 },
+- { 70, 293 },
+- { 73, 292 },
+- { 76, 291 },
+- { 78, 290 },
+- { 79, 289 },
+- { 81, 288 },
+- { 82, 287 },
+- { 83, 286 },
+- { 84, 285 },
+- { 85, 284 },
+- { 86, 283 },
+- { 88, 282 },
+- { 89, 281 },
+- { 256, 280 },
+-};
+-
+-static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
+- u16 *snr)
+-{
+- int i, ret = -EINVAL;
+- dprintk("%s()\n", __func__);
+-
+- for (i = 0; i < sz; i++) {
+- if (mse < tab[i].val) {
+- *snr = tab[i].data;
+- ret = 0;
+- break;
+- }
+- }
+- dprintk("%s() snr=%d\n", __func__, *snr);
+- return ret;
+-}
+-
+-static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+- u8 r0b5, r0b6, r0b7;
+- char *ifmhz;
+-
+- switch (if_freq) {
+- case AU8522_IF_3_25MHZ:
+- ifmhz = "3.25";
+- r0b5 = 0x00;
+- r0b6 = 0x3d;
+- r0b7 = 0xa0;
+- break;
+- case AU8522_IF_4MHZ:
+- ifmhz = "4.00";
+- r0b5 = 0x00;
+- r0b6 = 0x4b;
+- r0b7 = 0xd9;
+- break;
+- case AU8522_IF_6MHZ:
+- ifmhz = "6.00";
+- r0b5 = 0xfb;
+- r0b6 = 0x8e;
+- r0b7 = 0x39;
+- break;
+- default:
+- dprintk("%s() IF Frequency not supported\n", __func__);
+- return -EINVAL;
+- }
+- dprintk("%s() %s MHz\n", __func__, ifmhz);
+- au8522_writereg(state, 0x80b5, r0b5);
+- au8522_writereg(state, 0x80b6, r0b6);
+- au8522_writereg(state, 0x80b7, r0b7);
+-
+- return 0;
+-}
+-
+-/* VSB Modulation table */
+-static struct {
+- u16 reg;
+- u16 data;
+-} VSB_mod_tab[] = {
+- { 0x8090, 0x84 },
+- { 0x4092, 0x11 },
+- { 0x2005, 0x00 },
+- { 0x8091, 0x80 },
+- { 0x80a3, 0x0c },
+- { 0x80a4, 0xe8 },
+- { 0x8081, 0xc4 },
+- { 0x80a5, 0x40 },
+- { 0x80a7, 0x40 },
+- { 0x80a6, 0x67 },
+- { 0x8262, 0x20 },
+- { 0x821c, 0x30 },
+- { 0x80d8, 0x1a },
+- { 0x8227, 0xa0 },
+- { 0x8121, 0xff },
+- { 0x80a8, 0xf0 },
+- { 0x80a9, 0x05 },
+- { 0x80aa, 0x77 },
+- { 0x80ab, 0xf0 },
+- { 0x80ac, 0x05 },
+- { 0x80ad, 0x77 },
+- { 0x80ae, 0x41 },
+- { 0x80af, 0x66 },
+- { 0x821b, 0xcc },
+- { 0x821d, 0x80 },
+- { 0x80a4, 0xe8 },
+- { 0x8231, 0x13 },
+-};
+-
+-/* QAM Modulation table */
+-static struct {
+- u16 reg;
+- u16 data;
+-} QAM_mod_tab[] = {
+- { 0x80a3, 0x09 },
+- { 0x80a4, 0x00 },
+- { 0x8081, 0xc4 },
+- { 0x80a5, 0x40 },
+- { 0x80aa, 0x77 },
+- { 0x80ad, 0x77 },
+- { 0x80a6, 0x67 },
+- { 0x8262, 0x20 },
+- { 0x821c, 0x30 },
+- { 0x80b8, 0x3e },
+- { 0x80b9, 0xf0 },
+- { 0x80ba, 0x01 },
+- { 0x80bb, 0x18 },
+- { 0x80bc, 0x50 },
+- { 0x80bd, 0x00 },
+- { 0x80be, 0xea },
+- { 0x80bf, 0xef },
+- { 0x80c0, 0xfc },
+- { 0x80c1, 0xbd },
+- { 0x80c2, 0x1f },
+- { 0x80c3, 0xfc },
+- { 0x80c4, 0xdd },
+- { 0x80c5, 0xaf },
+- { 0x80c6, 0x00 },
+- { 0x80c7, 0x38 },
+- { 0x80c8, 0x30 },
+- { 0x80c9, 0x05 },
+- { 0x80ca, 0x4a },
+- { 0x80cb, 0xd0 },
+- { 0x80cc, 0x01 },
+- { 0x80cd, 0xd9 },
+- { 0x80ce, 0x6f },
+- { 0x80cf, 0xf9 },
+- { 0x80d0, 0x70 },
+- { 0x80d1, 0xdf },
+- { 0x80d2, 0xf7 },
+- { 0x80d3, 0xc2 },
+- { 0x80d4, 0xdf },
+- { 0x80d5, 0x02 },
+- { 0x80d6, 0x9a },
+- { 0x80d7, 0xd0 },
+- { 0x8250, 0x0d },
+- { 0x8251, 0xcd },
+- { 0x8252, 0xe0 },
+- { 0x8253, 0x05 },
+- { 0x8254, 0xa7 },
+- { 0x8255, 0xff },
+- { 0x8256, 0xed },
+- { 0x8257, 0x5b },
+- { 0x8258, 0xae },
+- { 0x8259, 0xe6 },
+- { 0x825a, 0x3d },
+- { 0x825b, 0x0f },
+- { 0x825c, 0x0d },
+- { 0x825d, 0xea },
+- { 0x825e, 0xf2 },
+- { 0x825f, 0x51 },
+- { 0x8260, 0xf5 },
+- { 0x8261, 0x06 },
+- { 0x821a, 0x00 },
+- { 0x8546, 0x40 },
+- { 0x8210, 0x26 },
+- { 0x8211, 0xf6 },
+- { 0x8212, 0x84 },
+- { 0x8213, 0x02 },
+- { 0x8502, 0x01 },
+- { 0x8121, 0x04 },
+- { 0x8122, 0x04 },
+- { 0x852e, 0x10 },
+- { 0x80a4, 0xca },
+- { 0x80a7, 0x40 },
+- { 0x8526, 0x01 },
+-};
+-
+-static int au8522_enable_modulation(struct dvb_frontend *fe,
+- fe_modulation_t m)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+- int i;
+-
+- dprintk("%s(0x%08x)\n", __func__, m);
+-
+- switch (m) {
+- case VSB_8:
+- dprintk("%s() VSB_8\n", __func__);
+- for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
+- au8522_writereg(state,
+- VSB_mod_tab[i].reg,
+- VSB_mod_tab[i].data);
+- au8522_set_if(fe, state->config->vsb_if);
+- break;
+- case QAM_64:
+- case QAM_256:
+- dprintk("%s() QAM 64/256\n", __func__);
+- for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
+- au8522_writereg(state,
+- QAM_mod_tab[i].reg,
+- QAM_mod_tab[i].data);
+- au8522_set_if(fe, state->config->qam_if);
+- break;
+- default:
+- dprintk("%s() Invalid modulation\n", __func__);
+- return -EINVAL;
+- }
+-
+- state->current_modulation = m;
+-
+- return 0;
+-}
+-
+-/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+-static int au8522_set_frontend(struct dvb_frontend *fe,
+- struct dvb_frontend_parameters *p)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+- int ret = -EINVAL;
+-
+- dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+-
+- if ((state->current_frequency == p->frequency) &&
+- (state->current_modulation == p->u.vsb.modulation))
+- return 0;
+-
+- au8522_enable_modulation(fe, p->u.vsb.modulation);
+-
+- /* Allow the demod to settle */
+- msleep(100);
+-
+- if (fe->ops.tuner_ops.set_params) {
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+- ret = fe->ops.tuner_ops.set_params(fe, p);
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 0);
+- }
+-
+- if (ret < 0)
+- return ret;
+-
+- state->current_frequency = p->frequency;
+-
+- return 0;
+-}
+-
+-/* Reset the demod hardware and reset all of the configuration registers
+- to a default state. */
+-static int au8522_init(struct dvb_frontend *fe)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+- dprintk("%s()\n", __func__);
+-
+- au8522_writereg(state, 0xa4, 1 << 5);
+-
+- au8522_i2c_gate_ctrl(fe, 1);
+-
+- return 0;
+-}
+-
+-static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
+-{
+- struct au8522_led_config *led_config = state->config->led_cfg;
+- u8 val;
+-
+- /* bail out if we cant control an LED */
+- if (!led_config || !led_config->gpio_output ||
+- !led_config->gpio_output_enable || !led_config->gpio_output_disable)
+- return 0;
+-
+- val = au8522_readreg(state, 0x4000 |
+- (led_config->gpio_output & ~0xc000));
+- if (onoff) {
+- /* enable GPIO output */
+- val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
+- val |= (led_config->gpio_output_enable & 0xff);
+- } else {
+- /* disable GPIO output */
+- val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
+- val |= (led_config->gpio_output_disable & 0xff);
+- }
+- return au8522_writereg(state, 0x8000 |
+- (led_config->gpio_output & ~0xc000), val);
+-}
+-
+-/* led = 0 | off
+- * led = 1 | signal ok
+- * led = 2 | signal strong
+- * led < 0 | only light led if leds are currently off
+- */
+-static int au8522_led_ctrl(struct au8522_state *state, int led)
+-{
+- struct au8522_led_config *led_config = state->config->led_cfg;
+- int i, ret = 0;
+-
+- /* bail out if we cant control an LED */
+- if (!led_config || !led_config->gpio_leds ||
+- !led_config->num_led_states || !led_config->led_states)
+- return 0;
+-
+- if (led < 0) {
+- /* if LED is already lit, then leave it as-is */
+- if (state->led_state)
+- return 0;
+- else
+- led *= -1;
+- }
+-
+- /* toggle LED if changing state */
+- if (state->led_state != led) {
+- u8 val;
+-
+- dprintk("%s: %d\n", __func__, led);
+-
+- au8522_led_gpio_enable(state, 1);
+-
+- val = au8522_readreg(state, 0x4000 |
+- (led_config->gpio_leds & ~0xc000));
+-
+- /* start with all leds off */
+- for (i = 0; i < led_config->num_led_states; i++)
+- val &= ~led_config->led_states[i];
+-
+- /* set selected LED state */
+- if (led < led_config->num_led_states)
+- val |= led_config->led_states[led];
+- else if (led_config->num_led_states)
+- val |=
+- led_config->led_states[led_config->num_led_states - 1];
+-
+- ret = au8522_writereg(state, 0x8000 |
+- (led_config->gpio_leds & ~0xc000), val);
+- if (ret < 0)
+- return ret;
+-
+- state->led_state = led;
+-
+- if (led == 0)
+- au8522_led_gpio_enable(state, 0);
+- }
+-
+- return 0;
+-}
+-
+-static int au8522_sleep(struct dvb_frontend *fe)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+- dprintk("%s()\n", __func__);
+-
+- /* turn off led */
+- au8522_led_ctrl(state, 0);
+-
+- state->current_frequency = 0;
+-
+- return 0;
+-}
+-
+-static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+- u8 reg;
+- u32 tuner_status = 0;
+-
+- *status = 0;
+-
+- if (state->current_modulation == VSB_8) {
+- dprintk("%s() Checking VSB_8\n", __func__);
+- reg = au8522_readreg(state, 0x4088);
+- if ((reg & 0x03) == 0x03)
+- *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
+- } else {
+- dprintk("%s() Checking QAM\n", __func__);
+- reg = au8522_readreg(state, 0x4541);
+- if (reg & 0x80)
+- *status |= FE_HAS_VITERBI;
+- if (reg & 0x20)
+- *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+- }
+-
+- switch (state->config->status_mode) {
+- case AU8522_DEMODLOCKING:
+- dprintk("%s() DEMODLOCKING\n", __func__);
+- if (*status & FE_HAS_VITERBI)
+- *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+- break;
+- case AU8522_TUNERLOCKING:
+- /* Get the tuner status */
+- dprintk("%s() TUNERLOCKING\n", __func__);
+- if (fe->ops.tuner_ops.get_status) {
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 1);
+-
+- fe->ops.tuner_ops.get_status(fe, &tuner_status);
+-
+- if (fe->ops.i2c_gate_ctrl)
+- fe->ops.i2c_gate_ctrl(fe, 0);
+- }
+- if (tuner_status)
+- *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+- break;
+- }
+- state->fe_status = *status;
+-
+- if (*status & FE_HAS_LOCK)
+- /* turn on LED, if it isn't on already */
+- au8522_led_ctrl(state, -1);
+- else
+- /* turn off LED */
+- au8522_led_ctrl(state, 0);
+-
+- dprintk("%s() status 0x%08x\n", __func__, *status);
+-
+- return 0;
+-}
+-
+-static int au8522_led_status(struct au8522_state *state, const u16 *snr)
+-{
+- struct au8522_led_config *led_config = state->config->led_cfg;
+- int led;
+- u16 strong;
+-
+- /* bail out if we cant control an LED */
+- if (!led_config)
+- return 0;
+-
+- if (0 == (state->fe_status & FE_HAS_LOCK))
+- return au8522_led_ctrl(state, 0);
+- else if (state->current_modulation == QAM_256)
+- strong = led_config->qam256_strong;
+- else if (state->current_modulation == QAM_64)
+- strong = led_config->qam64_strong;
+- else /* (state->current_modulation == VSB_8) */
+- strong = led_config->vsb8_strong;
+-
+- if (*snr >= strong)
+- led = 2;
+- else
+- led = 1;
+-
+- if ((state->led_state) &&
+- (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
+- /* snr didn't change enough to bother
+- * changing the color of the led */
+- return 0;
+-
+- return au8522_led_ctrl(state, led);
+-}
+-
+-static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+- int ret = -EINVAL;
+-
+- dprintk("%s()\n", __func__);
+-
+- if (state->current_modulation == QAM_256)
+- ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
+- ARRAY_SIZE(qam256_mse2snr_tab),
+- au8522_readreg(state, 0x4522),
+- snr);
+- else if (state->current_modulation == QAM_64)
+- ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
+- ARRAY_SIZE(qam64_mse2snr_tab),
+- au8522_readreg(state, 0x4522),
+- snr);
+- else /* VSB_8 */
+- ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
+- ARRAY_SIZE(vsb_mse2snr_tab),
+- au8522_readreg(state, 0x4311),
+- snr);
+-
+- if (state->config->led_cfg)
+- au8522_led_status(state, snr);
+-
+- return ret;
+-}
+-
+-static int au8522_read_signal_strength(struct dvb_frontend *fe,
+- u16 *signal_strength)
+-{
+- return au8522_read_snr(fe, signal_strength);
+-}
+-
+-static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+-
+- if (state->current_modulation == VSB_8)
+- *ucblocks = au8522_readreg(state, 0x4087);
+- else
+- *ucblocks = au8522_readreg(state, 0x4543);
+-
+- return 0;
+-}
+-
+-static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
+-{
+- return au8522_read_ucblocks(fe, ber);
+-}
+-
+-static int au8522_get_frontend(struct dvb_frontend *fe,
+- struct dvb_frontend_parameters *p)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+-
+- p->frequency = state->current_frequency;
+- p->u.vsb.modulation = state->current_modulation;
+-
+- return 0;
+-}
+-
+-static int au8522_get_tune_settings(struct dvb_frontend *fe,
+- struct dvb_frontend_tune_settings *tune)
+-{
+- tune->min_delay_ms = 1000;
+- return 0;
+-}
+-
+-static void au8522_release(struct dvb_frontend *fe)
+-{
+- struct au8522_state *state = fe->demodulator_priv;
+- kfree(state);
+-}
+-
+-static struct dvb_frontend_ops au8522_ops;
+-
+-struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+- struct i2c_adapter *i2c)
+-{
+- struct au8522_state *state = NULL;
+-
+- /* allocate memory for the internal state */
+- state = kmalloc(sizeof(struct au8522_state), GFP_KERNEL);
+- if (state == NULL)
+- goto error;
+-
+- /* setup the state */
+- state->config = config;
+- state->i2c = i2c;
+- /* create dvb_frontend */
+- memcpy(&state->frontend.ops, &au8522_ops,
+- sizeof(struct dvb_frontend_ops));
+- state->frontend.demodulator_priv = state;
+-
+- if (au8522_init(&state->frontend) != 0) {
+- printk(KERN_ERR "%s: Failed to initialize correctly\n",
+- __func__);
+- goto error;
+- }
+-
+- /* Note: Leaving the I2C gate open here. */
+- au8522_i2c_gate_ctrl(&state->frontend, 1);
+-
+- return &state->frontend;
+-
+-error:
+- kfree(state);
+- return NULL;
+-}
+-EXPORT_SYMBOL(au8522_attach);
+-
+-static struct dvb_frontend_ops au8522_ops = {
+-
+- .info = {
+- .name = "Auvitek AU8522 QAM/8VSB Frontend",
+- .type = FE_ATSC,
+- .frequency_min = 54000000,
+- .frequency_max = 858000000,
+- .frequency_stepsize = 62500,
+- .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+- },
+-
+- .init = au8522_init,
+- .sleep = au8522_sleep,
+- .i2c_gate_ctrl = au8522_i2c_gate_ctrl,
+- .set_frontend = au8522_set_frontend,
+- .get_frontend = au8522_get_frontend,
+- .get_tune_settings = au8522_get_tune_settings,
+- .read_status = au8522_read_status,
+- .read_ber = au8522_read_ber,
+- .read_signal_strength = au8522_read_signal_strength,
+- .read_snr = au8522_read_snr,
+- .read_ucblocks = au8522_read_ucblocks,
+- .release = au8522_release,
+-};
+-
+-module_param(debug, int, 0644);
+-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+-
+-MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
+-MODULE_AUTHOR("Steven Toth");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h
+index 7b94f55..565dcf3 100644
+--- a/drivers/media/dvb/frontends/au8522.h
++++ b/drivers/media/dvb/frontends/au8522.h
+@@ -74,6 +74,22 @@ struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+ }
+ #endif /* CONFIG_DVB_AU8522 */
+
++/* Other modes may need to be added later */
++enum au8522_video_input {
++ AU8522_COMPOSITE_CH1 = 1,
++ AU8522_COMPOSITE_CH2,
++ AU8522_COMPOSITE_CH3,
++ AU8522_COMPOSITE_CH4,
++ AU8522_COMPOSITE_CH4_SIF,
++ AU8522_SVIDEO_CH13,
++ AU8522_SVIDEO_CH24,
++};
++
++enum au8522_audio_input {
++ AU8522_AUDIO_NONE,
++ AU8522_AUDIO_SIF,
++};
++
+ #endif /* __AU8522_H__ */
+
+ /*
+diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
+new file mode 100644
+index 0000000..d63e152
+--- /dev/null
++++ b/drivers/media/dvb/frontends/au8522_decoder.c
+@@ -0,0 +1,835 @@
++/*
++ * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder
++ *
++ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
++ * Copyright (C) 2005-2008 Auvitek International, Ltd.
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA.
++ */
++
++/* Developer notes:
++ *
++ * VBI support is not yet working
++ * Saturation and hue setting are not yet working
++ * Enough is implemented here for CVBS and S-Video inputs, but the actual
++ * analog demodulator code isn't implemented (not needed for xc5000 since it
++ * has its own demodulator and outputs CVBS)
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/videodev2.h>
++#include <linux/i2c.h>
++#include <linux/delay.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
++#include <media/v4l2-device.h>
++#include "au8522.h"
++#include "au8522_priv.h"
++
++MODULE_AUTHOR("Devin Heitmueller");
++MODULE_LICENSE("GPL");
++
++static int au8522_analog_debug;
++
++
++module_param_named(analog_debug, au8522_analog_debug, int, 0644);
++
++MODULE_PARM_DESC(analog_debug,
++ "Analog debugging messages [0=Off (default) 1=On]");
++
++struct au8522_register_config {
++ u16 reg_name;
++ u8 reg_val[8];
++};
++
++
++/* Video Decoder Filter Coefficients
++ The values are as follows from left to right
++ 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13"
++*/
++struct au8522_register_config filter_coef[] = {
++ {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} },
++ {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} },
++ {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} },
++ {AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} },
++ {AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} },
++ {AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} },
++ {AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} },
++ {AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} },
++ {AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} },
++ {AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} },
++ {AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} },
++ {AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} },
++ {AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} },
++ {AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} },
++ {AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} },
++ {AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} },
++ {AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} },
++ {AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} },
++ {AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} },
++ {AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} },
++ {AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} },
++ {AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} },
++ {AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} },
++ {AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} },
++ {AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} },
++ {AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} },
++ {AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} },
++ {AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} },
++ {AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} },
++ {AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} },
++
++};
++#define NUM_FILTER_COEF (sizeof(filter_coef)\
++ / sizeof(struct au8522_register_config))
++
++
++/* Registers 0x060b through 0x0652 are the LP Filter coefficients
++ The values are as follows from left to right
++ 0="SIF" 1="ATVRF/ATVRF13"
++ Note: the "ATVRF/ATVRF13" mode has never been tested
++*/
++struct au8522_register_config lpfilter_coef[] = {
++ {0x060b, {0x21, 0x0b} },
++ {0x060c, {0xad, 0xad} },
++ {0x060d, {0x70, 0xf0} },
++ {0x060e, {0xea, 0xe9} },
++ {0x060f, {0xdd, 0xdd} },
++ {0x0610, {0x08, 0x64} },
++ {0x0611, {0x60, 0x60} },
++ {0x0612, {0xf8, 0xb2} },
++ {0x0613, {0x01, 0x02} },
++ {0x0614, {0xe4, 0xb4} },
++ {0x0615, {0x19, 0x02} },
++ {0x0616, {0xae, 0x2e} },
++ {0x0617, {0xee, 0xc5} },
++ {0x0618, {0x56, 0x56} },
++ {0x0619, {0x30, 0x58} },
++ {0x061a, {0xf9, 0xf8} },
++ {0x061b, {0x24, 0x64} },
++ {0x061c, {0x07, 0x07} },
++ {0x061d, {0x30, 0x30} },
++ {0x061e, {0xa9, 0xed} },
++ {0x061f, {0x09, 0x0b} },
++ {0x0620, {0x42, 0xc2} },
++ {0x0621, {0x1d, 0x2a} },
++ {0x0622, {0xd6, 0x56} },
++ {0x0623, {0x95, 0x8b} },
++ {0x0624, {0x2b, 0x2b} },
++ {0x0625, {0x30, 0x24} },
++ {0x0626, {0x3e, 0x3e} },
++ {0x0627, {0x62, 0xe2} },
++ {0x0628, {0xe9, 0xf5} },
++ {0x0629, {0x99, 0x19} },
++ {0x062a, {0xd4, 0x11} },
++ {0x062b, {0x03, 0x04} },
++ {0x062c, {0xb5, 0x85} },
++ {0x062d, {0x1e, 0x20} },
++ {0x062e, {0x2a, 0xea} },
++ {0x062f, {0xd7, 0xd2} },
++ {0x0630, {0x15, 0x15} },
++ {0x0631, {0xa3, 0xa9} },
++ {0x0632, {0x1f, 0x1f} },
++ {0x0633, {0xf9, 0xd1} },
++ {0x0634, {0xc0, 0xc3} },
++ {0x0635, {0x4d, 0x8d} },
++ {0x0636, {0x21, 0x31} },
++ {0x0637, {0x83, 0x83} },
++ {0x0638, {0x08, 0x8c} },
++ {0x0639, {0x19, 0x19} },
++ {0x063a, {0x45, 0xa5} },
++ {0x063b, {0xef, 0xec} },
++ {0x063c, {0x8a, 0x8a} },
++ {0x063d, {0xf4, 0xf6} },
++ {0x063e, {0x8f, 0x8f} },
++ {0x063f, {0x44, 0x0c} },
++ {0x0640, {0xef, 0xf0} },
++ {0x0641, {0x66, 0x66} },
++ {0x0642, {0xcc, 0xd2} },
++ {0x0643, {0x41, 0x41} },
++ {0x0644, {0x63, 0x93} },
++ {0x0645, {0x8e, 0x8e} },
++ {0x0646, {0xa2, 0x42} },
++ {0x0647, {0x7b, 0x7b} },
++ {0x0648, {0x04, 0x04} },
++ {0x0649, {0x00, 0x00} },
++ {0x064a, {0x40, 0x40} },
++ {0x064b, {0x8c, 0x98} },
++ {0x064c, {0x00, 0x00} },
++ {0x064d, {0x63, 0xc3} },
++ {0x064e, {0x04, 0x04} },
++ {0x064f, {0x20, 0x20} },
++ {0x0650, {0x00, 0x00} },
++ {0x0651, {0x40, 0x40} },
++ {0x0652, {0x01, 0x01} },
++};
++#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\
++ / sizeof(struct au8522_register_config))
++
++static inline struct au8522_state *to_state(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct au8522_state, sd);
++}
++
++static void setup_vbi(struct au8522_state *state, int aud_input)
++{
++ int i;
++
++ /* These are set to zero regardless of what mode we're in */
++ au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_L_REG018H, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_THRESH1_REG01CH, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H,
++ 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H,
++ 0x00);
++ au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H,
++ 0x00);
++
++ /* Setup the VBI registers */
++ for (i = 0x30; i < 0x60; i++)
++ au8522_writereg(state, i, 0x40);
++
++ /* For some reason, every register is 0x40 except register 0x44
++ (confirmed via the HVR-950q USB capture) */
++ au8522_writereg(state, 0x44, 0x60);
++
++ /* Enable VBI (we always do this regardless of whether the user is
++ viewing closed caption info) */
++ au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H,
++ AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON);
++
++}
++
++static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
++{
++ int i;
++ int filter_coef_type;
++
++ /* Provide reasonable defaults for picture tuning values */
++ au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07);
++ au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed);
++ state->brightness = 0xed - 128;
++ au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79);
++ state->contrast = 0x79;
++ au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
++ au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
++ au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
++ au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
++
++ /* Other decoder registers */
++ au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
++
++ if (input_mode == 0x23) {
++ /* S-Video input mapping */
++ au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
++ } else {
++ /* All other modes (CVBS/ATVRF etc.) */
++ au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
++ }
++
++ au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
++ AU8522_TVDEC_PGA_REG012H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H,
++ AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
++ au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
++ AU8522_TVDED_DBG_MODE_REG060H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
++ AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13);
++ au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
++ AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13);
++ au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
++ AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
++ AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H,
++ AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H,
++ AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H,
++ AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H,
++ AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H,
++ AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH,
++ AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
++ AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
++ AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
++ AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
++ AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
++ AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H,
++ AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS);
++ au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS);
++ au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H,
++ AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS);
++ au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS);
++ au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H,
++ AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H,
++ AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H,
++ AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH,
++ AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH,
++ AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS);
++ au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H,
++ AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS);
++ au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H,
++ AU8522_TOREGAAGC_REG0E5H_CVBS);
++ au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS);
++
++ setup_vbi(state, 0);
++
++ if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
++ input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
++ /* Despite what the table says, for the HVR-950q we still need
++ to be in CVBS mode for the S-Video input (reason uknown). */
++ /* filter_coef_type = 3; */
++ filter_coef_type = 5;
++ } else {
++ filter_coef_type = 5;
++ }
++
++ /* Load the Video Decoder Filter Coefficients */
++ for (i = 0; i < NUM_FILTER_COEF; i++) {
++ au8522_writereg(state, filter_coef[i].reg_name,
++ filter_coef[i].reg_val[filter_coef_type]);
++ }
++
++ /* It's not clear what these registers are for, but they are always
++ set to the same value regardless of what mode we're in */
++ au8522_writereg(state, AU8522_REG42EH, 0x87);
++ au8522_writereg(state, AU8522_REG42FH, 0xa2);
++ au8522_writereg(state, AU8522_REG430H, 0xbf);
++ au8522_writereg(state, AU8522_REG431H, 0xcb);
++ au8522_writereg(state, AU8522_REG432H, 0xa1);
++ au8522_writereg(state, AU8522_REG433H, 0x41);
++ au8522_writereg(state, AU8522_REG434H, 0x88);
++ au8522_writereg(state, AU8522_REG435H, 0xc2);
++ au8522_writereg(state, AU8522_REG436H, 0x3c);
++}
++
++static void au8522_setup_cvbs_mode(struct au8522_state *state)
++{
++ /* here we're going to try the pre-programmed route */
++ au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
++ AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
++
++ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
++ au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
++ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
++
++ au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
++ AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
++
++ setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
++
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
++ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
++}
++
++static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
++{
++ /* here we're going to try the pre-programmed route */
++ au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
++ AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
++
++ /* It's not clear why they turn off the PGA before enabling the clamp
++ control, but the Windows trace does it so we will too... */
++ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
++
++ /* Enable clamping control */
++ au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
++
++ /* Turn on the PGA */
++ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
++
++ /* Set input mode to CVBS on channel 4 with SIF audio input enabled */
++ au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
++ AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
++
++ setup_decoder_defaults(state,
++ AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
++
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
++ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
++}
++
++static void au8522_setup_svideo_mode(struct au8522_state *state)
++{
++ au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
++ AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
++
++ /* Set input to Y on Channe1, C on Channel 3 */
++ au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
++ AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
++
++ /* Disable clamping control (required for S-video) */
++ au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
++
++ setup_decoder_defaults(state,
++ AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
++
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
++ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
++}
++
++/* ----------------------------------------------------------------------- */
++
++static void disable_audio_input(struct au8522_state *state)
++{
++ /* This can probably be optimized */
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
++ au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
++ au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
++
++ au8522_writereg(state, AU8522_ENA_USB_REG101H, 0x00);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
++ au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
++ au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x40);
++
++ au8522_writereg(state, AU8522_GPIO_DATA_REG0E2H, 0x11);
++ msleep(5);
++ au8522_writereg(state, AU8522_GPIO_DATA_REG0E2H, 0x00);
++
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
++ au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
++ au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
++
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
++ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
++}
++
++/* 0=disable, 1=SIF */
++static void set_audio_input(struct au8522_state *state, int aud_input)
++{
++ int i;
++
++ /* Note that this function needs to be used in conjunction with setting
++ the input routing via register 0x81 */
++
++ if (aud_input == AU8522_AUDIO_NONE) {
++ disable_audio_input(state);
++ return;
++ }
++
++ if (aud_input != AU8522_AUDIO_SIF) {
++ /* The caller asked for a mode we don't currently support */
++ printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n",
++ aud_input);
++ return;
++ }
++
++ /* Load the Audio Decoder Filter Coefficients */
++ for (i = 0; i < NUM_LPFILTER_COEF; i++) {
++ au8522_writereg(state, lpfilter_coef[i].reg_name,
++ lpfilter_coef[i].reg_val[0]);
++ }
++
++ /* Setup audio */
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
++ au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
++ au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
++ msleep(150);
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00);
++ msleep(1);
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d);
++ msleep(50);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff);
++ msleep(80);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
++ au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
++ au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
++ au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82);
++ msleep(70);
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09);
++ au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
++ au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2);
++}
++
++/* ----------------------------------------------------------------------- */
++
++static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct au8522_state *state = to_state(sd);
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ state->brightness = ctrl->value;
++ au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH,
++ ctrl->value - 128);
++ break;
++ case V4L2_CID_CONTRAST:
++ state->contrast = ctrl->value;
++ au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH,
++ ctrl->value);
++ break;
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_AUDIO_VOLUME:
++ case V4L2_CID_AUDIO_BASS:
++ case V4L2_CID_AUDIO_TREBLE:
++ case V4L2_CID_AUDIO_BALANCE:
++ case V4L2_CID_AUDIO_MUTE:
++ /* Not yet implemented */
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct au8522_state *state = to_state(sd);
++
++ /* Note that we are using values cached in the state structure instead
++ of reading the registers due to issues with i2c reads not working
++ properly/consistently yet on the HVR-950q */
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ ctrl->value = state->brightness;
++ break;
++ case V4L2_CID_CONTRAST:
++ ctrl->value = state->contrast;
++ break;
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_AUDIO_VOLUME:
++ case V4L2_CID_AUDIO_BASS:
++ case V4L2_CID_AUDIO_TREBLE:
++ case V4L2_CID_AUDIO_BALANCE:
++ case V4L2_CID_AUDIO_MUTE:
++ /* Not yet supported */
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/* ----------------------------------------------------------------------- */
++
++static int au8522_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
++{
++ switch (fmt->type) {
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int au8522_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
++{
++ switch (fmt->type) {
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ /* Not yet implemented */
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/* ----------------------------------------------------------------------- */
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int au8522_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct au8522_state *state = to_state(sd);
++
++ if (!v4l2_chip_match_i2c_client(client, &reg->match))
++ return -EINVAL;
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ reg->val = au8522_readreg(state, reg->reg & 0xffff);
++ return 0;
++}
++
++static int au8522_s_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct au8522_state *state = to_state(sd);
++
++ if (!v4l2_chip_match_i2c_client(client, &reg->match))
++ return -EINVAL;
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ au8522_writereg(state, reg->reg, reg->val & 0xff);
++ return 0;
++}
++#endif
++
++static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct au8522_state *state = to_state(sd);
++
++ if (enable) {
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
++ 0x01);
++ msleep(1);
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
++ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
++ } else {
++ /* This does not completely power down the device
++ (it only reduces it from around 140ma to 80ma) */
++ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
++ 1 << 5);
++ }
++ return 0;
++}
++
++static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
++{
++ switch (qc->id) {
++ case V4L2_CID_CONTRAST:
++ return v4l2_ctrl_query_fill(qc, 0, 255, 1,
++ AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
++ case V4L2_CID_BRIGHTNESS:
++ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ /* Not yet implemented */
++ default:
++ break;
++ }
++
++ qc->type = 0;
++ return -EINVAL;
++}
++
++static int au8522_reset(struct v4l2_subdev *sd, u32 val)
++{
++ struct au8522_state *state = to_state(sd);
++
++ au8522_writereg(state, 0xa4, 1 << 5);
++
++ return 0;
++}
++
++static int au8522_s_video_routing(struct v4l2_subdev *sd,
++ const struct v4l2_routing *route)
++{
++ struct au8522_state *state = to_state(sd);
++
++ au8522_reset(sd, 0);
++
++ /* Jam open the i2c gate to the tuner. We do this here to handle the
++ case where the user went into digital mode (causing the gate to be
++ closed), and then came back to analog mode */
++ au8522_writereg(state, 0x106, 1);
++
++ if (route->input == AU8522_COMPOSITE_CH1) {
++ au8522_setup_cvbs_mode(state);
++ } else if (route->input == AU8522_SVIDEO_CH13) {
++ au8522_setup_svideo_mode(state);
++ } else if (route->input == AU8522_COMPOSITE_CH4_SIF) {
++ au8522_setup_cvbs_tuner_mode(state);
++ } else {
++ printk(KERN_ERR "au8522 mode not currently supported\n");
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int au8522_s_audio_routing(struct v4l2_subdev *sd,
++ const struct v4l2_routing *route)
++{
++ struct au8522_state *state = to_state(sd);
++ set_audio_input(state, route->input);
++ return 0;
++}
++
++static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
++{
++ int val = 0;
++ struct au8522_state *state = to_state(sd);
++ u8 lock_status;
++
++ /* Interrogate the decoder to see if we are getting a real signal */
++ lock_status = au8522_readreg(state, 0x00);
++ if (lock_status == 0xa2)
++ vt->signal = 0x01;
++ else
++ vt->signal = 0x00;
++
++ vt->capability |=
++ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
++ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
++
++ val = V4L2_TUNER_SUB_MONO;
++ vt->rxsubchans = val;
++ vt->audmode = V4L2_TUNER_MODE_STEREO;
++ return 0;
++}
++
++static int au8522_g_chip_ident(struct v4l2_subdev *sd,
++ struct v4l2_dbg_chip_ident *chip)
++{
++ struct au8522_state *state = to_state(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
++}
++
++static int au8522_log_status(struct v4l2_subdev *sd)
++{
++ /* FIXME: Add some status info here */
++ return 0;
++}
++
++/* ----------------------------------------------------------------------- */
++
++static const struct v4l2_subdev_core_ops au8522_core_ops = {
++ .log_status = au8522_log_status,
++ .g_chip_ident = au8522_g_chip_ident,
++ .g_ctrl = au8522_g_ctrl,
++ .s_ctrl = au8522_s_ctrl,
++ .queryctrl = au8522_queryctrl,
++ .reset = au8522_reset,
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = au8522_g_register,
++ .s_register = au8522_s_register,
++#endif
++};
++
++static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = {
++ .g_tuner = au8522_g_tuner,
++};
++
++static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
++ .s_routing = au8522_s_audio_routing,
++};
++
++static const struct v4l2_subdev_video_ops au8522_video_ops = {
++ .s_routing = au8522_s_video_routing,
++ .g_fmt = au8522_g_fmt,
++ .s_fmt = au8522_s_fmt,
++ .s_stream = au8522_s_stream,
++};
++
++static const struct v4l2_subdev_ops au8522_ops = {
++ .core = &au8522_core_ops,
++ .tuner = &au8522_tuner_ops,
++ .audio = &au8522_audio_ops,
++ .video = &au8522_video_ops,
++};
++
++/* ----------------------------------------------------------------------- */
++
++static int au8522_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct au8522_state *state;
++ struct v4l2_subdev *sd;
++ int instance;
++ struct au8522_config *demod_config;
++
++ /* Check if the adapter supports the needed features */
++ if (!i2c_check_functionality(client->adapter,
++ I2C_FUNC_SMBUS_BYTE_DATA)) {
++ return -EIO;
++ }
++
++ /* allocate memory for the internal state */
++ instance = au8522_get_state(&state, client->adapter, client->addr);
++ switch (instance) {
++ case 0:
++ printk(KERN_ERR "au8522_decoder allocation failed\n");
++ return -EIO;
++ case 1:
++ /* new demod instance */
++ printk(KERN_INFO "au8522_decoder creating new instance...\n");
++ break;
++ default:
++ /* existing demod instance */
++ printk(KERN_INFO "au8522_decoder attach existing instance.\n");
++ break;
++ }
++
++ demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
++ demod_config->demod_address = 0x8e >> 1;
++
++ state->config = demod_config;
++ state->i2c = client->adapter;
++
++ sd = &state->sd;
++ v4l2_i2c_subdev_init(sd, client, &au8522_ops);
++
++ state->c = client;
++ state->vid_input = AU8522_COMPOSITE_CH1;
++ state->aud_input = AU8522_AUDIO_NONE;
++ state->id = 8522;
++ state->rev = 0;
++
++ /* Jam open the i2c gate to the tuner */
++ au8522_writereg(state, 0x106, 1);
++
++ return 0;
++}
++
++static int au8522_remove(struct i2c_client *client)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ v4l2_device_unregister_subdev(sd);
++ au8522_release_state(to_state(sd));
++ return 0;
++}
++
++static const struct i2c_device_id au8522_id[] = {
++ {"au8522", 0},
++ {}
++};
++
++MODULE_DEVICE_TABLE(i2c, au8522_id);
++
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++ .name = "au8522",
++ .probe = au8522_probe,
++ .remove = au8522_remove,
++ .id_table = au8522_id,
++};
+diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c
+new file mode 100644
+index 0000000..3573125
+--- /dev/null
++++ b/drivers/media/dvb/frontends/au8522_dig.c
+@@ -0,0 +1,902 @@
++/*
++ Auvitek AU8522 QAM/8VSB demodulator driver
++
++ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++*/
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include "dvb_frontend.h"
++#include "au8522.h"
++#include "au8522_priv.h"
++
++static int debug;
++
++/* Despite the name "hybrid_tuner", the framework works just as well for
++ hybrid demodulators as well... */
++static LIST_HEAD(hybrid_tuner_instance_list);
++static DEFINE_MUTEX(au8522_list_mutex);
++
++#define dprintk(arg...)\
++ do { if (debug)\
++ printk(arg);\
++ } while (0)
++
++/* 16 bit registers, 8 bit values */
++int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
++{
++ int ret;
++ u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
++
++ struct i2c_msg msg = { .addr = state->config->demod_address,
++ .flags = 0, .buf = buf, .len = 3 };
++
++ ret = i2c_transfer(state->i2c, &msg, 1);
++
++ if (ret != 1)
++ printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
++ "ret == %i)\n", __func__, reg, data, ret);
++
++ return (ret != 1) ? -1 : 0;
++}
++
++u8 au8522_readreg(struct au8522_state *state, u16 reg)
++{
++ int ret;
++ u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
++ u8 b1[] = { 0 };
++
++ struct i2c_msg msg[] = {
++ { .addr = state->config->demod_address, .flags = 0,
++ .buf = b0, .len = 2 },
++ { .addr = state->config->demod_address, .flags = I2C_M_RD,
++ .buf = b1, .len = 1 } };
++
++ ret = i2c_transfer(state->i2c, msg, 2);
++
++ if (ret != 2)
++ printk(KERN_ERR "%s: readreg error (ret == %i)\n",
++ __func__, ret);
++ return b1[0];
++}
++
++static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++
++ dprintk("%s(%d)\n", __func__, enable);
++
++ if (enable)
++ return au8522_writereg(state, 0x106, 1);
++ else
++ return au8522_writereg(state, 0x106, 0);
++}
++
++struct mse2snr_tab {
++ u16 val;
++ u16 data;
++};
++
++/* VSB SNR lookup table */
++static struct mse2snr_tab vsb_mse2snr_tab[] = {
++ { 0, 270 },
++ { 2, 250 },
++ { 3, 240 },
++ { 5, 230 },
++ { 7, 220 },
++ { 9, 210 },
++ { 12, 200 },
++ { 13, 195 },
++ { 15, 190 },
++ { 17, 185 },
++ { 19, 180 },
++ { 21, 175 },
++ { 24, 170 },
++ { 27, 165 },
++ { 31, 160 },
++ { 32, 158 },
++ { 33, 156 },
++ { 36, 152 },
++ { 37, 150 },
++ { 39, 148 },
++ { 40, 146 },
++ { 41, 144 },
++ { 43, 142 },
++ { 44, 140 },
++ { 48, 135 },
++ { 50, 130 },
++ { 43, 142 },
++ { 53, 125 },
++ { 56, 120 },
++ { 256, 115 },
++};
++
++/* QAM64 SNR lookup table */
++static struct mse2snr_tab qam64_mse2snr_tab[] = {
++ { 15, 0 },
++ { 16, 290 },
++ { 17, 288 },
++ { 18, 286 },
++ { 19, 284 },
++ { 20, 282 },
++ { 21, 281 },
++ { 22, 279 },
++ { 23, 277 },
++ { 24, 275 },
++ { 25, 273 },
++ { 26, 271 },
++ { 27, 269 },
++ { 28, 268 },
++ { 29, 266 },
++ { 30, 264 },
++ { 31, 262 },
++ { 32, 260 },
++ { 33, 259 },
++ { 34, 258 },
++ { 35, 256 },
++ { 36, 255 },
++ { 37, 254 },
++ { 38, 252 },
++ { 39, 251 },
++ { 40, 250 },
++ { 41, 249 },
++ { 42, 248 },
++ { 43, 246 },
++ { 44, 245 },
++ { 45, 244 },
++ { 46, 242 },
++ { 47, 241 },
++ { 48, 240 },
++ { 50, 239 },
++ { 51, 238 },
++ { 53, 237 },
++ { 54, 236 },
++ { 56, 235 },
++ { 57, 234 },
++ { 59, 233 },
++ { 60, 232 },
++ { 62, 231 },
++ { 63, 230 },
++ { 65, 229 },
++ { 67, 228 },
++ { 68, 227 },
++ { 70, 226 },
++ { 71, 225 },
++ { 73, 224 },
++ { 74, 223 },
++ { 76, 222 },
++ { 78, 221 },
++ { 80, 220 },
++ { 82, 219 },
++ { 85, 218 },
++ { 88, 217 },
++ { 90, 216 },
++ { 92, 215 },
++ { 93, 214 },
++ { 94, 212 },
++ { 95, 211 },
++ { 97, 210 },
++ { 99, 209 },
++ { 101, 208 },
++ { 102, 207 },
++ { 104, 206 },
++ { 107, 205 },
++ { 111, 204 },
++ { 114, 203 },
++ { 118, 202 },
++ { 122, 201 },
++ { 125, 200 },
++ { 128, 199 },
++ { 130, 198 },
++ { 132, 197 },
++ { 256, 190 },
++};
++
++/* QAM256 SNR lookup table */
++static struct mse2snr_tab qam256_mse2snr_tab[] = {
++ { 16, 0 },
++ { 17, 400 },
++ { 18, 398 },
++ { 19, 396 },
++ { 20, 394 },
++ { 21, 392 },
++ { 22, 390 },
++ { 23, 388 },
++ { 24, 386 },
++ { 25, 384 },
++ { 26, 382 },
++ { 27, 380 },
++ { 28, 379 },
++ { 29, 378 },
++ { 30, 377 },
++ { 31, 376 },
++ { 32, 375 },
++ { 33, 374 },
++ { 34, 373 },
++ { 35, 372 },
++ { 36, 371 },
++ { 37, 370 },
++ { 38, 362 },
++ { 39, 354 },
++ { 40, 346 },
++ { 41, 338 },
++ { 42, 330 },
++ { 43, 328 },
++ { 44, 326 },
++ { 45, 324 },
++ { 46, 322 },
++ { 47, 320 },
++ { 48, 319 },
++ { 49, 318 },
++ { 50, 317 },
++ { 51, 316 },
++ { 52, 315 },
++ { 53, 314 },
++ { 54, 313 },
++ { 55, 312 },
++ { 56, 311 },
++ { 57, 310 },
++ { 58, 308 },
++ { 59, 306 },
++ { 60, 304 },
++ { 61, 302 },
++ { 62, 300 },
++ { 63, 298 },
++ { 65, 295 },
++ { 68, 294 },
++ { 70, 293 },
++ { 73, 292 },
++ { 76, 291 },
++ { 78, 290 },
++ { 79, 289 },
++ { 81, 288 },
++ { 82, 287 },
++ { 83, 286 },
++ { 84, 285 },
++ { 85, 284 },
++ { 86, 283 },
++ { 88, 282 },
++ { 89, 281 },
++ { 256, 280 },
++};
++
++static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
++ u16 *snr)
++{
++ int i, ret = -EINVAL;
++ dprintk("%s()\n", __func__);
++
++ for (i = 0; i < sz; i++) {
++ if (mse < tab[i].val) {
++ *snr = tab[i].data;
++ ret = 0;
++ break;
++ }
++ }
++ dprintk("%s() snr=%d\n", __func__, *snr);
++ return ret;
++}
++
++static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++ u8 r0b5, r0b6, r0b7;
++ char *ifmhz;
++
++ switch (if_freq) {
++ case AU8522_IF_3_25MHZ:
++ ifmhz = "3.25";
++ r0b5 = 0x00;
++ r0b6 = 0x3d;
++ r0b7 = 0xa0;
++ break;
++ case AU8522_IF_4MHZ:
++ ifmhz = "4.00";
++ r0b5 = 0x00;
++ r0b6 = 0x4b;
++ r0b7 = 0xd9;
++ break;
++ case AU8522_IF_6MHZ:
++ ifmhz = "6.00";
++ r0b5 = 0xfb;
++ r0b6 = 0x8e;
++ r0b7 = 0x39;
++ break;
++ default:
++ dprintk("%s() IF Frequency not supported\n", __func__);
++ return -EINVAL;
++ }
++ dprintk("%s() %s MHz\n", __func__, ifmhz);
++ au8522_writereg(state, 0x80b5, r0b5);
++ au8522_writereg(state, 0x80b6, r0b6);
++ au8522_writereg(state, 0x80b7, r0b7);
++
++ return 0;
++}
++
++/* VSB Modulation table */
++static struct {
++ u16 reg;
++ u16 data;
++} VSB_mod_tab[] = {
++ { 0x8090, 0x84 },
++ { 0x4092, 0x11 },
++ { 0x2005, 0x00 },
++ { 0x8091, 0x80 },
++ { 0x80a3, 0x0c },
++ { 0x80a4, 0xe8 },
++ { 0x8081, 0xc4 },
++ { 0x80a5, 0x40 },
++ { 0x80a7, 0x40 },
++ { 0x80a6, 0x67 },
++ { 0x8262, 0x20 },
++ { 0x821c, 0x30 },
++ { 0x80d8, 0x1a },
++ { 0x8227, 0xa0 },
++ { 0x8121, 0xff },
++ { 0x80a8, 0xf0 },
++ { 0x80a9, 0x05 },
++ { 0x80aa, 0x77 },
++ { 0x80ab, 0xf0 },
++ { 0x80ac, 0x05 },
++ { 0x80ad, 0x77 },
++ { 0x80ae, 0x41 },
++ { 0x80af, 0x66 },
++ { 0x821b, 0xcc },
++ { 0x821d, 0x80 },
++ { 0x80a4, 0xe8 },
++ { 0x8231, 0x13 },
++};
++
++/* QAM Modulation table */
++static struct {
++ u16 reg;
++ u16 data;
++} QAM_mod_tab[] = {
++ { 0x80a3, 0x09 },
++ { 0x80a4, 0x00 },
++ { 0x8081, 0xc4 },
++ { 0x80a5, 0x40 },
++ { 0x80aa, 0x77 },
++ { 0x80ad, 0x77 },
++ { 0x80a6, 0x67 },
++ { 0x8262, 0x20 },
++ { 0x821c, 0x30 },
++ { 0x80b8, 0x3e },
++ { 0x80b9, 0xf0 },
++ { 0x80ba, 0x01 },
++ { 0x80bb, 0x18 },
++ { 0x80bc, 0x50 },
++ { 0x80bd, 0x00 },
++ { 0x80be, 0xea },
++ { 0x80bf, 0xef },
++ { 0x80c0, 0xfc },
++ { 0x80c1, 0xbd },
++ { 0x80c2, 0x1f },
++ { 0x80c3, 0xfc },
++ { 0x80c4, 0xdd },
++ { 0x80c5, 0xaf },
++ { 0x80c6, 0x00 },
++ { 0x80c7, 0x38 },
++ { 0x80c8, 0x30 },
++ { 0x80c9, 0x05 },
++ { 0x80ca, 0x4a },
++ { 0x80cb, 0xd0 },
++ { 0x80cc, 0x01 },
++ { 0x80cd, 0xd9 },
++ { 0x80ce, 0x6f },
++ { 0x80cf, 0xf9 },
++ { 0x80d0, 0x70 },
++ { 0x80d1, 0xdf },
++ { 0x80d2, 0xf7 },
++ { 0x80d3, 0xc2 },
++ { 0x80d4, 0xdf },
++ { 0x80d5, 0x02 },
++ { 0x80d6, 0x9a },
++ { 0x80d7, 0xd0 },
++ { 0x8250, 0x0d },
++ { 0x8251, 0xcd },
++ { 0x8252, 0xe0 },
++ { 0x8253, 0x05 },
++ { 0x8254, 0xa7 },
++ { 0x8255, 0xff },
++ { 0x8256, 0xed },
++ { 0x8257, 0x5b },
++ { 0x8258, 0xae },
++ { 0x8259, 0xe6 },
++ { 0x825a, 0x3d },
++ { 0x825b, 0x0f },
++ { 0x825c, 0x0d },
++ { 0x825d, 0xea },
++ { 0x825e, 0xf2 },
++ { 0x825f, 0x51 },
++ { 0x8260, 0xf5 },
++ { 0x8261, 0x06 },
++ { 0x821a, 0x00 },
++ { 0x8546, 0x40 },
++ { 0x8210, 0x26 },
++ { 0x8211, 0xf6 },
++ { 0x8212, 0x84 },
++ { 0x8213, 0x02 },
++ { 0x8502, 0x01 },
++ { 0x8121, 0x04 },
++ { 0x8122, 0x04 },
++ { 0x852e, 0x10 },
++ { 0x80a4, 0xca },
++ { 0x80a7, 0x40 },
++ { 0x8526, 0x01 },
++};
++
++static int au8522_enable_modulation(struct dvb_frontend *fe,
++ fe_modulation_t m)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++ int i;
++
++ dprintk("%s(0x%08x)\n", __func__, m);
++
++ switch (m) {
++ case VSB_8:
++ dprintk("%s() VSB_8\n", __func__);
++ for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
++ au8522_writereg(state,
++ VSB_mod_tab[i].reg,
++ VSB_mod_tab[i].data);
++ au8522_set_if(fe, state->config->vsb_if);
++ break;
++ case QAM_64:
++ case QAM_256:
++ dprintk("%s() QAM 64/256\n", __func__);
++ for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
++ au8522_writereg(state,
++ QAM_mod_tab[i].reg,
++ QAM_mod_tab[i].data);
++ au8522_set_if(fe, state->config->qam_if);
++ break;
++ default:
++ dprintk("%s() Invalid modulation\n", __func__);
++ return -EINVAL;
++ }
++
++ state->current_modulation = m;
++
++ return 0;
++}
++
++/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
++static int au8522_set_frontend(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *p)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++ int ret = -EINVAL;
++
++ dprintk("%s(frequency=%d)\n", __func__, p->frequency);
++
++ if ((state->current_frequency == p->frequency) &&
++ (state->current_modulation == p->u.vsb.modulation))
++ return 0;
++
++ au8522_enable_modulation(fe, p->u.vsb.modulation);
++
++ /* Allow the demod to settle */
++ msleep(100);
++
++ if (fe->ops.tuner_ops.set_params) {
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++ ret = fe->ops.tuner_ops.set_params(fe, p);
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++ }
++
++ if (ret < 0)
++ return ret;
++
++ state->current_frequency = p->frequency;
++
++ return 0;
++}
++
++/* Reset the demod hardware and reset all of the configuration registers
++ to a default state. */
++int au8522_init(struct dvb_frontend *fe)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++ dprintk("%s()\n", __func__);
++
++ au8522_writereg(state, 0xa4, 1 << 5);
++
++ au8522_i2c_gate_ctrl(fe, 1);
++
++ return 0;
++}
++
++static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
++{
++ struct au8522_led_config *led_config = state->config->led_cfg;
++ u8 val;
++
++ /* bail out if we cant control an LED */
++ if (!led_config || !led_config->gpio_output ||
++ !led_config->gpio_output_enable || !led_config->gpio_output_disable)
++ return 0;
++
++ val = au8522_readreg(state, 0x4000 |
++ (led_config->gpio_output & ~0xc000));
++ if (onoff) {
++ /* enable GPIO output */
++ val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
++ val |= (led_config->gpio_output_enable & 0xff);
++ } else {
++ /* disable GPIO output */
++ val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
++ val |= (led_config->gpio_output_disable & 0xff);
++ }
++ return au8522_writereg(state, 0x8000 |
++ (led_config->gpio_output & ~0xc000), val);
++}
++
++/* led = 0 | off
++ * led = 1 | signal ok
++ * led = 2 | signal strong
++ * led < 0 | only light led if leds are currently off
++ */
++static int au8522_led_ctrl(struct au8522_state *state, int led)
++{
++ struct au8522_led_config *led_config = state->config->led_cfg;
++ int i, ret = 0;
++
++ /* bail out if we cant control an LED */
++ if (!led_config || !led_config->gpio_leds ||
++ !led_config->num_led_states || !led_config->led_states)
++ return 0;
++
++ if (led < 0) {
++ /* if LED is already lit, then leave it as-is */
++ if (state->led_state)
++ return 0;
++ else
++ led *= -1;
++ }
++
++ /* toggle LED if changing state */
++ if (state->led_state != led) {
++ u8 val;
++
++ dprintk("%s: %d\n", __func__, led);
++
++ au8522_led_gpio_enable(state, 1);
++
++ val = au8522_readreg(state, 0x4000 |
++ (led_config->gpio_leds & ~0xc000));
++
++ /* start with all leds off */
++ for (i = 0; i < led_config->num_led_states; i++)
++ val &= ~led_config->led_states[i];
++
++ /* set selected LED state */
++ if (led < led_config->num_led_states)
++ val |= led_config->led_states[led];
++ else if (led_config->num_led_states)
++ val |=
++ led_config->led_states[led_config->num_led_states - 1];
++
++ ret = au8522_writereg(state, 0x8000 |
++ (led_config->gpio_leds & ~0xc000), val);
++ if (ret < 0)
++ return ret;
++
++ state->led_state = led;
++
++ if (led == 0)
++ au8522_led_gpio_enable(state, 0);
++ }
++
++ return 0;
++}
++
++int au8522_sleep(struct dvb_frontend *fe)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++ dprintk("%s()\n", __func__);
++
++ /* turn off led */
++ au8522_led_ctrl(state, 0);
++
++ /* Power down the chip */
++ au8522_writereg(state, 0xa4, 1 << 5);
++
++ state->current_frequency = 0;
++
++ return 0;
++}
++
++static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++ u8 reg;
++ u32 tuner_status = 0;
++
++ *status = 0;
++
++ if (state->current_modulation == VSB_8) {
++ dprintk("%s() Checking VSB_8\n", __func__);
++ reg = au8522_readreg(state, 0x4088);
++ if ((reg & 0x03) == 0x03)
++ *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
++ } else {
++ dprintk("%s() Checking QAM\n", __func__);
++ reg = au8522_readreg(state, 0x4541);
++ if (reg & 0x80)
++ *status |= FE_HAS_VITERBI;
++ if (reg & 0x20)
++ *status |= FE_HAS_LOCK | FE_HAS_SYNC;
++ }
++
++ switch (state->config->status_mode) {
++ case AU8522_DEMODLOCKING:
++ dprintk("%s() DEMODLOCKING\n", __func__);
++ if (*status & FE_HAS_VITERBI)
++ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
++ break;
++ case AU8522_TUNERLOCKING:
++ /* Get the tuner status */
++ dprintk("%s() TUNERLOCKING\n", __func__);
++ if (fe->ops.tuner_ops.get_status) {
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++
++ fe->ops.tuner_ops.get_status(fe, &tuner_status);
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++ }
++ if (tuner_status)
++ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
++ break;
++ }
++ state->fe_status = *status;
++
++ if (*status & FE_HAS_LOCK)
++ /* turn on LED, if it isn't on already */
++ au8522_led_ctrl(state, -1);
++ else
++ /* turn off LED */
++ au8522_led_ctrl(state, 0);
++
++ dprintk("%s() status 0x%08x\n", __func__, *status);
++
++ return 0;
++}
++
++static int au8522_led_status(struct au8522_state *state, const u16 *snr)
++{
++ struct au8522_led_config *led_config = state->config->led_cfg;
++ int led;
++ u16 strong;
++
++ /* bail out if we cant control an LED */
++ if (!led_config)
++ return 0;
++
++ if (0 == (state->fe_status & FE_HAS_LOCK))
++ return au8522_led_ctrl(state, 0);
++ else if (state->current_modulation == QAM_256)
++ strong = led_config->qam256_strong;
++ else if (state->current_modulation == QAM_64)
++ strong = led_config->qam64_strong;
++ else /* (state->current_modulation == VSB_8) */
++ strong = led_config->vsb8_strong;
++
++ if (*snr >= strong)
++ led = 2;
++ else
++ led = 1;
++
++ if ((state->led_state) &&
++ (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
++ /* snr didn't change enough to bother
++ * changing the color of the led */
++ return 0;
++
++ return au8522_led_ctrl(state, led);
++}
++
++static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++ int ret = -EINVAL;
++
++ dprintk("%s()\n", __func__);
++
++ if (state->current_modulation == QAM_256)
++ ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
++ ARRAY_SIZE(qam256_mse2snr_tab),
++ au8522_readreg(state, 0x4522),
++ snr);
++ else if (state->current_modulation == QAM_64)
++ ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
++ ARRAY_SIZE(qam64_mse2snr_tab),
++ au8522_readreg(state, 0x4522),
++ snr);
++ else /* VSB_8 */
++ ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
++ ARRAY_SIZE(vsb_mse2snr_tab),
++ au8522_readreg(state, 0x4311),
++ snr);
++
++ if (state->config->led_cfg)
++ au8522_led_status(state, snr);
++
++ return ret;
++}
++
++static int au8522_read_signal_strength(struct dvb_frontend *fe,
++ u16 *signal_strength)
++{
++ return au8522_read_snr(fe, signal_strength);
++}
++
++static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++
++ if (state->current_modulation == VSB_8)
++ *ucblocks = au8522_readreg(state, 0x4087);
++ else
++ *ucblocks = au8522_readreg(state, 0x4543);
++
++ return 0;
++}
++
++static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
++{
++ return au8522_read_ucblocks(fe, ber);
++}
++
++static int au8522_get_frontend(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *p)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++
++ p->frequency = state->current_frequency;
++ p->u.vsb.modulation = state->current_modulation;
++
++ return 0;
++}
++
++static int au8522_get_tune_settings(struct dvb_frontend *fe,
++ struct dvb_frontend_tune_settings *tune)
++{
++ tune->min_delay_ms = 1000;
++ return 0;
++}
++
++static struct dvb_frontend_ops au8522_ops;
++
++int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
++ u8 client_address)
++{
++ int ret;
++
++ mutex_lock(&au8522_list_mutex);
++ ret = hybrid_tuner_request_state(struct au8522_state, (*state),
++ hybrid_tuner_instance_list,
++ i2c, client_address, "au8522");
++ mutex_unlock(&au8522_list_mutex);
++
++ return ret;
++}
++
++void au8522_release_state(struct au8522_state *state)
++{
++ mutex_lock(&au8522_list_mutex);
++ if (state != NULL)
++ hybrid_tuner_release_state(state);
++ mutex_unlock(&au8522_list_mutex);
++}
++
++
++static void au8522_release(struct dvb_frontend *fe)
++{
++ struct au8522_state *state = fe->demodulator_priv;
++ au8522_release_state(state);
++}
++
++struct dvb_frontend *au8522_attach(const struct au8522_config *config,
++ struct i2c_adapter *i2c)
++{
++ struct au8522_state *state = NULL;
++ int instance;
++
++ /* allocate memory for the internal state */
++ instance = au8522_get_state(&state, i2c, config->demod_address);
++ switch (instance) {
++ case 0:
++ dprintk("%s state allocation failed\n", __func__);
++ break;
++ case 1:
++ /* new demod instance */
++ dprintk("%s using new instance\n", __func__);
++ break;
++ default:
++ /* existing demod instance */
++ dprintk("%s using existing instance\n", __func__);
++ break;
++ }
++
++ /* setup the state */
++ state->config = config;
++ state->i2c = i2c;
++ /* create dvb_frontend */
++ memcpy(&state->frontend.ops, &au8522_ops,
++ sizeof(struct dvb_frontend_ops));
++ state->frontend.demodulator_priv = state;
++
++ if (au8522_init(&state->frontend) != 0) {
++ printk(KERN_ERR "%s: Failed to initialize correctly\n",
++ __func__);
++ goto error;
++ }
++
++ /* Note: Leaving the I2C gate open here. */
++ au8522_i2c_gate_ctrl(&state->frontend, 1);
++
++ return &state->frontend;
++
++error:
++ au8522_release_state(state);
++ return NULL;
++}
++EXPORT_SYMBOL(au8522_attach);
++
++static struct dvb_frontend_ops au8522_ops = {
++
++ .info = {
++ .name = "Auvitek AU8522 QAM/8VSB Frontend",
++ .type = FE_ATSC,
++ .frequency_min = 54000000,
++ .frequency_max = 858000000,
++ .frequency_stepsize = 62500,
++ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
++ },
++
++ .init = au8522_init,
++ .sleep = au8522_sleep,
++ .i2c_gate_ctrl = au8522_i2c_gate_ctrl,
++ .set_frontend = au8522_set_frontend,
++ .get_frontend = au8522_get_frontend,
++ .get_tune_settings = au8522_get_tune_settings,
++ .read_status = au8522_read_status,
++ .read_ber = au8522_read_ber,
++ .read_signal_strength = au8522_read_signal_strength,
++ .read_snr = au8522_read_snr,
++ .read_ucblocks = au8522_read_ucblocks,
++ .release = au8522_release,
++};
++
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Enable verbose debug messages");
++
++MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
++MODULE_AUTHOR("Steven Toth");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
+new file mode 100644
+index 0000000..f328f2b
+--- /dev/null
++++ b/drivers/media/dvb/frontends/au8522_priv.h
+@@ -0,0 +1,412 @@
++/*
++ Auvitek AU8522 QAM/8VSB demodulator driver
++
++ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
++ Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
++ Copyright (C) 2005-2008 Auvitek International, Ltd.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++*/
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <linux/i2c.h>
++#include "dvb_frontend.h"
++#include "au8522.h"
++#include "tuner-i2c.h"
++
++struct au8522_state {
++ struct i2c_client *c;
++ struct i2c_adapter *i2c;
++
++ /* Used for sharing of the state between analog and digital mode */
++ struct tuner_i2c_props i2c_props;
++ struct list_head hybrid_tuner_instance_list;
++
++ /* configuration settings */
++ const struct au8522_config *config;
++
++ struct dvb_frontend frontend;
++
++ u32 current_frequency;
++ fe_modulation_t current_modulation;
++
++ u32 fe_status;
++ unsigned int led_state;
++
++ /* Analog settings */
++ struct v4l2_subdev sd;
++ v4l2_std_id std;
++ int vid_input;
++ int aud_input;
++ u32 id;
++ u32 rev;
++ u8 brightness;
++ u8 contrast;
++};
++
++/* These are routines shared by both the VSB/QAM demodulator and the analog
++ decoder */
++int au8522_writereg(struct au8522_state *state, u16 reg, u8 data);
++u8 au8522_readreg(struct au8522_state *state, u16 reg);
++int au8522_init(struct dvb_frontend *fe);
++int au8522_sleep(struct dvb_frontend *fe);
++
++int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
++ u8 client_address);
++void au8522_release_state(struct au8522_state *state);
++
++/* REGISTERS */
++#define AU8522_INPUT_CONTROL_REG081H 0x081
++#define AU8522_PGA_CONTROL_REG082H 0x082
++#define AU8522_CLAMPING_CONTROL_REG083H 0x083
++
++#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H 0x0A3
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H 0x0A4
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H 0x0A5
++#define AU8522_AGC_CONTROL_RANGE_REG0A6H 0x0A6
++#define AU8522_SYSTEM_GAIN_CONTROL_REG0A7H 0x0A7
++#define AU8522_TUNER_AGC_RF_STOP_REG0A8H 0x0A8
++#define AU8522_TUNER_AGC_RF_START_REG0A9H 0x0A9
++#define AU8522_TUNER_RF_AGC_DEFAULT_REG0AAH 0x0AA
++#define AU8522_TUNER_AGC_IF_STOP_REG0ABH 0x0AB
++#define AU8522_TUNER_AGC_IF_START_REG0ACH 0x0AC
++#define AU8522_TUNER_AGC_IF_DEFAULT_REG0ADH 0x0AD
++#define AU8522_TUNER_AGC_STEP_REG0AEH 0x0AE
++#define AU8522_TUNER_GAIN_STEP_REG0AFH 0x0AF
++
++/* Receiver registers */
++#define AU8522_FRMREGTHRD1_REG0B0H 0x0B0
++#define AU8522_FRMREGAGC1H_REG0B1H 0x0B1
++#define AU8522_FRMREGSHIFT1_REG0B2H 0x0B2
++#define AU8522_TOREGAGC1_REG0B3H 0x0B3
++#define AU8522_TOREGASHIFT1_REG0B4H 0x0B4
++#define AU8522_FRMREGBBH_REG0B5H 0x0B5
++#define AU8522_FRMREGBBM_REG0B6H 0x0B6
++#define AU8522_FRMREGBBL_REG0B7H 0x0B7
++/* 0xB8 TO 0xD7 are the filter coefficients */
++#define AU8522_FRMREGTHRD2_REG0D8H 0x0D8
++#define AU8522_FRMREGAGC2H_REG0D9H 0x0D9
++#define AU8522_TOREGAGC2_REG0DAH 0x0DA
++#define AU8522_TOREGSHIFT2_REG0DBH 0x0DB
++#define AU8522_FRMREGPILOTH_REG0DCH 0x0DC
++#define AU8522_FRMREGPILOTM_REG0DDH 0x0DD
++#define AU8522_FRMREGPILOTL_REG0DEH 0x0DE
++#define AU8522_TOREGFREQ_REG0DFH 0x0DF
++
++#define AU8522_RX_PGA_RFOUT_REG0EBH 0x0EB
++#define AU8522_RX_PGA_IFOUT_REG0ECH 0x0EC
++#define AU8522_RX_PGA_PGAOUT_REG0EDH 0x0ED
++
++#define AU8522_CHIP_MODE_REG0FEH 0x0FE
++
++/* I2C bus control registers */
++#define AU8522_I2C_CONTROL_REG0_REG090H 0x090
++#define AU8522_I2C_CONTROL_REG1_REG091H 0x091
++#define AU8522_I2C_STATUS_REG092H 0x092
++#define AU8522_I2C_WR_DATA0_REG093H 0x093
++#define AU8522_I2C_WR_DATA1_REG094H 0x094
++#define AU8522_I2C_WR_DATA2_REG095H 0x095
++#define AU8522_I2C_WR_DATA3_REG096H 0x096
++#define AU8522_I2C_WR_DATA4_REG097H 0x097
++#define AU8522_I2C_WR_DATA5_REG098H 0x098
++#define AU8522_I2C_WR_DATA6_REG099H 0x099
++#define AU8522_I2C_WR_DATA7_REG09AH 0x09A
++#define AU8522_I2C_RD_DATA0_REG09BH 0x09B
++#define AU8522_I2C_RD_DATA1_REG09CH 0x09C
++#define AU8522_I2C_RD_DATA2_REG09DH 0x09D
++#define AU8522_I2C_RD_DATA3_REG09EH 0x09E
++#define AU8522_I2C_RD_DATA4_REG09FH 0x09F
++#define AU8522_I2C_RD_DATA5_REG0A0H 0x0A0
++#define AU8522_I2C_RD_DATA6_REG0A1H 0x0A1
++#define AU8522_I2C_RD_DATA7_REG0A2H 0x0A2
++
++#define AU8522_ENA_USB_REG101H 0x101
++
++#define AU8522_I2S_CTRL_0_REG110H 0x110
++#define AU8522_I2S_CTRL_1_REG111H 0x111
++#define AU8522_I2S_CTRL_2_REG112H 0x112
++
++#define AU8522_FRMREGFFECONTROL_REG121H 0x121
++#define AU8522_FRMREGDFECONTROL_REG122H 0x122
++
++#define AU8522_CARRFREQOFFSET0_REG201H 0x201
++#define AU8522_CARRFREQOFFSET1_REG202H 0x202
++
++#define AU8522_DECIMATION_GAIN_REG21AH 0x21A
++#define AU8522_FRMREGIFSLP_REG21BH 0x21B
++#define AU8522_FRMREGTHRDL2_REG21CH 0x21C
++#define AU8522_FRMREGSTEP3DB_REG21DH 0x21D
++#define AU8522_DAGC_GAIN_ADJUSTMENT_REG21EH 0x21E
++#define AU8522_FRMREGPLLMODE_REG21FH 0x21F
++#define AU8522_FRMREGCSTHRD_REG220H 0x220
++#define AU8522_FRMREGCRLOCKDMAX_REG221H 0x221
++#define AU8522_FRMREGCRPERIODMASK_REG222H 0x222
++#define AU8522_FRMREGCRLOCK0THH_REG223H 0x223
++#define AU8522_FRMREGCRLOCK1THH_REG224H 0x224
++#define AU8522_FRMREGCRLOCK0THL_REG225H 0x225
++#define AU8522_FRMREGCRLOCK1THL_REG226H 0x226
++#define AU_FRMREGPLLACQPHASESCL_REG227H 0x227
++#define AU8522_FRMREGFREQFBCTRL_REG228H 0x228
++
++/* Analog TV Decoder */
++#define AU8522_TVDEC_STATUS_REG000H 0x000
++#define AU8522_TVDEC_INT_STATUS_REG001H 0x001
++#define AU8522_TVDEC_MACROVISION_STATUS_REG002H 0x002
++#define AU8522_TVDEC_SHARPNESSREG009H 0x009
++#define AU8522_TVDEC_BRIGHTNESS_REG00AH 0x00A
++#define AU8522_TVDEC_CONTRAST_REG00BH 0x00B
++#define AU8522_TVDEC_SATURATION_CB_REG00CH 0x00C
++#define AU8522_TVDEC_SATURATION_CR_REG00DH 0x00D
++#define AU8522_TVDEC_HUE_H_REG00EH 0x00E
++#define AU8522_TVDEC_HUE_L_REG00FH 0x00F
++#define AU8522_TVDEC_INT_MASK_REG010H 0x010
++#define AU8522_VIDEO_MODE_REG011H 0x011
++#define AU8522_TVDEC_PGA_REG012H 0x012
++#define AU8522_TVDEC_COMB_MODE_REG015H 0x015
++#define AU8522_REG016H 0x016
++#define AU8522_TVDED_DBG_MODE_REG060H 0x060
++#define AU8522_TVDEC_FORMAT_CTRL1_REG061H 0x061
++#define AU8522_TVDEC_FORMAT_CTRL2_REG062H 0x062
++#define AU8522_TVDEC_VCR_DET_LLIM_REG063H 0x063
++#define AU8522_TVDEC_VCR_DET_HLIM_REG064H 0x064
++#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H 0x065
++#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H 0x066
++#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H 0x067
++#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H 0x068
++#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H 0x069
++#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH 0x06A
++#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH 0x06B
++#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH 0x06C
++#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH 0x06D
++#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH 0x06E
++#define AU8522_TVDEC_UV_SEP_THR_REG06FH 0x06F
++#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H 0x070
++#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H 0x073
++#define AU8522_TVDEC_DCAGC_CTRL_REG077H 0x077
++#define AU8522_TVDEC_PIC_START_ADJ_REG078H 0x078
++#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H 0x079
++#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH 0x07A
++#define AU8522_TVDEC_INTRP_CTRL_REG07BH 0x07B
++#define AU8522_TVDEC_PLL_STATUS_REG07EH 0x07E
++#define AU8522_TVDEC_FSC_FREQ_REG07FH 0x07F
++
++#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H 0x0E4
++#define AU8522_TOREGAAGC_REG0E5H 0x0E5
++
++#define AU8522_TVDEC_CHROMA_AGC_REG401H 0x401
++#define AU8522_TVDEC_CHROMA_SFT_REG402H 0x402
++#define AU8522_FILTER_COEF_R410 0x410
++#define AU8522_FILTER_COEF_R411 0x411
++#define AU8522_FILTER_COEF_R412 0x412
++#define AU8522_FILTER_COEF_R413 0x413
++#define AU8522_FILTER_COEF_R414 0x414
++#define AU8522_FILTER_COEF_R415 0x415
++#define AU8522_FILTER_COEF_R416 0x416
++#define AU8522_FILTER_COEF_R417 0x417
++#define AU8522_FILTER_COEF_R418 0x418
++#define AU8522_FILTER_COEF_R419 0x419
++#define AU8522_FILTER_COEF_R41A 0x41A
++#define AU8522_FILTER_COEF_R41B 0x41B
++#define AU8522_FILTER_COEF_R41C 0x41C
++#define AU8522_FILTER_COEF_R41D 0x41D
++#define AU8522_FILTER_COEF_R41E 0x41E
++#define AU8522_FILTER_COEF_R41F 0x41F
++#define AU8522_FILTER_COEF_R420 0x420
++#define AU8522_FILTER_COEF_R421 0x421
++#define AU8522_FILTER_COEF_R422 0x422
++#define AU8522_FILTER_COEF_R423 0x423
++#define AU8522_FILTER_COEF_R424 0x424
++#define AU8522_FILTER_COEF_R425 0x425
++#define AU8522_FILTER_COEF_R426 0x426
++#define AU8522_FILTER_COEF_R427 0x427
++#define AU8522_FILTER_COEF_R428 0x428
++#define AU8522_FILTER_COEF_R429 0x429
++#define AU8522_FILTER_COEF_R42A 0x42A
++#define AU8522_FILTER_COEF_R42B 0x42B
++#define AU8522_FILTER_COEF_R42C 0x42C
++#define AU8522_FILTER_COEF_R42D 0x42D
++
++/* VBI Control Registers */
++#define AU8522_TVDEC_VBI_RX_FIFO_CONTAIN_REG004H 0x004
++#define AU8522_TVDEC_VBI_TX_FIFO_CONTAIN_REG005H 0x005
++#define AU8522_TVDEC_VBI_RX_FIFO_READ_REG006H 0x006
++#define AU8522_TVDEC_VBI_FIFO_STATUS_REG007H 0x007
++#define AU8522_TVDEC_VBI_CTRL_H_REG017H 0x017
++#define AU8522_TVDEC_VBI_CTRL_L_REG018H 0x018
++#define AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H 0x019
++#define AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH 0x01A
++#define AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH 0x01B
++#define AU8522_TVDEC_VBI_USER_THRESH1_REG01CH 0x01C
++#define AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH 0x01E
++#define AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH 0x01F
++#define AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H 0x020
++#define AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H 0x021
++#define AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H 0x022
++#define AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H 0x023
++
++#define AU8522_REG071H 0x071
++#define AU8522_REG072H 0x072
++#define AU8522_REG074H 0x074
++#define AU8522_REG075H 0x075
++
++/* Digital Demodulator Registers */
++#define AU8522_FRAME_COUNT0_REG084H 0x084
++#define AU8522_RS_STATUS_G0_REG085H 0x085
++#define AU8522_RS_STATUS_B0_REG086H 0x086
++#define AU8522_RS_STATUS_E_REG087H 0x087
++#define AU8522_DEMODULATION_STATUS_REG088H 0x088
++#define AU8522_TOREGTRESTATUS_REG0E6H 0x0E6
++#define AU8522_TSPORT_CONTROL_REG10BH 0x10B
++#define AU8522_TSTHES_REG10CH 0x10C
++#define AU8522_FRMREGDFEKEEP_REG301H 0x301
++#define AU8522_DFE_AVERAGE_REG302H 0x302
++#define AU8522_FRMREGEQLERRWIN_REG303H 0x303
++#define AU8522_FRMREGFFEKEEP_REG304H 0x304
++#define AU8522_FRMREGDFECONTROL1_REG305H 0x305
++#define AU8522_FRMREGEQLERRLOW_REG306H 0x306
++
++#define AU8522_REG42EH 0x42E
++#define AU8522_REG42FH 0x42F
++#define AU8522_REG430H 0x430
++#define AU8522_REG431H 0x431
++#define AU8522_REG432H 0x432
++#define AU8522_REG433H 0x433
++#define AU8522_REG434H 0x434
++#define AU8522_REG435H 0x435
++#define AU8522_REG436H 0x436
++
++/* GPIO Registers */
++#define AU8522_GPIO_CONTROL_REG0E0H 0x0E0
++#define AU8522_GPIO_STATUS_REG0E1H 0x0E1
++#define AU8522_GPIO_DATA_REG0E2H 0x0E2
++
++/* Audio Control Registers */
++#define AU8522_AUDIOAGC_REG0EEH 0x0EE
++#define AU8522_AUDIO_STATUS_REG0F0H 0x0F0
++#define AU8522_AUDIO_MODE_REG0F1H 0x0F1
++#define AU8522_AUDIO_VOLUME_L_REG0F2H 0x0F2
++#define AU8522_AUDIO_VOLUME_R_REG0F3H 0x0F3
++#define AU8522_AUDIO_VOLUME_REG0F4H 0x0F4
++#define AU8522_FRMREGAUPHASE_REG0F7H 0x0F7
++#define AU8522_REG0F9H 0x0F9
++
++#define AU8522_AUDIOAGC2_REG605H 0x605
++#define AU8522_AUDIOFREQ_REG606H 0x606
++
++
++/**************************************************************/
++
++#define AU8522_INPUT_CONTROL_REG081H_ATSC 0xC4
++#define AU8522_INPUT_CONTROL_REG081H_ATVRF 0xC4
++#define AU8522_INPUT_CONTROL_REG081H_ATVRF13 0xC4
++#define AU8522_INPUT_CONTROL_REG081H_J83B64 0xC4
++#define AU8522_INPUT_CONTROL_REG081H_J83B256 0xC4
++#define AU8522_INPUT_CONTROL_REG081H_CVBS 0x20
++#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH1 0xA2
++#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH2 0xA0
++#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH3 0x69
++#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4 0x68
++#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF 0x28
++/* CH1 AS Y,CH3 AS C */
++#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 0x23
++/* CH2 AS Y,CH4 AS C */
++#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24 0x20
++#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATSC 0x0C
++#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B64 0x09
++#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B256 0x09
++#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS 0x12
++#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF 0x1A
++#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF13 0x1A
++#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO 0x02
++
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CLEAR 0x00
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO 0x9C
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS 0x9D
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATSC 0xE8
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B256 0xCA
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B64 0xCA
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF 0xDD
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF13 0xDD
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_PAL 0xDD
++#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_FM 0xDD
++
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATSC 0x80
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B256 0x80
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B64 0x80
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_ATSC 0x40
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B256 0x40
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B64 0x40
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_CLEAR 0x00
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF 0x01
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF13 0x01
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_SVIDEO 0x04
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_CVBS 0x01
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PWM 0x03
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_IIS 0x09
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PAL 0x01
++#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_FM 0x01
++
++/* STILL NEED TO BE REFACTORED @@@@@@@@@@@@@@ */
++#define AU8522_TVDEC_CONTRAST_REG00BH_CVBS 0x79
++#define AU8522_TVDEC_SATURATION_CB_REG00CH_CVBS 0x80
++#define AU8522_TVDEC_SATURATION_CR_REG00DH_CVBS 0x80
++#define AU8522_TVDEC_HUE_H_REG00EH_CVBS 0x00
++#define AU8522_TVDEC_HUE_L_REG00FH_CVBS 0x00
++#define AU8522_TVDEC_PGA_REG012H_CVBS 0x0F
++#define AU8522_TVDEC_COMB_MODE_REG015H_CVBS 0x00
++#define AU8522_REG016H_CVBS 0x00
++#define AU8522_TVDED_DBG_MODE_REG060H_CVBS 0x00
++#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS 0x0B
++#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13 0x03
++#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13 0x00
++#define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS 0x19
++#define AU8522_REG0F9H_AUDIO 0x20
++#define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS 0xA7
++#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS 0x0A
++#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS 0x32
++#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS 0x19
++#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS 0x23
++#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS 0x41
++#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS 0x0A
++#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS 0x32
++#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS 0x34
++#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS 0x05
++#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS 0x6E
++#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS 0x0F
++#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS 0x80
++#define AU8522_REG071H_CVBS 0x18
++#define AU8522_REG072H_CVBS 0x30
++#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS 0xF0
++#define AU8522_REG074H_CVBS 0x80
++#define AU8522_REG075H_CVBS 0xF0
++#define AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS 0xFB
++#define AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS 0x04
++#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS 0x00
++#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS 0x00
++#define AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS 0xEE
++#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS 0xFE
++#define AU8522_TOREGAAGC_REG0E5H_CVBS 0x00
++#define AU8522_TVDEC_VBI6A_REG035H_CVBS 0x40
++
++/* Enables Closed captioning */
++#define AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON 0x21
+diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c
+index f6e7b03..e4fd533 100644
+--- a/drivers/media/dvb/frontends/cx24113.c
++++ b/drivers/media/dvb/frontends/cx24113.c
+@@ -559,7 +559,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
+ kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
+ int rc;
+ if (state == NULL) {
+- err("Unable to kmalloc\n");
++ err("Unable to kzalloc\n");
+ goto error;
+ }
+
+diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c
+index 28ad609..9b9f572 100644
+--- a/drivers/media/dvb/frontends/cx24116.c
++++ b/drivers/media/dvb/frontends/cx24116.c
+@@ -15,6 +15,9 @@
+ September, 9th 2008
+ Fixed locking on high symbol rates (>30000).
+ Implement MPEG initialization parameter.
++ January, 17th 2009
++ Fill set_voltage with actually control voltage code.
++ Correct set tone to not affect voltage.
+
+ 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
+@@ -146,7 +149,7 @@ enum cmds {
+ CMD_GETAGC = 0x19,
+ CMD_LNBCONFIG = 0x20,
+ CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
+- CMD_SET_TONEPRE = 0x22,
++ CMD_LNBDCLEVEL = 0x22,
+ CMD_SET_TONE = 0x23,
+ CMD_UPDFWVERS = 0x35,
+ CMD_TUNERSLEEP = 0x36,
+@@ -667,16 +670,6 @@ static int cx24116_load_firmware(struct dvb_frontend *fe,
+ return 0;
+ }
+
+-static int cx24116_set_voltage(struct dvb_frontend *fe,
+- fe_sec_voltage_t voltage)
+-{
+- /* The isl6421 module will override this function in the fops. */
+- dprintk("%s() This should never appear if the isl6421 module "
+- "is loaded correctly\n", __func__);
+-
+- return -EOPNOTSUPP;
+-}
+-
+ static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
+ {
+ struct cx24116_state *state = fe->demodulator_priv;
+@@ -837,6 +830,34 @@ static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
+ return -ETIMEDOUT; /* -EBUSY ? */
+ }
+
++static int cx24116_set_voltage(struct dvb_frontend *fe,
++ fe_sec_voltage_t voltage)
++{
++ struct cx24116_cmd cmd;
++ int ret;
++
++ dprintk("%s: %s\n", __func__,
++ voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
++ voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
++
++ /* Wait for LNB ready */
++ ret = cx24116_wait_for_lnb(fe);
++ if (ret != 0)
++ return ret;
++
++ /* Wait for voltage/min repeat delay */
++ msleep(100);
++
++ cmd.args[0x00] = CMD_LNBDCLEVEL;
++ cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
++ cmd.len = 0x02;
++
++ /* Min delay time before DiSEqC send */
++ msleep(15);
++
++ return cx24116_cmd_execute(fe, &cmd);
++}
++
+ static int cx24116_set_tone(struct dvb_frontend *fe,
+ fe_sec_tone_mode_t tone)
+ {
+@@ -857,14 +878,6 @@ static int cx24116_set_tone(struct dvb_frontend *fe,
+ /* Min delay time after DiSEqC send */
+ msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
+
+- /* This is always done before the tone is set */
+- cmd.args[0x00] = CMD_SET_TONEPRE;
+- cmd.args[0x01] = 0x00;
+- cmd.len = 0x02;
+- ret = cx24116_cmd_execute(fe, &cmd);
+- if (ret != 0)
+- return ret;
+-
+ /* Now we set the tone */
+ cmd.args[0x00] = CMD_SET_TONE;
+ cmd.args[0x01] = 0x00;
+@@ -1099,13 +1112,10 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
+ dprintk("%s\n", __func__);
+
+ /* allocate memory for the internal state */
+- state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
++ state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error1;
+
+- /* setup the state */
+- memset(state, 0, sizeof(struct cx24116_state));
+-
+ state->config = config;
+ state->i2c = i2c;
+
+@@ -1154,7 +1164,12 @@ static int cx24116_initfe(struct dvb_frontend *fe)
+ if (ret != 0)
+ return ret;
+
+- return cx24116_diseqc_init(fe);
++ ret = cx24116_diseqc_init(fe);
++ if (ret != 0)
++ return ret;
++
++ /* HVR-4000 needs this */
++ return cx24116_set_voltage(fe, SEC_VOLTAGE_13);
+ }
+
+ /*
+diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
+index 1a8c36f..0592f04 100644
+--- a/drivers/media/dvb/frontends/cx24123.c
++++ b/drivers/media/dvb/frontends/cx24123.c
+@@ -1069,13 +1069,13 @@ static struct dvb_frontend_ops cx24123_ops;
+ struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
+ struct i2c_adapter *i2c)
+ {
++ /* allocate memory for the internal state */
+ struct cx24123_state *state =
+ kzalloc(sizeof(struct cx24123_state), GFP_KERNEL);
+
+ dprintk("\n");
+- /* allocate memory for the internal state */
+ if (state == NULL) {
+- err("Unable to kmalloc\n");
++ err("Unable to kzalloc\n");
+ goto error;
+ }
+
+diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h
+index 21f2c51..9670f5d 100644
+--- a/drivers/media/dvb/frontends/dib0070.h
++++ b/drivers/media/dvb/frontends/dib0070.h
+@@ -58,6 +58,4 @@ static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+ }
+ #endif
+
+-extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
+-
+ #endif
+diff --git a/drivers/media/dvb/frontends/dib3000mc.h b/drivers/media/dvb/frontends/dib3000mc.h
+index 4142ed7..d75ffad 100644
+--- a/drivers/media/dvb/frontends/dib3000mc.h
++++ b/drivers/media/dvb/frontends/dib3000mc.h
+@@ -39,19 +39,43 @@ struct dib3000mc_config {
+ #define DEFAULT_DIB3000MC_I2C_ADDRESS 16
+ #define DEFAULT_DIB3000P_I2C_ADDRESS 24
+
+-#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE))
+-extern struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg);
++#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && \
++ defined(MODULE))
++extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap,
++ u8 i2c_addr,
++ struct dib3000mc_config *cfg);
++extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c,
++ int no_of_demods, u8 default_addr,
++ struct dib3000mc_config cfg[]);
++extern
++struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
++ int gating);
+ #else
+-static inline struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
++static inline
++struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
++ struct dib3000mc_config *cfg)
+ {
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+ }
+-#endif // CONFIG_DVB_DIB3000MC
+
+-extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]);
++static inline
++int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c,
++ int no_of_demods, u8 default_addr,
++ struct dib3000mc_config cfg[])
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return -ENODEV;
++}
+
+-extern struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating);
++static inline
++struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
++ int gating)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif // CONFIG_DVB_DIB3000MC
+
+ extern int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff);
+ extern int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff);
+diff --git a/drivers/media/dvb/frontends/dib7000m.h b/drivers/media/dvb/frontends/dib7000m.h
+index 597e9cc..113819c 100644
+--- a/drivers/media/dvb/frontends/dib7000m.h
++++ b/drivers/media/dvb/frontends/dib7000m.h
+@@ -38,8 +38,32 @@ struct dib7000m_config {
+
+ #define DEFAULT_DIB7000M_I2C_ADDRESS 18
+
+-extern struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg);
+-extern struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
++#if defined(CONFIG_DVB_DIB7000M) || (defined(CONFIG_DVB_DIB7000M_MODULE) && \
++ defined(MODULE))
++extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
++ u8 i2c_addr,
++ struct dib7000m_config *cfg);
++extern struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *,
++ enum dibx000_i2c_interface,
++ int);
++#else
++static inline
++struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
++ u8 i2c_addr, struct dib7000m_config *cfg)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++
++static inline
++struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *demod,
++ enum dibx000_i2c_interface intf,
++ int gating)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif
+
+ /* TODO
+ extern INT dib7000m_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
+diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
+index aab8112..02a4c82 100644
+--- a/drivers/media/dvb/frontends/dib7000p.h
++++ b/drivers/media/dvb/frontends/dib7000p.h
+@@ -37,7 +37,8 @@ struct dib7000p_config {
+
+ #define DEFAULT_DIB7000P_I2C_ADDRESS 18
+
+-#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && defined(MODULE))
++#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \
++ defined(MODULE))
+ extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ struct dib7000p_config *cfg);
+@@ -49,10 +50,11 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+ struct dib7000p_config cfg[]);
+ extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+ extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
++extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
+ #else
+-static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
+- u8 i2c_addr,
+- struct dib7000p_config *cfg)
++static inline
++struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
++ struct dib7000p_config *cfg)
+ {
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+@@ -60,36 +62,39 @@ static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
+
+ static inline
+ struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
+- enum dibx000_i2c_interface i, int x)
++ enum dibx000_i2c_interface i,
++ int x)
+ {
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+ }
+
+-static inline
+-int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+- int no_of_demods, u8 default_addr,
+- struct dib7000p_config cfg[])
++static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
++ int no_of_demods, u8 default_addr,
++ struct dib7000p_config cfg[])
+ {
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+ }
+
+-static inline
+-int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
++static inline int dib7000p_set_gpio(struct dvb_frontend *fe,
++ u8 num, u8 dir, u8 val)
+ {
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+ }
+
+-static inline
+-int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
++static inline int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+ {
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+ }
+-#endif
+
+-extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
++static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return -ENODEV;
++}
++#endif
+
+ #endif
+diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.h b/drivers/media/dvb/frontends/dvb_dummy_fe.h
+index 8210f19..1fcb987 100644
+--- a/drivers/media/dvb/frontends/dvb_dummy_fe.h
++++ b/drivers/media/dvb/frontends/dvb_dummy_fe.h
+@@ -25,8 +25,27 @@
+ #include <linux/dvb/frontend.h>
+ #include "dvb_frontend.h"
+
++#if defined(CONFIG_DVB_DUMMY_FE) || (defined(CONFIG_DVB_DUMMY_FE_MODULE) && \
++defined(MODULE))
+ extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void);
+ extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void);
+ extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void);
++#else
++static inline struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++static inline struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++static inline struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif /* CONFIG_DVB_DUMMY_FE */
+
+ #endif // DVB_DUMMY_FE_H
+diff --git a/drivers/media/dvb/frontends/itd1000_priv.h b/drivers/media/dvb/frontends/itd1000_priv.h
+index 8cdc54e..08ca851 100644
+--- a/drivers/media/dvb/frontends/itd1000_priv.h
++++ b/drivers/media/dvb/frontends/itd1000_priv.h
+@@ -31,7 +31,7 @@ struct itd1000_state {
+ /* ugly workaround for flexcop's incapable i2c-controller
+ * FIXME, if possible
+ */
+- u8 shadow[255];
++ u8 shadow[256];
+ };
+
+ enum itd1000_register {
+diff --git a/drivers/media/dvb/frontends/lgdt3304.c b/drivers/media/dvb/frontends/lgdt3304.c
+index 3bb0c43..eb72a98 100644
+--- a/drivers/media/dvb/frontends/lgdt3304.c
++++ b/drivers/media/dvb/frontends/lgdt3304.c
+@@ -363,7 +363,6 @@ struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
+
+ struct lgdt3304_state *state;
+ state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
+- memset(state, 0x0, sizeof(struct lgdt3304_state));
+ state->addr = config->i2c_address;
+ state->i2c = i2c;
+
+diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c
+new file mode 100644
+index 0000000..d92d055
+--- /dev/null
++++ b/drivers/media/dvb/frontends/lgdt3305.c
+@@ -0,0 +1,1087 @@
++/*
++ * Support for LGDT3305 - VSB/QAM
++ *
++ * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
++ *
++ * 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/dvb/frontend.h>
++#include "dvb_math.h"
++#include "lgdt3305.h"
++
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
++
++#define DBG_INFO 1
++#define DBG_REG 2
++
++#define lg_printk(kern, fmt, arg...) \
++ printk(kern "%s: " fmt, __func__, ##arg)
++
++#define lg_info(fmt, arg...) printk(KERN_INFO "lgdt3305: " fmt, ##arg)
++#define lg_warn(fmt, arg...) lg_printk(KERN_WARNING, fmt, ##arg)
++#define lg_err(fmt, arg...) lg_printk(KERN_ERR, fmt, ##arg)
++#define lg_dbg(fmt, arg...) if (debug & DBG_INFO) \
++ lg_printk(KERN_DEBUG, fmt, ##arg)
++#define lg_reg(fmt, arg...) if (debug & DBG_REG) \
++ lg_printk(KERN_DEBUG, fmt, ##arg)
++
++#define lg_fail(ret) \
++({ \
++ int __ret; \
++ __ret = (ret < 0); \
++ if (__ret) \
++ lg_err("error %d on line %d\n", ret, __LINE__); \
++ __ret; \
++})
++
++struct lgdt3305_state {
++ struct i2c_adapter *i2c_adap;
++ const struct lgdt3305_config *cfg;
++
++ struct dvb_frontend frontend;
++
++ fe_modulation_t current_modulation;
++ u32 current_frequency;
++ u32 snr;
++};
++
++/* ------------------------------------------------------------------------ */
++
++#define LGDT3305_GEN_CTRL_1 0x0000
++#define LGDT3305_GEN_CTRL_2 0x0001
++#define LGDT3305_GEN_CTRL_3 0x0002
++#define LGDT3305_GEN_STATUS 0x0003
++#define LGDT3305_GEN_CONTROL 0x0007
++#define LGDT3305_GEN_CTRL_4 0x000a
++#define LGDT3305_DGTL_AGC_REF_1 0x0012
++#define LGDT3305_DGTL_AGC_REF_2 0x0013
++#define LGDT3305_CR_CTR_FREQ_1 0x0106
++#define LGDT3305_CR_CTR_FREQ_2 0x0107
++#define LGDT3305_CR_CTR_FREQ_3 0x0108
++#define LGDT3305_CR_CTR_FREQ_4 0x0109
++#define LGDT3305_CR_MSE_1 0x011b
++#define LGDT3305_CR_MSE_2 0x011c
++#define LGDT3305_CR_LOCK_STATUS 0x011d
++#define LGDT3305_CR_CTRL_7 0x0126
++#define LGDT3305_AGC_POWER_REF_1 0x0300
++#define LGDT3305_AGC_POWER_REF_2 0x0301
++#define LGDT3305_AGC_DELAY_PT_1 0x0302
++#define LGDT3305_AGC_DELAY_PT_2 0x0303
++#define LGDT3305_RFAGC_LOOP_FLTR_BW_1 0x0306
++#define LGDT3305_RFAGC_LOOP_FLTR_BW_2 0x0307
++#define LGDT3305_IFBW_1 0x0308
++#define LGDT3305_IFBW_2 0x0309
++#define LGDT3305_AGC_CTRL_1 0x030c
++#define LGDT3305_AGC_CTRL_4 0x0314
++#define LGDT3305_EQ_MSE_1 0x0413
++#define LGDT3305_EQ_MSE_2 0x0414
++#define LGDT3305_EQ_MSE_3 0x0415
++#define LGDT3305_PT_MSE_1 0x0417
++#define LGDT3305_PT_MSE_2 0x0418
++#define LGDT3305_PT_MSE_3 0x0419
++#define LGDT3305_FEC_BLOCK_CTRL 0x0504
++#define LGDT3305_FEC_LOCK_STATUS 0x050a
++#define LGDT3305_FEC_PKT_ERR_1 0x050c
++#define LGDT3305_FEC_PKT_ERR_2 0x050d
++#define LGDT3305_TP_CTRL_1 0x050e
++#define LGDT3305_BERT_PERIOD 0x0801
++#define LGDT3305_BERT_ERROR_COUNT_1 0x080a
++#define LGDT3305_BERT_ERROR_COUNT_2 0x080b
++#define LGDT3305_BERT_ERROR_COUNT_3 0x080c
++#define LGDT3305_BERT_ERROR_COUNT_4 0x080d
++
++static int lgdt3305_write_reg(struct lgdt3305_state *state, u16 reg, u8 val)
++{
++ int ret;
++ u8 buf[] = { reg >> 8, reg & 0xff, val };
++ struct i2c_msg msg = {
++ .addr = state->cfg->i2c_addr, .flags = 0,
++ .buf = buf, .len = 3,
++ };
++
++ lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
++
++ ret = i2c_transfer(state->i2c_adap, &msg, 1);
++
++ if (ret != 1) {
++ lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
++ msg.buf[0], msg.buf[1], msg.buf[2], ret);
++ if (ret < 0)
++ return ret;
++ else
++ return -EREMOTEIO;
++ }
++ return 0;
++}
++
++static int lgdt3305_read_reg(struct lgdt3305_state *state, u16 reg, u8 *val)
++{
++ int ret;
++ u8 reg_buf[] = { reg >> 8, reg & 0xff };
++ struct i2c_msg msg[] = {
++ { .addr = state->cfg->i2c_addr,
++ .flags = 0, .buf = reg_buf, .len = 2 },
++ { .addr = state->cfg->i2c_addr,
++ .flags = I2C_M_RD, .buf = val, .len = 1 },
++ };
++
++ lg_reg("reg: 0x%04x\n", reg);
++
++ ret = i2c_transfer(state->i2c_adap, msg, 2);
++
++ if (ret != 2) {
++ lg_err("error (addr %02x reg %04x error (ret == %i)\n",
++ state->cfg->i2c_addr, reg, ret);
++ if (ret < 0)
++ return ret;
++ else
++ return -EREMOTEIO;
++ }
++ return 0;
++}
++
++#define read_reg(state, reg) \
++({ \
++ u8 __val; \
++ int ret = lgdt3305_read_reg(state, reg, &__val); \
++ if (lg_fail(ret)) \
++ __val = 0; \
++ __val; \
++})
++
++static int lgdt3305_set_reg_bit(struct lgdt3305_state *state,
++ u16 reg, int bit, int onoff)
++{
++ u8 val;
++ int ret;
++
++ lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
++
++ ret = lgdt3305_read_reg(state, reg, &val);
++ if (lg_fail(ret))
++ goto fail;
++
++ val &= ~(1 << bit);
++ val |= (onoff & 1) << bit;
++
++ ret = lgdt3305_write_reg(state, reg, val);
++fail:
++ return ret;
++}
++
++struct lgdt3305_reg {
++ u16 reg;
++ u8 val;
++};
++
++static int lgdt3305_write_regs(struct lgdt3305_state *state,
++ struct lgdt3305_reg *regs, int len)
++{
++ int i, ret;
++
++ lg_reg("writing %d registers...\n", len);
++
++ for (i = 0; i < len - 1; i++) {
++ ret = lgdt3305_write_reg(state, regs[i].reg, regs[i].val);
++ if (lg_fail(ret))
++ return ret;
++ }
++ return 0;
++}
++
++/* ------------------------------------------------------------------------ */
++
++static int lgdt3305_soft_reset(struct lgdt3305_state *state)
++{
++ int ret;
++
++ lg_dbg("\n");
++
++ ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 0);
++ if (lg_fail(ret))
++ goto fail;
++
++ msleep(20);
++ ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 1);
++fail:
++ return ret;
++}
++
++static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state,
++ enum lgdt3305_mpeg_mode mode)
++{
++ lg_dbg("(%d)\n", mode);
++ return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode);
++}
++
++static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state,
++ enum lgdt3305_tp_clock_edge edge,
++ enum lgdt3305_tp_valid_polarity valid)
++{
++ u8 val;
++ int ret;
++
++ lg_dbg("edge = %d, valid = %d\n", edge, valid);
++
++ ret = lgdt3305_read_reg(state, LGDT3305_TP_CTRL_1, &val);
++ if (lg_fail(ret))
++ goto fail;
++
++ val &= ~0x09;
++
++ if (edge)
++ val |= 0x08;
++ if (valid)
++ val |= 0x01;
++
++ ret = lgdt3305_write_reg(state, LGDT3305_TP_CTRL_1, val);
++ if (lg_fail(ret))
++ goto fail;
++
++ ret = lgdt3305_soft_reset(state);
++fail:
++ return ret;
++}
++
++static int lgdt3305_set_modulation(struct lgdt3305_state *state,
++ struct dvb_frontend_parameters *param)
++{
++ u8 opermode;
++ int ret;
++
++ lg_dbg("\n");
++
++ ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_1, &opermode);
++ if (lg_fail(ret))
++ goto fail;
++
++ opermode &= ~0x03;
++
++ switch (param->u.vsb.modulation) {
++ case VSB_8:
++ opermode |= 0x03;
++ break;
++ case QAM_64:
++ opermode |= 0x00;
++ break;
++ case QAM_256:
++ opermode |= 0x01;
++ break;
++ default:
++ return -EINVAL;
++ }
++ ret = lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_1, opermode);
++fail:
++ return ret;
++}
++
++static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,
++ struct dvb_frontend_parameters *param)
++{
++ int val;
++
++ switch (param->u.vsb.modulation) {
++ case VSB_8:
++ val = 0;
++ break;
++ case QAM_64:
++ case QAM_256:
++ val = 1;
++ break;
++ default:
++ return -EINVAL;
++ }
++ lg_dbg("val = %d\n", val);
++
++ return lgdt3305_set_reg_bit(state, 0x043f, 2, val);
++}
++
++/* ------------------------------------------------------------------------ */
++
++static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,
++ struct dvb_frontend_parameters *param)
++{
++ u16 agc_ref;
++
++ switch (param->u.vsb.modulation) {
++ case VSB_8:
++ agc_ref = 0x32c4;
++ break;
++ case QAM_64:
++ agc_ref = 0x2a00;
++ break;
++ case QAM_256:
++ agc_ref = 0x2a80;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ lg_dbg("agc ref: 0x%04x\n", agc_ref);
++
++ lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_1, agc_ref >> 8);
++ lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_2, agc_ref & 0xff);
++
++ return 0;
++}
++
++static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
++ struct dvb_frontend_parameters *param)
++{
++ u16 ifbw, rfbw, agcdelay;
++
++ switch (param->u.vsb.modulation) {
++ case VSB_8:
++ agcdelay = 0x04c0;
++ rfbw = 0x8000;
++ ifbw = 0x8000;
++ break;
++ case QAM_64:
++ case QAM_256:
++ agcdelay = 0x046b;
++ rfbw = 0x8889;
++ ifbw = 0x8888;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ if (state->cfg->rf_agc_loop) {
++ lg_dbg("agcdelay: 0x%04x, rfbw: 0x%04x\n", agcdelay, rfbw);
++
++ /* rf agc loop filter bandwidth */
++ lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_1,
++ agcdelay >> 8);
++ lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_2,
++ agcdelay & 0xff);
++
++ lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_1,
++ rfbw >> 8);
++ lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_2,
++ rfbw & 0xff);
++ } else {
++ lg_dbg("ifbw: 0x%04x\n", ifbw);
++
++ /* if agc loop filter bandwidth */
++ lgdt3305_write_reg(state, LGDT3305_IFBW_1, ifbw >> 8);
++ lgdt3305_write_reg(state, LGDT3305_IFBW_2, ifbw & 0xff);
++ }
++
++ return 0;
++}
++
++static int lgdt3305_agc_setup(struct lgdt3305_state *state,
++ struct dvb_frontend_parameters *param)
++{
++ int lockdten, acqen;
++
++ switch (param->u.vsb.modulation) {
++ case VSB_8:
++ lockdten = 0;
++ acqen = 0;
++ break;
++ case QAM_64:
++ case QAM_256:
++ lockdten = 1;
++ acqen = 1;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
++
++ /* control agc function */
++ lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
++ lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
++
++ return lgdt3305_rfagc_loop(state, param);
++}
++
++static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,
++ struct dvb_frontend_parameters *param)
++{
++ u16 usref = 0;
++
++ switch (param->u.vsb.modulation) {
++ case VSB_8:
++ if (state->cfg->usref_8vsb)
++ usref = state->cfg->usref_8vsb;
++ break;
++ case QAM_64:
++ if (state->cfg->usref_qam64)
++ usref = state->cfg->usref_qam64;
++ break;
++ case QAM_256:
++ if (state->cfg->usref_qam256)
++ usref = state->cfg->usref_qam256;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ if (usref) {
++ lg_dbg("set manual mode: 0x%04x\n", usref);
++
++ lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 3, 1);
++
++ lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_1,
++ 0xff & (usref >> 8));
++ lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_2,
++ 0xff & (usref >> 0));
++ }
++ return 0;
++}
++
++/* ------------------------------------------------------------------------ */
++
++static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,
++ struct dvb_frontend_parameters *param,
++ int inversion)
++{
++ int ret;
++
++ lg_dbg("(%d)\n", inversion);
++
++ switch (param->u.vsb.modulation) {
++ case VSB_8:
++ ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7,
++ inversion ? 0xf9 : 0x79);
++ break;
++ case QAM_64:
++ case QAM_256:
++ ret = lgdt3305_write_reg(state, LGDT3305_FEC_BLOCK_CTRL,
++ inversion ? 0xfd : 0xff);
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ return ret;
++}
++
++static int lgdt3305_set_if(struct lgdt3305_state *state,
++ struct dvb_frontend_parameters *param)
++{
++ u16 if_freq_khz;
++ u8 nco1, nco2, nco3, nco4;
++ u64 nco;
++
++ switch (param->u.vsb.modulation) {
++ case VSB_8:
++ if_freq_khz = state->cfg->vsb_if_khz;
++ break;
++ case QAM_64:
++ case QAM_256:
++ if_freq_khz = state->cfg->qam_if_khz;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ nco = if_freq_khz / 10;
++
++#define LGDT3305_64BIT_DIVISION_ENABLED 0
++ /* FIXME: 64bit division disabled to avoid linking error:
++ * WARNING: "__udivdi3" [lgdt3305.ko] undefined!
++ */
++ switch (param->u.vsb.modulation) {
++ case VSB_8:
++#if LGDT3305_64BIT_DIVISION_ENABLED
++ nco <<= 24;
++ nco /= 625;
++#else
++ nco *= ((1 << 24) / 625);
++#endif
++ break;
++ case QAM_64:
++ case QAM_256:
++#if LGDT3305_64BIT_DIVISION_ENABLED
++ nco <<= 28;
++ nco /= 625;
++#else
++ nco *= ((1 << 28) / 625);
++#endif
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ nco1 = (nco >> 24) & 0x3f;
++ nco1 |= 0x40;
++ nco2 = (nco >> 16) & 0xff;
++ nco3 = (nco >> 8) & 0xff;
++ nco4 = nco & 0xff;
++
++ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, nco1);
++ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, nco2);
++ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, nco3);
++ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, nco4);
++
++ lg_dbg("%d KHz -> [%02x%02x%02x%02x]\n",
++ if_freq_khz, nco1, nco2, nco3, nco4);
++
++ return 0;
++}
++
++/* ------------------------------------------------------------------------ */
++
++static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
++{
++ struct lgdt3305_state *state = fe->demodulator_priv;
++
++ if (state->cfg->deny_i2c_rptr)
++ return 0;
++
++ lg_dbg("(%d)\n", enable);
++
++ return lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_2, 5,
++ enable ? 0 : 1);
++}
++
++static int lgdt3305_sleep(struct dvb_frontend *fe)
++{
++ struct lgdt3305_state *state = fe->demodulator_priv;
++ u8 gen_ctrl_3, gen_ctrl_4;
++
++ lg_dbg("\n");
++
++ gen_ctrl_3 = read_reg(state, LGDT3305_GEN_CTRL_3);
++ gen_ctrl_4 = read_reg(state, LGDT3305_GEN_CTRL_4);
++
++ /* hold in software reset while sleeping */
++ gen_ctrl_3 &= ~0x01;
++ /* tristate the IF-AGC pin */
++ gen_ctrl_3 |= 0x02;
++ /* tristate the RF-AGC pin */
++ gen_ctrl_3 |= 0x04;
++
++ /* disable vsb/qam module */
++ gen_ctrl_4 &= ~0x01;
++ /* disable adc module */
++ gen_ctrl_4 &= ~0x02;
++
++ lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_3, gen_ctrl_3);
++ lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_4, gen_ctrl_4);
++
++ return 0;
++}
++
++static int lgdt3305_init(struct dvb_frontend *fe)
++{
++ struct lgdt3305_state *state = fe->demodulator_priv;
++ int ret;
++
++ static struct lgdt3305_reg lgdt3305_init_data[] = {
++ { .reg = LGDT3305_GEN_CTRL_1,
++ .val = 0x03, },
++ { .reg = LGDT3305_GEN_CTRL_2,
++ .val = 0xb0, },
++ { .reg = LGDT3305_GEN_CTRL_3,
++ .val = 0x01, },
++ { .reg = LGDT3305_GEN_CONTROL,
++ .val = 0x6f, },
++ { .reg = LGDT3305_GEN_CTRL_4,
++ .val = 0x03, },
++ { .reg = LGDT3305_DGTL_AGC_REF_1,
++ .val = 0x32, },
++ { .reg = LGDT3305_DGTL_AGC_REF_2,
++ .val = 0xc4, },
++ { .reg = LGDT3305_CR_CTR_FREQ_1,
++ .val = 0x00, },
++ { .reg = LGDT3305_CR_CTR_FREQ_2,
++ .val = 0x00, },
++ { .reg = LGDT3305_CR_CTR_FREQ_3,
++ .val = 0x00, },
++ { .reg = LGDT3305_CR_CTR_FREQ_4,
++ .val = 0x00, },
++ { .reg = LGDT3305_CR_CTRL_7,
++ .val = 0x79, },
++ { .reg = LGDT3305_AGC_POWER_REF_1,
++ .val = 0x32, },
++ { .reg = LGDT3305_AGC_POWER_REF_2,
++ .val = 0xc4, },
++ { .reg = LGDT3305_AGC_DELAY_PT_1,
++ .val = 0x0d, },
++ { .reg = LGDT3305_AGC_DELAY_PT_2,
++ .val = 0x30, },
++ { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1,
++ .val = 0x80, },
++ { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2,
++ .val = 0x00, },
++ { .reg = LGDT3305_IFBW_1,
++ .val = 0x80, },
++ { .reg = LGDT3305_IFBW_2,
++ .val = 0x00, },
++ { .reg = LGDT3305_AGC_CTRL_1,
++ .val = 0x30, },
++ { .reg = LGDT3305_AGC_CTRL_4,
++ .val = 0x61, },
++ { .reg = LGDT3305_FEC_BLOCK_CTRL,
++ .val = 0xff, },
++ { .reg = LGDT3305_TP_CTRL_1,
++ .val = 0x1b, },
++ };
++
++ lg_dbg("\n");
++
++ ret = lgdt3305_write_regs(state, lgdt3305_init_data,
++ ARRAY_SIZE(lgdt3305_init_data));
++ if (lg_fail(ret))
++ goto fail;
++
++ ret = lgdt3305_soft_reset(state);
++fail:
++ return ret;
++}
++
++static int lgdt3305_set_parameters(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *param)
++{
++ struct lgdt3305_state *state = fe->demodulator_priv;
++ int ret;
++
++ lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
++
++ if (fe->ops.tuner_ops.set_params) {
++ ret = fe->ops.tuner_ops.set_params(fe, param);
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++ if (lg_fail(ret))
++ goto fail;
++ state->current_frequency = param->frequency;
++ }
++
++ ret = lgdt3305_set_modulation(state, param);
++ if (lg_fail(ret))
++ goto fail;
++
++ ret = lgdt3305_passband_digital_agc(state, param);
++ if (lg_fail(ret))
++ goto fail;
++ ret = lgdt3305_set_agc_power_ref(state, param);
++ if (lg_fail(ret))
++ goto fail;
++ ret = lgdt3305_agc_setup(state, param);
++ if (lg_fail(ret))
++ goto fail;
++
++ /* low if */
++ ret = lgdt3305_write_reg(state, LGDT3305_GEN_CONTROL, 0x2f);
++ if (lg_fail(ret))
++ goto fail;
++ ret = lgdt3305_set_reg_bit(state, LGDT3305_CR_CTR_FREQ_1, 6, 1);
++ if (lg_fail(ret))
++ goto fail;
++
++ ret = lgdt3305_set_if(state, param);
++ if (lg_fail(ret))
++ goto fail;
++ ret = lgdt3305_spectral_inversion(state, param,
++ state->cfg->spectral_inversion
++ ? 1 : 0);
++ if (lg_fail(ret))
++ goto fail;
++
++ ret = lgdt3305_set_filter_extension(state, param);
++ if (lg_fail(ret))
++ goto fail;
++
++ state->current_modulation = param->u.vsb.modulation;
++
++ ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
++ if (lg_fail(ret))
++ goto fail;
++
++ /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
++ ret = lgdt3305_mpeg_mode_polarity(state,
++ state->cfg->tpclk_edge,
++ state->cfg->tpvalid_polarity);
++fail:
++ return ret;
++}
++
++static int lgdt3305_get_frontend(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *param)
++{
++ struct lgdt3305_state *state = fe->demodulator_priv;
++
++ lg_dbg("\n");
++
++ param->u.vsb.modulation = state->current_modulation;
++ param->frequency = state->current_frequency;
++ return 0;
++}
++
++/* ------------------------------------------------------------------------ */
++
++static int lgdt3305_read_cr_lock_status(struct lgdt3305_state *state,
++ int *locked)
++{
++ u8 val;
++ int ret;
++ char *cr_lock_state = "";
++
++ *locked = 0;
++
++ ret = lgdt3305_read_reg(state, LGDT3305_CR_LOCK_STATUS, &val);
++ if (lg_fail(ret))
++ goto fail;
++
++ switch (state->current_modulation) {
++ case QAM_256:
++ case QAM_64:
++ if (val & (1 << 1))
++ *locked = 1;
++
++ switch (val & 0x07) {
++ case 0:
++ cr_lock_state = "QAM UNLOCK";
++ break;
++ case 4:
++ cr_lock_state = "QAM 1stLock";
++ break;
++ case 6:
++ cr_lock_state = "QAM 2ndLock";
++ break;
++ case 7:
++ cr_lock_state = "QAM FinalLock";
++ break;
++ default:
++ cr_lock_state = "CLOCKQAM-INVALID!";
++ break;
++ }
++ break;
++ case VSB_8:
++ if (val & (1 << 7)) {
++ *locked = 1;
++ cr_lock_state = "CLOCKVSB";
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ lg_dbg("(%d) %s\n", *locked, cr_lock_state);
++fail:
++ return ret;
++}
++
++static int lgdt3305_read_fec_lock_status(struct lgdt3305_state *state,
++ int *locked)
++{
++ u8 val;
++ int ret, mpeg_lock, fec_lock, viterbi_lock;
++
++ *locked = 0;
++
++ switch (state->current_modulation) {
++ case QAM_256:
++ case QAM_64:
++ ret = lgdt3305_read_reg(state,
++ LGDT3305_FEC_LOCK_STATUS, &val);
++ if (lg_fail(ret))
++ goto fail;
++
++ mpeg_lock = (val & (1 << 0)) ? 1 : 0;
++ fec_lock = (val & (1 << 2)) ? 1 : 0;
++ viterbi_lock = (val & (1 << 3)) ? 1 : 0;
++
++ *locked = mpeg_lock && fec_lock && viterbi_lock;
++
++ lg_dbg("(%d) %s%s%s\n", *locked,
++ mpeg_lock ? "mpeg lock " : "",
++ fec_lock ? "fec lock " : "",
++ viterbi_lock ? "viterbi lock" : "");
++ break;
++ case VSB_8:
++ default:
++ ret = -EINVAL;
++ }
++fail:
++ return ret;
++}
++
++static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status)
++{
++ struct lgdt3305_state *state = fe->demodulator_priv;
++ u8 val;
++ int ret, signal, inlock, nofecerr, snrgood,
++ cr_lock, fec_lock, sync_lock;
++
++ *status = 0;
++
++ ret = lgdt3305_read_reg(state, LGDT3305_GEN_STATUS, &val);
++ if (lg_fail(ret))
++ goto fail;
++
++ signal = (val & (1 << 4)) ? 1 : 0;
++ inlock = (val & (1 << 3)) ? 0 : 1;
++ sync_lock = (val & (1 << 2)) ? 1 : 0;
++ nofecerr = (val & (1 << 1)) ? 1 : 0;
++ snrgood = (val & (1 << 0)) ? 1 : 0;
++
++ lg_dbg("%s%s%s%s%s\n",
++ signal ? "SIGNALEXIST " : "",
++ inlock ? "INLOCK " : "",
++ sync_lock ? "SYNCLOCK " : "",
++ nofecerr ? "NOFECERR " : "",
++ snrgood ? "SNRGOOD " : "");
++
++ ret = lgdt3305_read_cr_lock_status(state, &cr_lock);
++ if (lg_fail(ret))
++ goto fail;
++
++ if (signal)
++ *status |= FE_HAS_SIGNAL;
++ if (cr_lock)
++ *status |= FE_HAS_CARRIER;
++ if (nofecerr)
++ *status |= FE_HAS_VITERBI;
++ if (sync_lock)
++ *status |= FE_HAS_SYNC;
++
++ switch (state->current_modulation) {
++ case QAM_256:
++ case QAM_64:
++ ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
++ if (lg_fail(ret))
++ goto fail;
++
++ if (fec_lock)
++ *status |= FE_HAS_LOCK;
++ break;
++ case VSB_8:
++ if (inlock)
++ *status |= FE_HAS_LOCK;
++ break;
++ default:
++ ret = -EINVAL;
++ }
++fail:
++ return ret;
++}
++
++/* ------------------------------------------------------------------------ */
++
++/* borrowed from lgdt330x.c */
++static u32 calculate_snr(u32 mse, u32 c)
++{
++ if (mse == 0) /* no signal */
++ return 0;
++
++ mse = intlog10(mse);
++ if (mse > c) {
++ /* Negative SNR, which is possible, but realisticly the
++ demod will lose lock before the signal gets this bad. The
++ API only allows for unsigned values, so just return 0 */
++ return 0;
++ }
++ return 10*(c - mse);
++}
++
++static int lgdt3305_read_snr(struct dvb_frontend *fe, u16 *snr)
++{
++ struct lgdt3305_state *state = fe->demodulator_priv;
++ u32 noise; /* noise value */
++ u32 c; /* per-modulation SNR calculation constant */
++
++ switch (state->current_modulation) {
++ case VSB_8:
++#ifdef USE_PTMSE
++ /* Use Phase Tracker Mean-Square Error Register */
++ /* SNR for ranges from -13.11 to +44.08 */
++ noise = ((read_reg(state, LGDT3305_PT_MSE_1) & 0x07) << 16) |
++ (read_reg(state, LGDT3305_PT_MSE_2) << 8) |
++ (read_reg(state, LGDT3305_PT_MSE_3) & 0xff);
++ c = 73957994; /* log10(25*32^2)*2^24 */
++#else
++ /* Use Equalizer Mean-Square Error Register */
++ /* SNR for ranges from -16.12 to +44.08 */
++ noise = ((read_reg(state, LGDT3305_EQ_MSE_1) & 0x0f) << 16) |
++ (read_reg(state, LGDT3305_EQ_MSE_2) << 8) |
++ (read_reg(state, LGDT3305_EQ_MSE_3) & 0xff);
++ c = 73957994; /* log10(25*32^2)*2^24 */
++#endif
++ break;
++ case QAM_64:
++ case QAM_256:
++ noise = (read_reg(state, LGDT3305_CR_MSE_1) << 8) |
++ (read_reg(state, LGDT3305_CR_MSE_2) & 0xff);
++
++ c = (state->current_modulation == QAM_64) ?
++ 97939837 : 98026066;
++ /* log10(688128)*2^24 and log10(696320)*2^24 */
++ break;
++ default:
++ return -EINVAL;
++ }
++ state->snr = calculate_snr(noise, c);
++ /* report SNR in dB * 10 */
++ *snr = (state->snr / ((1 << 24) / 10));
++ lg_dbg("noise = 0x%08x, snr = %d.%02d dB\n", noise,
++ state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
++
++ return 0;
++}
++
++static int lgdt3305_read_signal_strength(struct dvb_frontend *fe,
++ u16 *strength)
++{
++ /* borrowed from lgdt330x.c
++ *
++ * Calculate strength from SNR up to 35dB
++ * Even though the SNR can go higher than 35dB,
++ * there is some comfort factor in having a range of
++ * strong signals that can show at 100%
++ */
++ struct lgdt3305_state *state = fe->demodulator_priv;
++ u16 snr;
++ int ret;
++
++ *strength = 0;
++
++ ret = fe->ops.read_snr(fe, &snr);
++ if (lg_fail(ret))
++ goto fail;
++ /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
++ /* scale the range 0 - 35*2^24 into 0 - 65535 */
++ if (state->snr >= 8960 * 0x10000)
++ *strength = 0xffff;
++ else
++ *strength = state->snr / 8960;
++fail:
++ return ret;
++}
++
++/* ------------------------------------------------------------------------ */
++
++static int lgdt3305_read_ber(struct dvb_frontend *fe, u32 *ber)
++{
++ *ber = 0;
++ return 0;
++}
++
++static int lgdt3305_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
++{
++ struct lgdt3305_state *state = fe->demodulator_priv;
++
++ *ucblocks =
++ (read_reg(state, LGDT3305_FEC_PKT_ERR_1) << 8) |
++ (read_reg(state, LGDT3305_FEC_PKT_ERR_2) & 0xff);
++
++ return 0;
++}
++
++static int lgdt3305_get_tune_settings(struct dvb_frontend *fe,
++ struct dvb_frontend_tune_settings
++ *fe_tune_settings)
++{
++ fe_tune_settings->min_delay_ms = 500;
++ lg_dbg("\n");
++ return 0;
++}
++
++static void lgdt3305_release(struct dvb_frontend *fe)
++{
++ struct lgdt3305_state *state = fe->demodulator_priv;
++ lg_dbg("\n");
++ kfree(state);
++}
++
++static struct dvb_frontend_ops lgdt3305_ops;
++
++struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
++ struct i2c_adapter *i2c_adap)
++{
++ struct lgdt3305_state *state = NULL;
++ int ret;
++ u8 val;
++
++ lg_dbg("(%d-%04x)\n",
++ i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
++ config ? config->i2c_addr : 0);
++
++ state = kzalloc(sizeof(struct lgdt3305_state), GFP_KERNEL);
++ if (state == NULL)
++ goto fail;
++
++ state->cfg = config;
++ state->i2c_adap = i2c_adap;
++
++ memcpy(&state->frontend.ops, &lgdt3305_ops,
++ sizeof(struct dvb_frontend_ops));
++ state->frontend.demodulator_priv = state;
++
++ /* verify that we're talking to a lg dt3305 */
++ ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
++ if ((lg_fail(ret)) | (val == 0))
++ goto fail;
++ ret = lgdt3305_write_reg(state, 0x0808, 0x80);
++ if (lg_fail(ret))
++ goto fail;
++ ret = lgdt3305_read_reg(state, 0x0808, &val);
++ if ((lg_fail(ret)) | (val != 0x80))
++ goto fail;
++ ret = lgdt3305_write_reg(state, 0x0808, 0x00);
++ if (lg_fail(ret))
++ goto fail;
++
++ state->current_frequency = -1;
++ state->current_modulation = -1;
++
++ return &state->frontend;
++fail:
++ lg_warn("unable to detect LGDT3305 hardware\n");
++ kfree(state);
++ return NULL;
++}
++EXPORT_SYMBOL(lgdt3305_attach);
++
++static struct dvb_frontend_ops lgdt3305_ops = {
++ .info = {
++ .name = "LG Electronics LGDT3305 VSB/QAM Frontend",
++ .type = FE_ATSC,
++ .frequency_min = 54000000,
++ .frequency_max = 858000000,
++ .frequency_stepsize = 62500,
++ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
++ },
++ .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl,
++ .init = lgdt3305_init,
++ .sleep = lgdt3305_sleep,
++ .set_frontend = lgdt3305_set_parameters,
++ .get_frontend = lgdt3305_get_frontend,
++ .get_tune_settings = lgdt3305_get_tune_settings,
++ .read_status = lgdt3305_read_status,
++ .read_ber = lgdt3305_read_ber,
++ .read_signal_strength = lgdt3305_read_signal_strength,
++ .read_snr = lgdt3305_read_snr,
++ .read_ucblocks = lgdt3305_read_ucblocks,
++ .release = lgdt3305_release,
++};
++
++MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver");
++MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
++MODULE_LICENSE("GPL");
++MODULE_VERSION("0.1");
++
++/*
++ * Local variables:
++ * c-basic-offset: 8
++ * End:
++ */
+diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
+new file mode 100644
+index 0000000..4fa6e52
+--- /dev/null
++++ b/drivers/media/dvb/frontends/lgdt3305.h
+@@ -0,0 +1,85 @@
++/*
++ * Support for LGDT3305 - VSB/QAM
++ *
++ * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
++ *
++ * 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 _LGDT3305_H_
++#define _LGDT3305_H_
++
++#include <linux/i2c.h>
++#include "dvb_frontend.h"
++
++
++enum lgdt3305_mpeg_mode {
++ LGDT3305_MPEG_PARALLEL = 0,
++ LGDT3305_MPEG_SERIAL = 1,
++};
++
++enum lgdt3305_tp_clock_edge {
++ LGDT3305_TPCLK_RISING_EDGE = 0,
++ LGDT3305_TPCLK_FALLING_EDGE = 1,
++};
++
++enum lgdt3305_tp_valid_polarity {
++ LGDT3305_TP_VALID_LOW = 0,
++ LGDT3305_TP_VALID_HIGH = 1,
++};
++
++struct lgdt3305_config {
++ u8 i2c_addr;
++
++ /* user defined IF frequency in KHz */
++ u16 qam_if_khz;
++ u16 vsb_if_khz;
++
++ /* AGC Power reference - defaults are used if left unset */
++ u16 usref_8vsb; /* default: 0x32c4 */
++ u16 usref_qam64; /* default: 0x5400 */
++ u16 usref_qam256; /* default: 0x2a80 */
++
++ /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
++ int deny_i2c_rptr:1;
++
++ /* spectral inversion - 0:disabled 1:enabled */
++ int spectral_inversion:1;
++
++ /* use RF AGC loop - 0:disabled 1:enabled */
++ int rf_agc_loop:1;
++
++ enum lgdt3305_mpeg_mode mpeg_mode;
++ enum lgdt3305_tp_clock_edge tpclk_edge;
++ enum lgdt3305_tp_valid_polarity tpvalid_polarity;
++};
++
++#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
++ defined(MODULE))
++extern
++struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
++ struct i2c_adapter *i2c_adap);
++#else
++static inline
++struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
++ struct i2c_adapter *i2c_adap)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif /* CONFIG_DVB_LGDT3305 */
++
++#endif /* _LGDT3305_H_ */
+diff --git a/drivers/media/dvb/frontends/lnbh24.h b/drivers/media/dvb/frontends/lnbh24.h
+new file mode 100644
+index 0000000..c059b16
+--- /dev/null
++++ b/drivers/media/dvb/frontends/lnbh24.h
+@@ -0,0 +1,55 @@
++/*
++ * lnbh24.h - driver for lnb supply and control ic lnbh24
++ *
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ *
++ * 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 _LNBH24_H
++#define _LNBH24_H
++
++/* system register bits */
++#define LNBH24_OLF 0x01
++#define LNBH24_OTF 0x02
++#define LNBH24_EN 0x04
++#define LNBH24_VSEL 0x08
++#define LNBH24_LLC 0x10
++#define LNBH24_TEN 0x20
++#define LNBH24_TTX 0x40
++#define LNBH24_PCL 0x80
++
++#include <linux/dvb/frontend.h>
++
++#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
++ && defined(MODULE))
++/* override_set and override_clear control which
++ system register bits (above) to always set & clear */
++extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, u8 override_set,
++ u8 override_clear, u8 i2c_addr);
++#else
++static inline struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, u8 override_set,
++ u8 override_clear, u8 i2c_addr)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif
++
++#endif
+diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
+index 76f935d..1dcc56f 100644
+--- a/drivers/media/dvb/frontends/lnbp21.c
++++ b/drivers/media/dvb/frontends/lnbp21.c
+@@ -1,7 +1,8 @@
+ /*
+- * lnbp21.h - driver for lnb supply and control ic lnbp21
++ * lnbp21.c - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -33,18 +34,21 @@
+
+ #include "dvb_frontend.h"
+ #include "lnbp21.h"
++#include "lnbh24.h"
+
+ struct lnbp21 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
++ u8 i2c_addr;
+ };
+
+-static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
++static int lnbp21_set_voltage(struct dvb_frontend *fe,
++ fe_sec_voltage_t voltage)
+ {
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
+- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
++ struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+@@ -72,7 +76,7 @@ static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+ {
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
+- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
++ struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+@@ -97,15 +101,18 @@ static void lnbp21_release(struct dvb_frontend *fe)
+ fe->sec_priv = NULL;
+ }
+
+-struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
++static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, u8 override_set,
++ u8 override_clear, u8 i2c_addr, u8 config)
+ {
+ struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+ if (!lnbp21)
+ return NULL;
+
+ /* default configuration */
+- lnbp21->config = LNBP21_ISEL;
++ lnbp21->config = config;
+ lnbp21->i2c = i2c;
++ lnbp21->i2c_addr = i2c_addr;
+ fe->sec_priv = lnbp21;
+
+ /* bits which should be forced to '1' */
+@@ -126,11 +133,29 @@ struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *
+ /* override frontend ops */
+ fe->ops.set_voltage = lnbp21_set_voltage;
+ fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
++ printk(KERN_INFO "LNBx2x attached on addr=%x", lnbp21->i2c_addr);
+
+ return fe;
+ }
++
++struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, u8 override_set,
++ u8 override_clear, u8 i2c_addr)
++{
++ return lnbx2x_attach(fe, i2c, override_set, override_clear,
++ i2c_addr, LNBH24_TTX);
++}
++EXPORT_SYMBOL(lnbh24_attach);
++
++struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, u8 override_set,
++ u8 override_clear)
++{
++ return lnbx2x_attach(fe, i2c, override_set, override_clear,
++ 0x08, LNBP21_ISEL);
++}
+ EXPORT_SYMBOL(lnbp21_attach);
+
+-MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21");
+-MODULE_AUTHOR("Oliver Endriss");
++MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24");
++MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
+index 8fe094b..fcdf1c6 100644
+--- a/drivers/media/dvb/frontends/lnbp21.h
++++ b/drivers/media/dvb/frontends/lnbp21.h
+@@ -28,26 +28,48 @@
+ #define _LNBP21_H
+
+ /* system register bits */
++/* [RO] 0=OK; 1=over current limit flag */
+ #define LNBP21_OLF 0x01
++/* [RO] 0=OK; 1=over temperature flag (150 C) */
+ #define LNBP21_OTF 0x02
++/* [RW] 0=disable LNB power, enable loopthrough
++ 1=enable LNB power, disable loopthrough */
+ #define LNBP21_EN 0x04
++/* [RW] 0=low voltage (13/14V, vert pol)
++ 1=high voltage (18/19V,horiz pol) */
+ #define LNBP21_VSEL 0x08
++/* [RW] increase LNB voltage by 1V:
++ 0=13/18V; 1=14/19V */
+ #define LNBP21_LLC 0x10
++/* [RW] 0=tone controlled by DSQIN pin
++ 1=tone enable, disable DSQIN */
+ #define LNBP21_TEN 0x20
++/* [RW] current limit select:
++ 0:Iout=500-650mA Isc=300mA
++ 1:Iout=400-550mA Isc=200mA */
+ #define LNBP21_ISEL 0x40
++/* [RW] short-circuit protect:
++ 0=pulsed (dynamic) curr limiting
++ 1=static curr limiting */
+ #define LNBP21_PCL 0x80
+
+ #include <linux/dvb/frontend.h>
+
+-#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) && defined(MODULE))
+-/* override_set and override_clear control which system register bits (above) to always set & clear */
+-extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
++#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
++ && defined(MODULE))
++/* override_set and override_clear control which
++ system register bits (above) to always set & clear */
++extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, u8 override_set,
++ u8 override_clear);
+ #else
+-static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
++static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
++ struct i2c_adapter *i2c, u8 override_set,
++ u8 override_clear)
+ {
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+ }
+-#endif // CONFIG_DVB_LNBP21
++#endif
+
+-#endif // _LNBP21_H
++#endif
+diff --git a/drivers/media/dvb/frontends/s921_module.c b/drivers/media/dvb/frontends/s921_module.c
+index 892af8c..3f5a0e1 100644
+--- a/drivers/media/dvb/frontends/s921_module.c
++++ b/drivers/media/dvb/frontends/s921_module.c
+@@ -169,7 +169,6 @@ struct dvb_frontend* s921_attach(const struct s921_config *config,
+
+ struct s921_state *state;
+ state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
+- memset(state, 0x0, sizeof(struct s921_state));
+
+ state->addr = config->i2c_address;
+ state->i2c = i2c;
+diff --git a/drivers/media/dvb/frontends/stb6100_cfg.h b/drivers/media/dvb/frontends/stb6100_cfg.h
+index d313340..6314d18 100644
+--- a/drivers/media/dvb/frontends/stb6100_cfg.h
++++ b/drivers/media/dvb/frontends/stb6100_cfg.h
+@@ -36,7 +36,6 @@ static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+ return err;
+ }
+ *frequency = t_state.frequency;
+- printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+ }
+ return 0;
+ }
+@@ -59,7 +58,6 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
+ return err;
+ }
+ }
+- printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+ return 0;
+ }
+
+@@ -81,7 +79,6 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+ }
+ *bandwidth = t_state.bandwidth;
+ }
+- printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
+ return 0;
+ }
+
+@@ -103,6 +100,5 @@ static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+ return err;
+ }
+ }
+- printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
+ return 0;
+ }
+diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb/frontends/stv0900.h
+new file mode 100644
+index 0000000..8a1332c
+--- /dev/null
++++ b/drivers/media/dvb/frontends/stv0900.h
+@@ -0,0 +1,62 @@
++/*
++ * stv0900.h
++ *
++ * Driver for ST STV0900 satellite demodulator IC.
++ *
++ * Copyright (C) ST Microelectronics.
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ *
++ * 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 STV0900_H
++#define STV0900_H
++
++#include <linux/dvb/frontend.h>
++#include "dvb_frontend.h"
++
++struct stv0900_config {
++ u8 demod_address;
++ u32 xtal;
++ u8 clkmode;/* 0 for CLKI, 2 for XTALI */
++
++ u8 diseqc_mode;
++
++ u8 path1_mode;
++ u8 path2_mode;
++
++ u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */
++ u8 tun2_maddress;
++ u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
++ u8 tun2_adc;
++};
++
++#if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \
++ && defined(MODULE))
++extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
++ struct i2c_adapter *i2c, int demod);
++#else
++static inline struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
++ struct i2c_adapter *i2c, int demod)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif
++
++#endif
++
+diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
+new file mode 100644
+index 0000000..8499bcf
+--- /dev/null
++++ b/drivers/media/dvb/frontends/stv0900_core.c
+@@ -0,0 +1,1949 @@
++/*
++ * stv0900_core.c
++ *
++ * Driver for ST STV0900 satellite demodulator IC.
++ *
++ * Copyright (C) ST Microelectronics.
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++
++#include "stv0900.h"
++#include "stv0900_reg.h"
++#include "stv0900_priv.h"
++#include "stv0900_init.h"
++
++static int stvdebug = 1;
++module_param_named(debug, stvdebug, int, 0644);
++
++/* internal params node */
++struct stv0900_inode {
++ /* pointer for internal params, one for each pair of demods */
++ struct stv0900_internal *internal;
++ struct stv0900_inode *next_inode;
++};
++
++/* first internal params */
++static struct stv0900_inode *stv0900_first_inode;
++
++/* find chip by i2c adapter and i2c address */
++static struct stv0900_inode *find_inode(struct i2c_adapter *i2c_adap,
++ u8 i2c_addr)
++{
++ struct stv0900_inode *temp_chip = stv0900_first_inode;
++
++ if (temp_chip != NULL) {
++ /*
++ Search of the last stv0900 chip or
++ find it by i2c adapter and i2c address */
++ while ((temp_chip != NULL) &&
++ ((temp_chip->internal->i2c_adap != i2c_adap) ||
++ (temp_chip->internal->i2c_addr != i2c_addr)))
++
++ temp_chip = temp_chip->next_inode;
++
++ }
++
++ return temp_chip;
++}
++
++/* deallocating chip */
++static void remove_inode(struct stv0900_internal *internal)
++{
++ struct stv0900_inode *prev_node = stv0900_first_inode;
++ struct stv0900_inode *del_node = find_inode(internal->i2c_adap,
++ internal->i2c_addr);
++
++ if (del_node != NULL) {
++ if (del_node == stv0900_first_inode) {
++ stv0900_first_inode = del_node->next_inode;
++ } else {
++ while (prev_node->next_inode != del_node)
++ prev_node = prev_node->next_inode;
++
++ if (del_node->next_inode == NULL)
++ prev_node->next_inode = NULL;
++ else
++ prev_node->next_inode =
++ prev_node->next_inode->next_inode;
++ }
++
++ kfree(del_node);
++ }
++}
++
++/* allocating new chip */
++static struct stv0900_inode *append_internal(struct stv0900_internal *internal)
++{
++ struct stv0900_inode *new_node = stv0900_first_inode;
++
++ if (new_node == NULL) {
++ new_node = kmalloc(sizeof(struct stv0900_inode), GFP_KERNEL);
++ stv0900_first_inode = new_node;
++ } else {
++ while (new_node->next_inode != NULL)
++ new_node = new_node->next_inode;
++
++ new_node->next_inode = kmalloc(sizeof(struct stv0900_inode), GFP_KERNEL);
++ if (new_node->next_inode != NULL)
++ new_node = new_node->next_inode;
++ else
++ new_node = NULL;
++ }
++
++ if (new_node != NULL) {
++ new_node->internal = internal;
++ new_node->next_inode = NULL;
++ }
++
++ return new_node;
++}
++
++s32 ge2comp(s32 a, s32 width)
++{
++ if (width == 32)
++ return a;
++ else
++ return (a >= (1 << (width - 1))) ? (a - (1 << width)) : a;
++}
++
++void stv0900_write_reg(struct stv0900_internal *i_params, u16 reg_addr,
++ u8 reg_data)
++{
++ u8 data[3];
++ int ret;
++ struct i2c_msg i2cmsg = {
++ .addr = i_params->i2c_addr,
++ .flags = 0,
++ .len = 3,
++ .buf = data,
++ };
++
++ data[0] = MSB(reg_addr);
++ data[1] = LSB(reg_addr);
++ data[2] = reg_data;
++
++ ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
++ if (ret != 1)
++ dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
++}
++
++u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg_addr)
++{
++ u8 data[2];
++ int ret;
++ struct i2c_msg i2cmsg = {
++ .addr = i_params->i2c_addr,
++ .flags = 0,
++ .len = 2,
++ .buf = data,
++ };
++
++ data[0] = MSB(reg_addr);
++ data[1] = LSB(reg_addr);
++
++ ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
++ if (ret != 1)
++ dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
++
++ i2cmsg.flags = I2C_M_RD;
++ i2cmsg.len = 1;
++ ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
++ if (ret != 1)
++ dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
++
++ return data[0];
++}
++
++void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
++{
++ u8 position = 0, i = 0;
++
++ (*mask) = label & 0xff;
++
++ while ((position == 0) && (i < 8)) {
++ position = ((*mask) >> i) & 0x01;
++ i++;
++ }
++
++ (*pos) = (i - 1);
++}
++
++void stv0900_write_bits(struct stv0900_internal *i_params, u32 label, u8 val)
++{
++ u8 reg, mask, pos;
++
++ reg = stv0900_read_reg(i_params, (label >> 16) & 0xffff);
++ extract_mask_pos(label, &mask, &pos);
++
++ val = mask & (val << pos);
++
++ reg = (reg & (~mask)) | val;
++ stv0900_write_reg(i_params, (label >> 16) & 0xffff, reg);
++
++}
++
++u8 stv0900_get_bits(struct stv0900_internal *i_params, u32 label)
++{
++ u8 val = 0xff;
++ u8 mask, pos;
++
++ extract_mask_pos(label, &mask, &pos);
++
++ val = stv0900_read_reg(i_params, label >> 16);
++ val = (val & mask) >> pos;
++
++ return val;
++}
++
++enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *i_params)
++{
++ s32 i;
++ enum fe_stv0900_error error;
++
++ if (i_params != NULL) {
++ i_params->chip_id = stv0900_read_reg(i_params, R0900_MID);
++ if (i_params->errs == STV0900_NO_ERROR) {
++ /*Startup sequence*/
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x5c);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5c);
++ stv0900_write_reg(i_params, R0900_P1_TNRCFG, 0x6c);
++ stv0900_write_reg(i_params, R0900_P2_TNRCFG, 0x6f);
++ stv0900_write_reg(i_params, R0900_P1_I2CRPT, 0x24);
++ stv0900_write_reg(i_params, R0900_P2_I2CRPT, 0x24);
++ stv0900_write_reg(i_params, R0900_NCOARSE, 0x13);
++ msleep(3);
++ stv0900_write_reg(i_params, R0900_I2CCFG, 0x08);
++
++ switch (i_params->clkmode) {
++ case 0:
++ case 2:
++ stv0900_write_reg(i_params, R0900_SYNTCTRL, 0x20
++ | i_params->clkmode);
++ break;
++ default:
++ /* preserve SELOSCI bit */
++ i = 0x02 & stv0900_read_reg(i_params, R0900_SYNTCTRL);
++ stv0900_write_reg(i_params, R0900_SYNTCTRL, 0x20 | i);
++ break;
++ }
++
++ msleep(3);
++ for (i = 0; i < 182; i++)
++ stv0900_write_reg(i_params, STV0900_InitVal[i][0], STV0900_InitVal[i][1]);
++
++ if (stv0900_read_reg(i_params, R0900_MID) >= 0x20) {
++ stv0900_write_reg(i_params, R0900_TSGENERAL, 0x0c);
++ for (i = 0; i < 32; i++)
++ stv0900_write_reg(i_params, STV0900_Cut20_AddOnVal[i][0], STV0900_Cut20_AddOnVal[i][1]);
++ }
++
++ stv0900_write_reg(i_params, R0900_P1_FSPYCFG, 0x6c);
++ stv0900_write_reg(i_params, R0900_P2_FSPYCFG, 0x6c);
++ stv0900_write_reg(i_params, R0900_TSTRES0, 0x80);
++ stv0900_write_reg(i_params, R0900_TSTRES0, 0x00);
++ }
++ error = i_params->errs;
++ } else
++ error = STV0900_INVALID_HANDLE;
++
++ return error;
++
++}
++
++u32 stv0900_get_mclk_freq(struct stv0900_internal *i_params, u32 ext_clk)
++{
++ u32 mclk = 90000000, div = 0, ad_div = 0;
++
++ div = stv0900_get_bits(i_params, F0900_M_DIV);
++ ad_div = ((stv0900_get_bits(i_params, F0900_SELX1RATIO) == 1) ? 4 : 6);
++
++ mclk = (div + 1) * ext_clk / ad_div;
++
++ dprintk(KERN_INFO "%s: Calculated Mclk = %d\n", __func__, mclk);
++
++ return mclk;
++}
++
++enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *i_params, u32 mclk)
++{
++ enum fe_stv0900_error error = STV0900_NO_ERROR;
++ u32 m_div, clk_sel;
++
++ dprintk(KERN_INFO "%s: Mclk set to %d, Quartz = %d\n", __func__, mclk,
++ i_params->quartz);
++
++ if (i_params == NULL)
++ error = STV0900_INVALID_HANDLE;
++ else {
++ if (i_params->errs)
++ error = STV0900_I2C_ERROR;
++ else {
++ clk_sel = ((stv0900_get_bits(i_params, F0900_SELX1RATIO) == 1) ? 4 : 6);
++ m_div = ((clk_sel * mclk) / i_params->quartz) - 1;
++ stv0900_write_bits(i_params, F0900_M_DIV, m_div);
++ i_params->mclk = stv0900_get_mclk_freq(i_params,
++ i_params->quartz);
++
++ /*Set the DiseqC frequency to 22KHz */
++ /*
++ Formula:
++ DiseqC_TX_Freq= MasterClock/(32*F22TX_Reg)
++ DiseqC_RX_Freq= MasterClock/(32*F22RX_Reg)
++ */
++ m_div = i_params->mclk / 704000;
++ stv0900_write_reg(i_params, R0900_P1_F22TX, m_div);
++ stv0900_write_reg(i_params, R0900_P1_F22RX, m_div);
++
++ stv0900_write_reg(i_params, R0900_P2_F22TX, m_div);
++ stv0900_write_reg(i_params, R0900_P2_F22RX, m_div);
++
++ if ((i_params->errs))
++ error = STV0900_I2C_ERROR;
++ }
++ }
++
++ return error;
++}
++
++u32 stv0900_get_err_count(struct stv0900_internal *i_params, int cntr,
++ enum fe_stv0900_demod_num demod)
++{
++ u32 lsb, msb, hsb, err_val;
++ s32 err1field_hsb, err1field_msb, err1field_lsb;
++ s32 err2field_hsb, err2field_msb, err2field_lsb;
++
++ dmd_reg(err1field_hsb, F0900_P1_ERR_CNT12, F0900_P2_ERR_CNT12);
++ dmd_reg(err1field_msb, F0900_P1_ERR_CNT11, F0900_P2_ERR_CNT11);
++ dmd_reg(err1field_lsb, F0900_P1_ERR_CNT10, F0900_P2_ERR_CNT10);
++
++ dmd_reg(err2field_hsb, F0900_P1_ERR_CNT22, F0900_P2_ERR_CNT22);
++ dmd_reg(err2field_msb, F0900_P1_ERR_CNT21, F0900_P2_ERR_CNT21);
++ dmd_reg(err2field_lsb, F0900_P1_ERR_CNT20, F0900_P2_ERR_CNT20);
++
++ switch (cntr) {
++ case 0:
++ default:
++ hsb = stv0900_get_bits(i_params, err1field_hsb);
++ msb = stv0900_get_bits(i_params, err1field_msb);
++ lsb = stv0900_get_bits(i_params, err1field_lsb);
++ break;
++ case 1:
++ hsb = stv0900_get_bits(i_params, err2field_hsb);
++ msb = stv0900_get_bits(i_params, err2field_msb);
++ lsb = stv0900_get_bits(i_params, err2field_lsb);
++ break;
++ }
++
++ err_val = (hsb << 16) + (msb << 8) + (lsb);
++
++ return err_val;
++}
++
++static int stv0900_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++
++ u32 fi2c;
++
++ dmd_reg(fi2c, F0900_P1_I2CT_ON, F0900_P2_I2CT_ON);
++ if (enable)
++ stv0900_write_bits(i_params, fi2c, 1);
++
++ return 0;
++}
++
++static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params,
++ enum fe_stv0900_clock_type path1_ts,
++ enum fe_stv0900_clock_type path2_ts)
++{
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ if (i_params->chip_id >= 0x20) {
++ switch (path1_ts) {
++ case STV0900_PARALLEL_PUNCT_CLOCK:
++ case STV0900_DVBCI_CLOCK:
++ switch (path2_ts) {
++ case STV0900_SERIAL_PUNCT_CLOCK:
++ case STV0900_SERIAL_CONT_CLOCK:
++ default:
++ stv0900_write_reg(i_params, R0900_TSGENERAL,
++ 0x00);
++ break;
++ case STV0900_PARALLEL_PUNCT_CLOCK:
++ case STV0900_DVBCI_CLOCK:
++ stv0900_write_reg(i_params, R0900_TSGENERAL,
++ 0x06);
++ stv0900_write_bits(i_params,
++ F0900_P1_TSFIFO_MANSPEED, 3);
++ stv0900_write_bits(i_params,
++ F0900_P2_TSFIFO_MANSPEED, 0);
++ stv0900_write_reg(i_params,
++ R0900_P1_TSSPEED, 0x14);
++ stv0900_write_reg(i_params,
++ R0900_P2_TSSPEED, 0x28);
++ break;
++ }
++ break;
++ case STV0900_SERIAL_PUNCT_CLOCK:
++ case STV0900_SERIAL_CONT_CLOCK:
++ default:
++ switch (path2_ts) {
++ case STV0900_SERIAL_PUNCT_CLOCK:
++ case STV0900_SERIAL_CONT_CLOCK:
++ default:
++ stv0900_write_reg(i_params,
++ R0900_TSGENERAL, 0x0C);
++ break;
++ case STV0900_PARALLEL_PUNCT_CLOCK:
++ case STV0900_DVBCI_CLOCK:
++ stv0900_write_reg(i_params,
++ R0900_TSGENERAL, 0x0A);
++ dprintk(KERN_INFO "%s: 0x0a\n", __func__);
++ break;
++ }
++ break;
++ }
++ } else {
++ switch (path1_ts) {
++ case STV0900_PARALLEL_PUNCT_CLOCK:
++ case STV0900_DVBCI_CLOCK:
++ switch (path2_ts) {
++ case STV0900_SERIAL_PUNCT_CLOCK:
++ case STV0900_SERIAL_CONT_CLOCK:
++ default:
++ stv0900_write_reg(i_params, R0900_TSGENERAL1X,
++ 0x10);
++ break;
++ case STV0900_PARALLEL_PUNCT_CLOCK:
++ case STV0900_DVBCI_CLOCK:
++ stv0900_write_reg(i_params, R0900_TSGENERAL1X,
++ 0x16);
++ stv0900_write_bits(i_params,
++ F0900_P1_TSFIFO_MANSPEED, 3);
++ stv0900_write_bits(i_params,
++ F0900_P2_TSFIFO_MANSPEED, 0);
++ stv0900_write_reg(i_params, R0900_P1_TSSPEED,
++ 0x14);
++ stv0900_write_reg(i_params, R0900_P2_TSSPEED,
++ 0x28);
++ break;
++ }
++
++ break;
++ case STV0900_SERIAL_PUNCT_CLOCK:
++ case STV0900_SERIAL_CONT_CLOCK:
++ default:
++ switch (path2_ts) {
++ case STV0900_SERIAL_PUNCT_CLOCK:
++ case STV0900_SERIAL_CONT_CLOCK:
++ default:
++ stv0900_write_reg(i_params, R0900_TSGENERAL1X,
++ 0x14);
++ break;
++ case STV0900_PARALLEL_PUNCT_CLOCK:
++ case STV0900_DVBCI_CLOCK:
++ stv0900_write_reg(i_params, R0900_TSGENERAL1X,
++ 0x12);
++ dprintk(KERN_INFO "%s: 0x12\n", __func__);
++ break;
++ }
++
++ break;
++ }
++ }
++
++ switch (path1_ts) {
++ case STV0900_PARALLEL_PUNCT_CLOCK:
++ stv0900_write_bits(i_params, F0900_P1_TSFIFO_SERIAL, 0x00);
++ stv0900_write_bits(i_params, F0900_P1_TSFIFO_DVBCI, 0x00);
++ break;
++ case STV0900_DVBCI_CLOCK:
++ stv0900_write_bits(i_params, F0900_P1_TSFIFO_SERIAL, 0x00);
++ stv0900_write_bits(i_params, F0900_P1_TSFIFO_DVBCI, 0x01);
++ break;
++ case STV0900_SERIAL_PUNCT_CLOCK:
++ stv0900_write_bits(i_params, F0900_P1_TSFIFO_SERIAL, 0x01);
++ stv0900_write_bits(i_params, F0900_P1_TSFIFO_DVBCI, 0x00);
++ break;
++ case STV0900_SERIAL_CONT_CLOCK:
++ stv0900_write_bits(i_params, F0900_P1_TSFIFO_SERIAL, 0x01);
++ stv0900_write_bits(i_params, F0900_P1_TSFIFO_DVBCI, 0x01);
++ break;
++ default:
++ break;
++ }
++
++ switch (path2_ts) {
++ case STV0900_PARALLEL_PUNCT_CLOCK:
++ stv0900_write_bits(i_params, F0900_P2_TSFIFO_SERIAL, 0x00);
++ stv0900_write_bits(i_params, F0900_P2_TSFIFO_DVBCI, 0x00);
++ break;
++ case STV0900_DVBCI_CLOCK:
++ stv0900_write_bits(i_params, F0900_P2_TSFIFO_SERIAL, 0x00);
++ stv0900_write_bits(i_params, F0900_P2_TSFIFO_DVBCI, 0x01);
++ break;
++ case STV0900_SERIAL_PUNCT_CLOCK:
++ stv0900_write_bits(i_params, F0900_P2_TSFIFO_SERIAL, 0x01);
++ stv0900_write_bits(i_params, F0900_P2_TSFIFO_DVBCI, 0x00);
++ break;
++ case STV0900_SERIAL_CONT_CLOCK:
++ stv0900_write_bits(i_params, F0900_P2_TSFIFO_SERIAL, 0x01);
++ stv0900_write_bits(i_params, F0900_P2_TSFIFO_DVBCI, 0x01);
++ break;
++ default:
++ break;
++ }
++
++ stv0900_write_bits(i_params, F0900_P2_RST_HWARE, 1);
++ stv0900_write_bits(i_params, F0900_P2_RST_HWARE, 0);
++ stv0900_write_bits(i_params, F0900_P1_RST_HWARE, 1);
++ stv0900_write_bits(i_params, F0900_P1_RST_HWARE, 0);
++}
++
++void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
++ u32 bandwidth)
++{
++ struct dvb_frontend_ops *frontend_ops = NULL;
++ struct dvb_tuner_ops *tuner_ops = NULL;
++
++ if (&fe->ops)
++ frontend_ops = &fe->ops;
++
++ if (&frontend_ops->tuner_ops)
++ tuner_ops = &frontend_ops->tuner_ops;
++
++ if (tuner_ops->set_frequency) {
++ if ((tuner_ops->set_frequency(fe, frequency)) < 0)
++ dprintk("%s: Invalid parameter\n", __func__);
++ else
++ dprintk("%s: Frequency=%d\n", __func__, frequency);
++
++ }
++
++ if (tuner_ops->set_bandwidth) {
++ if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
++ dprintk("%s: Invalid parameter\n", __func__);
++ else
++ dprintk("%s: Bandwidth=%d\n", __func__, bandwidth);
++
++ }
++}
++
++void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
++{
++ struct dvb_frontend_ops *frontend_ops = NULL;
++ struct dvb_tuner_ops *tuner_ops = NULL;
++
++ if (&fe->ops)
++ frontend_ops = &fe->ops;
++
++ if (&frontend_ops->tuner_ops)
++ tuner_ops = &frontend_ops->tuner_ops;
++
++ if (tuner_ops->set_bandwidth) {
++ if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
++ dprintk("%s: Invalid parameter\n", __func__);
++ else
++ dprintk("%s: Bandwidth=%d\n", __func__, bandwidth);
++
++ }
++}
++
++static s32 stv0900_get_rf_level(struct stv0900_internal *i_params,
++ const struct stv0900_table *lookup,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 agc_gain = 0,
++ imin,
++ imax,
++ i,
++ rf_lvl = 0;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ if ((lookup != NULL) && lookup->size) {
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ agc_gain = MAKEWORD(stv0900_get_bits(i_params, F0900_P1_AGCIQ_VALUE1),
++ stv0900_get_bits(i_params, F0900_P1_AGCIQ_VALUE0));
++ break;
++ case STV0900_DEMOD_2:
++ agc_gain = MAKEWORD(stv0900_get_bits(i_params, F0900_P2_AGCIQ_VALUE1),
++ stv0900_get_bits(i_params, F0900_P2_AGCIQ_VALUE0));
++ break;
++ }
++
++ imin = 0;
++ imax = lookup->size - 1;
++ if (INRANGE(lookup->table[imin].regval, agc_gain, lookup->table[imax].regval)) {
++ while ((imax - imin) > 1) {
++ i = (imax + imin) >> 1;
++
++ if (INRANGE(lookup->table[imin].regval, agc_gain, lookup->table[i].regval))
++ imax = i;
++ else
++ imin = i;
++ }
++
++ rf_lvl = (((s32)agc_gain - lookup->table[imin].regval)
++ * (lookup->table[imax].realval - lookup->table[imin].realval)
++ / (lookup->table[imax].regval - lookup->table[imin].regval))
++ + lookup->table[imin].realval;
++ } else if (agc_gain > lookup->table[0].regval)
++ rf_lvl = 5;
++ else if (agc_gain < lookup->table[lookup->size-1].regval)
++ rf_lvl = -100;
++
++ }
++
++ dprintk(KERN_INFO "%s: RFLevel = %d\n", __func__, rf_lvl);
++
++ return rf_lvl;
++}
++
++static int stv0900_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *internal = state->internal;
++ s32 rflevel = stv0900_get_rf_level(internal, &stv0900_rf,
++ state->demod);
++
++ *strength = (rflevel + 100) * (16383 / 105);
++
++ return 0;
++}
++
++
++static s32 stv0900_carr_get_quality(struct dvb_frontend *fe,
++ const struct stv0900_table *lookup)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++
++ s32 c_n = -100,
++ regval, imin, imax,
++ i,
++ lock_flag_field,
++ noise_field1,
++ noise_field0;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ dmd_reg(lock_flag_field, F0900_P1_LOCK_DEFINITIF,
++ F0900_P2_LOCK_DEFINITIF);
++ if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) {
++ dmd_reg(noise_field1, F0900_P1_NOSPLHT_NORMED1,
++ F0900_P2_NOSPLHT_NORMED1);
++ dmd_reg(noise_field0, F0900_P1_NOSPLHT_NORMED0,
++ F0900_P2_NOSPLHT_NORMED0);
++ } else {
++ dmd_reg(noise_field1, F0900_P1_NOSDATAT_NORMED1,
++ F0900_P2_NOSDATAT_NORMED1);
++ dmd_reg(noise_field0, F0900_P1_NOSDATAT_NORMED0,
++ F0900_P2_NOSDATAT_NORMED0);
++ }
++
++ if (stv0900_get_bits(i_params, lock_flag_field)) {
++ if ((lookup != NULL) && lookup->size) {
++ regval = 0;
++ msleep(5);
++ for (i = 0; i < 16; i++) {
++ regval += MAKEWORD(stv0900_get_bits(i_params,
++ noise_field1),
++ stv0900_get_bits(i_params,
++ noise_field0));
++ msleep(1);
++ }
++
++ regval /= 16;
++ imin = 0;
++ imax = lookup->size - 1;
++ if (INRANGE(lookup->table[imin].regval,
++ regval,
++ lookup->table[imax].regval)) {
++ while ((imax - imin) > 1) {
++ i = (imax + imin) >> 1;
++ if (INRANGE(lookup->table[imin].regval,
++ regval,
++ lookup->table[i].regval))
++ imax = i;
++ else
++ imin = i;
++ }
++
++ c_n = ((regval - lookup->table[imin].regval)
++ * (lookup->table[imax].realval
++ - lookup->table[imin].realval)
++ / (lookup->table[imax].regval
++ - lookup->table[imin].regval))
++ + lookup->table[imin].realval;
++ } else if (regval < lookup->table[imin].regval)
++ c_n = 1000;
++ }
++ }
++
++ return c_n;
++}
++
++static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr)
++{
++ *snr = stv0900_carr_get_quality(fe,
++ (const struct stv0900_table *)&stv0900_s2_cn);
++ *snr += 30;
++ *snr *= (16383 / 1030);
++
++ return 0;
++}
++
++static u32 stv0900_get_ber(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ u32 ber = 10000000, i;
++ s32 dmd_state_reg;
++ s32 demod_state;
++ s32 vstatus_reg;
++ s32 prvit_field;
++ s32 pdel_status_reg;
++ s32 pdel_lock_field;
++
++ dmd_reg(dmd_state_reg, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
++ dmd_reg(vstatus_reg, R0900_P1_VSTATUSVIT, R0900_P2_VSTATUSVIT);
++ dmd_reg(prvit_field, F0900_P1_PRFVIT, F0900_P2_PRFVIT);
++ dmd_reg(pdel_status_reg, R0900_P1_PDELSTATUS1, R0900_P2_PDELSTATUS1);
++ dmd_reg(pdel_lock_field, F0900_P1_PKTDELIN_LOCK,
++ F0900_P2_PKTDELIN_LOCK);
++
++ demod_state = stv0900_get_bits(i_params, dmd_state_reg);
++
++ switch (demod_state) {
++ case STV0900_SEARCH:
++ case STV0900_PLH_DETECTED:
++ default:
++ ber = 10000000;
++ break;
++ case STV0900_DVBS_FOUND:
++ ber = 0;
++ for (i = 0; i < 5; i++) {
++ msleep(5);
++ ber += stv0900_get_err_count(i_params, 0, demod);
++ }
++
++ ber /= 5;
++ if (stv0900_get_bits(i_params, prvit_field)) {
++ ber *= 9766;
++ ber = ber >> 13;
++ }
++
++ break;
++ case STV0900_DVBS2_FOUND:
++ ber = 0;
++ for (i = 0; i < 5; i++) {
++ msleep(5);
++ ber += stv0900_get_err_count(i_params, 0, demod);
++ }
++
++ ber /= 5;
++ if (stv0900_get_bits(i_params, pdel_lock_field)) {
++ ber *= 9766;
++ ber = ber >> 13;
++ }
++
++ break;
++ }
++
++ return ber;
++}
++
++static int stv0900_read_ber(struct dvb_frontend *fe, u32 *ber)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *internal = state->internal;
++
++ *ber = stv0900_get_ber(internal, state->demod);
++
++ return 0;
++}
++
++int stv0900_get_demod_lock(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod, s32 time_out)
++{
++ s32 timer = 0,
++ lock = 0,
++ header_field,
++ lock_field;
++
++ enum fe_stv0900_search_state dmd_state;
++
++ dmd_reg(header_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
++ dmd_reg(lock_field, F0900_P1_LOCK_DEFINITIF, F0900_P2_LOCK_DEFINITIF);
++ while ((timer < time_out) && (lock == 0)) {
++ dmd_state = stv0900_get_bits(i_params, header_field);
++ dprintk("Demod State = %d\n", dmd_state);
++ switch (dmd_state) {
++ case STV0900_SEARCH:
++ case STV0900_PLH_DETECTED:
++ default:
++ lock = 0;
++ break;
++ case STV0900_DVBS2_FOUND:
++ case STV0900_DVBS_FOUND:
++ lock = stv0900_get_bits(i_params, lock_field);
++ break;
++ }
++
++ if (lock == 0)
++ msleep(10);
++
++ timer += 10;
++ }
++
++ if (lock)
++ dprintk("DEMOD LOCK OK\n");
++ else
++ dprintk("DEMOD LOCK FAIL\n");
++
++ return lock;
++}
++
++void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 regflist,
++ i;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ dmd_reg(regflist, R0900_P1_MODCODLST0, R0900_P2_MODCODLST0);
++
++ for (i = 0; i < 16; i++)
++ stv0900_write_reg(i_params, regflist + i, 0xff);
++}
++
++void stv0900_activate_s2_modcode(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ u32 matype,
++ mod_code,
++ fmod,
++ reg_index,
++ field_index;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ if (i_params->chip_id <= 0x11) {
++ msleep(5);
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ mod_code = stv0900_read_reg(i_params,
++ R0900_P1_PLHMODCOD);
++ matype = mod_code & 0x3;
++ mod_code = (mod_code & 0x7f) >> 2;
++
++ reg_index = R0900_P1_MODCODLSTF - mod_code / 2;
++ field_index = mod_code % 2;
++ break;
++ case STV0900_DEMOD_2:
++ mod_code = stv0900_read_reg(i_params,
++ R0900_P2_PLHMODCOD);
++ matype = mod_code & 0x3;
++ mod_code = (mod_code & 0x7f) >> 2;
++
++ reg_index = R0900_P2_MODCODLSTF - mod_code / 2;
++ field_index = mod_code % 2;
++ break;
++ }
++
++
++ switch (matype) {
++ case 0:
++ default:
++ fmod = 14;
++ break;
++ case 1:
++ fmod = 13;
++ break;
++ case 2:
++ fmod = 11;
++ break;
++ case 3:
++ fmod = 7;
++ break;
++ }
++
++ if ((INRANGE(STV0900_QPSK_12, mod_code, STV0900_8PSK_910))
++ && (matype <= 1)) {
++ if (field_index == 0)
++ stv0900_write_reg(i_params, reg_index,
++ 0xf0 | fmod);
++ else
++ stv0900_write_reg(i_params, reg_index,
++ (fmod << 4) | 0xf);
++ }
++ } else if (i_params->chip_id >= 0x12) {
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ for (reg_index = 0; reg_index < 7; reg_index++)
++ stv0900_write_reg(i_params, R0900_P1_MODCODLST0 + reg_index, 0xff);
++
++ stv0900_write_reg(i_params, R0900_P1_MODCODLSTE, 0xff);
++ stv0900_write_reg(i_params, R0900_P1_MODCODLSTF, 0xcf);
++ for (reg_index = 0; reg_index < 8; reg_index++)
++ stv0900_write_reg(i_params, R0900_P1_MODCODLST7 + reg_index, 0xcc);
++
++ break;
++ case STV0900_DEMOD_2:
++ for (reg_index = 0; reg_index < 7; reg_index++)
++ stv0900_write_reg(i_params, R0900_P2_MODCODLST0 + reg_index, 0xff);
++
++ stv0900_write_reg(i_params, R0900_P2_MODCODLSTE, 0xff);
++ stv0900_write_reg(i_params, R0900_P2_MODCODLSTF, 0xcf);
++ for (reg_index = 0; reg_index < 8; reg_index++)
++ stv0900_write_reg(i_params, R0900_P2_MODCODLST7 + reg_index, 0xcc);
++
++ break;
++ }
++
++ }
++}
++
++void stv0900_activate_s2_modcode_single(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ u32 reg_index;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ stv0900_write_reg(i_params, R0900_P1_MODCODLST0, 0xff);
++ stv0900_write_reg(i_params, R0900_P1_MODCODLST1, 0xf0);
++ stv0900_write_reg(i_params, R0900_P1_MODCODLSTF, 0x0f);
++ for (reg_index = 0; reg_index < 13; reg_index++)
++ stv0900_write_reg(i_params,
++ R0900_P1_MODCODLST2 + reg_index, 0);
++
++ break;
++ case STV0900_DEMOD_2:
++ stv0900_write_reg(i_params, R0900_P2_MODCODLST0, 0xff);
++ stv0900_write_reg(i_params, R0900_P2_MODCODLST1, 0xf0);
++ stv0900_write_reg(i_params, R0900_P2_MODCODLSTF, 0x0f);
++ for (reg_index = 0; reg_index < 13; reg_index++)
++ stv0900_write_reg(i_params,
++ R0900_P2_MODCODLST2 + reg_index, 0);
++
++ break;
++ }
++}
++
++static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe)
++{
++ return DVBFE_ALGO_CUSTOM;
++}
++
++static int stb0900_set_property(struct dvb_frontend *fe,
++ struct dtv_property *tvp)
++{
++ dprintk(KERN_INFO "%s(..)\n", __func__);
++
++ return 0;
++}
++
++static int stb0900_get_property(struct dvb_frontend *fe,
++ struct dtv_property *tvp)
++{
++ dprintk(KERN_INFO "%s(..)\n", __func__);
++
++ return 0;
++}
++
++void stv0900_start_search(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ stv0900_write_bits(i_params, F0900_P1_I2C_DEMOD_MODE, 0x1f);
++
++ if (i_params->chip_id == 0x10)
++ stv0900_write_reg(i_params, R0900_P1_CORRELEXP, 0xaa);
++
++ if (i_params->chip_id < 0x20)
++ stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x55);
++
++ if (i_params->dmd1_symbol_rate <= 5000000) {
++ stv0900_write_reg(i_params, R0900_P1_CARCFG, 0x44);
++ stv0900_write_reg(i_params, R0900_P1_CFRUP1, 0x0f);
++ stv0900_write_reg(i_params, R0900_P1_CFRUP0, 0xff);
++ stv0900_write_reg(i_params, R0900_P1_CFRLOW1, 0xf0);
++ stv0900_write_reg(i_params, R0900_P1_CFRLOW0, 0x00);
++ stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x68);
++ } else {
++ stv0900_write_reg(i_params, R0900_P1_CARCFG, 0xc4);
++ stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x44);
++ }
++
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, 0);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, 0);
++
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P1_EQUALCFG, 0x41);
++ stv0900_write_reg(i_params, R0900_P1_FFECFG, 0x41);
++
++ if ((i_params->dmd1_srch_standard == STV0900_SEARCH_DVBS1) || (i_params->dmd1_srch_standard == STV0900_SEARCH_DSS) || (i_params->dmd1_srch_standard == STV0900_AUTO_SEARCH)) {
++ stv0900_write_reg(i_params, R0900_P1_VITSCALE, 0x82);
++ stv0900_write_reg(i_params, R0900_P1_VAVSRVIT, 0x0);
++ }
++ }
++
++ stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x00);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, 0xe0);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, 0xc0);
++ stv0900_write_bits(i_params, F0900_P1_SCAN_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
++ stv0900_write_bits(i_params, F0900_P1_S1S2_SEQUENTIAL, 0);
++ stv0900_write_reg(i_params, R0900_P1_RTC, 0x88);
++ if (i_params->chip_id >= 0x20) {
++ if (i_params->dmd1_symbol_rate < 2000000) {
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x39);
++ stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x40);
++ }
++
++ if (i_params->dmd1_symbol_rate < 10000000) {
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x4c);
++ stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x20);
++ } else {
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x4b);
++ stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x20);
++ }
++
++ } else {
++ if (i_params->dmd1_symbol_rate < 10000000)
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xef);
++ else
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xed);
++ }
++
++ switch (i_params->dmd1_srch_algo) {
++ case STV0900_WARM_START:
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1f);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
++ break;
++ case STV0900_COLD_START:
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1f);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x15);
++ break;
++ default:
++ break;
++ }
++
++ break;
++ case STV0900_DEMOD_2:
++ stv0900_write_bits(i_params, F0900_P2_I2C_DEMOD_MODE, 0x1f);
++ if (i_params->chip_id == 0x10)
++ stv0900_write_reg(i_params, R0900_P2_CORRELEXP, 0xaa);
++
++ if (i_params->chip_id < 0x20)
++ stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x55);
++
++ if (i_params->dmd2_symbol_rate <= 5000000) {
++ stv0900_write_reg(i_params, R0900_P2_CARCFG, 0x44);
++ stv0900_write_reg(i_params, R0900_P2_CFRUP1, 0x0f);
++ stv0900_write_reg(i_params, R0900_P2_CFRUP0, 0xff);
++ stv0900_write_reg(i_params, R0900_P2_CFRLOW1, 0xf0);
++ stv0900_write_reg(i_params, R0900_P2_CFRLOW0, 0x00);
++ stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x68);
++ } else {
++ stv0900_write_reg(i_params, R0900_P2_CARCFG, 0xc4);
++ stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x44);
++ }
++
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, 0);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, 0);
++
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P2_EQUALCFG, 0x41);
++ stv0900_write_reg(i_params, R0900_P2_FFECFG, 0x41);
++ if ((i_params->dmd2_srch_stndrd == STV0900_SEARCH_DVBS1) || (i_params->dmd2_srch_stndrd == STV0900_SEARCH_DSS) || (i_params->dmd2_srch_stndrd == STV0900_AUTO_SEARCH)) {
++ stv0900_write_reg(i_params, R0900_P2_VITSCALE, 0x82);
++ stv0900_write_reg(i_params, R0900_P2_VAVSRVIT, 0x0);
++ }
++ }
++
++ stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x00);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, 0xe0);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, 0xc0);
++ stv0900_write_bits(i_params, F0900_P2_SCAN_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
++ stv0900_write_bits(i_params, F0900_P2_S1S2_SEQUENTIAL, 0);
++ stv0900_write_reg(i_params, R0900_P2_RTC, 0x88);
++ if (i_params->chip_id >= 0x20) {
++ if (i_params->dmd2_symbol_rate < 2000000) {
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x39);
++ stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x40);
++ }
++
++ if (i_params->dmd2_symbol_rate < 10000000) {
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x4c);
++ stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x20);
++ } else {
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x4b);
++ stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x20);
++ }
++
++ } else {
++ if (i_params->dmd2_symbol_rate < 10000000)
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0xef);
++ else
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0xed);
++ }
++
++ switch (i_params->dmd2_srch_algo) {
++ case STV0900_WARM_START:
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1f);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
++ break;
++ case STV0900_COLD_START:
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1f);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x15);
++ break;
++ default:
++ break;
++ }
++
++ break;
++ }
++}
++
++u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode,
++ s32 pilot, u8 chip_id)
++{
++ u8 aclc_value = 0x29;
++ s32 i;
++ const struct stv0900_car_loop_optim *car_loop_s2;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ if (chip_id <= 0x12)
++ car_loop_s2 = FE_STV0900_S2CarLoop;
++ else if (chip_id == 0x20)
++ car_loop_s2 = FE_STV0900_S2CarLoopCut20;
++ else
++ car_loop_s2 = FE_STV0900_S2CarLoop;
++
++ if (modcode < STV0900_QPSK_12) {
++ i = 0;
++ while ((i < 3) && (modcode != FE_STV0900_S2LowQPCarLoopCut20[i].modcode))
++ i++;
++
++ if (i >= 3)
++ i = 2;
++ } else {
++ i = 0;
++ while ((i < 14) && (modcode != car_loop_s2[i].modcode))
++ i++;
++
++ if (i >= 14) {
++ i = 0;
++ while ((i < 11) && (modcode != FE_STV0900_S2APSKCarLoopCut20[i].modcode))
++ i++;
++
++ if (i >= 11)
++ i = 10;
++ }
++ }
++
++ if (modcode <= STV0900_QPSK_25) {
++ if (pilot) {
++ if (srate <= 3000000)
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_2;
++ else if (srate <= 7000000)
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_5;
++ else if (srate <= 15000000)
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_10;
++ else if (srate <= 25000000)
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_20;
++ else
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_30;
++ } else {
++ if (srate <= 3000000)
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_2;
++ else if (srate <= 7000000)
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_5;
++ else if (srate <= 15000000)
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_10;
++ else if (srate <= 25000000)
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_20;
++ else
++ aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_30;
++ }
++
++ } else if (modcode <= STV0900_8PSK_910) {
++ if (pilot) {
++ if (srate <= 3000000)
++ aclc_value = car_loop_s2[i].car_loop_pilots_on_2;
++ else if (srate <= 7000000)
++ aclc_value = car_loop_s2[i].car_loop_pilots_on_5;
++ else if (srate <= 15000000)
++ aclc_value = car_loop_s2[i].car_loop_pilots_on_10;
++ else if (srate <= 25000000)
++ aclc_value = car_loop_s2[i].car_loop_pilots_on_20;
++ else
++ aclc_value = car_loop_s2[i].car_loop_pilots_on_30;
++ } else {
++ if (srate <= 3000000)
++ aclc_value = car_loop_s2[i].car_loop_pilots_off_2;
++ else if (srate <= 7000000)
++ aclc_value = car_loop_s2[i].car_loop_pilots_off_5;
++ else if (srate <= 15000000)
++ aclc_value = car_loop_s2[i].car_loop_pilots_off_10;
++ else if (srate <= 25000000)
++ aclc_value = car_loop_s2[i].car_loop_pilots_off_20;
++ else
++ aclc_value = car_loop_s2[i].car_loop_pilots_off_30;
++ }
++
++ } else {
++ if (srate <= 3000000)
++ aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_2;
++ else if (srate <= 7000000)
++ aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_5;
++ else if (srate <= 15000000)
++ aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_10;
++ else if (srate <= 25000000)
++ aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_20;
++ else
++ aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_30;
++ }
++
++ return aclc_value;
++}
++
++u8 stv0900_get_optim_short_carr_loop(s32 srate, enum fe_stv0900_modulation modulation, u8 chip_id)
++{
++ s32 mod_index = 0;
++
++ u8 aclc_value = 0x0b;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ switch (modulation) {
++ case STV0900_QPSK:
++ default:
++ mod_index = 0;
++ break;
++ case STV0900_8PSK:
++ mod_index = 1;
++ break;
++ case STV0900_16APSK:
++ mod_index = 2;
++ break;
++ case STV0900_32APSK:
++ mod_index = 3;
++ break;
++ }
++
++ switch (chip_id) {
++ case 0x20:
++ if (srate <= 3000000)
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_2;
++ else if (srate <= 7000000)
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_5;
++ else if (srate <= 15000000)
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_10;
++ else if (srate <= 25000000)
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_20;
++ else
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_30;
++
++ break;
++ case 0x12:
++ default:
++ if (srate <= 3000000)
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_2;
++ else if (srate <= 7000000)
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_5;
++ else if (srate <= 15000000)
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_10;
++ else if (srate <= 25000000)
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_20;
++ else
++ aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_30;
++
++ break;
++ }
++
++ return aclc_value;
++}
++
++static enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_mode LDPC_Mode,
++ enum fe_stv0900_demod_num demod)
++{
++ enum fe_stv0900_error error = STV0900_NO_ERROR;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ switch (LDPC_Mode) {
++ case STV0900_DUAL:
++ default:
++ if ((i_params->demod_mode != STV0900_DUAL)
++ || (stv0900_get_bits(i_params, F0900_DDEMOD) != 1)) {
++ stv0900_write_reg(i_params, R0900_GENCFG, 0x1d);
++
++ i_params->demod_mode = STV0900_DUAL;
++
++ stv0900_write_bits(i_params, F0900_FRESFEC, 1);
++ stv0900_write_bits(i_params, F0900_FRESFEC, 0);
++ }
++
++ break;
++ case STV0900_SINGLE:
++ if (demod == STV0900_DEMOD_2)
++ stv0900_write_reg(i_params, R0900_GENCFG, 0x06);
++ else
++ stv0900_write_reg(i_params, R0900_GENCFG, 0x04);
++
++ i_params->demod_mode = STV0900_SINGLE;
++
++ stv0900_write_bits(i_params, F0900_FRESFEC, 1);
++ stv0900_write_bits(i_params, F0900_FRESFEC, 0);
++ stv0900_write_bits(i_params, F0900_P1_ALGOSWRST, 1);
++ stv0900_write_bits(i_params, F0900_P1_ALGOSWRST, 0);
++ stv0900_write_bits(i_params, F0900_P2_ALGOSWRST, 1);
++ stv0900_write_bits(i_params, F0900_P2_ALGOSWRST, 0);
++ break;
++ }
++
++ return error;
++}
++
++static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
++ struct stv0900_init_params *p_init)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ enum fe_stv0900_error error = STV0900_NO_ERROR;
++ enum fe_stv0900_error demodError = STV0900_NO_ERROR;
++ int selosci;
++
++ struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
++ state->config->demod_address);
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ if (temp_int != NULL) {
++ state->internal = temp_int->internal;
++ (state->internal->dmds_used)++;
++ dprintk(KERN_INFO "%s: Find Internal Structure!\n", __func__);
++ return STV0900_NO_ERROR;
++ } else {
++ state->internal = kmalloc(sizeof(struct stv0900_internal), GFP_KERNEL);
++ temp_int = append_internal(state->internal);
++ state->internal->dmds_used = 1;
++ state->internal->i2c_adap = state->i2c_adap;
++ state->internal->i2c_addr = state->config->demod_address;
++ state->internal->clkmode = state->config->clkmode;
++ state->internal->errs = STV0900_NO_ERROR;
++ dprintk(KERN_INFO "%s: Create New Internal Structure!\n", __func__);
++ }
++
++ if (state->internal != NULL) {
++ demodError = stv0900_initialize(state->internal);
++ if (demodError == STV0900_NO_ERROR) {
++ error = STV0900_NO_ERROR;
++ } else {
++ if (demodError == STV0900_INVALID_HANDLE)
++ error = STV0900_INVALID_HANDLE;
++ else
++ error = STV0900_I2C_ERROR;
++ }
++
++ if (state->internal != NULL) {
++ if (error == STV0900_NO_ERROR) {
++ state->internal->demod_mode = p_init->demod_mode;
++
++ stv0900_st_dvbs2_single(state->internal, state->internal->demod_mode, STV0900_DEMOD_1);
++
++ state->internal->chip_id = stv0900_read_reg(state->internal, R0900_MID);
++ state->internal->rolloff = p_init->rolloff;
++ state->internal->quartz = p_init->dmd_ref_clk;
++
++ stv0900_write_bits(state->internal, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff);
++ stv0900_write_bits(state->internal, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff);
++
++ stv0900_set_ts_parallel_serial(state->internal, p_init->path1_ts_clock, p_init->path2_ts_clock);
++ stv0900_write_bits(state->internal, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
++ switch (p_init->tuner1_adc) {
++ case 1:
++ stv0900_write_reg(state->internal, R0900_TSTTNR1, 0x26);
++ break;
++ default:
++ break;
++ }
++
++ stv0900_write_bits(state->internal, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
++ switch (p_init->tuner2_adc) {
++ case 1:
++ stv0900_write_reg(state->internal, R0900_TSTTNR3, 0x26);
++ break;
++ default:
++ break;
++ }
++
++ stv0900_write_bits(state->internal, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inversion);
++ stv0900_write_bits(state->internal, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inversion);
++ stv0900_set_mclk(state->internal, 135000000);
++ msleep(3);
++
++ switch (state->internal->clkmode) {
++ case 0:
++ case 2:
++ stv0900_write_reg(state->internal, R0900_SYNTCTRL, 0x20 | state->internal->clkmode);
++ break;
++ default:
++ selosci = 0x02 & stv0900_read_reg(state->internal, R0900_SYNTCTRL);
++ stv0900_write_reg(state->internal, R0900_SYNTCTRL, 0x20 | selosci);
++ break;
++ }
++ msleep(3);
++
++ state->internal->mclk = stv0900_get_mclk_freq(state->internal, state->internal->quartz);
++ if (state->internal->errs)
++ error = STV0900_I2C_ERROR;
++ }
++ } else {
++ error = STV0900_INVALID_HANDLE;
++ }
++ }
++
++ return error;
++}
++
++static int stv0900_status(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ enum fe_stv0900_search_state demod_state;
++ s32 mode_field, delin_field, lock_field, fifo_field, lockedvit_field;
++ int locked = FALSE;
++
++ dmd_reg(mode_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
++ dmd_reg(lock_field, F0900_P1_LOCK_DEFINITIF, F0900_P2_LOCK_DEFINITIF);
++ dmd_reg(delin_field, F0900_P1_PKTDELIN_LOCK, F0900_P2_PKTDELIN_LOCK);
++ dmd_reg(fifo_field, F0900_P1_TSFIFO_LINEOK, F0900_P2_TSFIFO_LINEOK);
++ dmd_reg(lockedvit_field, F0900_P1_LOCKEDVIT, F0900_P2_LOCKEDVIT);
++
++ demod_state = stv0900_get_bits(i_params, mode_field);
++ switch (demod_state) {
++ case STV0900_SEARCH:
++ case STV0900_PLH_DETECTED:
++ default:
++ locked = FALSE;
++ break;
++ case STV0900_DVBS2_FOUND:
++ locked = stv0900_get_bits(i_params, lock_field) &&
++ stv0900_get_bits(i_params, delin_field) &&
++ stv0900_get_bits(i_params, fifo_field);
++ break;
++ case STV0900_DVBS_FOUND:
++ locked = stv0900_get_bits(i_params, lock_field) &&
++ stv0900_get_bits(i_params, lockedvit_field) &&
++ stv0900_get_bits(i_params, fifo_field);
++ break;
++ }
++
++ return locked;
++}
++
++static enum dvbfe_search stv0900_search(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *params)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++
++ struct stv0900_search_params p_search;
++ struct stv0900_signal_info p_result;
++
++ enum fe_stv0900_error error = STV0900_NO_ERROR;
++
++ dprintk(KERN_INFO "%s: ", __func__);
++
++ p_result.locked = FALSE;
++ p_search.path = state->demod;
++ p_search.frequency = c->frequency;
++ p_search.symbol_rate = c->symbol_rate;
++ p_search.search_range = 10000000;
++ p_search.fec = STV0900_FEC_UNKNOWN;
++ p_search.standard = STV0900_AUTO_SEARCH;
++ p_search.iq_inversion = STV0900_IQ_AUTO;
++ p_search.search_algo = STV0900_BLIND_SEARCH;
++
++ if ((INRANGE(100000, p_search.symbol_rate, 70000000)) &&
++ (INRANGE(100000, p_search.search_range, 50000000))) {
++ switch (p_search.path) {
++ case STV0900_DEMOD_1:
++ default:
++ i_params->dmd1_srch_standard = p_search.standard;
++ i_params->dmd1_symbol_rate = p_search.symbol_rate;
++ i_params->dmd1_srch_range = p_search.search_range;
++ i_params->tuner1_freq = p_search.frequency;
++ i_params->dmd1_srch_algo = p_search.search_algo;
++ i_params->dmd1_srch_iq_inv = p_search.iq_inversion;
++ i_params->dmd1_fec = p_search.fec;
++ break;
++
++ case STV0900_DEMOD_2:
++ i_params->dmd2_srch_stndrd = p_search.standard;
++ i_params->dmd2_symbol_rate = p_search.symbol_rate;
++ i_params->dmd2_srch_range = p_search.search_range;
++ i_params->tuner2_freq = p_search.frequency;
++ i_params->dmd2_srch_algo = p_search.search_algo;
++ i_params->dmd2_srch_iq_inv = p_search.iq_inversion;
++ i_params->dmd2_fec = p_search.fec;
++ break;
++ }
++
++ if ((stv0900_algo(fe) == STV0900_RANGEOK) &&
++ (i_params->errs == STV0900_NO_ERROR)) {
++ switch (p_search.path) {
++ case STV0900_DEMOD_1:
++ default:
++ p_result.locked = i_params->dmd1_rslts.locked;
++ p_result.standard = i_params->dmd1_rslts.standard;
++ p_result.frequency = i_params->dmd1_rslts.frequency;
++ p_result.symbol_rate = i_params->dmd1_rslts.symbol_rate;
++ p_result.fec = i_params->dmd1_rslts.fec;
++ p_result.modcode = i_params->dmd1_rslts.modcode;
++ p_result.pilot = i_params->dmd1_rslts.pilot;
++ p_result.frame_length = i_params->dmd1_rslts.frame_length;
++ p_result.spectrum = i_params->dmd1_rslts.spectrum;
++ p_result.rolloff = i_params->dmd1_rslts.rolloff;
++ p_result.modulation = i_params->dmd1_rslts.modulation;
++ break;
++ case STV0900_DEMOD_2:
++ p_result.locked = i_params->dmd2_rslts.locked;
++ p_result.standard = i_params->dmd2_rslts.standard;
++ p_result.frequency = i_params->dmd2_rslts.frequency;
++ p_result.symbol_rate = i_params->dmd2_rslts.symbol_rate;
++ p_result.fec = i_params->dmd2_rslts.fec;
++ p_result.modcode = i_params->dmd2_rslts.modcode;
++ p_result.pilot = i_params->dmd2_rslts.pilot;
++ p_result.frame_length = i_params->dmd2_rslts.frame_length;
++ p_result.spectrum = i_params->dmd2_rslts.spectrum;
++ p_result.rolloff = i_params->dmd2_rslts.rolloff;
++ p_result.modulation = i_params->dmd2_rslts.modulation;
++ break;
++ }
++
++ } else {
++ p_result.locked = FALSE;
++ switch (p_search.path) {
++ case STV0900_DEMOD_1:
++ switch (i_params->dmd1_err) {
++ case STV0900_I2C_ERROR:
++ error = STV0900_I2C_ERROR;
++ break;
++ case STV0900_NO_ERROR:
++ default:
++ error = STV0900_SEARCH_FAILED;
++ break;
++ }
++ break;
++ case STV0900_DEMOD_2:
++ switch (i_params->dmd2_err) {
++ case STV0900_I2C_ERROR:
++ error = STV0900_I2C_ERROR;
++ break;
++ case STV0900_NO_ERROR:
++ default:
++ error = STV0900_SEARCH_FAILED;
++ break;
++ }
++ break;
++ }
++ }
++
++ } else
++ error = STV0900_BAD_PARAMETER;
++
++ if ((p_result.locked == TRUE) && (error == STV0900_NO_ERROR)) {
++ dprintk(KERN_INFO "Search Success\n");
++ return DVBFE_ALGO_SEARCH_SUCCESS;
++ } else {
++ dprintk(KERN_INFO "Search Fail\n");
++ return DVBFE_ALGO_SEARCH_FAILED;
++ }
++
++ return DVBFE_ALGO_SEARCH_ERROR;
++}
++
++static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++
++ dprintk("%s: ", __func__);
++
++ if ((stv0900_status(state->internal, state->demod)) == TRUE) {
++ dprintk("DEMOD LOCK OK\n");
++ *status = FE_HAS_CARRIER
++ | FE_HAS_VITERBI
++ | FE_HAS_SYNC
++ | FE_HAS_LOCK;
++ } else
++ dprintk("DEMOD LOCK FAIL\n");
++
++ return 0;
++}
++
++static int stv0900_track(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *p)
++{
++ return 0;
++}
++
++static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts)
++{
++
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++ s32 rst_field;
++
++ dmd_reg(rst_field, F0900_P1_RST_HWARE, F0900_P2_RST_HWARE);
++
++ if (stop_ts == TRUE)
++ stv0900_write_bits(i_params, rst_field, 1);
++ else
++ stv0900_write_bits(i_params, rst_field, 0);
++
++ return 0;
++}
++
++static int stv0900_diseqc_init(struct dvb_frontend *fe)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++ s32 mode_field, reset_field;
++
++ dmd_reg(mode_field, F0900_P1_DISTX_MODE, F0900_P2_DISTX_MODE);
++ dmd_reg(reset_field, F0900_P1_DISEQC_RESET, F0900_P2_DISEQC_RESET);
++
++ stv0900_write_bits(i_params, mode_field, state->config->diseqc_mode);
++ stv0900_write_bits(i_params, reset_field, 1);
++ stv0900_write_bits(i_params, reset_field, 0);
++
++ return 0;
++}
++
++static int stv0900_init(struct dvb_frontend *fe)
++{
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ stv0900_stop_ts(fe, 1);
++ stv0900_diseqc_init(fe);
++
++ return 0;
++}
++
++static int stv0900_diseqc_send(struct stv0900_internal *i_params , u8 *Data,
++ u32 NbData, enum fe_stv0900_demod_num demod)
++{
++ s32 i = 0;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ stv0900_write_bits(i_params, F0900_P1_DIS_PRECHARGE, 1);
++ while (i < NbData) {
++ while (stv0900_get_bits(i_params, F0900_P1_FIFO_FULL))
++ ;/* checkpatch complains */
++ stv0900_write_reg(i_params, R0900_P1_DISTXDATA, Data[i]);
++ i++;
++ }
++
++ stv0900_write_bits(i_params, F0900_P1_DIS_PRECHARGE, 0);
++ i = 0;
++ while ((stv0900_get_bits(i_params, F0900_P1_TX_IDLE) != 1) && (i < 10)) {
++ msleep(10);
++ i++;
++ }
++
++ break;
++ case STV0900_DEMOD_2:
++ stv0900_write_bits(i_params, F0900_P2_DIS_PRECHARGE, 1);
++
++ while (i < NbData) {
++ while (stv0900_get_bits(i_params, F0900_P2_FIFO_FULL))
++ ;/* checkpatch complains */
++ stv0900_write_reg(i_params, R0900_P2_DISTXDATA, Data[i]);
++ i++;
++ }
++
++ stv0900_write_bits(i_params, F0900_P2_DIS_PRECHARGE, 0);
++ i = 0;
++ while ((stv0900_get_bits(i_params, F0900_P2_TX_IDLE) != 1) && (i < 10)) {
++ msleep(10);
++ i++;
++ }
++
++ break;
++ }
++
++ return 0;
++}
++
++static int stv0900_send_master_cmd(struct dvb_frontend *fe,
++ struct dvb_diseqc_master_cmd *cmd)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++
++ return stv0900_diseqc_send(state->internal,
++ cmd->msg,
++ cmd->msg_len,
++ state->demod);
++}
++
++static int stv0900_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++ s32 mode_field;
++ u32 diseqc_fifo;
++
++ dmd_reg(mode_field, F0900_P1_DISTX_MODE, F0900_P2_DISTX_MODE);
++ dmd_reg(diseqc_fifo, R0900_P1_DISTXDATA, R0900_P2_DISTXDATA);
++
++ switch (burst) {
++ case SEC_MINI_A:
++ stv0900_write_bits(i_params, mode_field, 3);/* Unmodulated */
++ stv0900_write_reg(i_params, diseqc_fifo, 0x00);
++ break;
++ case SEC_MINI_B:
++ stv0900_write_bits(i_params, mode_field, 2);/* Modulated */
++ stv0900_write_reg(i_params, diseqc_fifo, 0xff);
++ break;
++ }
++
++ return 0;
++}
++
++static int stv0900_recv_slave_reply(struct dvb_frontend *fe,
++ struct dvb_diseqc_slave_reply *reply)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ s32 i = 0;
++
++ switch (state->demod) {
++ case STV0900_DEMOD_1:
++ default:
++ reply->msg_len = 0;
++
++ while ((stv0900_get_bits(i_params, F0900_P1_RX_END) != 1) && (i < 10)) {
++ msleep(10);
++ i++;
++ }
++
++ if (stv0900_get_bits(i_params, F0900_P1_RX_END)) {
++ reply->msg_len = stv0900_get_bits(i_params, F0900_P1_FIFO_BYTENBR);
++
++ for (i = 0; i < reply->msg_len; i++)
++ reply->msg[i] = stv0900_read_reg(i_params, R0900_P1_DISRXDATA);
++ }
++ break;
++ case STV0900_DEMOD_2:
++ reply->msg_len = 0;
++
++ while ((stv0900_get_bits(i_params, F0900_P2_RX_END) != 1) && (i < 10)) {
++ msleep(10);
++ i++;
++ }
++
++ if (stv0900_get_bits(i_params, F0900_P2_RX_END)) {
++ reply->msg_len = stv0900_get_bits(i_params, F0900_P2_FIFO_BYTENBR);
++
++ for (i = 0; i < reply->msg_len; i++)
++ reply->msg[i] = stv0900_read_reg(i_params, R0900_P2_DISRXDATA);
++ }
++ break;
++ }
++
++ return 0;
++}
++
++static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++ s32 mode_field, reset_field;
++
++ dprintk(KERN_INFO "%s: %s\n", __func__, ((tone == 0) ? "Off" : "On"));
++
++ dmd_reg(mode_field, F0900_P1_DISTX_MODE, F0900_P2_DISTX_MODE);
++ dmd_reg(reset_field, F0900_P1_DISEQC_RESET, F0900_P2_DISEQC_RESET);
++
++ if (tone) {
++ /*Set the DiseqC mode to 22Khz continues tone*/
++ stv0900_write_bits(i_params, mode_field, 0);
++ stv0900_write_bits(i_params, reset_field, 1);
++ /*release DiseqC reset to enable the 22KHz tone*/
++ stv0900_write_bits(i_params, reset_field, 0);
++ } else {
++ stv0900_write_bits(i_params, mode_field, 0);
++ /*maintain the DiseqC reset to disable the 22KHz tone*/
++ stv0900_write_bits(i_params, reset_field, 1);
++ }
++
++ return 0;
++}
++
++static void stv0900_release(struct dvb_frontend *fe)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ if ((--(state->internal->dmds_used)) <= 0) {
++
++ dprintk(KERN_INFO "%s: Actually removing\n", __func__);
++
++ remove_inode(state->internal);
++ kfree(state->internal);
++ }
++
++ kfree(state);
++}
++
++static struct dvb_frontend_ops stv0900_ops = {
++
++ .info = {
++ .name = "STV0900 frontend",
++ .type = FE_QPSK,
++ .frequency_min = 950000,
++ .frequency_max = 2150000,
++ .frequency_stepsize = 125,
++ .frequency_tolerance = 0,
++ .symbol_rate_min = 1000000,
++ .symbol_rate_max = 45000000,
++ .symbol_rate_tolerance = 500,
++ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
++ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
++ FE_CAN_FEC_7_8 | FE_CAN_QPSK |
++ FE_CAN_2G_MODULATION |
++ FE_CAN_FEC_AUTO
++ },
++ .release = stv0900_release,
++ .init = stv0900_init,
++ .get_frontend_algo = stv0900_frontend_algo,
++ .i2c_gate_ctrl = stv0900_i2c_gate_ctrl,
++ .diseqc_send_master_cmd = stv0900_send_master_cmd,
++ .diseqc_send_burst = stv0900_send_burst,
++ .diseqc_recv_slave_reply = stv0900_recv_slave_reply,
++ .set_tone = stv0900_set_tone,
++ .set_property = stb0900_set_property,
++ .get_property = stb0900_get_property,
++ .search = stv0900_search,
++ .track = stv0900_track,
++ .read_status = stv0900_read_status,
++ .read_ber = stv0900_read_ber,
++ .read_signal_strength = stv0900_read_signal_strength,
++ .read_snr = stv0900_read_snr,
++};
++
++struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
++ struct i2c_adapter *i2c,
++ int demod)
++{
++ struct stv0900_state *state = NULL;
++ struct stv0900_init_params init_params;
++ enum fe_stv0900_error err_stv0900;
++
++ state = kzalloc(sizeof(struct stv0900_state), GFP_KERNEL);
++ if (state == NULL)
++ goto error;
++
++ state->demod = demod;
++ state->config = config;
++ state->i2c_adap = i2c;
++
++ memcpy(&state->frontend.ops, &stv0900_ops,
++ sizeof(struct dvb_frontend_ops));
++ state->frontend.demodulator_priv = state;
++
++ switch (demod) {
++ case 0:
++ case 1:
++ init_params.dmd_ref_clk = config->xtal;
++ init_params.demod_mode = STV0900_DUAL;
++ init_params.rolloff = STV0900_35;
++ init_params.path1_ts_clock = config->path1_mode;
++ init_params.tun1_maddress = config->tun1_maddress;
++ init_params.tun1_iq_inversion = STV0900_IQ_NORMAL;
++ init_params.tuner1_adc = config->tun1_adc;
++ init_params.path2_ts_clock = config->path2_mode;
++ init_params.tun2_maddress = config->tun2_maddress;
++ init_params.tuner2_adc = config->tun2_adc;
++ init_params.tun2_iq_inversion = STV0900_IQ_SWAPPED;
++
++ err_stv0900 = stv0900_init_internal(&state->frontend,
++ &init_params);
++
++ if (err_stv0900)
++ goto error;
++
++ break;
++ default:
++ goto error;
++ break;
++ }
++
++ dprintk("%s: Attaching STV0900 demodulator(%d) \n", __func__, demod);
++ return &state->frontend;
++
++error:
++ dprintk("%s: Failed to attach STV0900 demodulator(%d) \n",
++ __func__, demod);
++ kfree(state);
++ return NULL;
++}
++EXPORT_SYMBOL(stv0900_attach);
++
++MODULE_PARM_DESC(debug, "Set debug");
++
++MODULE_AUTHOR("Igor M. Liplianin");
++MODULE_DESCRIPTION("ST STV0900 frontend");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/stv0900_init.h b/drivers/media/dvb/frontends/stv0900_init.h
+new file mode 100644
+index 0000000..ff388b4
+--- /dev/null
++++ b/drivers/media/dvb/frontends/stv0900_init.h
+@@ -0,0 +1,441 @@
++/*
++ * stv0900_init.h
++ *
++ * Driver for ST STV0900 satellite demodulator IC.
++ *
++ * Copyright (C) ST Microelectronics.
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ *
++ * 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 STV0900_INIT_H
++#define STV0900_INIT_H
++
++#include "stv0900_priv.h"
++
++/* DVBS2 C/N Look-Up table */
++static const struct stv0900_table stv0900_s2_cn = {
++ 55,
++ {
++ { -30, 13348 }, /*C/N=-3dB*/
++ { -20, 12640 }, /*C/N=-2dB*/
++ { -10, 11883 }, /*C/N=-1dB*/
++ { 0, 11101 }, /*C/N=-0dB*/
++ { 5, 10718 }, /*C/N=0.5dB*/
++ { 10, 10339 }, /*C/N=1.0dB*/
++ { 15, 9947 }, /*C/N=1.5dB*/
++ { 20, 9552 }, /*C/N=2.0dB*/
++ { 25, 9183 }, /*C/N=2.5dB*/
++ { 30, 8799 }, /*C/N=3.0dB*/
++ { 35, 8422 }, /*C/N=3.5dB*/
++ { 40, 8062 }, /*C/N=4.0dB*/
++ { 45, 7707 }, /*C/N=4.5dB*/
++ { 50, 7353 }, /*C/N=5.0dB*/
++ { 55, 7025 }, /*C/N=5.5dB*/
++ { 60, 6684 }, /*C/N=6.0dB*/
++ { 65, 6331 }, /*C/N=6.5dB*/
++ { 70, 6036 }, /*C/N=7.0dB*/
++ { 75, 5727 }, /*C/N=7.5dB*/
++ { 80, 5437 }, /*C/N=8.0dB*/
++ { 85, 5164 }, /*C/N=8.5dB*/
++ { 90, 4902 }, /*C/N=9.0dB*/
++ { 95, 4653 }, /*C/N=9.5dB*/
++ { 100, 4408 }, /*C/N=10.0dB*/
++ { 105, 4187 }, /*C/N=10.5dB*/
++ { 110, 3961 }, /*C/N=11.0dB*/
++ { 115, 3751 }, /*C/N=11.5dB*/
++ { 120, 3558 }, /*C/N=12.0dB*/
++ { 125, 3368 }, /*C/N=12.5dB*/
++ { 130, 3191 }, /*C/N=13.0dB*/
++ { 135, 3017 }, /*C/N=13.5dB*/
++ { 140, 2862 }, /*C/N=14.0dB*/
++ { 145, 2710 }, /*C/N=14.5dB*/
++ { 150, 2565 }, /*C/N=15.0dB*/
++ { 160, 2300 }, /*C/N=16.0dB*/
++ { 170, 2058 }, /*C/N=17.0dB*/
++ { 180, 1849 }, /*C/N=18.0dB*/
++ { 190, 1663 }, /*C/N=19.0dB*/
++ { 200, 1495 }, /*C/N=20.0dB*/
++ { 210, 1349 }, /*C/N=21.0dB*/
++ { 220, 1222 }, /*C/N=22.0dB*/
++ { 230, 1110 }, /*C/N=23.0dB*/
++ { 240, 1011 }, /*C/N=24.0dB*/
++ { 250, 925 }, /*C/N=25.0dB*/
++ { 260, 853 }, /*C/N=26.0dB*/
++ { 270, 789 }, /*C/N=27.0dB*/
++ { 280, 734 }, /*C/N=28.0dB*/
++ { 290, 690 }, /*C/N=29.0dB*/
++ { 300, 650 }, /*C/N=30.0dB*/
++ { 310, 619 }, /*C/N=31.0dB*/
++ { 320, 593 }, /*C/N=32.0dB*/
++ { 330, 571 }, /*C/N=33.0dB*/
++ { 400, 498 }, /*C/N=40.0dB*/
++ { 450, 484 }, /*C/N=45.0dB*/
++ { 500, 481 } /*C/N=50.0dB*/
++ }
++};
++
++/* RF level C/N Look-Up table */
++static const struct stv0900_table stv0900_rf = {
++ 14,
++ {
++ { -5, 0xCAA1 }, /*-5dBm*/
++ { -10, 0xC229 }, /*-10dBm*/
++ { -15, 0xBB08 }, /*-15dBm*/
++ { -20, 0xB4BC }, /*-20dBm*/
++ { -25, 0xAD5A }, /*-25dBm*/
++ { -30, 0xA298 }, /*-30dBm*/
++ { -35, 0x98A8 }, /*-35dBm*/
++ { -40, 0x8389 }, /*-40dBm*/
++ { -45, 0x59BE }, /*-45dBm*/
++ { -50, 0x3A14 }, /*-50dBm*/
++ { -55, 0x2D11 }, /*-55dBm*/
++ { -60, 0x210D }, /*-60dBm*/
++ { -65, 0xA14F }, /*-65dBm*/
++ { -70, 0x7AA } /*-70dBm*/
++ }
++};
++
++struct stv0900_car_loop_optim {
++ enum fe_stv0900_modcode modcode;
++ u8 car_loop_pilots_on_2;
++ u8 car_loop_pilots_off_2;
++ u8 car_loop_pilots_on_5;
++ u8 car_loop_pilots_off_5;
++ u8 car_loop_pilots_on_10;
++ u8 car_loop_pilots_off_10;
++ u8 car_loop_pilots_on_20;
++ u8 car_loop_pilots_off_20;
++ u8 car_loop_pilots_on_30;
++ u8 car_loop_pilots_off_30;
++
++};
++
++struct stv0900_short_frames_car_loop_optim {
++ enum fe_stv0900_modulation modulation;
++ u8 car_loop_cut12_2; /* Cut 1.2, SR<=3msps */
++ u8 car_loop_cut20_2; /* Cut 2.0, SR<3msps */
++ u8 car_loop_cut12_5; /* Cut 1.2, 3<SR<=7msps */
++ u8 car_loop_cut20_5; /* Cut 2.0, 3<SR<=7msps */
++ u8 car_loop_cut12_10; /* Cut 1.2, 7<SR<=15msps */
++ u8 car_loop_cut20_10; /* Cut 2.0, 7<SR<=15msps */
++ u8 car_loop_cut12_20; /* Cut 1.2, 10<SR<=25msps */
++ u8 car_loop_cut20_20; /* Cut 2.0, 10<SR<=25msps */
++ u8 car_loop_cut12_30; /* Cut 1.2, 25<SR<=45msps */
++ u8 car_loop_cut20_30; /* Cut 2.0, 10<SR<=45msps */
++
++};
++
++/* Cut 1.x Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
++static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoop[14] = {
++ /*Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
++ { STV0900_QPSK_12, 0x1C, 0x0D, 0x1B, 0x2C, 0x3A, 0x1C, 0x2A, 0x3B, 0x2A, 0x1B },
++ { STV0900_QPSK_35, 0x2C, 0x0D, 0x2B, 0x2C, 0x3A, 0x0C, 0x3A, 0x2B, 0x2A, 0x0B },
++ { STV0900_QPSK_23, 0x2C, 0x0D, 0x2B, 0x2C, 0x0B, 0x0C, 0x3A, 0x1B, 0x2A, 0x3A },
++ { STV0900_QPSK_34, 0x3C, 0x0D, 0x3B, 0x1C, 0x0B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
++ { STV0900_QPSK_45, 0x3C, 0x0D, 0x3B, 0x1C, 0x0B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
++ { STV0900_QPSK_56, 0x0D, 0x0D, 0x3B, 0x1C, 0x0B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
++ { STV0900_QPSK_89, 0x0D, 0x0D, 0x3B, 0x1C, 0x1B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
++ { STV0900_QPSK_910, 0x1D, 0x0D, 0x3B, 0x1C, 0x1B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
++ { STV0900_8PSK_35, 0x29, 0x3B, 0x09, 0x2B, 0x38, 0x0B, 0x18, 0x1A, 0x08, 0x0A },
++ { STV0900_8PSK_23, 0x0A, 0x3B, 0x29, 0x2B, 0x19, 0x0B, 0x38, 0x1A, 0x18, 0x0A },
++ { STV0900_8PSK_34, 0x3A, 0x3B, 0x2A, 0x2B, 0x39, 0x0B, 0x19, 0x1A, 0x38, 0x0A },
++ { STV0900_8PSK_56, 0x1B, 0x3B, 0x0B, 0x2B, 0x1A, 0x0B, 0x39, 0x1A, 0x19, 0x0A },
++ { STV0900_8PSK_89, 0x3B, 0x3B, 0x0B, 0x2B, 0x2A, 0x0B, 0x39, 0x1A, 0x29, 0x39 },
++ { STV0900_8PSK_910, 0x3B, 0x3B, 0x0B, 0x2B, 0x2A, 0x0B, 0x39, 0x1A, 0x29, 0x39 }
++};
++
++
++/* Cut 2.0 Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
++static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoopCut20[14] = {
++ /* Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
++ { STV0900_QPSK_12, 0x1F, 0x3F, 0x1E, 0x3F, 0x3D, 0x1F, 0x3D, 0x3E, 0x3D, 0x1E },
++ { STV0900_QPSK_35, 0x2F, 0x3F, 0x2E, 0x2F, 0x3D, 0x0F, 0x0E, 0x2E, 0x3D, 0x0E },
++ { STV0900_QPSK_23, 0x2F, 0x3F, 0x2E, 0x2F, 0x0E, 0x0F, 0x0E, 0x1E, 0x3D, 0x3D },
++ { STV0900_QPSK_34, 0x3F, 0x3F, 0x3E, 0x1F, 0x0E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
++ { STV0900_QPSK_45, 0x3F, 0x3F, 0x3E, 0x1F, 0x0E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
++ { STV0900_QPSK_56, 0x3F, 0x3F, 0x3E, 0x1F, 0x0E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
++ { STV0900_QPSK_89, 0x3F, 0x3F, 0x3E, 0x1F, 0x1E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
++ { STV0900_QPSK_910, 0x3F, 0x3F, 0x3E, 0x1F, 0x1E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
++ { STV0900_8PSK_35, 0x3c, 0x0c, 0x1c, 0x3b, 0x0c, 0x3b, 0x2b, 0x2b, 0x1b, 0x2b },
++ { STV0900_8PSK_23, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x3b, 0x0c, 0x2b, 0x2b, 0x2b },
++ { STV0900_8PSK_34, 0x0e, 0x1c, 0x3d, 0x0c, 0x0d, 0x3b, 0x2c, 0x3b, 0x0c, 0x2b },
++ { STV0900_8PSK_56, 0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d },
++ { STV0900_8PSK_89, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d },
++ { STV0900_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d }
++};
++
++
++
++/* Cut 2.0 Tracking carrier loop carrier 16APSK 2/3 to 32APSK 9/10 long Frame */
++static const struct stv0900_car_loop_optim FE_STV0900_S2APSKCarLoopCut20[11] = {
++ /* Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
++ { STV0900_16APSK_23, 0x0C, 0x0C, 0x0C, 0x0C, 0x1D, 0x0C, 0x3C, 0x0C, 0x2C, 0x0C },
++ { STV0900_16APSK_34, 0x0C, 0x0C, 0x0C, 0x0C, 0x0E, 0x0C, 0x2D, 0x0C, 0x1D, 0x0C },
++ { STV0900_16APSK_45, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x0C, 0x3D, 0x0C, 0x2D, 0x0C },
++ { STV0900_16APSK_56, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x0C, 0x3D, 0x0C, 0x2D, 0x0C },
++ { STV0900_16APSK_89, 0x0C, 0x0C, 0x0C, 0x0C, 0x2E, 0x0C, 0x0E, 0x0C, 0x3D, 0x0C },
++ { STV0900_16APSK_910, 0x0C, 0x0C, 0x0C, 0x0C, 0x2E, 0x0C, 0x0E, 0x0C, 0x3D, 0x0C },
++ { STV0900_32APSK_34, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
++ { STV0900_32APSK_45, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
++ { STV0900_32APSK_56, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
++ { STV0900_32APSK_89, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
++ { STV0900_32APSK_910, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C }
++};
++
++
++/* Cut 2.0 Tracking carrier loop carrier QPSK 1/4 to QPSK 2/5 long Frame */
++static const struct stv0900_car_loop_optim FE_STV0900_S2LowQPCarLoopCut20[3] = {
++ /* Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
++ { STV0900_QPSK_14, 0x0F, 0x3F, 0x0E, 0x3F, 0x2D, 0x2F, 0x2D, 0x1F, 0x3D, 0x3E },
++ { STV0900_QPSK_13, 0x0F, 0x3F, 0x0E, 0x3F, 0x2D, 0x2F, 0x3D, 0x0F, 0x3D, 0x2E },
++ { STV0900_QPSK_25, 0x1F, 0x3F, 0x1E, 0x3F, 0x3D, 0x1F, 0x3D, 0x3E, 0x3D, 0x2E }
++};
++
++
++/* Cut 2.0 Tracking carrier loop carrier short Frame, cut 1.2 and 2.0 */
++static const struct stv0900_short_frames_car_loop_optim FE_STV0900_S2ShortCarLoop[4] = {
++ /*Mod 2M_cut1.2 2M_cut2.0 5M_cut1.2 5M_cut2.0 10M_cut1.2 10M_cut2.0 20M_cut1.2 20M_cut2.0 30M_cut1.2 30M_cut2.0 */
++ { STV0900_QPSK, 0x3C, 0x2F, 0x2B, 0x2E, 0x0B, 0x0E, 0x3A, 0x0E, 0x2A, 0x3D },
++ { STV0900_8PSK, 0x0B, 0x3E, 0x2A, 0x0E, 0x0A, 0x2D, 0x19, 0x0D, 0x09, 0x3C },
++ { STV0900_16APSK, 0x1B, 0x1E, 0x1B, 0x1E, 0x1B, 0x1E, 0x3A, 0x3D, 0x2A, 0x2D },
++ { STV0900_32APSK, 0x1B, 0x1E, 0x1B, 0x1E, 0x1B, 0x1E, 0x3A, 0x3D, 0x2A, 0x2D }
++};
++
++static const u16 STV0900_InitVal[182][2] = {
++ { R0900_OUTCFG , 0x00 },
++ { R0900_MODECFG , 0xff },
++ { R0900_AGCRF1CFG , 0x11 },
++ { R0900_AGCRF2CFG , 0x13 },
++ { R0900_TSGENERAL1X , 0x14 },
++ { R0900_TSTTNR2 , 0x21 },
++ { R0900_TSTTNR4 , 0x21 },
++ { R0900_P2_DISTXCTL , 0x22 },
++ { R0900_P2_F22TX , 0xc0 },
++ { R0900_P2_F22RX , 0xc0 },
++ { R0900_P2_DISRXCTL , 0x00 },
++ { R0900_P2_TNRSTEPS , 0x87 },
++ { R0900_P2_TNRGAIN , 0x09 },
++ { R0900_P2_DMDCFGMD , 0xF9 },
++ { R0900_P2_DEMOD , 0x08 },
++ { R0900_P2_DMDCFG3 , 0xc4 },
++ { R0900_P2_CARFREQ , 0xed },
++ { R0900_P2_TNRCFG2 , 0x02 },
++ { R0900_P2_TNRCFG3 , 0x02 },
++ { R0900_P2_LDT , 0xd0 },
++ { R0900_P2_LDT2 , 0xb8 },
++ { R0900_P2_TMGCFG , 0xd2 },
++ { R0900_P2_TMGTHRISE , 0x20 },
++ { R0900_P2_TMGTHFALL , 0x00 },
++ { R0900_P2_FECSPY , 0x88 },
++ { R0900_P2_FSPYDATA , 0x3a },
++ { R0900_P2_FBERCPT4 , 0x00 },
++ { R0900_P2_FSPYBER , 0x10 },
++ { R0900_P2_ERRCTRL1 , 0x35 },
++ { R0900_P2_ERRCTRL2 , 0xc1 },
++ { R0900_P2_CFRICFG , 0xf8 },
++ { R0900_P2_NOSCFG , 0x1c },
++ { R0900_P2_DMDT0M , 0x20 },
++ { R0900_P2_CORRELMANT , 0x70 },
++ { R0900_P2_CORRELABS , 0x88 },
++ { R0900_P2_AGC2O , 0x5b },
++ { R0900_P2_AGC2REF , 0x38 },
++ { R0900_P2_CARCFG , 0xe4 },
++ { R0900_P2_ACLC , 0x1A },
++ { R0900_P2_BCLC , 0x09 },
++ { R0900_P2_CARHDR , 0x08 },
++ { R0900_P2_KREFTMG , 0xc1 },
++ { R0900_P2_SFRUPRATIO , 0xf0 },
++ { R0900_P2_SFRLOWRATIO , 0x70 },
++ { R0900_P2_SFRSTEP , 0x58 },
++ { R0900_P2_TMGCFG2 , 0x01 },
++ { R0900_P2_CAR2CFG , 0x26 },
++ { R0900_P2_BCLC2S2Q , 0x86 },
++ { R0900_P2_BCLC2S28 , 0x86 },
++ { R0900_P2_SMAPCOEF7 , 0x77 },
++ { R0900_P2_SMAPCOEF6 , 0x85 },
++ { R0900_P2_SMAPCOEF5 , 0x77 },
++ { R0900_P2_TSCFGL , 0x20 },
++ { R0900_P2_DMDCFG2 , 0x3b },
++ { R0900_P2_MODCODLST0 , 0xff },
++ { R0900_P2_MODCODLST1 , 0xff },
++ { R0900_P2_MODCODLST2 , 0xff },
++ { R0900_P2_MODCODLST3 , 0xff },
++ { R0900_P2_MODCODLST4 , 0xff },
++ { R0900_P2_MODCODLST5 , 0xff },
++ { R0900_P2_MODCODLST6 , 0xff },
++ { R0900_P2_MODCODLST7 , 0xcc },
++ { R0900_P2_MODCODLST8 , 0xcc },
++ { R0900_P2_MODCODLST9 , 0xcc },
++ { R0900_P2_MODCODLSTA , 0xcc },
++ { R0900_P2_MODCODLSTB , 0xcc },
++ { R0900_P2_MODCODLSTC , 0xcc },
++ { R0900_P2_MODCODLSTD , 0xcc },
++ { R0900_P2_MODCODLSTE , 0xcc },
++ { R0900_P2_MODCODLSTF , 0xcf },
++ { R0900_P1_DISTXCTL , 0x22 },
++ { R0900_P1_F22TX , 0xc0 },
++ { R0900_P1_F22RX , 0xc0 },
++ { R0900_P1_DISRXCTL , 0x00 },
++ { R0900_P1_TNRSTEPS , 0x87 },
++ { R0900_P1_TNRGAIN , 0x09 },
++ { R0900_P1_DMDCFGMD , 0xf9 },
++ { R0900_P1_DEMOD , 0x08 },
++ { R0900_P1_DMDCFG3 , 0xc4 },
++ { R0900_P1_DMDT0M , 0x20 },
++ { R0900_P1_CARFREQ , 0xed },
++ { R0900_P1_TNRCFG2 , 0x82 },
++ { R0900_P1_TNRCFG3 , 0x02 },
++ { R0900_P1_LDT , 0xd0 },
++ { R0900_P1_LDT2 , 0xb8 },
++ { R0900_P1_TMGCFG , 0xd2 },
++ { R0900_P1_TMGTHRISE , 0x20 },
++ { R0900_P1_TMGTHFALL , 0x00 },
++ { R0900_P1_SFRUPRATIO , 0xf0 },
++ { R0900_P1_SFRLOWRATIO , 0x70 },
++ { R0900_P1_TSCFGL , 0x20 },
++ { R0900_P1_FECSPY , 0x88 },
++ { R0900_P1_FSPYDATA , 0x3a },
++ { R0900_P1_FBERCPT4 , 0x00 },
++ { R0900_P1_FSPYBER , 0x10 },
++ { R0900_P1_ERRCTRL1 , 0x35 },
++ { R0900_P1_ERRCTRL2 , 0xc1 },
++ { R0900_P1_CFRICFG , 0xf8 },
++ { R0900_P1_NOSCFG , 0x1c },
++ { R0900_P1_CORRELMANT , 0x70 },
++ { R0900_P1_CORRELABS , 0x88 },
++ { R0900_P1_AGC2O , 0x5b },
++ { R0900_P1_AGC2REF , 0x38 },
++ { R0900_P1_CARCFG , 0xe4 },
++ { R0900_P1_ACLC , 0x1A },
++ { R0900_P1_BCLC , 0x09 },
++ { R0900_P1_CARHDR , 0x08 },
++ { R0900_P1_KREFTMG , 0xc1 },
++ { R0900_P1_SFRSTEP , 0x58 },
++ { R0900_P1_TMGCFG2 , 0x01 },
++ { R0900_P1_CAR2CFG , 0x26 },
++ { R0900_P1_BCLC2S2Q , 0x86 },
++ { R0900_P1_BCLC2S28 , 0x86 },
++ { R0900_P1_SMAPCOEF7 , 0x77 },
++ { R0900_P1_SMAPCOEF6 , 0x85 },
++ { R0900_P1_SMAPCOEF5 , 0x77 },
++ { R0900_P1_DMDCFG2 , 0x3b },
++ { R0900_P1_MODCODLST0 , 0xff },
++ { R0900_P1_MODCODLST1 , 0xff },
++ { R0900_P1_MODCODLST2 , 0xff },
++ { R0900_P1_MODCODLST3 , 0xff },
++ { R0900_P1_MODCODLST4 , 0xff },
++ { R0900_P1_MODCODLST5 , 0xff },
++ { R0900_P1_MODCODLST6 , 0xff },
++ { R0900_P1_MODCODLST7 , 0xcc },
++ { R0900_P1_MODCODLST8 , 0xcc },
++ { R0900_P1_MODCODLST9 , 0xcc },
++ { R0900_P1_MODCODLSTA , 0xcc },
++ { R0900_P1_MODCODLSTB , 0xcc },
++ { R0900_P1_MODCODLSTC , 0xcc },
++ { R0900_P1_MODCODLSTD , 0xcc },
++ { R0900_P1_MODCODLSTE , 0xcc },
++ { R0900_P1_MODCODLSTF , 0xcf },
++ { R0900_GENCFG , 0x1d },
++ { R0900_NBITER_NF4 , 0x37 },
++ { R0900_NBITER_NF5 , 0x29 },
++ { R0900_NBITER_NF6 , 0x37 },
++ { R0900_NBITER_NF7 , 0x33 },
++ { R0900_NBITER_NF8 , 0x31 },
++ { R0900_NBITER_NF9 , 0x2f },
++ { R0900_NBITER_NF10 , 0x39 },
++ { R0900_NBITER_NF11 , 0x3a },
++ { R0900_NBITER_NF12 , 0x29 },
++ { R0900_NBITER_NF13 , 0x37 },
++ { R0900_NBITER_NF14 , 0x33 },
++ { R0900_NBITER_NF15 , 0x2f },
++ { R0900_NBITER_NF16 , 0x39 },
++ { R0900_NBITER_NF17 , 0x3a },
++ { R0900_NBITERNOERR , 0x04 },
++ { R0900_GAINLLR_NF4 , 0x0C },
++ { R0900_GAINLLR_NF5 , 0x0F },
++ { R0900_GAINLLR_NF6 , 0x11 },
++ { R0900_GAINLLR_NF7 , 0x14 },
++ { R0900_GAINLLR_NF8 , 0x17 },
++ { R0900_GAINLLR_NF9 , 0x19 },
++ { R0900_GAINLLR_NF10 , 0x20 },
++ { R0900_GAINLLR_NF11 , 0x21 },
++ { R0900_GAINLLR_NF12 , 0x0D },
++ { R0900_GAINLLR_NF13 , 0x0F },
++ { R0900_GAINLLR_NF14 , 0x13 },
++ { R0900_GAINLLR_NF15 , 0x1A },
++ { R0900_GAINLLR_NF16 , 0x1F },
++ { R0900_GAINLLR_NF17 , 0x21 },
++ { R0900_RCCFGH , 0x20 },
++ { R0900_P1_FECM , 0x01 }, /*disable DSS modes*/
++ { R0900_P2_FECM , 0x01 }, /*disable DSS modes*/
++ { R0900_P1_PRVIT , 0x2F }, /*disable puncture rate 6/7*/
++ { R0900_P2_PRVIT , 0x2F }, /*disable puncture rate 6/7*/
++ { R0900_STROUT1CFG , 0x4c },
++ { R0900_STROUT2CFG , 0x4c },
++ { R0900_CLKOUT1CFG , 0x50 },
++ { R0900_CLKOUT2CFG , 0x50 },
++ { R0900_DPN1CFG , 0x4a },
++ { R0900_DPN2CFG , 0x4a },
++ { R0900_DATA71CFG , 0x52 },
++ { R0900_DATA72CFG , 0x52 },
++ { R0900_P1_TSCFGM , 0xc0 },
++ { R0900_P2_TSCFGM , 0xc0 },
++ { R0900_P1_TSCFGH , 0xe0 }, /* DVB-CI timings */
++ { R0900_P2_TSCFGH , 0xe0 }, /* DVB-CI timings */
++ { R0900_P1_TSSPEED , 0x40 },
++ { R0900_P2_TSSPEED , 0x40 },
++};
++
++static const u16 STV0900_Cut20_AddOnVal[32][2] = {
++ { R0900_P2_DMDCFG3 , 0xe8 },
++ { R0900_P2_DMDCFG4 , 0x10 },
++ { R0900_P2_CARFREQ , 0x38 },
++ { R0900_P2_CARHDR , 0x20 },
++ { R0900_P2_KREFTMG , 0x5a },
++ { R0900_P2_SMAPCOEF7 , 0x06 },
++ { R0900_P2_SMAPCOEF6 , 0x00 },
++ { R0900_P2_SMAPCOEF5 , 0x04 },
++ { R0900_P2_NOSCFG , 0x0c },
++ { R0900_P1_DMDCFG3 , 0xe8 },
++ { R0900_P1_DMDCFG4 , 0x10 },
++ { R0900_P1_CARFREQ , 0x38 },
++ { R0900_P1_CARHDR , 0x20 },
++ { R0900_P1_KREFTMG , 0x5a },
++ { R0900_P1_SMAPCOEF7 , 0x06 },
++ { R0900_P1_SMAPCOEF6 , 0x00 },
++ { R0900_P1_SMAPCOEF5 , 0x04 },
++ { R0900_P1_NOSCFG , 0x0c },
++ { R0900_GAINLLR_NF4 , 0x21 },
++ { R0900_GAINLLR_NF5 , 0x21 },
++ { R0900_GAINLLR_NF6 , 0x20 },
++ { R0900_GAINLLR_NF7 , 0x1F },
++ { R0900_GAINLLR_NF8 , 0x1E },
++ { R0900_GAINLLR_NF9 , 0x1E },
++ { R0900_GAINLLR_NF10 , 0x1D },
++ { R0900_GAINLLR_NF11 , 0x1B },
++ { R0900_GAINLLR_NF12 , 0x20 },
++ { R0900_GAINLLR_NF13 , 0x20 },
++ { R0900_GAINLLR_NF14 , 0x20 },
++ { R0900_GAINLLR_NF15 , 0x20 },
++ { R0900_GAINLLR_NF16 , 0x20 },
++ { R0900_GAINLLR_NF17 , 0x21 }
++
++};
++
++#endif
+diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h
+new file mode 100644
+index 0000000..762d5af
+--- /dev/null
++++ b/drivers/media/dvb/frontends/stv0900_priv.h
+@@ -0,0 +1,430 @@
++/*
++ * stv0900_priv.h
++ *
++ * Driver for ST STV0900 satellite demodulator IC.
++ *
++ * Copyright (C) ST Microelectronics.
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ *
++ * 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 STV0900_PRIV_H
++#define STV0900_PRIV_H
++
++#include <linux/i2c.h>
++
++#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
++#define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \
++ || (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0)
++
++#ifndef MAKEWORD
++#define MAKEWORD(X, Y) (((X) << 8) + (Y))
++#endif
++
++#define LSB(X) (((X) & 0xFF))
++#define MSB(Y) (((Y) >> 8) & 0xFF)
++
++#ifndef TRUE
++#define TRUE (1 == 1)
++#endif
++#ifndef FALSE
++#define FALSE (!TRUE)
++#endif
++
++#define dmd_reg(a, b, c) \
++ do { \
++ a = 0; \
++ switch (demod) { \
++ case STV0900_DEMOD_1: \
++ default: \
++ a = b; \
++ break; \
++ case STV0900_DEMOD_2: \
++ a = c; \
++ break; \
++ } \
++ } while (0)
++
++#define dmd_choose(a, b) (demod = STV0900_DEMOD_2 ? b : a))
++
++static int stvdebug;
++
++#define dprintk(args...) \
++ do { \
++ if (stvdebug) \
++ printk(KERN_DEBUG args); \
++ } while (0)
++
++#define STV0900_MAXLOOKUPSIZE 500
++#define STV0900_BLIND_SEARCH_AGC2_TH 700
++
++/* One point of the lookup table */
++struct stv000_lookpoint {
++ s32 realval;/* real value */
++ s32 regval;/* binary value */
++};
++
++/* Lookup table definition */
++struct stv0900_table{
++ s32 size;/* Size of the lookup table */
++ struct stv000_lookpoint table[STV0900_MAXLOOKUPSIZE];/* Lookup table */
++};
++
++enum fe_stv0900_error {
++ STV0900_NO_ERROR = 0,
++ STV0900_INVALID_HANDLE,
++ STV0900_BAD_PARAMETER,
++ STV0900_I2C_ERROR,
++ STV0900_SEARCH_FAILED,
++};
++
++enum fe_stv0900_clock_type {
++ STV0900_USE_REGISTERS_DEFAULT,
++ STV0900_SERIAL_PUNCT_CLOCK,/*Serial punctured clock */
++ STV0900_SERIAL_CONT_CLOCK,/*Serial continues clock */
++ STV0900_PARALLEL_PUNCT_CLOCK,/*Parallel punctured clock */
++ STV0900_DVBCI_CLOCK/*Parallel continues clock : DVBCI */
++};
++
++enum fe_stv0900_search_state {
++ STV0900_SEARCH = 0,
++ STV0900_PLH_DETECTED,
++ STV0900_DVBS2_FOUND,
++ STV0900_DVBS_FOUND
++
++};
++
++enum fe_stv0900_ldpc_state {
++ STV0900_PATH1_OFF_PATH2_OFF = 0,
++ STV0900_PATH1_ON_PATH2_OFF = 1,
++ STV0900_PATH1_OFF_PATH2_ON = 2,
++ STV0900_PATH1_ON_PATH2_ON = 3
++};
++
++enum fe_stv0900_signal_type {
++ STV0900_NOAGC1 = 0,
++ STV0900_AGC1OK,
++ STV0900_NOTIMING,
++ STV0900_ANALOGCARRIER,
++ STV0900_TIMINGOK,
++ STV0900_NOAGC2,
++ STV0900_AGC2OK,
++ STV0900_NOCARRIER,
++ STV0900_CARRIEROK,
++ STV0900_NODATA,
++ STV0900_DATAOK,
++ STV0900_OUTOFRANGE,
++ STV0900_RANGEOK
++};
++
++enum fe_stv0900_demod_num {
++ STV0900_DEMOD_1,
++ STV0900_DEMOD_2
++};
++
++enum fe_stv0900_tracking_standard {
++ STV0900_DVBS1_STANDARD,/* Found Standard*/
++ STV0900_DVBS2_STANDARD,
++ STV0900_DSS_STANDARD,
++ STV0900_TURBOCODE_STANDARD,
++ STV0900_UNKNOWN_STANDARD
++};
++
++enum fe_stv0900_search_standard {
++ STV0900_AUTO_SEARCH,
++ STV0900_SEARCH_DVBS1,/* Search Standard*/
++ STV0900_SEARCH_DVBS2,
++ STV0900_SEARCH_DSS,
++ STV0900_SEARCH_TURBOCODE
++};
++
++enum fe_stv0900_search_algo {
++ STV0900_BLIND_SEARCH,/* offset freq and SR are Unknown */
++ STV0900_COLD_START,/* only the SR is known */
++ STV0900_WARM_START/* offset freq and SR are known */
++};
++
++enum fe_stv0900_modulation {
++ STV0900_QPSK,
++ STV0900_8PSK,
++ STV0900_16APSK,
++ STV0900_32APSK,
++ STV0900_UNKNOWN
++};
++
++enum fe_stv0900_modcode {
++ STV0900_DUMMY_PLF,
++ STV0900_QPSK_14,
++ STV0900_QPSK_13,
++ STV0900_QPSK_25,
++ STV0900_QPSK_12,
++ STV0900_QPSK_35,
++ STV0900_QPSK_23,
++ STV0900_QPSK_34,
++ STV0900_QPSK_45,
++ STV0900_QPSK_56,
++ STV0900_QPSK_89,
++ STV0900_QPSK_910,
++ STV0900_8PSK_35,
++ STV0900_8PSK_23,
++ STV0900_8PSK_34,
++ STV0900_8PSK_56,
++ STV0900_8PSK_89,
++ STV0900_8PSK_910,
++ STV0900_16APSK_23,
++ STV0900_16APSK_34,
++ STV0900_16APSK_45,
++ STV0900_16APSK_56,
++ STV0900_16APSK_89,
++ STV0900_16APSK_910,
++ STV0900_32APSK_34,
++ STV0900_32APSK_45,
++ STV0900_32APSK_56,
++ STV0900_32APSK_89,
++ STV0900_32APSK_910,
++ STV0900_MODCODE_UNKNOWN
++};
++
++enum fe_stv0900_fec {/*DVBS1, DSS and turbo code puncture rate*/
++ STV0900_FEC_1_2 = 0,
++ STV0900_FEC_2_3,
++ STV0900_FEC_3_4,
++ STV0900_FEC_4_5,/*for turbo code only*/
++ STV0900_FEC_5_6,
++ STV0900_FEC_6_7,/*for DSS only */
++ STV0900_FEC_7_8,
++ STV0900_FEC_8_9,/*for turbo code only*/
++ STV0900_FEC_UNKNOWN
++};
++
++enum fe_stv0900_frame_length {
++ STV0900_LONG_FRAME,
++ STV0900_SHORT_FRAME
++};
++
++enum fe_stv0900_pilot {
++ STV0900_PILOTS_OFF,
++ STV0900_PILOTS_ON
++};
++
++enum fe_stv0900_rolloff {
++ STV0900_35,
++ STV0900_25,
++ STV0900_20
++};
++
++enum fe_stv0900_search_iq {
++ STV0900_IQ_AUTO,
++ STV0900_IQ_AUTO_NORMAL_FIRST,
++ STV0900_IQ_FORCE_NORMAL,
++ STV0900_IQ_FORCE_SWAPPED
++};
++
++enum stv0900_iq_inversion {
++ STV0900_IQ_NORMAL,
++ STV0900_IQ_SWAPPED
++};
++
++enum fe_stv0900_diseqc_mode {
++ STV0900_22KHZ_Continues = 0,
++ STV0900_DISEQC_2_3_PWM = 2,
++ STV0900_DISEQC_3_3_PWM = 3,
++ STV0900_DISEQC_2_3_ENVELOP = 4,
++ STV0900_DISEQC_3_3_ENVELOP = 5
++};
++
++enum fe_stv0900_demod_mode {
++ STV0900_SINGLE = 0,
++ STV0900_DUAL
++};
++
++struct stv0900_init_params{
++ u32 dmd_ref_clk;/* Refrence,Input clock for the demod in Hz */
++
++ /* Demodulator Type (single demod or dual demod) */
++ enum fe_stv0900_demod_mode demod_mode;
++ enum fe_stv0900_rolloff rolloff;
++ enum fe_stv0900_clock_type path1_ts_clock;
++
++ u8 tun1_maddress;
++ int tuner1_adc;
++
++ /* IQ from the tuner1 to the demod */
++ enum stv0900_iq_inversion tun1_iq_inversion;
++ enum fe_stv0900_clock_type path2_ts_clock;
++
++ u8 tun2_maddress;
++ int tuner2_adc;
++
++ /* IQ from the tuner2 to the demod */
++ enum stv0900_iq_inversion tun2_iq_inversion;
++};
++
++struct stv0900_search_params {
++ enum fe_stv0900_demod_num path;/* Path Used demod1 or 2 */
++
++ u32 frequency;/* Transponder frequency (in KHz) */
++ u32 symbol_rate;/* Transponder symbol rate (in bds)*/
++ u32 search_range;/* Range of the search (in Hz) */
++
++ enum fe_stv0900_search_standard standard;
++ enum fe_stv0900_modulation modulation;
++ enum fe_stv0900_fec fec;
++ enum fe_stv0900_modcode modcode;
++ enum fe_stv0900_search_iq iq_inversion;
++ enum fe_stv0900_search_algo search_algo;
++
++};
++
++struct stv0900_signal_info {
++ int locked;/* Transponder locked */
++ u32 frequency;/* Transponder frequency (in KHz) */
++ u32 symbol_rate;/* Transponder symbol rate (in Mbds) */
++
++ enum fe_stv0900_tracking_standard standard;
++ enum fe_stv0900_fec fec;
++ enum fe_stv0900_modcode modcode;
++ enum fe_stv0900_modulation modulation;
++ enum fe_stv0900_pilot pilot;
++ enum fe_stv0900_frame_length frame_length;
++ enum stv0900_iq_inversion spectrum;
++ enum fe_stv0900_rolloff rolloff;
++
++ s32 Power;/* Power of the RF signal (dBm) */
++ s32 C_N;/* Carrier to noise ratio (dB x10)*/
++ u32 BER;/* Bit error rate (x10^7) */
++
++};
++
++struct stv0900_internal{
++ s32 quartz;
++ s32 mclk;
++ /* manual RollOff for DVBS1/DSS only */
++ enum fe_stv0900_rolloff rolloff;
++ /* Demodulator use for single demod or for dual demod) */
++ enum fe_stv0900_demod_mode demod_mode;
++
++ /*Demod 1*/
++ s32 tuner1_freq;
++ s32 tuner1_bw;
++ s32 dmd1_symbol_rate;
++ s32 dmd1_srch_range;
++
++ /* algorithm for search Blind, Cold or Warm*/
++ enum fe_stv0900_search_algo dmd1_srch_algo;
++ /* search standard: Auto, DVBS1/DSS only or DVBS2 only*/
++ enum fe_stv0900_search_standard dmd1_srch_standard;
++ /* inversion search : auto, auto norma first, normal or inverted */
++ enum fe_stv0900_search_iq dmd1_srch_iq_inv;
++ enum fe_stv0900_modcode dmd1_modcode;
++ enum fe_stv0900_modulation dmd1_modulation;
++ enum fe_stv0900_fec dmd1_fec;
++
++ struct stv0900_signal_info dmd1_rslts;
++ enum fe_stv0900_signal_type dmd1_state;
++
++ enum fe_stv0900_error dmd1_err;
++
++ /*Demod 2*/
++ s32 tuner2_freq;
++ s32 tuner2_bw;
++ s32 dmd2_symbol_rate;
++ s32 dmd2_srch_range;
++
++ enum fe_stv0900_search_algo dmd2_srch_algo;
++ enum fe_stv0900_search_standard dmd2_srch_stndrd;
++ /* inversion search : auto, auto normal first, normal or inverted */
++ enum fe_stv0900_search_iq dmd2_srch_iq_inv;
++ enum fe_stv0900_modcode dmd2_modcode;
++ enum fe_stv0900_modulation dmd2_modulation;
++ enum fe_stv0900_fec dmd2_fec;
++
++ /* results of the search*/
++ struct stv0900_signal_info dmd2_rslts;
++ /* current state of the search algorithm */
++ enum fe_stv0900_signal_type dmd2_state;
++
++ enum fe_stv0900_error dmd2_err;
++
++ struct i2c_adapter *i2c_adap;
++ u8 i2c_addr;
++ u8 clkmode;/* 0 for CLKI, 2 for XTALI */
++ u8 chip_id;
++ enum fe_stv0900_error errs;
++ int dmds_used;
++};
++
++/* state for each demod */
++struct stv0900_state {
++ /* pointer for internal params, one for each pair of demods */
++ struct stv0900_internal *internal;
++ struct i2c_adapter *i2c_adap;
++ const struct stv0900_config *config;
++ struct dvb_frontend frontend;
++ int demod;
++};
++
++extern s32 ge2comp(s32 a, s32 width);
++
++extern void stv0900_write_reg(struct stv0900_internal *i_params,
++ u16 reg_addr, u8 reg_data);
++
++extern u8 stv0900_read_reg(struct stv0900_internal *i_params,
++ u16 reg_addr);
++
++extern void stv0900_write_bits(struct stv0900_internal *i_params,
++ u32 label, u8 val);
++
++extern u8 stv0900_get_bits(struct stv0900_internal *i_params,
++ u32 label);
++
++extern int stv0900_get_demod_lock(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod, s32 time_out);
++extern int stv0900_check_signal_presence(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod);
++
++extern enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe);
++
++extern void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
++ u32 bandwidth);
++extern void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth);
++
++extern void stv0900_start_search(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod);
++
++extern u8 stv0900_get_optim_carr_loop(s32 srate,
++ enum fe_stv0900_modcode modcode,
++ s32 pilot, u8 chip_id);
++
++extern u8 stv0900_get_optim_short_carr_loop(s32 srate,
++ enum fe_stv0900_modulation modulation,
++ u8 chip_id);
++
++extern void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod);
++
++extern void stv0900_activate_s2_modcode(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod);
++
++extern void stv0900_activate_s2_modcode_single(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod);
++
++extern enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
++ enum fe_stv0900_demod_num demod);
++
++#endif
+diff --git a/drivers/media/dvb/frontends/stv0900_reg.h b/drivers/media/dvb/frontends/stv0900_reg.h
+new file mode 100644
+index 0000000..264f9cf
+--- /dev/null
++++ b/drivers/media/dvb/frontends/stv0900_reg.h
+@@ -0,0 +1,3787 @@
++/*
++ * stv0900_reg.h
++ *
++ * Driver for ST STV0900 satellite demodulator IC.
++ *
++ * Copyright (C) ST Microelectronics.
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ *
++ * 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 STV0900_REG_H
++#define STV0900_REG_H
++
++/*MID*/
++#define R0900_MID 0xf100
++#define F0900_MCHIP_IDENT 0xf10000f0
++#define F0900_MRELEASE 0xf100000f
++
++/*DACR1*/
++#define R0900_DACR1 0xf113
++#define F0900_DAC_MODE 0xf11300e0
++#define F0900_DAC_VALUE1 0xf113000f
++
++/*DACR2*/
++#define R0900_DACR2 0xf114
++#define F0900_DAC_VALUE0 0xf11400ff
++
++/*OUTCFG*/
++#define R0900_OUTCFG 0xf11c
++#define F0900_INV_DATA6 0xf11c0080
++#define F0900_OUTSERRS1_HZ 0xf11c0040
++#define F0900_OUTSERRS2_HZ 0xf11c0020
++#define F0900_OUTSERRS3_HZ 0xf11c0010
++#define F0900_OUTPARRS3_HZ 0xf11c0008
++#define F0900_OUTHZ3_CONTROL 0xf11c0007
++
++/*MODECFG*/
++#define R0900_MODECFG 0xf11d
++#define F0900_FECSPY_SEL_2 0xf11d0020
++#define F0900_HWARE_SEL_2 0xf11d0010
++#define F0900_PKTDEL_SEL_2 0xf11d0008
++#define F0900_DISEQC_SEL_2 0xf11d0004
++#define F0900_VIT_SEL_2 0xf11d0002
++#define F0900_DEMOD_SEL_2 0xf11d0001
++
++/*IRQSTATUS3*/
++#define R0900_IRQSTATUS3 0xf120
++#define F0900_SPLL_LOCK 0xf1200020
++#define F0900_SSTREAM_LCK_3 0xf1200010
++#define F0900_SSTREAM_LCK_2 0xf1200008
++#define F0900_SSTREAM_LCK_1 0xf1200004
++#define F0900_SDVBS1_PRF_2 0xf1200002
++#define F0900_SDVBS1_PRF_1 0xf1200001
++
++/*IRQSTATUS2*/
++#define R0900_IRQSTATUS2 0xf121
++#define F0900_SSPY_ENDSIM_3 0xf1210080
++#define F0900_SSPY_ENDSIM_2 0xf1210040
++#define F0900_SSPY_ENDSIM_1 0xf1210020
++#define F0900_SPKTDEL_ERROR_2 0xf1210010
++#define F0900_SPKTDEL_LOCKB_2 0xf1210008
++#define F0900_SPKTDEL_LOCK_2 0xf1210004
++#define F0900_SPKTDEL_ERROR_1 0xf1210002
++#define F0900_SPKTDEL_LOCKB_1 0xf1210001
++
++/*IRQSTATUS1*/
++#define R0900_IRQSTATUS1 0xf122
++#define F0900_SPKTDEL_LOCK_1 0xf1220080
++#define F0900_SEXTPINB2 0xf1220040
++#define F0900_SEXTPIN2 0xf1220020
++#define F0900_SEXTPINB1 0xf1220010
++#define F0900_SEXTPIN1 0xf1220008
++#define F0900_SDEMOD_LOCKB_2 0xf1220004
++#define F0900_SDEMOD_LOCK_2 0xf1220002
++#define F0900_SDEMOD_IRQ_2 0xf1220001
++
++/*IRQSTATUS0*/
++#define R0900_IRQSTATUS0 0xf123
++#define F0900_SDEMOD_LOCKB_1 0xf1230080
++#define F0900_SDEMOD_LOCK_1 0xf1230040
++#define F0900_SDEMOD_IRQ_1 0xf1230020
++#define F0900_SBCH_ERRFLAG 0xf1230010
++#define F0900_SDISEQC2RX_IRQ 0xf1230008
++#define F0900_SDISEQC2TX_IRQ 0xf1230004
++#define F0900_SDISEQC1RX_IRQ 0xf1230002
++#define F0900_SDISEQC1TX_IRQ 0xf1230001
++
++/*IRQMASK3*/
++#define R0900_IRQMASK3 0xf124
++#define F0900_MPLL_LOCK 0xf1240020
++#define F0900_MSTREAM_LCK_3 0xf1240010
++#define F0900_MSTREAM_LCK_2 0xf1240008
++#define F0900_MSTREAM_LCK_1 0xf1240004
++#define F0900_MDVBS1_PRF_2 0xf1240002
++#define F0900_MDVBS1_PRF_1 0xf1240001
++
++/*IRQMASK2*/
++#define R0900_IRQMASK2 0xf125
++#define F0900_MSPY_ENDSIM_3 0xf1250080
++#define F0900_MSPY_ENDSIM_2 0xf1250040
++#define F0900_MSPY_ENDSIM_1 0xf1250020
++#define F0900_MPKTDEL_ERROR_2 0xf1250010
++#define F0900_MPKTDEL_LOCKB_2 0xf1250008
++#define F0900_MPKTDEL_LOCK_2 0xf1250004
++#define F0900_MPKTDEL_ERROR_1 0xf1250002
++#define F0900_MPKTDEL_LOCKB_1 0xf1250001
++
++/*IRQMASK1*/
++#define R0900_IRQMASK1 0xf126
++#define F0900_MPKTDEL_LOCK_1 0xf1260080
++#define F0900_MEXTPINB2 0xf1260040
++#define F0900_MEXTPIN2 0xf1260020
++#define F0900_MEXTPINB1 0xf1260010
++#define F0900_MEXTPIN1 0xf1260008
++#define F0900_MDEMOD_LOCKB_2 0xf1260004
++#define F0900_MDEMOD_LOCK_2 0xf1260002
++#define F0900_MDEMOD_IRQ_2 0xf1260001
++
++/*IRQMASK0*/
++#define R0900_IRQMASK0 0xf127
++#define F0900_MDEMOD_LOCKB_1 0xf1270080
++#define F0900_MDEMOD_LOCK_1 0xf1270040
++#define F0900_MDEMOD_IRQ_1 0xf1270020
++#define F0900_MBCH_ERRFLAG 0xf1270010
++#define F0900_MDISEQC2RX_IRQ 0xf1270008
++#define F0900_MDISEQC2TX_IRQ 0xf1270004
++#define F0900_MDISEQC1RX_IRQ 0xf1270002
++#define F0900_MDISEQC1TX_IRQ 0xf1270001
++
++/*I2CCFG*/
++#define R0900_I2CCFG 0xf129
++#define F0900_I2C2_FASTMODE 0xf1290080
++#define F0900_STATUS_WR2 0xf1290040
++#define F0900_I2C2ADDR_INC 0xf1290030
++#define F0900_I2C_FASTMODE 0xf1290008
++#define F0900_STATUS_WR 0xf1290004
++#define F0900_I2CADDR_INC 0xf1290003
++
++/*P1_I2CRPT*/
++#define R0900_P1_I2CRPT 0xf12a
++#define F0900_P1_I2CT_ON 0xf12a0080
++#define F0900_P1_ENARPT_LEVEL 0xf12a0070
++#define F0900_P1_SCLT_DELAY 0xf12a0008
++#define F0900_P1_STOP_ENABLE 0xf12a0004
++#define F0900_P1_STOP_SDAT2SDA 0xf12a0002
++
++/*P2_I2CRPT*/
++#define R0900_P2_I2CRPT 0xf12b
++#define F0900_P2_I2CT_ON 0xf12b0080
++#define F0900_P2_ENARPT_LEVEL 0xf12b0070
++#define F0900_P2_SCLT_DELAY 0xf12b0008
++#define F0900_P2_STOP_ENABLE 0xf12b0004
++#define F0900_P2_STOP_SDAT2SDA 0xf12b0002
++
++/*CLKI2CFG*/
++#define R0900_CLKI2CFG 0xf140
++#define F0900_CLKI2_OPD 0xf1400080
++#define F0900_CLKI2_CONFIG 0xf140007e
++#define F0900_CLKI2_XOR 0xf1400001
++
++/*GPIO1CFG*/
++#define R0900_GPIO1CFG 0xf141
++#define F0900_GPIO1_OPD 0xf1410080
++#define F0900_GPIO1_CONFIG 0xf141007e
++#define F0900_GPIO1_XOR 0xf1410001
++
++/*GPIO2CFG*/
++#define R0900_GPIO2CFG 0xf142
++#define F0900_GPIO2_OPD 0xf1420080
++#define F0900_GPIO2_CONFIG 0xf142007e
++#define F0900_GPIO2_XOR 0xf1420001
++
++/*GPIO3CFG*/
++#define R0900_GPIO3CFG 0xf143
++#define F0900_GPIO3_OPD 0xf1430080
++#define F0900_GPIO3_CONFIG 0xf143007e
++#define F0900_GPIO3_XOR 0xf1430001
++
++/*GPIO4CFG*/
++#define R0900_GPIO4CFG 0xf144
++#define F0900_GPIO4_OPD 0xf1440080
++#define F0900_GPIO4_CONFIG 0xf144007e
++#define F0900_GPIO4_XOR 0xf1440001
++
++/*GPIO5CFG*/
++#define R0900_GPIO5CFG 0xf145
++#define F0900_GPIO5_OPD 0xf1450080
++#define F0900_GPIO5_CONFIG 0xf145007e
++#define F0900_GPIO5_XOR 0xf1450001
++
++/*GPIO6CFG*/
++#define R0900_GPIO6CFG 0xf146
++#define F0900_GPIO6_OPD 0xf1460080
++#define F0900_GPIO6_CONFIG 0xf146007e
++#define F0900_GPIO6_XOR 0xf1460001
++
++/*GPIO7CFG*/
++#define R0900_GPIO7CFG 0xf147
++#define F0900_GPIO7_OPD 0xf1470080
++#define F0900_GPIO7_CONFIG 0xf147007e
++#define F0900_GPIO7_XOR 0xf1470001
++
++/*GPIO8CFG*/
++#define R0900_GPIO8CFG 0xf148
++#define F0900_GPIO8_OPD 0xf1480080
++#define F0900_GPIO8_CONFIG 0xf148007e
++#define F0900_GPIO8_XOR 0xf1480001
++
++/*GPIO9CFG*/
++#define R0900_GPIO9CFG 0xf149
++#define F0900_GPIO9_OPD 0xf1490080
++#define F0900_GPIO9_CONFIG 0xf149007e
++#define F0900_GPIO9_XOR 0xf1490001
++
++/*GPIO10CFG*/
++#define R0900_GPIO10CFG 0xf14a
++#define F0900_GPIO10_OPD 0xf14a0080
++#define F0900_GPIO10_CONFIG 0xf14a007e
++#define F0900_GPIO10_XOR 0xf14a0001
++
++/*GPIO11CFG*/
++#define R0900_GPIO11CFG 0xf14b
++#define F0900_GPIO11_OPD 0xf14b0080
++#define F0900_GPIO11_CONFIG 0xf14b007e
++#define F0900_GPIO11_XOR 0xf14b0001
++
++/*GPIO12CFG*/
++#define R0900_GPIO12CFG 0xf14c
++#define F0900_GPIO12_OPD 0xf14c0080
++#define F0900_GPIO12_CONFIG 0xf14c007e
++#define F0900_GPIO12_XOR 0xf14c0001
++
++/*GPIO13CFG*/
++#define R0900_GPIO13CFG 0xf14d
++#define F0900_GPIO13_OPD 0xf14d0080
++#define F0900_GPIO13_CONFIG 0xf14d007e
++#define F0900_GPIO13_XOR 0xf14d0001
++
++/*CS0CFG*/
++#define R0900_CS0CFG 0xf14e
++#define F0900_CS0_OPD 0xf14e0080
++#define F0900_CS0_CONFIG 0xf14e007e
++#define F0900_CS0_XOR 0xf14e0001
++
++/*CS1CFG*/
++#define R0900_CS1CFG 0xf14f
++#define F0900_CS1_OPD 0xf14f0080
++#define F0900_CS1_CONFIG 0xf14f007e
++#define F0900_CS1_XOR 0xf14f0001
++
++/*STDBYCFG*/
++#define R0900_STDBYCFG 0xf150
++#define F0900_STDBY_OPD 0xf1500080
++#define F0900_STDBY_CONFIG 0xf150007e
++#define F0900_STBDY_XOR 0xf1500001
++
++/*DIRCLKCFG*/
++#define R0900_DIRCLKCFG 0xf151
++#define F0900_DIRCLK_OPD 0xf1510080
++#define F0900_DIRCLK_CONFIG 0xf151007e
++#define F0900_DIRCLK_XOR 0xf1510001
++
++/*AGCRF1CFG*/
++#define R0900_AGCRF1CFG 0xf152
++#define F0900_AGCRF1_OPD 0xf1520080
++#define F0900_AGCRF1_CONFIG 0xf152007e
++#define F0900_AGCRF1_XOR 0xf1520001
++
++/*SDAT1CFG*/
++#define R0900_SDAT1CFG 0xf153
++#define F0900_SDAT1_OPD 0xf1530080
++#define F0900_SDAT1_CONFIG 0xf153007e
++#define F0900_SDAT1_XOR 0xf1530001
++
++/*SCLT1CFG*/
++#define R0900_SCLT1CFG 0xf154
++#define F0900_SCLT1_OPD 0xf1540080
++#define F0900_SCLT1_CONFIG 0xf154007e
++#define F0900_SCLT1_XOR 0xf1540001
++
++/*DISEQCO1CFG*/
++#define R0900_DISEQCO1CFG 0xf155
++#define F0900_DISEQCO1_OPD 0xf1550080
++#define F0900_DISEQCO1_CONFIG 0xf155007e
++#define F0900_DISEQC1_XOR 0xf1550001
++
++/*AGCRF2CFG*/
++#define R0900_AGCRF2CFG 0xf156
++#define F0900_AGCRF2_OPD 0xf1560080
++#define F0900_AGCRF2_CONFIG 0xf156007e
++#define F0900_AGCRF2_XOR 0xf1560001
++
++/*SDAT2CFG*/
++#define R0900_SDAT2CFG 0xf157
++#define F0900_SDAT2_OPD 0xf1570080
++#define F0900_SDAT2_CONFIG 0xf157007e
++#define F0900_SDAT2_XOR 0xf1570001
++
++/*SCLT2CFG*/
++#define R0900_SCLT2CFG 0xf158
++#define F0900_SCLT2_OPD 0xf1580080
++#define F0900_SCLT2_CONFIG 0xf158007e
++#define F0900_SCLT2_XOR 0xf1580001
++
++/*DISEQCO2CFG*/
++#define R0900_DISEQCO2CFG 0xf159
++#define F0900_DISEQCO2_OPD 0xf1590080
++#define F0900_DISEQCO2_CONFIG 0xf159007e
++#define F0900_DISEQC2_XOR 0xf1590001
++
++/*CLKOUT27CFG*/
++#define R0900_CLKOUT27CFG 0xf15a
++#define F0900_CLKOUT27_OPD 0xf15a0080
++#define F0900_CLKOUT27_CONFIG 0xf15a007e
++#define F0900_CLKOUT27_XOR 0xf15a0001
++
++/*ERROR1CFG*/
++#define R0900_ERROR1CFG 0xf15b
++#define F0900_ERROR1_OPD 0xf15b0080
++#define F0900_ERROR1_CONFIG 0xf15b007e
++#define F0900_ERROR1_XOR 0xf15b0001
++
++/*DPN1CFG*/
++#define R0900_DPN1CFG 0xf15c
++#define F0900_DPN1_OPD 0xf15c0080
++#define F0900_DPN1_CONFIG 0xf15c007e
++#define F0900_DPN1_XOR 0xf15c0001
++
++/*STROUT1CFG*/
++#define R0900_STROUT1CFG 0xf15d
++#define F0900_STROUT1_OPD 0xf15d0080
++#define F0900_STROUT1_CONFIG 0xf15d007e
++#define F0900_STROUT1_XOR 0xf15d0001
++
++/*CLKOUT1CFG*/
++#define R0900_CLKOUT1CFG 0xf15e
++#define F0900_CLKOUT1_OPD 0xf15e0080
++#define F0900_CLKOUT1_CONFIG 0xf15e007e
++#define F0900_CLKOUT1_XOR 0xf15e0001
++
++/*DATA71CFG*/
++#define R0900_DATA71CFG 0xf15f
++#define F0900_DATA71_OPD 0xf15f0080
++#define F0900_DATA71_CONFIG 0xf15f007e
++#define F0900_DATA71_XOR 0xf15f0001
++
++/*ERROR2CFG*/
++#define R0900_ERROR2CFG 0xf160
++#define F0900_ERROR2_OPD 0xf1600080
++#define F0900_ERROR2_CONFIG 0xf160007e
++#define F0900_ERROR2_XOR 0xf1600001
++
++/*DPN2CFG*/
++#define R0900_DPN2CFG 0xf161
++#define F0900_DPN2_OPD 0xf1610080
++#define F0900_DPN2_CONFIG 0xf161007e
++#define F0900_DPN2_XOR 0xf1610001
++
++/*STROUT2CFG*/
++#define R0900_STROUT2CFG 0xf162
++#define F0900_STROUT2_OPD 0xf1620080
++#define F0900_STROUT2_CONFIG 0xf162007e
++#define F0900_STROUT2_XOR 0xf1620001
++
++/*CLKOUT2CFG*/
++#define R0900_CLKOUT2CFG 0xf163
++#define F0900_CLKOUT2_OPD 0xf1630080
++#define F0900_CLKOUT2_CONFIG 0xf163007e
++#define F0900_CLKOUT2_XOR 0xf1630001
++
++/*DATA72CFG*/
++#define R0900_DATA72CFG 0xf164
++#define F0900_DATA72_OPD 0xf1640080
++#define F0900_DATA72_CONFIG 0xf164007e
++#define F0900_DATA72_XOR 0xf1640001
++
++/*ERROR3CFG*/
++#define R0900_ERROR3CFG 0xf165
++#define F0900_ERROR3_OPD 0xf1650080
++#define F0900_ERROR3_CONFIG 0xf165007e
++#define F0900_ERROR3_XOR 0xf1650001
++
++/*DPN3CFG*/
++#define R0900_DPN3CFG 0xf166
++#define F0900_DPN3_OPD 0xf1660080
++#define F0900_DPN3_CONFIG 0xf166007e
++#define F0900_DPN3_XOR 0xf1660001
++
++/*STROUT3CFG*/
++#define R0900_STROUT3CFG 0xf167
++#define F0900_STROUT3_OPD 0xf1670080
++#define F0900_STROUT3_CONFIG 0xf167007e
++#define F0900_STROUT3_XOR 0xf1670001
++
++/*CLKOUT3CFG*/
++#define R0900_CLKOUT3CFG 0xf168
++#define F0900_CLKOUT3_OPD 0xf1680080
++#define F0900_CLKOUT3_CONFIG 0xf168007e
++#define F0900_CLKOUT3_XOR 0xf1680001
++
++/*DATA73CFG*/
++#define R0900_DATA73CFG 0xf169
++#define F0900_DATA73_OPD 0xf1690080
++#define F0900_DATA73_CONFIG 0xf169007e
++#define F0900_DATA73_XOR 0xf1690001
++
++/*FSKTFC2*/
++#define R0900_FSKTFC2 0xf170
++#define F0900_FSKT_KMOD 0xf17000fc
++#define F0900_FSKT_CAR2 0xf1700003
++
++/*FSKTFC1*/
++#define R0900_FSKTFC1 0xf171
++#define F0900_FSKT_CAR1 0xf17100ff
++
++/*FSKTFC0*/
++#define R0900_FSKTFC0 0xf172
++#define F0900_FSKT_CAR0 0xf17200ff
++
++/*FSKTDELTAF1*/
++#define R0900_FSKTDELTAF1 0xf173
++#define F0900_FSKT_DELTAF1 0xf173000f
++
++/*FSKTDELTAF0*/
++#define R0900_FSKTDELTAF0 0xf174
++#define F0900_FSKT_DELTAF0 0xf17400ff
++
++/*FSKTCTRL*/
++#define R0900_FSKTCTRL 0xf175
++#define F0900_FSKT_EN_SGN 0xf1750040
++#define F0900_FSKT_MOD_SGN 0xf1750020
++#define F0900_FSKT_MOD_EN 0xf175001c
++#define F0900_FSKT_DACMODE 0xf1750003
++
++/*FSKRFC2*/
++#define R0900_FSKRFC2 0xf176
++#define F0900_FSKR_DETSGN 0xf1760040
++#define F0900_FSKR_OUTSGN 0xf1760020
++#define F0900_FSKR_KAGC 0xf176001c
++#define F0900_FSKR_CAR2 0xf1760003
++
++/*FSKRFC1*/
++#define R0900_FSKRFC1 0xf177
++#define F0900_FSKR_CAR1 0xf17700ff
++
++/*FSKRFC0*/
++#define R0900_FSKRFC0 0xf178
++#define F0900_FSKR_CAR0 0xf17800ff
++
++/*FSKRK1*/
++#define R0900_FSKRK1 0xf179
++#define F0900_FSKR_K1_EXP 0xf17900e0
++#define F0900_FSKR_K1_MANT 0xf179001f
++
++/*FSKRK2*/
++#define R0900_FSKRK2 0xf17a
++#define F0900_FSKR_K2_EXP 0xf17a00e0
++#define F0900_FSKR_K2_MANT 0xf17a001f
++
++/*FSKRAGCR*/
++#define R0900_FSKRAGCR 0xf17b
++#define F0900_FSKR_OUTCTL 0xf17b00c0
++#define F0900_FSKR_AGC_REF 0xf17b003f
++
++/*FSKRAGC*/
++#define R0900_FSKRAGC 0xf17c
++#define F0900_FSKR_AGC_ACCU 0xf17c00ff
++
++/*FSKRALPHA*/
++#define R0900_FSKRALPHA 0xf17d
++#define F0900_FSKR_ALPHA_EXP 0xf17d001c
++#define F0900_FSKR_ALPHA_M 0xf17d0003
++
++/*FSKRPLTH1*/
++#define R0900_FSKRPLTH1 0xf17e
++#define F0900_FSKR_BETA 0xf17e00f0
++#define F0900_FSKR_PLL_TRESH1 0xf17e000f
++
++/*FSKRPLTH0*/
++#define R0900_FSKRPLTH0 0xf17f
++#define F0900_FSKR_PLL_TRESH0 0xf17f00ff
++
++/*FSKRDF1*/
++#define R0900_FSKRDF1 0xf180
++#define F0900_FSKR_OUT 0xf1800080
++#define F0900_FSKR_DELTAF1 0xf180001f
++
++/*FSKRDF0*/
++#define R0900_FSKRDF0 0xf181
++#define F0900_FSKR_DELTAF0 0xf18100ff
++
++/*FSKRSTEPP*/
++#define R0900_FSKRSTEPP 0xf182
++#define F0900_FSKR_STEP_PLUS 0xf18200ff
++
++/*FSKRSTEPM*/
++#define R0900_FSKRSTEPM 0xf183
++#define F0900_FSKR_STEP_MINUS 0xf18300ff
++
++/*FSKRDET1*/
++#define R0900_FSKRDET1 0xf184
++#define F0900_FSKR_DETECT 0xf1840080
++#define F0900_FSKR_CARDET_ACCU1 0xf184000f
++
++/*FSKRDET0*/
++#define R0900_FSKRDET0 0xf185
++#define F0900_FSKR_CARDET_ACCU0 0xf18500ff
++
++/*FSKRDTH1*/
++#define R0900_FSKRDTH1 0xf186
++#define F0900_FSKR_CARLOSS_THRESH1 0xf18600f0
++#define F0900_FSKR_CARDET_THRESH1 0xf186000f
++
++/*FSKRDTH0*/
++#define R0900_FSKRDTH0 0xf187
++#define F0900_FSKR_CARDET_THRESH0 0xf18700ff
++
++/*FSKRLOSS*/
++#define R0900_FSKRLOSS 0xf188
++#define F0900_FSKR_CARLOSS_THRESH0 0xf18800ff
++
++/*P2_DISTXCTL*/
++#define R0900_P2_DISTXCTL 0xf190
++#define F0900_P2_TIM_OFF 0xf1900080
++#define F0900_P2_DISEQC_RESET 0xf1900040
++#define F0900_P2_TIM_CMD 0xf1900030
++#define F0900_P2_DIS_PRECHARGE 0xf1900008
++#define F0900_P2_DISTX_MODE 0xf1900007
++
++/*P2_DISRXCTL*/
++#define R0900_P2_DISRXCTL 0xf191
++#define F0900_P2_RECEIVER_ON 0xf1910080
++#define F0900_P2_IGNO_SHORT22K 0xf1910040
++#define F0900_P2_ONECHIP_TRX 0xf1910020
++#define F0900_P2_EXT_ENVELOP 0xf1910010
++#define F0900_P2_PIN_SELECT 0xf191000c
++#define F0900_P2_IRQ_RXEND 0xf1910002
++#define F0900_P2_IRQ_4NBYTES 0xf1910001
++
++/*P2_DISRX_ST0*/
++#define R0900_P2_DISRX_ST0 0xf194
++#define F0900_P2_RX_END 0xf1940080
++#define F0900_P2_RX_ACTIVE 0xf1940040
++#define F0900_P2_SHORT_22KHZ 0xf1940020
++#define F0900_P2_CONT_TONE 0xf1940010
++#define F0900_P2_FIFO_4BREADY 0xf1940008
++#define F0900_P2_FIFO_EMPTY 0xf1940004
++#define F0900_P2_ABORT_DISRX 0xf1940001
++
++/*P2_DISRX_ST1*/
++#define R0900_P2_DISRX_ST1 0xf195
++#define F0900_P2_RX_FAIL 0xf1950080
++#define F0900_P2_FIFO_PARITYFAIL 0xf1950040
++#define F0900_P2_RX_NONBYTE 0xf1950020
++#define F0900_P2_FIFO_OVERFLOW 0xf1950010
++#define F0900_P2_FIFO_BYTENBR 0xf195000f
++
++/*P2_DISRXDATA*/
++#define R0900_P2_DISRXDATA 0xf196
++#define F0900_P2_DISRX_DATA 0xf19600ff
++
++/*P2_DISTXDATA*/
++#define R0900_P2_DISTXDATA 0xf197
++#define F0900_P2_DISEQC_FIFO 0xf19700ff
++
++/*P2_DISTXSTATUS*/
++#define R0900_P2_DISTXSTATUS 0xf198
++#define F0900_P2_TX_FAIL 0xf1980080
++#define F0900_P2_FIFO_FULL 0xf1980040
++#define F0900_P2_TX_IDLE 0xf1980020
++#define F0900_P2_GAP_BURST 0xf1980010
++#define F0900_P2_TXFIFO_BYTES 0xf198000f
++
++/*P2_F22TX*/
++#define R0900_P2_F22TX 0xf199
++#define F0900_P2_F22_REG 0xf19900ff
++
++/*P2_F22RX*/
++#define R0900_P2_F22RX 0xf19a
++#define F0900_P2_F22RX_REG 0xf19a00ff
++
++/*P2_ACRPRESC*/
++#define R0900_P2_ACRPRESC 0xf19c
++#define F0900_P2_ACR_CODFRDY 0xf19c0008
++#define F0900_P2_ACR_PRESC 0xf19c0007
++
++/*P2_ACRDIV*/
++#define R0900_P2_ACRDIV 0xf19d
++#define F0900_P2_ACR_DIV 0xf19d00ff
++
++/*P1_DISTXCTL*/
++#define R0900_P1_DISTXCTL 0xf1a0
++#define F0900_P1_TIM_OFF 0xf1a00080
++#define F0900_P1_DISEQC_RESET 0xf1a00040
++#define F0900_P1_TIM_CMD 0xf1a00030
++#define F0900_P1_DIS_PRECHARGE 0xf1a00008
++#define F0900_P1_DISTX_MODE 0xf1a00007
++
++/*P1_DISRXCTL*/
++#define R0900_P1_DISRXCTL 0xf1a1
++#define F0900_P1_RECEIVER_ON 0xf1a10080
++#define F0900_P1_IGNO_SHORT22K 0xf1a10040
++#define F0900_P1_ONECHIP_TRX 0xf1a10020
++#define F0900_P1_EXT_ENVELOP 0xf1a10010
++#define F0900_P1_PIN_SELECT 0xf1a1000c
++#define F0900_P1_IRQ_RXEND 0xf1a10002
++#define F0900_P1_IRQ_4NBYTES 0xf1a10001
++
++/*P1_DISRX_ST0*/
++#define R0900_P1_DISRX_ST0 0xf1a4
++#define F0900_P1_RX_END 0xf1a40080
++#define F0900_P1_RX_ACTIVE 0xf1a40040
++#define F0900_P1_SHORT_22KHZ 0xf1a40020
++#define F0900_P1_CONT_TONE 0xf1a40010
++#define F0900_P1_FIFO_4BREADY 0xf1a40008
++#define F0900_P1_FIFO_EMPTY 0xf1a40004
++#define F0900_P1_ABORT_DISRX 0xf1a40001
++
++/*P1_DISRX_ST1*/
++#define R0900_P1_DISRX_ST1 0xf1a5
++#define F0900_P1_RX_FAIL 0xf1a50080
++#define F0900_P1_FIFO_PARITYFAIL 0xf1a50040
++#define F0900_P1_RX_NONBYTE 0xf1a50020
++#define F0900_P1_FIFO_OVERFLOW 0xf1a50010
++#define F0900_P1_FIFO_BYTENBR 0xf1a5000f
++
++/*P1_DISRXDATA*/
++#define R0900_P1_DISRXDATA 0xf1a6
++#define F0900_P1_DISRX_DATA 0xf1a600ff
++
++/*P1_DISTXDATA*/
++#define R0900_P1_DISTXDATA 0xf1a7
++#define F0900_P1_DISEQC_FIFO 0xf1a700ff
++
++/*P1_DISTXSTATUS*/
++#define R0900_P1_DISTXSTATUS 0xf1a8
++#define F0900_P1_TX_FAIL 0xf1a80080
++#define F0900_P1_FIFO_FULL 0xf1a80040
++#define F0900_P1_TX_IDLE 0xf1a80020
++#define F0900_P1_GAP_BURST 0xf1a80010
++#define F0900_P1_TXFIFO_BYTES 0xf1a8000f
++
++/*P1_F22TX*/
++#define R0900_P1_F22TX 0xf1a9
++#define F0900_P1_F22_REG 0xf1a900ff
++
++/*P1_F22RX*/
++#define R0900_P1_F22RX 0xf1aa
++#define F0900_P1_F22RX_REG 0xf1aa00ff
++
++/*P1_ACRPRESC*/
++#define R0900_P1_ACRPRESC 0xf1ac
++#define F0900_P1_ACR_CODFRDY 0xf1ac0008
++#define F0900_P1_ACR_PRESC 0xf1ac0007
++
++/*P1_ACRDIV*/
++#define R0900_P1_ACRDIV 0xf1ad
++#define F0900_P1_ACR_DIV 0xf1ad00ff
++
++/*NCOARSE*/
++#define R0900_NCOARSE 0xf1b3
++#define F0900_M_DIV 0xf1b300ff
++
++/*SYNTCTRL*/
++#define R0900_SYNTCTRL 0xf1b6
++#define F0900_STANDBY 0xf1b60080
++#define F0900_BYPASSPLLCORE 0xf1b60040
++#define F0900_SELX1RATIO 0xf1b60020
++#define F0900_I2C_TUD 0xf1b60010
++#define F0900_STOP_PLL 0xf1b60008
++#define F0900_BYPASSPLLFSK 0xf1b60004
++#define F0900_SELOSCI 0xf1b60002
++#define F0900_BYPASSPLLADC 0xf1b60001
++
++/*FILTCTRL*/
++#define R0900_FILTCTRL 0xf1b7
++#define F0900_INV_CLK135 0xf1b70080
++#define F0900_PERM_BYPDIS 0xf1b70040
++#define F0900_SEL_FSKCKDIV 0xf1b70004
++#define F0900_INV_CLKFSK 0xf1b70002
++#define F0900_BYPASS_APPLI 0xf1b70001
++
++/*PLLSTAT*/
++#define R0900_PLLSTAT 0xf1b8
++#define F0900_ACM_SEL 0xf1b80080
++#define F0900_DTV_SEL 0xf1b80040
++#define F0900_PLLLOCK 0xf1b80001
++
++/*STOPCLK1*/
++#define R0900_STOPCLK1 0xf1c2
++#define F0900_STOP_CLKPKDT2 0xf1c20040
++#define F0900_STOP_CLKPKDT1 0xf1c20020
++#define F0900_STOP_CLKFEC 0xf1c20010
++#define F0900_STOP_CLKADCI2 0xf1c20008
++#define F0900_INV_CLKADCI2 0xf1c20004
++#define F0900_STOP_CLKADCI1 0xf1c20002
++#define F0900_INV_CLKADCI1 0xf1c20001
++
++/*STOPCLK2*/
++#define R0900_STOPCLK2 0xf1c3
++#define F0900_STOP_CLKSAMP2 0xf1c30010
++#define F0900_STOP_CLKSAMP1 0xf1c30008
++#define F0900_STOP_CLKVIT2 0xf1c30004
++#define F0900_STOP_CLKVIT1 0xf1c30002
++#define F0900_STOP_CLKTS 0xf1c30001
++
++/*TSTTNR0*/
++#define R0900_TSTTNR0 0xf1df
++#define F0900_SEL_FSK 0xf1df0080
++#define F0900_FSK_PON 0xf1df0004
++#define F0900_FSK_OPENLOOP 0xf1df0002
++
++/*TSTTNR1*/
++#define R0900_TSTTNR1 0xf1e0
++#define F0900_BYPASS_ADC1 0xf1e00080
++#define F0900_INVADC1_CKOUT 0xf1e00040
++#define F0900_SELIQSRC1 0xf1e00030
++#define F0900_ADC1_PON 0xf1e00002
++#define F0900_ADC1_INMODE 0xf1e00001
++
++/*TSTTNR2*/
++#define R0900_TSTTNR2 0xf1e1
++#define F0900_DISEQC1_PON 0xf1e10020
++#define F0900_DISEQC1_TEST 0xf1e1001f
++
++/*TSTTNR3*/
++#define R0900_TSTTNR3 0xf1e2
++#define F0900_BYPASS_ADC2 0xf1e20080
++#define F0900_INVADC2_CKOUT 0xf1e20040
++#define F0900_SELIQSRC2 0xf1e20030
++#define F0900_ADC2_PON 0xf1e20002
++#define F0900_ADC2_INMODE 0xf1e20001
++
++/*TSTTNR4*/
++#define R0900_TSTTNR4 0xf1e3
++#define F0900_DISEQC2_PON 0xf1e30020
++#define F0900_DISEQC2_TEST 0xf1e3001f
++
++/*P2_IQCONST*/
++#define R0900_P2_IQCONST 0xf200
++#define F0900_P2_CONSTEL_SELECT 0xf2000060
++#define F0900_P2_IQSYMB_SEL 0xf200001f
++
++/*P2_NOSCFG*/
++#define R0900_P2_NOSCFG 0xf201
++#define F0900_P2_DUMMYPL_NOSDATA 0xf2010020
++#define F0900_P2_NOSPLH_BETA 0xf2010018
++#define F0900_P2_NOSDATA_BETA 0xf2010007
++
++/*P2_ISYMB*/
++#define R0900_P2_ISYMB 0xf202
++#define F0900_P2_I_SYMBOL 0xf20201ff
++
++/*P2_QSYMB*/
++#define R0900_P2_QSYMB 0xf203
++#define F0900_P2_Q_SYMBOL 0xf20301ff
++
++/*P2_AGC1CFG*/
++#define R0900_P2_AGC1CFG 0xf204
++#define F0900_P2_DC_FROZEN 0xf2040080
++#define F0900_P2_DC_CORRECT 0xf2040040
++#define F0900_P2_AMM_FROZEN 0xf2040020
++#define F0900_P2_AMM_CORRECT 0xf2040010
++#define F0900_P2_QUAD_FROZEN 0xf2040008
++#define F0900_P2_QUAD_CORRECT 0xf2040004
++#define F0900_P2_DCCOMP_SLOW 0xf2040002
++#define F0900_P2_IQMISM_SLOW 0xf2040001
++
++/*P2_AGC1CN*/
++#define R0900_P2_AGC1CN 0xf206
++#define F0900_P2_AGC1_LOCKED 0xf2060080
++#define F0900_P2_AGC1_OVERFLOW 0xf2060040
++#define F0900_P2_AGC1_NOSLOWLK 0xf2060020
++#define F0900_P2_AGC1_MINPOWER 0xf2060010
++#define F0900_P2_AGCOUT_FAST 0xf2060008
++#define F0900_P2_AGCIQ_BETA 0xf2060007
++
++/*P2_AGC1REF*/
++#define R0900_P2_AGC1REF 0xf207
++#define F0900_P2_AGCIQ_REF 0xf20700ff
++
++/*P2_IDCCOMP*/
++#define R0900_P2_IDCCOMP 0xf208
++#define F0900_P2_IAVERAGE_ADJ 0xf20801ff
++
++/*P2_QDCCOMP*/
++#define R0900_P2_QDCCOMP 0xf209
++#define F0900_P2_QAVERAGE_ADJ 0xf20901ff
++
++/*P2_POWERI*/
++#define R0900_P2_POWERI 0xf20a
++#define F0900_P2_POWER_I 0xf20a00ff
++
++/*P2_POWERQ*/
++#define R0900_P2_POWERQ 0xf20b
++#define F0900_P2_POWER_Q 0xf20b00ff
++
++/*P2_AGC1AMM*/
++#define R0900_P2_AGC1AMM 0xf20c
++#define F0900_P2_AMM_VALUE 0xf20c00ff
++
++/*P2_AGC1QUAD*/
++#define R0900_P2_AGC1QUAD 0xf20d
++#define F0900_P2_QUAD_VALUE 0xf20d01ff
++
++/*P2_AGCIQIN1*/
++#define R0900_P2_AGCIQIN1 0xf20e
++#define F0900_P2_AGCIQ_VALUE1 0xf20e00ff
++
++/*P2_AGCIQIN0*/
++#define R0900_P2_AGCIQIN0 0xf20f
++#define F0900_P2_AGCIQ_VALUE0 0xf20f00ff
++
++/*P2_DEMOD*/
++#define R0900_P2_DEMOD 0xf210
++#define F0900_P2_DEMOD_STOP 0xf2100040
++#define F0900_P2_SPECINV_CONTROL 0xf2100030
++#define F0900_P2_FORCE_ENASAMP 0xf2100008
++#define F0900_P2_MANUAL_ROLLOFF 0xf2100004
++#define F0900_P2_ROLLOFF_CONTROL 0xf2100003
++
++/*P2_DMDMODCOD*/
++#define R0900_P2_DMDMODCOD 0xf211
++#define F0900_P2_MANUAL_MODCOD 0xf2110080
++#define F0900_P2_DEMOD_MODCOD 0xf211007c
++#define F0900_P2_DEMOD_TYPE 0xf2110003
++
++/*P2_DSTATUS*/
++#define R0900_P2_DSTATUS 0xf212
++#define F0900_P2_CAR_LOCK 0xf2120080
++#define F0900_P2_TMGLOCK_QUALITY 0xf2120060
++#define F0900_P2_SDVBS1_ENABLE 0xf2120010
++#define F0900_P2_LOCK_DEFINITIF 0xf2120008
++#define F0900_P2_TIMING_IS_LOCKED 0xf2120004
++#define F0900_P2_COARSE_TMGLOCK 0xf2120002
++#define F0900_P2_COARSE_CARLOCK 0xf2120001
++
++/*P2_DSTATUS2*/
++#define R0900_P2_DSTATUS2 0xf213
++#define F0900_P2_DEMOD_DELOCK 0xf2130080
++#define F0900_P2_DEMOD_TIMEOUT 0xf2130040
++#define F0900_P2_MODCODRQ_SYNCTAG 0xf2130020
++#define F0900_P2_POLYPH_SATEVENT 0xf2130010
++#define F0900_P2_AGC1_NOSIGNALACK 0xf2130008
++#define F0900_P2_AGC2_OVERFLOW 0xf2130004
++#define F0900_P2_CFR_OVERFLOW 0xf2130002
++#define F0900_P2_GAMMA_OVERUNDER 0xf2130001
++
++/*P2_DMDCFGMD*/
++#define R0900_P2_DMDCFGMD 0xf214
++#define F0900_P2_DVBS2_ENABLE 0xf2140080
++#define F0900_P2_DVBS1_ENABLE 0xf2140040
++#define F0900_P2_CFR_AUTOSCAN 0xf2140020
++#define F0900_P2_SCAN_ENABLE 0xf2140010
++#define F0900_P2_TUN_AUTOSCAN 0xf2140008
++#define F0900_P2_NOFORCE_RELOCK 0xf2140004
++#define F0900_P2_TUN_RNG 0xf2140003
++
++/*P2_DMDCFG2*/
++#define R0900_P2_DMDCFG2 0xf215
++#define F0900_P2_AGC1_WAITLOCK 0xf2150080
++#define F0900_P2_S1S2_SEQUENTIAL 0xf2150040
++#define F0900_P2_OVERFLOW_TIMEOUT 0xf2150020
++#define F0900_P2_SCANFAIL_TIMEOUT 0xf2150010
++#define F0900_P2_DMDTOUT_BACK 0xf2150008
++#define F0900_P2_CARLOCK_S1ENABLE 0xf2150004
++#define F0900_P2_COARSE_LK3MODE 0xf2150002
++#define F0900_P2_COARSE_LK2MODE 0xf2150001
++
++/*P2_DMDISTATE*/
++#define R0900_P2_DMDISTATE 0xf216
++#define F0900_P2_I2C_NORESETDMODE 0xf2160080
++#define F0900_P2_FORCE_ETAPED 0xf2160040
++#define F0900_P2_SDMDRST_DIRCLK 0xf2160020
++#define F0900_P2_I2C_DEMOD_MODE 0xf216001f
++
++/*P2_DMDT0M*/
++#define R0900_P2_DMDT0M 0xf217
++#define F0900_P2_DMDT0_MIN 0xf21700ff
++
++/*P2_DMDSTATE*/
++#define R0900_P2_DMDSTATE 0xf21b
++#define F0900_P2_DEMOD_LOCKED 0xf21b0080
++#define F0900_P2_HEADER_MODE 0xf21b0060
++#define F0900_P2_DEMOD_MODE 0xf21b001f
++
++/*P2_DMDFLYW*/
++#define R0900_P2_DMDFLYW 0xf21c
++#define F0900_P2_I2C_IRQVAL 0xf21c00f0
++#define F0900_P2_FLYWHEEL_CPT 0xf21c000f
++
++/*P2_DSTATUS3*/
++#define R0900_P2_DSTATUS3 0xf21d
++#define F0900_P2_CFR_ZIGZAG 0xf21d0080
++#define F0900_P2_DEMOD_CFGMODE 0xf21d0060
++#define F0900_P2_GAMMA_LOWBAUDRATE 0xf21d0010
++#define F0900_P2_RELOCK_MODE 0xf21d0008
++#define F0900_P2_DEMOD_FAIL 0xf21d0004
++#define F0900_P2_ETAPE1A_DVBXMEM 0xf21d0003
++
++/*P2_DMDCFG3*/
++#define R0900_P2_DMDCFG3 0xf21e
++#define F0900_P2_DVBS1_TMGWAIT 0xf21e0080
++#define F0900_P2_NO_BWCENTERING 0xf21e0040
++#define F0900_P2_INV_SEQSRCH 0xf21e0020
++#define F0900_P2_DIS_SFRUPLOW_TRK 0xf21e0010
++#define F0900_P2_NOSTOP_FIFOFULL 0xf21e0008
++#define F0900_P2_LOCKTIME_MODE 0xf21e0007
++
++/*P2_DMDCFG4*/
++#define R0900_P2_DMDCFG4 0xf21f
++#define F0900_P2_TUNER_NRELAUNCH 0xf21f0008
++#define F0900_P2_DIS_CLKENABLE 0xf21f0004
++#define F0900_P2_DIS_HDRDIVLOCK 0xf21f0002
++#define F0900_P2_NO_TNRWBINIT 0xf21f0001
++
++/*P2_CORRELMANT*/
++#define R0900_P2_CORRELMANT 0xf220
++#define F0900_P2_CORREL_MANT 0xf22000ff
++
++/*P2_CORRELABS*/
++#define R0900_P2_CORRELABS 0xf221
++#define F0900_P2_CORREL_ABS 0xf22100ff
++
++/*P2_CORRELEXP*/
++#define R0900_P2_CORRELEXP 0xf222
++#define F0900_P2_CORREL_ABSEXP 0xf22200f0
++#define F0900_P2_CORREL_EXP 0xf222000f
++
++/*P2_PLHMODCOD*/
++#define R0900_P2_PLHMODCOD 0xf224
++#define F0900_P2_SPECINV_DEMOD 0xf2240080
++#define F0900_P2_PLH_MODCOD 0xf224007c
++#define F0900_P2_PLH_TYPE 0xf2240003
++
++/*P2_AGCK32*/
++#define R0900_P2_AGCK32 0xf22b
++#define F0900_P2_R3ADJOFF_32APSK 0xf22b0080
++#define F0900_P2_R2ADJOFF_32APSK 0xf22b0040
++#define F0900_P2_R1ADJOFF_32APSK 0xf22b0020
++#define F0900_P2_RADJ_32APSK 0xf22b001f
++
++/*P2_AGC2O*/
++#define R0900_P2_AGC2O 0xf22c
++#define F0900_P2_AGC2REF_ADJUSTING 0xf22c0080
++#define F0900_P2_AGC2_COARSEFAST 0xf22c0040
++#define F0900_P2_AGC2_LKSQRT 0xf22c0020
++#define F0900_P2_AGC2_LKMODE 0xf22c0010
++#define F0900_P2_AGC2_LKEQUA 0xf22c0008
++#define F0900_P2_AGC2_COEF 0xf22c0007
++
++/*P2_AGC2REF*/
++#define R0900_P2_AGC2REF 0xf22d
++#define F0900_P2_AGC2_REF 0xf22d00ff
++
++/*P2_AGC1ADJ*/
++#define R0900_P2_AGC1ADJ 0xf22e
++#define F0900_P2_AGC1ADJ_MANUAL 0xf22e0080
++#define F0900_P2_AGC1_ADJUSTED 0xf22e017f
++
++/*P2_AGC2I1*/
++#define R0900_P2_AGC2I1 0xf236
++#define F0900_P2_AGC2_INTEGRATOR1 0xf23600ff
++
++/*P2_AGC2I0*/
++#define R0900_P2_AGC2I0 0xf237
++#define F0900_P2_AGC2_INTEGRATOR0 0xf23700ff
++
++/*P2_CARCFG*/
++#define R0900_P2_CARCFG 0xf238
++#define F0900_P2_CFRUPLOW_AUTO 0xf2380080
++#define F0900_P2_CFRUPLOW_TEST 0xf2380040
++#define F0900_P2_EN_CAR2CENTER 0xf2380020
++#define F0900_P2_CARHDR_NODIV8 0xf2380010
++#define F0900_P2_I2C_ROTA 0xf2380008
++#define F0900_P2_ROTAON 0xf2380004
++#define F0900_P2_PH_DET_ALGO 0xf2380003
++
++/*P2_ACLC*/
++#define R0900_P2_ACLC 0xf239
++#define F0900_P2_STOP_S2ALPHA 0xf23900c0
++#define F0900_P2_CAR_ALPHA_MANT 0xf2390030
++#define F0900_P2_CAR_ALPHA_EXP 0xf239000f
++
++/*P2_BCLC*/
++#define R0900_P2_BCLC 0xf23a
++#define F0900_P2_STOP_S2BETA 0xf23a00c0
++#define F0900_P2_CAR_BETA_MANT 0xf23a0030
++#define F0900_P2_CAR_BETA_EXP 0xf23a000f
++
++/*P2_CARFREQ*/
++#define R0900_P2_CARFREQ 0xf23d
++#define F0900_P2_KC_COARSE_EXP 0xf23d00f0
++#define F0900_P2_BETA_FREQ 0xf23d000f
++
++/*P2_CARHDR*/
++#define R0900_P2_CARHDR 0xf23e
++#define F0900_P2_K_FREQ_HDR 0xf23e00ff
++
++/*P2_LDT*/
++#define R0900_P2_LDT 0xf23f
++#define F0900_P2_CARLOCK_THRES 0xf23f01ff
++
++/*P2_LDT2*/
++#define R0900_P2_LDT2 0xf240
++#define F0900_P2_CARLOCK_THRES2 0xf24001ff
++
++/*P2_CFRICFG*/
++#define R0900_P2_CFRICFG 0xf241
++#define F0900_P2_CFRINIT_UNVALRNG 0xf2410080
++#define F0900_P2_CFRINIT_LUNVALCPT 0xf2410040
++#define F0900_P2_CFRINIT_ABORTDBL 0xf2410020
++#define F0900_P2_CFRINIT_ABORTPRED 0xf2410010
++#define F0900_P2_CFRINIT_UNVALSKIP 0xf2410008
++#define F0900_P2_CFRINIT_CSTINC 0xf2410004
++#define F0900_P2_NEG_CFRSTEP 0xf2410001
++
++/*P2_CFRUP1*/
++#define R0900_P2_CFRUP1 0xf242
++#define F0900_P2_CFR_UP1 0xf24201ff
++
++/*P2_CFRUP0*/
++#define R0900_P2_CFRUP0 0xf243
++#define F0900_P2_CFR_UP0 0xf24300ff
++
++/*P2_CFRLOW1*/
++#define R0900_P2_CFRLOW1 0xf246
++#define F0900_P2_CFR_LOW1 0xf24601ff
++
++/*P2_CFRLOW0*/
++#define R0900_P2_CFRLOW0 0xf247
++#define F0900_P2_CFR_LOW0 0xf24700ff
++
++/*P2_CFRINIT1*/
++#define R0900_P2_CFRINIT1 0xf248
++#define F0900_P2_CFR_INIT1 0xf24801ff
++
++/*P2_CFRINIT0*/
++#define R0900_P2_CFRINIT0 0xf249
++#define F0900_P2_CFR_INIT0 0xf24900ff
++
++/*P2_CFRINC1*/
++#define R0900_P2_CFRINC1 0xf24a
++#define F0900_P2_MANUAL_CFRINC 0xf24a0080
++#define F0900_P2_CFR_INC1 0xf24a017f
++
++/*P2_CFRINC0*/
++#define R0900_P2_CFRINC0 0xf24b
++#define F0900_P2_CFR_INC0 0xf24b00f0
++
++/*P2_CFR2*/
++#define R0900_P2_CFR2 0xf24c
++#define F0900_P2_CAR_FREQ2 0xf24c01ff
++
++/*P2_CFR1*/
++#define R0900_P2_CFR1 0xf24d
++#define F0900_P2_CAR_FREQ1 0xf24d00ff
++
++/*P2_CFR0*/
++#define R0900_P2_CFR0 0xf24e
++#define F0900_P2_CAR_FREQ0 0xf24e00ff
++
++/*P2_LDI*/
++#define R0900_P2_LDI 0xf24f
++#define F0900_P2_LOCK_DET_INTEGR 0xf24f01ff
++
++/*P2_TMGCFG*/
++#define R0900_P2_TMGCFG 0xf250
++#define F0900_P2_TMGLOCK_BETA 0xf25000c0
++#define F0900_P2_NOTMG_GROUPDELAY 0xf2500020
++#define F0900_P2_DO_TIMING_CORR 0xf2500010
++#define F0900_P2_MANUAL_SCAN 0xf250000c
++#define F0900_P2_TMG_MINFREQ 0xf2500003
++
++/*P2_RTC*/
++#define R0900_P2_RTC 0xf251
++#define F0900_P2_TMGALPHA_EXP 0xf25100f0
++#define F0900_P2_TMGBETA_EXP 0xf251000f
++
++/*P2_RTCS2*/
++#define R0900_P2_RTCS2 0xf252
++#define F0900_P2_TMGALPHAS2_EXP 0xf25200f0
++#define F0900_P2_TMGBETAS2_EXP 0xf252000f
++
++/*P2_TMGTHRISE*/
++#define R0900_P2_TMGTHRISE 0xf253
++#define F0900_P2_TMGLOCK_THRISE 0xf25300ff
++
++/*P2_TMGTHFALL*/
++#define R0900_P2_TMGTHFALL 0xf254
++#define F0900_P2_TMGLOCK_THFALL 0xf25400ff
++
++/*P2_SFRUPRATIO*/
++#define R0900_P2_SFRUPRATIO 0xf255
++#define F0900_P2_SFR_UPRATIO 0xf25500ff
++
++/*P2_SFRLOWRATIO*/
++#define R0900_P2_SFRLOWRATIO 0xf256
++#define F0900_P2_SFR_LOWRATIO 0xf25600ff
++
++/*P2_KREFTMG*/
++#define R0900_P2_KREFTMG 0xf258
++#define F0900_P2_KREF_TMG 0xf25800ff
++
++/*P2_SFRSTEP*/
++#define R0900_P2_SFRSTEP 0xf259
++#define F0900_P2_SFR_SCANSTEP 0xf25900f0
++#define F0900_P2_SFR_CENTERSTEP 0xf259000f
++
++/*P2_TMGCFG2*/
++#define R0900_P2_TMGCFG2 0xf25a
++#define F0900_P2_DIS_AUTOSAMP 0xf25a0008
++#define F0900_P2_SCANINIT_QUART 0xf25a0004
++#define F0900_P2_NOTMG_DVBS1DERAT 0xf25a0002
++#define F0900_P2_SFRRATIO_FINE 0xf25a0001
++
++/*P2_SFRINIT1*/
++#define R0900_P2_SFRINIT1 0xf25e
++#define F0900_P2_SFR_INIT1 0xf25e00ff
++
++/*P2_SFRINIT0*/
++#define R0900_P2_SFRINIT0 0xf25f
++#define F0900_P2_SFR_INIT0 0xf25f00ff
++
++/*P2_SFRUP1*/
++#define R0900_P2_SFRUP1 0xf260
++#define F0900_P2_AUTO_GUP 0xf2600080
++#define F0900_P2_SYMB_FREQ_UP1 0xf260007f
++
++/*P2_SFRUP0*/
++#define R0900_P2_SFRUP0 0xf261
++#define F0900_P2_SYMB_FREQ_UP0 0xf26100ff
++
++/*P2_SFRLOW1*/
++#define R0900_P2_SFRLOW1 0xf262
++#define F0900_P2_AUTO_GLOW 0xf2620080
++#define F0900_P2_SYMB_FREQ_LOW1 0xf262007f
++
++/*P2_SFRLOW0*/
++#define R0900_P2_SFRLOW0 0xf263
++#define F0900_P2_SYMB_FREQ_LOW0 0xf26300ff
++
++/*P2_SFR3*/
++#define R0900_P2_SFR3 0xf264
++#define F0900_P2_SYMB_FREQ3 0xf26400ff
++
++/*P2_SFR2*/
++#define R0900_P2_SFR2 0xf265
++#define F0900_P2_SYMB_FREQ2 0xf26500ff
++
++/*P2_SFR1*/
++#define R0900_P2_SFR1 0xf266
++#define F0900_P2_SYMB_FREQ1 0xf26600ff
++
++/*P2_SFR0*/
++#define R0900_P2_SFR0 0xf267
++#define F0900_P2_SYMB_FREQ0 0xf26700ff
++
++/*P2_TMGREG2*/
++#define R0900_P2_TMGREG2 0xf268
++#define F0900_P2_TMGREG2 0xf26800ff
++
++/*P2_TMGREG1*/
++#define R0900_P2_TMGREG1 0xf269
++#define F0900_P2_TMGREG1 0xf26900ff
++
++/*P2_TMGREG0*/
++#define R0900_P2_TMGREG0 0xf26a
++#define F0900_P2_TMGREG0 0xf26a00ff
++
++/*P2_TMGLOCK1*/
++#define R0900_P2_TMGLOCK1 0xf26b
++#define F0900_P2_TMGLOCK_LEVEL1 0xf26b01ff
++
++/*P2_TMGLOCK0*/
++#define R0900_P2_TMGLOCK0 0xf26c
++#define F0900_P2_TMGLOCK_LEVEL0 0xf26c00ff
++
++/*P2_TMGOBS*/
++#define R0900_P2_TMGOBS 0xf26d
++#define F0900_P2_ROLLOFF_STATUS 0xf26d00c0
++#define F0900_P2_SCAN_SIGN 0xf26d0030
++#define F0900_P2_TMG_SCANNING 0xf26d0008
++#define F0900_P2_CHCENTERING_MODE 0xf26d0004
++#define F0900_P2_TMG_SCANFAIL 0xf26d0002
++
++/*P2_EQUALCFG*/
++#define R0900_P2_EQUALCFG 0xf26f
++#define F0900_P2_NOTMG_NEGALWAIT 0xf26f0080
++#define F0900_P2_EQUAL_ON 0xf26f0040
++#define F0900_P2_SEL_EQUALCOR 0xf26f0038
++#define F0900_P2_MU_EQUALDFE 0xf26f0007
++
++/*P2_EQUAI1*/
++#define R0900_P2_EQUAI1 0xf270
++#define F0900_P2_EQUA_ACCI1 0xf27001ff
++
++/*P2_EQUAQ1*/
++#define R0900_P2_EQUAQ1 0xf271
++#define F0900_P2_EQUA_ACCQ1 0xf27101ff
++
++/*P2_EQUAI2*/
++#define R0900_P2_EQUAI2 0xf272
++#define F0900_P2_EQUA_ACCI2 0xf27201ff
++
++/*P2_EQUAQ2*/
++#define R0900_P2_EQUAQ2 0xf273
++#define F0900_P2_EQUA_ACCQ2 0xf27301ff
++
++/*P2_EQUAI3*/
++#define R0900_P2_EQUAI3 0xf274
++#define F0900_P2_EQUA_ACCI3 0xf27401ff
++
++/*P2_EQUAQ3*/
++#define R0900_P2_EQUAQ3 0xf275
++#define F0900_P2_EQUA_ACCQ3 0xf27501ff
++
++/*P2_EQUAI4*/
++#define R0900_P2_EQUAI4 0xf276
++#define F0900_P2_EQUA_ACCI4 0xf27601ff
++
++/*P2_EQUAQ4*/
++#define R0900_P2_EQUAQ4 0xf277
++#define F0900_P2_EQUA_ACCQ4 0xf27701ff
++
++/*P2_EQUAI5*/
++#define R0900_P2_EQUAI5 0xf278
++#define F0900_P2_EQUA_ACCI5 0xf27801ff
++
++/*P2_EQUAQ5*/
++#define R0900_P2_EQUAQ5 0xf279
++#define F0900_P2_EQUA_ACCQ5 0xf27901ff
++
++/*P2_EQUAI6*/
++#define R0900_P2_EQUAI6 0xf27a
++#define F0900_P2_EQUA_ACCI6 0xf27a01ff
++
++/*P2_EQUAQ6*/
++#define R0900_P2_EQUAQ6 0xf27b
++#define F0900_P2_EQUA_ACCQ6 0xf27b01ff
++
++/*P2_EQUAI7*/
++#define R0900_P2_EQUAI7 0xf27c
++#define F0900_P2_EQUA_ACCI7 0xf27c01ff
++
++/*P2_EQUAQ7*/
++#define R0900_P2_EQUAQ7 0xf27d
++#define F0900_P2_EQUA_ACCQ7 0xf27d01ff
++
++/*P2_EQUAI8*/
++#define R0900_P2_EQUAI8 0xf27e
++#define F0900_P2_EQUA_ACCI8 0xf27e01ff
++
++/*P2_EQUAQ8*/
++#define R0900_P2_EQUAQ8 0xf27f
++#define F0900_P2_EQUA_ACCQ8 0xf27f01ff
++
++/*P2_NNOSDATAT1*/
++#define R0900_P2_NNOSDATAT1 0xf280
++#define F0900_P2_NOSDATAT_NORMED1 0xf28000ff
++
++/*P2_NNOSDATAT0*/
++#define R0900_P2_NNOSDATAT0 0xf281
++#define F0900_P2_NOSDATAT_NORMED0 0xf28100ff
++
++/*P2_NNOSDATA1*/
++#define R0900_P2_NNOSDATA1 0xf282
++#define F0900_P2_NOSDATA_NORMED1 0xf28200ff
++
++/*P2_NNOSDATA0*/
++#define R0900_P2_NNOSDATA0 0xf283
++#define F0900_P2_NOSDATA_NORMED0 0xf28300ff
++
++/*P2_NNOSPLHT1*/
++#define R0900_P2_NNOSPLHT1 0xf284
++#define F0900_P2_NOSPLHT_NORMED1 0xf28400ff
++
++/*P2_NNOSPLHT0*/
++#define R0900_P2_NNOSPLHT0 0xf285
++#define F0900_P2_NOSPLHT_NORMED0 0xf28500ff
++
++/*P2_NNOSPLH1*/
++#define R0900_P2_NNOSPLH1 0xf286
++#define F0900_P2_NOSPLH_NORMED1 0xf28600ff
++
++/*P2_NNOSPLH0*/
++#define R0900_P2_NNOSPLH0 0xf287
++#define F0900_P2_NOSPLH_NORMED0 0xf28700ff
++
++/*P2_NOSDATAT1*/
++#define R0900_P2_NOSDATAT1 0xf288
++#define F0900_P2_NOSDATAT_UNNORMED1 0xf28800ff
++
++/*P2_NOSDATAT0*/
++#define R0900_P2_NOSDATAT0 0xf289
++#define F0900_P2_NOSDATAT_UNNORMED0 0xf28900ff
++
++/*P2_NOSDATA1*/
++#define R0900_P2_NOSDATA1 0xf28a
++#define F0900_P2_NOSDATA_UNNORMED1 0xf28a00ff
++
++/*P2_NOSDATA0*/
++#define R0900_P2_NOSDATA0 0xf28b
++#define F0900_P2_NOSDATA_UNNORMED0 0xf28b00ff
++
++/*P2_NOSPLHT1*/
++#define R0900_P2_NOSPLHT1 0xf28c
++#define F0900_P2_NOSPLHT_UNNORMED1 0xf28c00ff
++
++/*P2_NOSPLHT0*/
++#define R0900_P2_NOSPLHT0 0xf28d
++#define F0900_P2_NOSPLHT_UNNORMED0 0xf28d00ff
++
++/*P2_NOSPLH1*/
++#define R0900_P2_NOSPLH1 0xf28e
++#define F0900_P2_NOSPLH_UNNORMED1 0xf28e00ff
++
++/*P2_NOSPLH0*/
++#define R0900_P2_NOSPLH0 0xf28f
++#define F0900_P2_NOSPLH_UNNORMED0 0xf28f00ff
++
++/*P2_CAR2CFG*/
++#define R0900_P2_CAR2CFG 0xf290
++#define F0900_P2_DESCRAMB_OFF 0xf2900080
++#define F0900_P2_PN4_SELECT 0xf2900040
++#define F0900_P2_CFR2_STOPDVBS1 0xf2900020
++#define F0900_P2_STOP_CFR2UPDATE 0xf2900010
++#define F0900_P2_STOP_NCO2UPDATE 0xf2900008
++#define F0900_P2_ROTA2ON 0xf2900004
++#define F0900_P2_PH_DET_ALGO2 0xf2900003
++
++/*P2_ACLC2*/
++#define R0900_P2_ACLC2 0xf291
++#define F0900_P2_CAR2_PUNCT_ADERAT 0xf2910040
++#define F0900_P2_CAR2_ALPHA_MANT 0xf2910030
++#define F0900_P2_CAR2_ALPHA_EXP 0xf291000f
++
++/*P2_BCLC2*/
++#define R0900_P2_BCLC2 0xf292
++#define F0900_P2_DVBS2_NIP 0xf2920080
++#define F0900_P2_CAR2_PUNCT_BDERAT 0xf2920040
++#define F0900_P2_CAR2_BETA_MANT 0xf2920030
++#define F0900_P2_CAR2_BETA_EXP 0xf292000f
++
++/*P2_CFR22*/
++#define R0900_P2_CFR22 0xf293
++#define F0900_P2_CAR2_FREQ2 0xf29301ff
++
++/*P2_CFR21*/
++#define R0900_P2_CFR21 0xf294
++#define F0900_P2_CAR2_FREQ1 0xf29400ff
++
++/*P2_CFR20*/
++#define R0900_P2_CFR20 0xf295
++#define F0900_P2_CAR2_FREQ0 0xf29500ff
++
++/*P2_ACLC2S2Q*/
++#define R0900_P2_ACLC2S2Q 0xf297
++#define F0900_P2_ENAB_SPSKSYMB 0xf2970080
++#define F0900_P2_CAR2S2_QADERAT 0xf2970040
++#define F0900_P2_CAR2S2_Q_ALPH_M 0xf2970030
++#define F0900_P2_CAR2S2_Q_ALPH_E 0xf297000f
++
++/*P2_ACLC2S28*/
++#define R0900_P2_ACLC2S28 0xf298
++#define F0900_P2_OLDI3Q_MODE 0xf2980080
++#define F0900_P2_CAR2S2_8ADERAT 0xf2980040
++#define F0900_P2_CAR2S2_8_ALPH_M 0xf2980030
++#define F0900_P2_CAR2S2_8_ALPH_E 0xf298000f
++
++/*P2_ACLC2S216A*/
++#define R0900_P2_ACLC2S216A 0xf299
++#define F0900_P2_CAR2S2_16ADERAT 0xf2990040
++#define F0900_P2_CAR2S2_16A_ALPH_M 0xf2990030
++#define F0900_P2_CAR2S2_16A_ALPH_E 0xf299000f
++
++/*P2_ACLC2S232A*/
++#define R0900_P2_ACLC2S232A 0xf29a
++#define F0900_P2_CAR2S2_32ADERAT 0xf29a0040
++#define F0900_P2_CAR2S2_32A_ALPH_M 0xf29a0030
++#define F0900_P2_CAR2S2_32A_ALPH_E 0xf29a000f
++
++/*P2_BCLC2S2Q*/
++#define R0900_P2_BCLC2S2Q 0xf29c
++#define F0900_P2_DVBS2S2Q_NIP 0xf29c0080
++#define F0900_P2_CAR2S2_QBDERAT 0xf29c0040
++#define F0900_P2_CAR2S2_Q_BETA_M 0xf29c0030
++#define F0900_P2_CAR2S2_Q_BETA_E 0xf29c000f
++
++/*P2_BCLC2S28*/
++#define R0900_P2_BCLC2S28 0xf29d
++#define F0900_P2_DVBS2S28_NIP 0xf29d0080
++#define F0900_P2_CAR2S2_8BDERAT 0xf29d0040
++#define F0900_P2_CAR2S2_8_BETA_M 0xf29d0030
++#define F0900_P2_CAR2S2_8_BETA_E 0xf29d000f
++
++/*P2_BCLC2S216A*/
++#define R0900_P2_BCLC2S216A 0xf29e
++#define F0900_P2_DVBS2S216A_NIP 0xf29e0080
++#define F0900_P2_CAR2S2_16BDERAT 0xf29e0040
++#define F0900_P2_CAR2S2_16A_BETA_M 0xf29e0030
++#define F0900_P2_CAR2S2_16A_BETA_E 0xf29e000f
++
++/*P2_BCLC2S232A*/
++#define R0900_P2_BCLC2S232A 0xf29f
++#define F0900_P2_DVBS2S232A_NIP 0xf29f0080
++#define F0900_P2_CAR2S2_32BDERAT 0xf29f0040
++#define F0900_P2_CAR2S2_32A_BETA_M 0xf29f0030
++#define F0900_P2_CAR2S2_32A_BETA_E 0xf29f000f
++
++/*P2_PLROOT2*/
++#define R0900_P2_PLROOT2 0xf2ac
++#define F0900_P2_SHORTFR_DISABLE 0xf2ac0080
++#define F0900_P2_LONGFR_DISABLE 0xf2ac0040
++#define F0900_P2_DUMMYPL_DISABLE 0xf2ac0020
++#define F0900_P2_SHORTFR_AVOID 0xf2ac0010
++#define F0900_P2_PLSCRAMB_MODE 0xf2ac000c
++#define F0900_P2_PLSCRAMB_ROOT2 0xf2ac0003
++
++/*P2_PLROOT1*/
++#define R0900_P2_PLROOT1 0xf2ad
++#define F0900_P2_PLSCRAMB_ROOT1 0xf2ad00ff
++
++/*P2_PLROOT0*/
++#define R0900_P2_PLROOT0 0xf2ae
++#define F0900_P2_PLSCRAMB_ROOT0 0xf2ae00ff
++
++/*P2_MODCODLST0*/
++#define R0900_P2_MODCODLST0 0xf2b0
++#define F0900_P2_EN_TOKEN31 0xf2b00080
++#define F0900_P2_SYNCTAG_SELECT 0xf2b00040
++#define F0900_P2_MODCODRQ_MODE 0xf2b00030
++
++/*P2_MODCODLST1*/
++#define R0900_P2_MODCODLST1 0xf2b1
++#define F0900_P2_DIS_MODCOD29 0xf2b100f0
++#define F0900_P2_DIS_32PSK_9_10 0xf2b1000f
++
++/*P2_MODCODLST2*/
++#define R0900_P2_MODCODLST2 0xf2b2
++#define F0900_P2_DIS_32PSK_8_9 0xf2b200f0
++#define F0900_P2_DIS_32PSK_5_6 0xf2b2000f
++
++/*P2_MODCODLST3*/
++#define R0900_P2_MODCODLST3 0xf2b3
++#define F0900_P2_DIS_32PSK_4_5 0xf2b300f0
++#define F0900_P2_DIS_32PSK_3_4 0xf2b3000f
++
++/*P2_MODCODLST4*/
++#define R0900_P2_MODCODLST4 0xf2b4
++#define F0900_P2_DIS_16PSK_9_10 0xf2b400f0
++#define F0900_P2_DIS_16PSK_8_9 0xf2b4000f
++
++/*P2_MODCODLST5*/
++#define R0900_P2_MODCODLST5 0xf2b5
++#define F0900_P2_DIS_16PSK_5_6 0xf2b500f0
++#define F0900_P2_DIS_16PSK_4_5 0xf2b5000f
++
++/*P2_MODCODLST6*/
++#define R0900_P2_MODCODLST6 0xf2b6
++#define F0900_P2_DIS_16PSK_3_4 0xf2b600f0
++#define F0900_P2_DIS_16PSK_2_3 0xf2b6000f
++
++/*P2_MODCODLST7*/
++#define R0900_P2_MODCODLST7 0xf2b7
++#define F0900_P2_DIS_8P_9_10 0xf2b700f0
++#define F0900_P2_DIS_8P_8_9 0xf2b7000f
++
++/*P2_MODCODLST8*/
++#define R0900_P2_MODCODLST8 0xf2b8
++#define F0900_P2_DIS_8P_5_6 0xf2b800f0
++#define F0900_P2_DIS_8P_3_4 0xf2b8000f
++
++/*P2_MODCODLST9*/
++#define R0900_P2_MODCODLST9 0xf2b9
++#define F0900_P2_DIS_8P_2_3 0xf2b900f0
++#define F0900_P2_DIS_8P_3_5 0xf2b9000f
++
++/*P2_MODCODLSTA*/
++#define R0900_P2_MODCODLSTA 0xf2ba
++#define F0900_P2_DIS_QP_9_10 0xf2ba00f0
++#define F0900_P2_DIS_QP_8_9 0xf2ba000f
++
++/*P2_MODCODLSTB*/
++#define R0900_P2_MODCODLSTB 0xf2bb
++#define F0900_P2_DIS_QP_5_6 0xf2bb00f0
++#define F0900_P2_DIS_QP_4_5 0xf2bb000f
++
++/*P2_MODCODLSTC*/
++#define R0900_P2_MODCODLSTC 0xf2bc
++#define F0900_P2_DIS_QP_3_4 0xf2bc00f0
++#define F0900_P2_DIS_QP_2_3 0xf2bc000f
++
++/*P2_MODCODLSTD*/
++#define R0900_P2_MODCODLSTD 0xf2bd
++#define F0900_P2_DIS_QP_3_5 0xf2bd00f0
++#define F0900_P2_DIS_QP_1_2 0xf2bd000f
++
++/*P2_MODCODLSTE*/
++#define R0900_P2_MODCODLSTE 0xf2be
++#define F0900_P2_DIS_QP_2_5 0xf2be00f0
++#define F0900_P2_DIS_QP_1_3 0xf2be000f
++
++/*P2_MODCODLSTF*/
++#define R0900_P2_MODCODLSTF 0xf2bf
++#define F0900_P2_DIS_QP_1_4 0xf2bf00f0
++#define F0900_P2_DDEMOD_SET 0xf2bf0002
++#define F0900_P2_DDEMOD_MASK 0xf2bf0001
++
++/*P2_DMDRESCFG*/
++#define R0900_P2_DMDRESCFG 0xf2c6
++#define F0900_P2_DMDRES_RESET 0xf2c60080
++#define F0900_P2_DMDRES_NOISESQR 0xf2c60010
++#define F0900_P2_DMDRES_STRALL 0xf2c60008
++#define F0900_P2_DMDRES_NEWONLY 0xf2c60004
++#define F0900_P2_DMDRES_NOSTORE 0xf2c60002
++#define F0900_P2_DMDRES_AGC2MEM 0xf2c60001
++
++/*P2_DMDRESADR*/
++#define R0900_P2_DMDRESADR 0xf2c7
++#define F0900_P2_SUSP_PREDCANAL 0xf2c70080
++#define F0900_P2_DMDRES_VALIDCFR 0xf2c70040
++#define F0900_P2_DMDRES_MEMFULL 0xf2c70030
++#define F0900_P2_DMDRES_RESNBR 0xf2c7000f
++
++/*P2_DMDRESDATA7*/
++#define R0900_P2_DMDRESDATA7 0xf2c8
++#define F0900_P2_DMDRES_DATA7 0xf2c800ff
++
++/*P2_DMDRESDATA6*/
++#define R0900_P2_DMDRESDATA6 0xf2c9
++#define F0900_P2_DMDRES_DATA6 0xf2c900ff
++
++/*P2_DMDRESDATA5*/
++#define R0900_P2_DMDRESDATA5 0xf2ca
++#define F0900_P2_DMDRES_DATA5 0xf2ca00ff
++
++/*P2_DMDRESDATA4*/
++#define R0900_P2_DMDRESDATA4 0xf2cb
++#define F0900_P2_DMDRES_DATA4 0xf2cb00ff
++
++/*P2_DMDRESDATA3*/
++#define R0900_P2_DMDRESDATA3 0xf2cc
++#define F0900_P2_DMDRES_DATA3 0xf2cc00ff
++
++/*P2_DMDRESDATA2*/
++#define R0900_P2_DMDRESDATA2 0xf2cd
++#define F0900_P2_DMDRES_DATA2 0xf2cd00ff
++
++/*P2_DMDRESDATA1*/
++#define R0900_P2_DMDRESDATA1 0xf2ce
++#define F0900_P2_DMDRES_DATA1 0xf2ce00ff
++
++/*P2_DMDRESDATA0*/
++#define R0900_P2_DMDRESDATA0 0xf2cf
++#define F0900_P2_DMDRES_DATA0 0xf2cf00ff
++
++/*P2_FFEI1*/
++#define R0900_P2_FFEI1 0xf2d0
++#define F0900_P2_FFE_ACCI1 0xf2d001ff
++
++/*P2_FFEQ1*/
++#define R0900_P2_FFEQ1 0xf2d1
++#define F0900_P2_FFE_ACCQ1 0xf2d101ff
++
++/*P2_FFEI2*/
++#define R0900_P2_FFEI2 0xf2d2
++#define F0900_P2_FFE_ACCI2 0xf2d201ff
++
++/*P2_FFEQ2*/
++#define R0900_P2_FFEQ2 0xf2d3
++#define F0900_P2_FFE_ACCQ2 0xf2d301ff
++
++/*P2_FFEI3*/
++#define R0900_P2_FFEI3 0xf2d4
++#define F0900_P2_FFE_ACCI3 0xf2d401ff
++
++/*P2_FFEQ3*/
++#define R0900_P2_FFEQ3 0xf2d5
++#define F0900_P2_FFE_ACCQ3 0xf2d501ff
++
++/*P2_FFEI4*/
++#define R0900_P2_FFEI4 0xf2d6
++#define F0900_P2_FFE_ACCI4 0xf2d601ff
++
++/*P2_FFEQ4*/
++#define R0900_P2_FFEQ4 0xf2d7
++#define F0900_P2_FFE_ACCQ4 0xf2d701ff
++
++/*P2_FFECFG*/
++#define R0900_P2_FFECFG 0xf2d8
++#define F0900_P2_EQUALFFE_ON 0xf2d80040
++#define F0900_P2_EQUAL_USEDSYMB 0xf2d80030
++#define F0900_P2_MU_EQUALFFE 0xf2d80007
++
++/*P2_TNRCFG*/
++#define R0900_P2_TNRCFG 0xf2e0
++#define F0900_P2_TUN_ACKFAIL 0xf2e00080
++#define F0900_P2_TUN_TYPE 0xf2e00070
++#define F0900_P2_TUN_SECSTOP 0xf2e00008
++#define F0900_P2_TUN_VCOSRCH 0xf2e00004
++#define F0900_P2_TUN_MADDRESS 0xf2e00003
++
++/*P2_TNRCFG2*/
++#define R0900_P2_TNRCFG2 0xf2e1
++#define F0900_P2_TUN_IQSWAP 0xf2e10080
++#define F0900_P2_STB6110_STEP2MHZ 0xf2e10040
++#define F0900_P2_STB6120_DBLI2C 0xf2e10020
++#define F0900_P2_DIS_FCCK 0xf2e10010
++#define F0900_P2_DIS_LPEN 0xf2e10008
++#define F0900_P2_DIS_BWCALC 0xf2e10004
++#define F0900_P2_SHORT_WAITSTATES 0xf2e10002
++#define F0900_P2_DIS_2BWAGC1 0xf2e10001
++
++/*P2_TNRXTAL*/
++#define R0900_P2_TNRXTAL 0xf2e4
++#define F0900_P2_TUN_MCLKDECIMAL 0xf2e400e0
++#define F0900_P2_TUN_XTALFREQ 0xf2e4001f
++
++/*P2_TNRSTEPS*/
++#define R0900_P2_TNRSTEPS 0xf2e7
++#define F0900_P2_TUNER_BW1P6 0xf2e70080
++#define F0900_P2_BWINC_OFFSET 0xf2e70070
++#define F0900_P2_SOFTSTEP_RNG 0xf2e70008
++#define F0900_P2_TUN_BWOFFSET 0xf2e70107
++
++/*P2_TNRGAIN*/
++#define R0900_P2_TNRGAIN 0xf2e8
++#define F0900_P2_TUN_KDIVEN 0xf2e800c0
++#define F0900_P2_STB6X00_OCK 0xf2e80030
++#define F0900_P2_TUN_GAIN 0xf2e8000f
++
++/*P2_TNRRF1*/
++#define R0900_P2_TNRRF1 0xf2e9
++#define F0900_P2_TUN_RFFREQ2 0xf2e900ff
++
++/*P2_TNRRF0*/
++#define R0900_P2_TNRRF0 0xf2ea
++#define F0900_P2_TUN_RFFREQ1 0xf2ea00ff
++
++/*P2_TNRBW*/
++#define R0900_P2_TNRBW 0xf2eb
++#define F0900_P2_TUN_RFFREQ0 0xf2eb00c0
++#define F0900_P2_TUN_BW 0xf2eb003f
++
++/*P2_TNRADJ*/
++#define R0900_P2_TNRADJ 0xf2ec
++#define F0900_P2_STB61X0_RCLK 0xf2ec0080
++#define F0900_P2_STB61X0_CALTIME 0xf2ec0040
++#define F0900_P2_STB6X00_DLB 0xf2ec0038
++#define F0900_P2_STB6000_FCL 0xf2ec0007
++
++/*P2_TNRCTL2*/
++#define R0900_P2_TNRCTL2 0xf2ed
++#define F0900_P2_STB61X0_LCP1_RCCKOFF 0xf2ed0080
++#define F0900_P2_STB61X0_LCP0 0xf2ed0040
++#define F0900_P2_STB61X0_XTOUT_RFOUTS 0xf2ed0020
++#define F0900_P2_STB61X0_XTON_MCKDV 0xf2ed0010
++#define F0900_P2_STB61X0_CALOFF_DCOFF 0xf2ed0008
++#define F0900_P2_STB6110_LPT 0xf2ed0004
++#define F0900_P2_STB6110_RX 0xf2ed0002
++#define F0900_P2_STB6110_SYN 0xf2ed0001
++
++/*P2_TNRCFG3*/
++#define R0900_P2_TNRCFG3 0xf2ee
++#define F0900_P2_STB6120_DISCTRL1 0xf2ee0080
++#define F0900_P2_STB6120_INVORDER 0xf2ee0040
++#define F0900_P2_STB6120_ENCTRL6 0xf2ee0020
++#define F0900_P2_TUN_PLLFREQ 0xf2ee001c
++#define F0900_P2_TUN_I2CFREQ_MODE 0xf2ee0003
++
++/*P2_TNRLAUNCH*/
++#define R0900_P2_TNRLAUNCH 0xf2f0
++
++/*P2_TNRLD*/
++#define R0900_P2_TNRLD 0xf2f0
++#define F0900_P2_TUNLD_VCOING 0xf2f00080
++#define F0900_P2_TUN_REG1FAIL 0xf2f00040
++#define F0900_P2_TUN_REG2FAIL 0xf2f00020
++#define F0900_P2_TUN_REG3FAIL 0xf2f00010
++#define F0900_P2_TUN_REG4FAIL 0xf2f00008
++#define F0900_P2_TUN_REG5FAIL 0xf2f00004
++#define F0900_P2_TUN_BWING 0xf2f00002
++#define F0900_P2_TUN_LOCKED 0xf2f00001
++
++/*P2_TNROBSL*/
++#define R0900_P2_TNROBSL 0xf2f6
++#define F0900_P2_TUN_I2CABORTED 0xf2f60080
++#define F0900_P2_TUN_LPEN 0xf2f60040
++#define F0900_P2_TUN_FCCK 0xf2f60020
++#define F0900_P2_TUN_I2CLOCKED 0xf2f60010
++#define F0900_P2_TUN_PROGDONE 0xf2f6000c
++#define F0900_P2_TUN_RFRESTE1 0xf2f60003
++
++/*P2_TNRRESTE*/
++#define R0900_P2_TNRRESTE 0xf2f7
++#define F0900_P2_TUN_RFRESTE0 0xf2f700ff
++
++/*P2_SMAPCOEF7*/
++#define R0900_P2_SMAPCOEF7 0xf300
++#define F0900_P2_DIS_QSCALE 0xf3000080
++#define F0900_P2_SMAPCOEF_Q_LLR12 0xf300017f
++
++/*P2_SMAPCOEF6*/
++#define R0900_P2_SMAPCOEF6 0xf301
++#define F0900_P2_DIS_NEWSCALE 0xf3010008
++#define F0900_P2_ADJ_8PSKLLR1 0xf3010004
++#define F0900_P2_OLD_8PSKLLR1 0xf3010002
++#define F0900_P2_DIS_AB8PSK 0xf3010001
++
++/*P2_SMAPCOEF5*/
++#define R0900_P2_SMAPCOEF5 0xf302
++#define F0900_P2_DIS_8SCALE 0xf3020080
++#define F0900_P2_SMAPCOEF_8P_LLR23 0xf302017f
++
++/*P2_DMDPLHSTAT*/
++#define R0900_P2_DMDPLHSTAT 0xf320
++#define F0900_P2_PLH_STATISTIC 0xf32000ff
++
++/*P2_LOCKTIME3*/
++#define R0900_P2_LOCKTIME3 0xf322
++#define F0900_P2_DEMOD_LOCKTIME3 0xf32200ff
++
++/*P2_LOCKTIME2*/
++#define R0900_P2_LOCKTIME2 0xf323
++#define F0900_P2_DEMOD_LOCKTIME2 0xf32300ff
++
++/*P2_LOCKTIME1*/
++#define R0900_P2_LOCKTIME1 0xf324
++#define F0900_P2_DEMOD_LOCKTIME1 0xf32400ff
++
++/*P2_LOCKTIME0*/
++#define R0900_P2_LOCKTIME0 0xf325
++#define F0900_P2_DEMOD_LOCKTIME0 0xf32500ff
++
++/*P2_VITSCALE*/
++#define R0900_P2_VITSCALE 0xf332
++#define F0900_P2_NVTH_NOSRANGE 0xf3320080
++#define F0900_P2_VERROR_MAXMODE 0xf3320040
++#define F0900_P2_KDIV_MODE 0xf3320030
++#define F0900_P2_NSLOWSN_LOCKED 0xf3320008
++#define F0900_P2_DELOCK_PRFLOSS 0xf3320004
++#define F0900_P2_DIS_RSFLOCK 0xf3320002
++
++/*P2_FECM*/
++#define R0900_P2_FECM 0xf333
++#define F0900_P2_DSS_DVB 0xf3330080
++#define F0900_P2_DEMOD_BYPASS 0xf3330040
++#define F0900_P2_CMP_SLOWMODE 0xf3330020
++#define F0900_P2_DSS_SRCH 0xf3330010
++#define F0900_P2_DIFF_MODEVIT 0xf3330004
++#define F0900_P2_SYNCVIT 0xf3330002
++#define F0900_P2_IQINV 0xf3330001
++
++/*P2_VTH12*/
++#define R0900_P2_VTH12 0xf334
++#define F0900_P2_VTH12 0xf33400ff
++
++/*P2_VTH23*/
++#define R0900_P2_VTH23 0xf335
++#define F0900_P2_VTH23 0xf33500ff
++
++/*P2_VTH34*/
++#define R0900_P2_VTH34 0xf336
++#define F0900_P2_VTH34 0xf33600ff
++
++/*P2_VTH56*/
++#define R0900_P2_VTH56 0xf337
++#define F0900_P2_VTH56 0xf33700ff
++
++/*P2_VTH67*/
++#define R0900_P2_VTH67 0xf338
++#define F0900_P2_VTH67 0xf33800ff
++
++/*P2_VTH78*/
++#define R0900_P2_VTH78 0xf339
++#define F0900_P2_VTH78 0xf33900ff
++
++/*P2_VITCURPUN*/
++#define R0900_P2_VITCURPUN 0xf33a
++#define F0900_P2_VIT_MAPPING 0xf33a00e0
++#define F0900_P2_VIT_CURPUN 0xf33a001f
++
++/*P2_VERROR*/
++#define R0900_P2_VERROR 0xf33b
++#define F0900_P2_REGERR_VIT 0xf33b00ff
++
++/*P2_PRVIT*/
++#define R0900_P2_PRVIT 0xf33c
++#define F0900_P2_DIS_VTHLOCK 0xf33c0040
++#define F0900_P2_E7_8VIT 0xf33c0020
++#define F0900_P2_E6_7VIT 0xf33c0010
++#define F0900_P2_E5_6VIT 0xf33c0008
++#define F0900_P2_E3_4VIT 0xf33c0004
++#define F0900_P2_E2_3VIT 0xf33c0002
++#define F0900_P2_E1_2VIT 0xf33c0001
++
++/*P2_VAVSRVIT*/
++#define R0900_P2_VAVSRVIT 0xf33d
++#define F0900_P2_AMVIT 0xf33d0080
++#define F0900_P2_FROZENVIT 0xf33d0040
++#define F0900_P2_SNVIT 0xf33d0030
++#define F0900_P2_TOVVIT 0xf33d000c
++#define F0900_P2_HYPVIT 0xf33d0003
++
++/*P2_VSTATUSVIT*/
++#define R0900_P2_VSTATUSVIT 0xf33e
++#define F0900_P2_VITERBI_ON 0xf33e0080
++#define F0900_P2_END_LOOPVIT 0xf33e0040
++#define F0900_P2_VITERBI_DEPRF 0xf33e0020
++#define F0900_P2_PRFVIT 0xf33e0010
++#define F0900_P2_LOCKEDVIT 0xf33e0008
++#define F0900_P2_VITERBI_DELOCK 0xf33e0004
++#define F0900_P2_VIT_DEMODSEL 0xf33e0002
++#define F0900_P2_VITERBI_COMPOUT 0xf33e0001
++
++/*P2_VTHINUSE*/
++#define R0900_P2_VTHINUSE 0xf33f
++#define F0900_P2_VIT_INUSE 0xf33f00ff
++
++/*P2_KDIV12*/
++#define R0900_P2_KDIV12 0xf340
++#define F0900_P2_KDIV12_MANUAL 0xf3400080
++#define F0900_P2_K_DIVIDER_12 0xf340007f
++
++/*P2_KDIV23*/
++#define R0900_P2_KDIV23 0xf341
++#define F0900_P2_KDIV23_MANUAL 0xf3410080
++#define F0900_P2_K_DIVIDER_23 0xf341007f
++
++/*P2_KDIV34*/
++#define R0900_P2_KDIV34 0xf342
++#define F0900_P2_KDIV34_MANUAL 0xf3420080
++#define F0900_P2_K_DIVIDER_34 0xf342007f
++
++/*P2_KDIV56*/
++#define R0900_P2_KDIV56 0xf343
++#define F0900_P2_KDIV56_MANUAL 0xf3430080
++#define F0900_P2_K_DIVIDER_56 0xf343007f
++
++/*P2_KDIV67*/
++#define R0900_P2_KDIV67 0xf344
++#define F0900_P2_KDIV67_MANUAL 0xf3440080
++#define F0900_P2_K_DIVIDER_67 0xf344007f
++
++/*P2_KDIV78*/
++#define R0900_P2_KDIV78 0xf345
++#define F0900_P2_KDIV78_MANUAL 0xf3450080
++#define F0900_P2_K_DIVIDER_78 0xf345007f
++
++/*P2_PDELCTRL1*/
++#define R0900_P2_PDELCTRL1 0xf350
++#define F0900_P2_INV_MISMASK 0xf3500080
++#define F0900_P2_FORCE_ACCEPTED 0xf3500040
++#define F0900_P2_FILTER_EN 0xf3500020
++#define F0900_P2_FORCE_PKTDELINUSE 0xf3500010
++#define F0900_P2_HYSTEN 0xf3500008
++#define F0900_P2_HYSTSWRST 0xf3500004
++#define F0900_P2_EN_MIS00 0xf3500002
++#define F0900_P2_ALGOSWRST 0xf3500001
++
++/*P2_PDELCTRL2*/
++#define R0900_P2_PDELCTRL2 0xf351
++#define F0900_P2_FORCE_CONTINUOUS 0xf3510080
++#define F0900_P2_RESET_UPKO_COUNT 0xf3510040
++#define F0900_P2_USER_PKTDELIN_NB 0xf3510020
++#define F0900_P2_FORCE_LOCKED 0xf3510010
++#define F0900_P2_DATA_UNBBSCRAM 0xf3510008
++#define F0900_P2_FORCE_LONGPKT 0xf3510004
++#define F0900_P2_FRAME_MODE 0xf3510002
++
++/*P2_HYSTTHRESH*/
++#define R0900_P2_HYSTTHRESH 0xf354
++#define F0900_P2_UNLCK_THRESH 0xf35400f0
++#define F0900_P2_DELIN_LCK_THRESH 0xf354000f
++
++/*P2_ISIENTRY*/
++#define R0900_P2_ISIENTRY 0xf35e
++#define F0900_P2_ISI_ENTRY 0xf35e00ff
++
++/*P2_ISIBITENA*/
++#define R0900_P2_ISIBITENA 0xf35f
++#define F0900_P2_ISI_BIT_EN 0xf35f00ff
++
++/*P2_MATSTR1*/
++#define R0900_P2_MATSTR1 0xf360
++#define F0900_P2_MATYPE_CURRENT1 0xf36000ff
++
++/*P2_MATSTR0*/
++#define R0900_P2_MATSTR0 0xf361
++#define F0900_P2_MATYPE_CURRENT0 0xf36100ff
++
++/*P2_UPLSTR1*/
++#define R0900_P2_UPLSTR1 0xf362
++#define F0900_P2_UPL_CURRENT1 0xf36200ff
++
++/*P2_UPLSTR0*/
++#define R0900_P2_UPLSTR0 0xf363
++#define F0900_P2_UPL_CURRENT0 0xf36300ff
++
++/*P2_DFLSTR1*/
++#define R0900_P2_DFLSTR1 0xf364
++#define F0900_P2_DFL_CURRENT1 0xf36400ff
++
++/*P2_DFLSTR0*/
++#define R0900_P2_DFLSTR0 0xf365
++#define F0900_P2_DFL_CURRENT0 0xf36500ff
++
++/*P2_SYNCSTR*/
++#define R0900_P2_SYNCSTR 0xf366
++#define F0900_P2_SYNC_CURRENT 0xf36600ff
++
++/*P2_SYNCDSTR1*/
++#define R0900_P2_SYNCDSTR1 0xf367
++#define F0900_P2_SYNCD_CURRENT1 0xf36700ff
++
++/*P2_SYNCDSTR0*/
++#define R0900_P2_SYNCDSTR0 0xf368
++#define F0900_P2_SYNCD_CURRENT0 0xf36800ff
++
++/*P2_PDELSTATUS1*/
++#define R0900_P2_PDELSTATUS1 0xf369
++#define F0900_P2_PKTDELIN_DELOCK 0xf3690080
++#define F0900_P2_SYNCDUPDFL_BADDFL 0xf3690040
++#define F0900_P2_CONTINUOUS_STREAM 0xf3690020
++#define F0900_P2_UNACCEPTED_STREAM 0xf3690010
++#define F0900_P2_BCH_ERROR_FLAG 0xf3690008
++#define F0900_P2_BBHCRCKO 0xf3690004
++#define F0900_P2_PKTDELIN_LOCK 0xf3690002
++#define F0900_P2_FIRST_LOCK 0xf3690001
++
++/*P2_PDELSTATUS2*/
++#define R0900_P2_PDELSTATUS2 0xf36a
++#define F0900_P2_PKTDEL_DEMODSEL 0xf36a0080
++#define F0900_P2_FRAME_MODCOD 0xf36a007c
++#define F0900_P2_FRAME_TYPE 0xf36a0003
++
++/*P2_BBFCRCKO1*/
++#define R0900_P2_BBFCRCKO1 0xf36b
++#define F0900_P2_BBHCRC_KOCNT1 0xf36b00ff
++
++/*P2_BBFCRCKO0*/
++#define R0900_P2_BBFCRCKO0 0xf36c
++#define F0900_P2_BBHCRC_KOCNT0 0xf36c00ff
++
++/*P2_UPCRCKO1*/
++#define R0900_P2_UPCRCKO1 0xf36d
++#define F0900_P2_PKTCRC_KOCNT1 0xf36d00ff
++
++/*P2_UPCRCKO0*/
++#define R0900_P2_UPCRCKO0 0xf36e
++#define F0900_P2_PKTCRC_KOCNT0 0xf36e00ff
++
++/*P2_TSSTATEM*/
++#define R0900_P2_TSSTATEM 0xf370
++#define F0900_P2_TSDIL_ON 0xf3700080
++#define F0900_P2_TSSKIPRS_ON 0xf3700040
++#define F0900_P2_TSRS_ON 0xf3700020
++#define F0900_P2_TSDESCRAMB_ON 0xf3700010
++#define F0900_P2_TSFRAME_MODE 0xf3700008
++#define F0900_P2_TS_DISABLE 0xf3700004
++#define F0900_P2_TSACM_MODE 0xf3700002
++#define F0900_P2_TSOUT_NOSYNC 0xf3700001
++
++/*P2_TSCFGH*/
++#define R0900_P2_TSCFGH 0xf372
++#define F0900_P2_TSFIFO_DVBCI 0xf3720080
++#define F0900_P2_TSFIFO_SERIAL 0xf3720040
++#define F0900_P2_TSFIFO_TEIUPDATE 0xf3720020
++#define F0900_P2_TSFIFO_DUTY50 0xf3720010
++#define F0900_P2_TSFIFO_HSGNLOUT 0xf3720008
++#define F0900_P2_TSFIFO_ERRMODE 0xf3720006
++#define F0900_P2_RST_HWARE 0xf3720001
++
++/*P2_TSCFGM*/
++#define R0900_P2_TSCFGM 0xf373
++#define F0900_P2_TSFIFO_MANSPEED 0xf37300c0
++#define F0900_P2_TSFIFO_PERMDATA 0xf3730020
++#define F0900_P2_TSFIFO_NONEWSGNL 0xf3730010
++#define F0900_P2_TSFIFO_BITSPEED 0xf3730008
++#define F0900_P2_NPD_SPECDVBS2 0xf3730004
++#define F0900_P2_TSFIFO_STOPCKDIS 0xf3730002
++#define F0900_P2_TSFIFO_INVDATA 0xf3730001
++
++/*P2_TSCFGL*/
++#define R0900_P2_TSCFGL 0xf374
++#define F0900_P2_TSFIFO_BCLKDEL1CK 0xf37400c0
++#define F0900_P2_BCHERROR_MODE 0xf3740030
++#define F0900_P2_TSFIFO_NSGNL2DATA 0xf3740008
++#define F0900_P2_TSFIFO_EMBINDVB 0xf3740004
++#define F0900_P2_TSFIFO_DPUNACT 0xf3740002
++#define F0900_P2_TSFIFO_NPDOFF 0xf3740001
++
++/*P2_TSINSDELH*/
++#define R0900_P2_TSINSDELH 0xf376
++#define F0900_P2_TSDEL_SYNCBYTE 0xf3760080
++#define F0900_P2_TSDEL_XXHEADER 0xf3760040
++#define F0900_P2_TSDEL_BBHEADER 0xf3760020
++#define F0900_P2_TSDEL_DATAFIELD 0xf3760010
++#define F0900_P2_TSINSDEL_ISCR 0xf3760008
++#define F0900_P2_TSINSDEL_NPD 0xf3760004
++#define F0900_P2_TSINSDEL_RSPARITY 0xf3760002
++#define F0900_P2_TSINSDEL_CRC8 0xf3760001
++
++/*P2_TSSPEED*/
++#define R0900_P2_TSSPEED 0xf380
++#define F0900_P2_TSFIFO_OUTSPEED 0xf38000ff
++
++/*P2_TSSTATUS*/
++#define R0900_P2_TSSTATUS 0xf381
++#define F0900_P2_TSFIFO_LINEOK 0xf3810080
++#define F0900_P2_TSFIFO_ERROR 0xf3810040
++#define F0900_P2_TSFIFO_DATA7 0xf3810020
++#define F0900_P2_TSFIFO_NOSYNC 0xf3810010
++#define F0900_P2_ISCR_INITIALIZED 0xf3810008
++#define F0900_P2_ISCR_UPDATED 0xf3810004
++#define F0900_P2_SOFFIFO_UNREGUL 0xf3810002
++#define F0900_P2_DIL_READY 0xf3810001
++
++/*P2_TSSTATUS2*/
++#define R0900_P2_TSSTATUS2 0xf382
++#define F0900_P2_TSFIFO_DEMODSEL 0xf3820080
++#define F0900_P2_TSFIFOSPEED_STORE 0xf3820040
++#define F0900_P2_DILXX_RESET 0xf3820020
++#define F0900_P2_TSSERIAL_IMPOS 0xf3820010
++#define F0900_P2_TSFIFO_LINENOK 0xf3820008
++#define F0900_P2_BITSPEED_EVENT 0xf3820004
++#define F0900_P2_SCRAMBDETECT 0xf3820002
++#define F0900_P2_ULDTV67_FALSELOCK 0xf3820001
++
++/*P2_TSBITRATE1*/
++#define R0900_P2_TSBITRATE1 0xf383
++#define F0900_P2_TSFIFO_BITRATE1 0xf38300ff
++
++/*P2_TSBITRATE0*/
++#define R0900_P2_TSBITRATE0 0xf384
++#define F0900_P2_TSFIFO_BITRATE0 0xf38400ff
++
++/*P2_ERRCTRL1*/
++#define R0900_P2_ERRCTRL1 0xf398
++#define F0900_P2_ERR_SOURCE1 0xf39800f0
++#define F0900_P2_NUM_EVENT1 0xf3980007
++
++/*P2_ERRCNT12*/
++#define R0900_P2_ERRCNT12 0xf399
++#define F0900_P2_ERRCNT1_OLDVALUE 0xf3990080
++#define F0900_P2_ERR_CNT12 0xf399007f
++
++/*P2_ERRCNT11*/
++#define R0900_P2_ERRCNT11 0xf39a
++#define F0900_P2_ERR_CNT11 0xf39a00ff
++
++/*P2_ERRCNT10*/
++#define R0900_P2_ERRCNT10 0xf39b
++#define F0900_P2_ERR_CNT10 0xf39b00ff
++
++/*P2_ERRCTRL2*/
++#define R0900_P2_ERRCTRL2 0xf39c
++#define F0900_P2_ERR_SOURCE2 0xf39c00f0
++#define F0900_P2_NUM_EVENT2 0xf39c0007
++
++/*P2_ERRCNT22*/
++#define R0900_P2_ERRCNT22 0xf39d
++#define F0900_P2_ERRCNT2_OLDVALUE 0xf39d0080
++#define F0900_P2_ERR_CNT22 0xf39d007f
++
++/*P2_ERRCNT21*/
++#define R0900_P2_ERRCNT21 0xf39e
++#define F0900_P2_ERR_CNT21 0xf39e00ff
++
++/*P2_ERRCNT20*/
++#define R0900_P2_ERRCNT20 0xf39f
++#define F0900_P2_ERR_CNT20 0xf39f00ff
++
++/*P2_FECSPY*/
++#define R0900_P2_FECSPY 0xf3a0
++#define F0900_P2_SPY_ENABLE 0xf3a00080
++#define F0900_P2_NO_SYNCBYTE 0xf3a00040
++#define F0900_P2_SERIAL_MODE 0xf3a00020
++#define F0900_P2_UNUSUAL_PACKET 0xf3a00010
++#define F0900_P2_BER_PACKMODE 0xf3a00008
++#define F0900_P2_BERMETER_LMODE 0xf3a00002
++#define F0900_P2_BERMETER_RESET 0xf3a00001
++
++/*P2_FSPYCFG*/
++#define R0900_P2_FSPYCFG 0xf3a1
++#define F0900_P2_FECSPY_INPUT 0xf3a100c0
++#define F0900_P2_RST_ON_ERROR 0xf3a10020
++#define F0900_P2_ONE_SHOT 0xf3a10010
++#define F0900_P2_I2C_MODE 0xf3a1000c
++#define F0900_P2_SPY_HYSTERESIS 0xf3a10003
++
++/*P2_FSPYDATA*/
++#define R0900_P2_FSPYDATA 0xf3a2
++#define F0900_P2_SPY_STUFFING 0xf3a20080
++#define F0900_P2_NOERROR_PKTJITTER 0xf3a20040
++#define F0900_P2_SPY_CNULLPKT 0xf3a20020
++#define F0900_P2_SPY_OUTDATA_MODE 0xf3a2001f
++
++/*P2_FSPYOUT*/
++#define R0900_P2_FSPYOUT 0xf3a3
++#define F0900_P2_FSPY_DIRECT 0xf3a30080
++#define F0900_P2_SPY_OUTDATA_BUS 0xf3a30038
++#define F0900_P2_STUFF_MODE 0xf3a30007
++
++/*P2_FSTATUS*/
++#define R0900_P2_FSTATUS 0xf3a4
++#define F0900_P2_SPY_ENDSIM 0xf3a40080
++#define F0900_P2_VALID_SIM 0xf3a40040
++#define F0900_P2_FOUND_SIGNAL 0xf3a40020
++#define F0900_P2_DSS_SYNCBYTE 0xf3a40010
++#define F0900_P2_RESULT_STATE 0xf3a4000f
++
++/*P2_FBERCPT4*/
++#define R0900_P2_FBERCPT4 0xf3a8
++#define F0900_P2_FBERMETER_CPT4 0xf3a800ff
++
++/*P2_FBERCPT3*/
++#define R0900_P2_FBERCPT3 0xf3a9
++#define F0900_P2_FBERMETER_CPT3 0xf3a900ff
++
++/*P2_FBERCPT2*/
++#define R0900_P2_FBERCPT2 0xf3aa
++#define F0900_P2_FBERMETER_CPT2 0xf3aa00ff
++
++/*P2_FBERCPT1*/
++#define R0900_P2_FBERCPT1 0xf3ab
++#define F0900_P2_FBERMETER_CPT1 0xf3ab00ff
++
++/*P2_FBERCPT0*/
++#define R0900_P2_FBERCPT0 0xf3ac
++#define F0900_P2_FBERMETER_CPT0 0xf3ac00ff
++
++/*P2_FBERERR2*/
++#define R0900_P2_FBERERR2 0xf3ad
++#define F0900_P2_FBERMETER_ERR2 0xf3ad00ff
++
++/*P2_FBERERR1*/
++#define R0900_P2_FBERERR1 0xf3ae
++#define F0900_P2_FBERMETER_ERR1 0xf3ae00ff
++
++/*P2_FBERERR0*/
++#define R0900_P2_FBERERR0 0xf3af
++#define F0900_P2_FBERMETER_ERR0 0xf3af00ff
++
++/*P2_FSPYBER*/
++#define R0900_P2_FSPYBER 0xf3b2
++#define F0900_P2_FSPYOBS_XORREAD 0xf3b20040
++#define F0900_P2_FSPYBER_OBSMODE 0xf3b20020
++#define F0900_P2_FSPYBER_SYNCBYTE 0xf3b20010
++#define F0900_P2_FSPYBER_UNSYNC 0xf3b20008
++#define F0900_P2_FSPYBER_CTIME 0xf3b20007
++
++/*P1_IQCONST*/
++#define R0900_P1_IQCONST 0xf400
++#define F0900_P1_CONSTEL_SELECT 0xf4000060
++#define F0900_P1_IQSYMB_SEL 0xf400001f
++
++/*P1_NOSCFG*/
++#define R0900_P1_NOSCFG 0xf401
++#define F0900_P1_DUMMYPL_NOSDATA 0xf4010020
++#define F0900_P1_NOSPLH_BETA 0xf4010018
++#define F0900_P1_NOSDATA_BETA 0xf4010007
++
++/*P1_ISYMB*/
++#define R0900_P1_ISYMB 0xf402
++#define F0900_P1_I_SYMBOL 0xf40201ff
++
++/*P1_QSYMB*/
++#define R0900_P1_QSYMB 0xf403
++#define F0900_P1_Q_SYMBOL 0xf40301ff
++
++/*P1_AGC1CFG*/
++#define R0900_P1_AGC1CFG 0xf404
++#define F0900_P1_DC_FROZEN 0xf4040080
++#define F0900_P1_DC_CORRECT 0xf4040040
++#define F0900_P1_AMM_FROZEN 0xf4040020
++#define F0900_P1_AMM_CORRECT 0xf4040010
++#define F0900_P1_QUAD_FROZEN 0xf4040008
++#define F0900_P1_QUAD_CORRECT 0xf4040004
++#define F0900_P1_DCCOMP_SLOW 0xf4040002
++#define F0900_P1_IQMISM_SLOW 0xf4040001
++
++/*P1_AGC1CN*/
++#define R0900_P1_AGC1CN 0xf406
++#define F0900_P1_AGC1_LOCKED 0xf4060080
++#define F0900_P1_AGC1_OVERFLOW 0xf4060040
++#define F0900_P1_AGC1_NOSLOWLK 0xf4060020
++#define F0900_P1_AGC1_MINPOWER 0xf4060010
++#define F0900_P1_AGCOUT_FAST 0xf4060008
++#define F0900_P1_AGCIQ_BETA 0xf4060007
++
++/*P1_AGC1REF*/
++#define R0900_P1_AGC1REF 0xf407
++#define F0900_P1_AGCIQ_REF 0xf40700ff
++
++/*P1_IDCCOMP*/
++#define R0900_P1_IDCCOMP 0xf408
++#define F0900_P1_IAVERAGE_ADJ 0xf40801ff
++
++/*P1_QDCCOMP*/
++#define R0900_P1_QDCCOMP 0xf409
++#define F0900_P1_QAVERAGE_ADJ 0xf40901ff
++
++/*P1_POWERI*/
++#define R0900_P1_POWERI 0xf40a
++#define F0900_P1_POWER_I 0xf40a00ff
++
++/*P1_POWERQ*/
++#define R0900_P1_POWERQ 0xf40b
++#define F0900_P1_POWER_Q 0xf40b00ff
++
++/*P1_AGC1AMM*/
++#define R0900_P1_AGC1AMM 0xf40c
++#define F0900_P1_AMM_VALUE 0xf40c00ff
++
++/*P1_AGC1QUAD*/
++#define R0900_P1_AGC1QUAD 0xf40d
++#define F0900_P1_QUAD_VALUE 0xf40d01ff
++
++/*P1_AGCIQIN1*/
++#define R0900_P1_AGCIQIN1 0xf40e
++#define F0900_P1_AGCIQ_VALUE1 0xf40e00ff
++
++/*P1_AGCIQIN0*/
++#define R0900_P1_AGCIQIN0 0xf40f
++#define F0900_P1_AGCIQ_VALUE0 0xf40f00ff
++
++/*P1_DEMOD*/
++#define R0900_P1_DEMOD 0xf410
++#define F0900_P1_DEMOD_STOP 0xf4100040
++#define F0900_P1_SPECINV_CONTROL 0xf4100030
++#define F0900_P1_FORCE_ENASAMP 0xf4100008
++#define F0900_P1_MANUAL_ROLLOFF 0xf4100004
++#define F0900_P1_ROLLOFF_CONTROL 0xf4100003
++
++/*P1_DMDMODCOD*/
++#define R0900_P1_DMDMODCOD 0xf411
++#define F0900_P1_MANUAL_MODCOD 0xf4110080
++#define F0900_P1_DEMOD_MODCOD 0xf411007c
++#define F0900_P1_DEMOD_TYPE 0xf4110003
++
++/*P1_DSTATUS*/
++#define R0900_P1_DSTATUS 0xf412
++#define F0900_P1_CAR_LOCK 0xf4120080
++#define F0900_P1_TMGLOCK_QUALITY 0xf4120060
++#define F0900_P1_SDVBS1_ENABLE 0xf4120010
++#define F0900_P1_LOCK_DEFINITIF 0xf4120008
++#define F0900_P1_TIMING_IS_LOCKED 0xf4120004
++#define F0900_P1_COARSE_TMGLOCK 0xf4120002
++#define F0900_P1_COARSE_CARLOCK 0xf4120001
++
++/*P1_DSTATUS2*/
++#define R0900_P1_DSTATUS2 0xf413
++#define F0900_P1_DEMOD_DELOCK 0xf4130080
++#define F0900_P1_DEMOD_TIMEOUT 0xf4130040
++#define F0900_P1_MODCODRQ_SYNCTAG 0xf4130020
++#define F0900_P1_POLYPH_SATEVENT 0xf4130010
++#define F0900_P1_AGC1_NOSIGNALACK 0xf4130008
++#define F0900_P1_AGC2_OVERFLOW 0xf4130004
++#define F0900_P1_CFR_OVERFLOW 0xf4130002
++#define F0900_P1_GAMMA_OVERUNDER 0xf4130001
++
++/*P1_DMDCFGMD*/
++#define R0900_P1_DMDCFGMD 0xf414
++#define F0900_P1_DVBS2_ENABLE 0xf4140080
++#define F0900_P1_DVBS1_ENABLE 0xf4140040
++#define F0900_P1_CFR_AUTOSCAN 0xf4140020
++#define F0900_P1_SCAN_ENABLE 0xf4140010
++#define F0900_P1_TUN_AUTOSCAN 0xf4140008
++#define F0900_P1_NOFORCE_RELOCK 0xf4140004
++#define F0900_P1_TUN_RNG 0xf4140003
++
++/*P1_DMDCFG2*/
++#define R0900_P1_DMDCFG2 0xf415
++#define F0900_P1_AGC1_WAITLOCK 0xf4150080
++#define F0900_P1_S1S2_SEQUENTIAL 0xf4150040
++#define F0900_P1_OVERFLOW_TIMEOUT 0xf4150020
++#define F0900_P1_SCANFAIL_TIMEOUT 0xf4150010
++#define F0900_P1_DMDTOUT_BACK 0xf4150008
++#define F0900_P1_CARLOCK_S1ENABLE 0xf4150004
++#define F0900_P1_COARSE_LK3MODE 0xf4150002
++#define F0900_P1_COARSE_LK2MODE 0xf4150001
++
++/*P1_DMDISTATE*/
++#define R0900_P1_DMDISTATE 0xf416
++#define F0900_P1_I2C_NORESETDMODE 0xf4160080
++#define F0900_P1_FORCE_ETAPED 0xf4160040
++#define F0900_P1_SDMDRST_DIRCLK 0xf4160020
++#define F0900_P1_I2C_DEMOD_MODE 0xf416001f
++
++/*P1_DMDT0M*/
++#define R0900_P1_DMDT0M 0xf417
++#define F0900_P1_DMDT0_MIN 0xf41700ff
++
++/*P1_DMDSTATE*/
++#define R0900_P1_DMDSTATE 0xf41b
++#define F0900_P1_DEMOD_LOCKED 0xf41b0080
++#define F0900_P1_HEADER_MODE 0xf41b0060
++#define F0900_P1_DEMOD_MODE 0xf41b001f
++
++/*P1_DMDFLYW*/
++#define R0900_P1_DMDFLYW 0xf41c
++#define F0900_P1_I2C_IRQVAL 0xf41c00f0
++#define F0900_P1_FLYWHEEL_CPT 0xf41c000f
++
++/*P1_DSTATUS3*/
++#define R0900_P1_DSTATUS3 0xf41d
++#define F0900_P1_CFR_ZIGZAG 0xf41d0080
++#define F0900_P1_DEMOD_CFGMODE 0xf41d0060
++#define F0900_P1_GAMMA_LOWBAUDRATE 0xf41d0010
++#define F0900_P1_RELOCK_MODE 0xf41d0008
++#define F0900_P1_DEMOD_FAIL 0xf41d0004
++#define F0900_P1_ETAPE1A_DVBXMEM 0xf41d0003
++
++/*P1_DMDCFG3*/
++#define R0900_P1_DMDCFG3 0xf41e
++#define F0900_P1_DVBS1_TMGWAIT 0xf41e0080
++#define F0900_P1_NO_BWCENTERING 0xf41e0040
++#define F0900_P1_INV_SEQSRCH 0xf41e0020
++#define F0900_P1_DIS_SFRUPLOW_TRK 0xf41e0010
++#define F0900_P1_NOSTOP_FIFOFULL 0xf41e0008
++#define F0900_P1_LOCKTIME_MODE 0xf41e0007
++
++/*P1_DMDCFG4*/
++#define R0900_P1_DMDCFG4 0xf41f
++#define F0900_P1_TUNER_NRELAUNCH 0xf41f0008
++#define F0900_P1_DIS_CLKENABLE 0xf41f0004
++#define F0900_P1_DIS_HDRDIVLOCK 0xf41f0002
++#define F0900_P1_NO_TNRWBINIT 0xf41f0001
++
++/*P1_CORRELMANT*/
++#define R0900_P1_CORRELMANT 0xf420
++#define F0900_P1_CORREL_MANT 0xf42000ff
++
++/*P1_CORRELABS*/
++#define R0900_P1_CORRELABS 0xf421
++#define F0900_P1_CORREL_ABS 0xf42100ff
++
++/*P1_CORRELEXP*/
++#define R0900_P1_CORRELEXP 0xf422
++#define F0900_P1_CORREL_ABSEXP 0xf42200f0
++#define F0900_P1_CORREL_EXP 0xf422000f
++
++/*P1_PLHMODCOD*/
++#define R0900_P1_PLHMODCOD 0xf424
++#define F0900_P1_SPECINV_DEMOD 0xf4240080
++#define F0900_P1_PLH_MODCOD 0xf424007c
++#define F0900_P1_PLH_TYPE 0xf4240003
++
++/*P1_AGCK32*/
++#define R0900_P1_AGCK32 0xf42b
++#define F0900_P1_R3ADJOFF_32APSK 0xf42b0080
++#define F0900_P1_R2ADJOFF_32APSK 0xf42b0040
++#define F0900_P1_R1ADJOFF_32APSK 0xf42b0020
++#define F0900_P1_RADJ_32APSK 0xf42b001f
++
++/*P1_AGC2O*/
++#define R0900_P1_AGC2O 0xf42c
++#define F0900_P1_AGC2REF_ADJUSTING 0xf42c0080
++#define F0900_P1_AGC2_COARSEFAST 0xf42c0040
++#define F0900_P1_AGC2_LKSQRT 0xf42c0020
++#define F0900_P1_AGC2_LKMODE 0xf42c0010
++#define F0900_P1_AGC2_LKEQUA 0xf42c0008
++#define F0900_P1_AGC2_COEF 0xf42c0007
++
++/*P1_AGC2REF*/
++#define R0900_P1_AGC2REF 0xf42d
++#define F0900_P1_AGC2_REF 0xf42d00ff
++
++/*P1_AGC1ADJ*/
++#define R0900_P1_AGC1ADJ 0xf42e
++#define F0900_P1_AGC1ADJ_MANUAL 0xf42e0080
++#define F0900_P1_AGC1_ADJUSTED 0xf42e017f
++
++/*P1_AGC2I1*/
++#define R0900_P1_AGC2I1 0xf436
++#define F0900_P1_AGC2_INTEGRATOR1 0xf43600ff
++
++/*P1_AGC2I0*/
++#define R0900_P1_AGC2I0 0xf437
++#define F0900_P1_AGC2_INTEGRATOR0 0xf43700ff
++
++/*P1_CARCFG*/
++#define R0900_P1_CARCFG 0xf438
++#define F0900_P1_CFRUPLOW_AUTO 0xf4380080
++#define F0900_P1_CFRUPLOW_TEST 0xf4380040
++#define F0900_P1_EN_CAR2CENTER 0xf4380020
++#define F0900_P1_CARHDR_NODIV8 0xf4380010
++#define F0900_P1_I2C_ROTA 0xf4380008
++#define F0900_P1_ROTAON 0xf4380004
++#define F0900_P1_PH_DET_ALGO 0xf4380003
++
++/*P1_ACLC*/
++#define R0900_P1_ACLC 0xf439
++#define F0900_P1_STOP_S2ALPHA 0xf43900c0
++#define F0900_P1_CAR_ALPHA_MANT 0xf4390030
++#define F0900_P1_CAR_ALPHA_EXP 0xf439000f
++
++/*P1_BCLC*/
++#define R0900_P1_BCLC 0xf43a
++#define F0900_P1_STOP_S2BETA 0xf43a00c0
++#define F0900_P1_CAR_BETA_MANT 0xf43a0030
++#define F0900_P1_CAR_BETA_EXP 0xf43a000f
++
++/*P1_CARFREQ*/
++#define R0900_P1_CARFREQ 0xf43d
++#define F0900_P1_KC_COARSE_EXP 0xf43d00f0
++#define F0900_P1_BETA_FREQ 0xf43d000f
++
++/*P1_CARHDR*/
++#define R0900_P1_CARHDR 0xf43e
++#define F0900_P1_K_FREQ_HDR 0xf43e00ff
++
++/*P1_LDT*/
++#define R0900_P1_LDT 0xf43f
++#define F0900_P1_CARLOCK_THRES 0xf43f01ff
++
++/*P1_LDT2*/
++#define R0900_P1_LDT2 0xf440
++#define F0900_P1_CARLOCK_THRES2 0xf44001ff
++
++/*P1_CFRICFG*/
++#define R0900_P1_CFRICFG 0xf441
++#define F0900_P1_CFRINIT_UNVALRNG 0xf4410080
++#define F0900_P1_CFRINIT_LUNVALCPT 0xf4410040
++#define F0900_P1_CFRINIT_ABORTDBL 0xf4410020
++#define F0900_P1_CFRINIT_ABORTPRED 0xf4410010
++#define F0900_P1_CFRINIT_UNVALSKIP 0xf4410008
++#define F0900_P1_CFRINIT_CSTINC 0xf4410004
++#define F0900_P1_NEG_CFRSTEP 0xf4410001
++
++/*P1_CFRUP1*/
++#define R0900_P1_CFRUP1 0xf442
++#define F0900_P1_CFR_UP1 0xf44201ff
++
++/*P1_CFRUP0*/
++#define R0900_P1_CFRUP0 0xf443
++#define F0900_P1_CFR_UP0 0xf44300ff
++
++/*P1_CFRLOW1*/
++#define R0900_P1_CFRLOW1 0xf446
++#define F0900_P1_CFR_LOW1 0xf44601ff
++
++/*P1_CFRLOW0*/
++#define R0900_P1_CFRLOW0 0xf447
++#define F0900_P1_CFR_LOW0 0xf44700ff
++
++/*P1_CFRINIT1*/
++#define R0900_P1_CFRINIT1 0xf448
++#define F0900_P1_CFR_INIT1 0xf44801ff
++
++/*P1_CFRINIT0*/
++#define R0900_P1_CFRINIT0 0xf449
++#define F0900_P1_CFR_INIT0 0xf44900ff
++
++/*P1_CFRINC1*/
++#define R0900_P1_CFRINC1 0xf44a
++#define F0900_P1_MANUAL_CFRINC 0xf44a0080
++#define F0900_P1_CFR_INC1 0xf44a017f
++
++/*P1_CFRINC0*/
++#define R0900_P1_CFRINC0 0xf44b
++#define F0900_P1_CFR_INC0 0xf44b00f0
++
++/*P1_CFR2*/
++#define R0900_P1_CFR2 0xf44c
++#define F0900_P1_CAR_FREQ2 0xf44c01ff
++
++/*P1_CFR1*/
++#define R0900_P1_CFR1 0xf44d
++#define F0900_P1_CAR_FREQ1 0xf44d00ff
++
++/*P1_CFR0*/
++#define R0900_P1_CFR0 0xf44e
++#define F0900_P1_CAR_FREQ0 0xf44e00ff
++
++/*P1_LDI*/
++#define R0900_P1_LDI 0xf44f
++#define F0900_P1_LOCK_DET_INTEGR 0xf44f01ff
++
++/*P1_TMGCFG*/
++#define R0900_P1_TMGCFG 0xf450
++#define F0900_P1_TMGLOCK_BETA 0xf45000c0
++#define F0900_P1_NOTMG_GROUPDELAY 0xf4500020
++#define F0900_P1_DO_TIMING_CORR 0xf4500010
++#define F0900_P1_MANUAL_SCAN 0xf450000c
++#define F0900_P1_TMG_MINFREQ 0xf4500003
++
++/*P1_RTC*/
++#define R0900_P1_RTC 0xf451
++#define F0900_P1_TMGALPHA_EXP 0xf45100f0
++#define F0900_P1_TMGBETA_EXP 0xf451000f
++
++/*P1_RTCS2*/
++#define R0900_P1_RTCS2 0xf452
++#define F0900_P1_TMGALPHAS2_EXP 0xf45200f0
++#define F0900_P1_TMGBETAS2_EXP 0xf452000f
++
++/*P1_TMGTHRISE*/
++#define R0900_P1_TMGTHRISE 0xf453
++#define F0900_P1_TMGLOCK_THRISE 0xf45300ff
++
++/*P1_TMGTHFALL*/
++#define R0900_P1_TMGTHFALL 0xf454
++#define F0900_P1_TMGLOCK_THFALL 0xf45400ff
++
++/*P1_SFRUPRATIO*/
++#define R0900_P1_SFRUPRATIO 0xf455
++#define F0900_P1_SFR_UPRATIO 0xf45500ff
++
++/*P1_SFRLOWRATIO*/
++#define R0900_P1_SFRLOWRATIO 0xf456
++#define F0900_P1_SFR_LOWRATIO 0xf45600ff
++
++/*P1_KREFTMG*/
++#define R0900_P1_KREFTMG 0xf458
++#define F0900_P1_KREF_TMG 0xf45800ff
++
++/*P1_SFRSTEP*/
++#define R0900_P1_SFRSTEP 0xf459
++#define F0900_P1_SFR_SCANSTEP 0xf45900f0
++#define F0900_P1_SFR_CENTERSTEP 0xf459000f
++
++/*P1_TMGCFG2*/
++#define R0900_P1_TMGCFG2 0xf45a
++#define F0900_P1_DIS_AUTOSAMP 0xf45a0008
++#define F0900_P1_SCANINIT_QUART 0xf45a0004
++#define F0900_P1_NOTMG_DVBS1DERAT 0xf45a0002
++#define F0900_P1_SFRRATIO_FINE 0xf45a0001
++
++/*P1_SFRINIT1*/
++#define R0900_P1_SFRINIT1 0xf45e
++#define F0900_P1_SFR_INIT1 0xf45e00ff
++
++/*P1_SFRINIT0*/
++#define R0900_P1_SFRINIT0 0xf45f
++#define F0900_P1_SFR_INIT0 0xf45f00ff
++
++/*P1_SFRUP1*/
++#define R0900_P1_SFRUP1 0xf460
++#define F0900_P1_AUTO_GUP 0xf4600080
++#define F0900_P1_SYMB_FREQ_UP1 0xf460007f
++
++/*P1_SFRUP0*/
++#define R0900_P1_SFRUP0 0xf461
++#define F0900_P1_SYMB_FREQ_UP0 0xf46100ff
++
++/*P1_SFRLOW1*/
++#define R0900_P1_SFRLOW1 0xf462
++#define F0900_P1_AUTO_GLOW 0xf4620080
++#define F0900_P1_SYMB_FREQ_LOW1 0xf462007f
++
++/*P1_SFRLOW0*/
++#define R0900_P1_SFRLOW0 0xf463
++#define F0900_P1_SYMB_FREQ_LOW0 0xf46300ff
++
++/*P1_SFR3*/
++#define R0900_P1_SFR3 0xf464
++#define F0900_P1_SYMB_FREQ3 0xf46400ff
++
++/*P1_SFR2*/
++#define R0900_P1_SFR2 0xf465
++#define F0900_P1_SYMB_FREQ2 0xf46500ff
++
++/*P1_SFR1*/
++#define R0900_P1_SFR1 0xf466
++#define F0900_P1_SYMB_FREQ1 0xf46600ff
++
++/*P1_SFR0*/
++#define R0900_P1_SFR0 0xf467
++#define F0900_P1_SYMB_FREQ0 0xf46700ff
++
++/*P1_TMGREG2*/
++#define R0900_P1_TMGREG2 0xf468
++#define F0900_P1_TMGREG2 0xf46800ff
++
++/*P1_TMGREG1*/
++#define R0900_P1_TMGREG1 0xf469
++#define F0900_P1_TMGREG1 0xf46900ff
++
++/*P1_TMGREG0*/
++#define R0900_P1_TMGREG0 0xf46a
++#define F0900_P1_TMGREG0 0xf46a00ff
++
++/*P1_TMGLOCK1*/
++#define R0900_P1_TMGLOCK1 0xf46b
++#define F0900_P1_TMGLOCK_LEVEL1 0xf46b01ff
++
++/*P1_TMGLOCK0*/
++#define R0900_P1_TMGLOCK0 0xf46c
++#define F0900_P1_TMGLOCK_LEVEL0 0xf46c00ff
++
++/*P1_TMGOBS*/
++#define R0900_P1_TMGOBS 0xf46d
++#define F0900_P1_ROLLOFF_STATUS 0xf46d00c0
++#define F0900_P1_SCAN_SIGN 0xf46d0030
++#define F0900_P1_TMG_SCANNING 0xf46d0008
++#define F0900_P1_CHCENTERING_MODE 0xf46d0004
++#define F0900_P1_TMG_SCANFAIL 0xf46d0002
++
++/*P1_EQUALCFG*/
++#define R0900_P1_EQUALCFG 0xf46f
++#define F0900_P1_NOTMG_NEGALWAIT 0xf46f0080
++#define F0900_P1_EQUAL_ON 0xf46f0040
++#define F0900_P1_SEL_EQUALCOR 0xf46f0038
++#define F0900_P1_MU_EQUALDFE 0xf46f0007
++
++/*P1_EQUAI1*/
++#define R0900_P1_EQUAI1 0xf470
++#define F0900_P1_EQUA_ACCI1 0xf47001ff
++
++/*P1_EQUAQ1*/
++#define R0900_P1_EQUAQ1 0xf471
++#define F0900_P1_EQUA_ACCQ1 0xf47101ff
++
++/*P1_EQUAI2*/
++#define R0900_P1_EQUAI2 0xf472
++#define F0900_P1_EQUA_ACCI2 0xf47201ff
++
++/*P1_EQUAQ2*/
++#define R0900_P1_EQUAQ2 0xf473
++#define F0900_P1_EQUA_ACCQ2 0xf47301ff
++
++/*P1_EQUAI3*/
++#define R0900_P1_EQUAI3 0xf474
++#define F0900_P1_EQUA_ACCI3 0xf47401ff
++
++/*P1_EQUAQ3*/
++#define R0900_P1_EQUAQ3 0xf475
++#define F0900_P1_EQUA_ACCQ3 0xf47501ff
++
++/*P1_EQUAI4*/
++#define R0900_P1_EQUAI4 0xf476
++#define F0900_P1_EQUA_ACCI4 0xf47601ff
++
++/*P1_EQUAQ4*/
++#define R0900_P1_EQUAQ4 0xf477
++#define F0900_P1_EQUA_ACCQ4 0xf47701ff
++
++/*P1_EQUAI5*/
++#define R0900_P1_EQUAI5 0xf478
++#define F0900_P1_EQUA_ACCI5 0xf47801ff
++
++/*P1_EQUAQ5*/
++#define R0900_P1_EQUAQ5 0xf479
++#define F0900_P1_EQUA_ACCQ5 0xf47901ff
++
++/*P1_EQUAI6*/
++#define R0900_P1_EQUAI6 0xf47a
++#define F0900_P1_EQUA_ACCI6 0xf47a01ff
++
++/*P1_EQUAQ6*/
++#define R0900_P1_EQUAQ6 0xf47b
++#define F0900_P1_EQUA_ACCQ6 0xf47b01ff
++
++/*P1_EQUAI7*/
++#define R0900_P1_EQUAI7 0xf47c
++#define F0900_P1_EQUA_ACCI7 0xf47c01ff
++
++/*P1_EQUAQ7*/
++#define R0900_P1_EQUAQ7 0xf47d
++#define F0900_P1_EQUA_ACCQ7 0xf47d01ff
++
++/*P1_EQUAI8*/
++#define R0900_P1_EQUAI8 0xf47e
++#define F0900_P1_EQUA_ACCI8 0xf47e01ff
++
++/*P1_EQUAQ8*/
++#define R0900_P1_EQUAQ8 0xf47f
++#define F0900_P1_EQUA_ACCQ8 0xf47f01ff
++
++/*P1_NNOSDATAT1*/
++#define R0900_P1_NNOSDATAT1 0xf480
++#define F0900_P1_NOSDATAT_NORMED1 0xf48000ff
++
++/*P1_NNOSDATAT0*/
++#define R0900_P1_NNOSDATAT0 0xf481
++#define F0900_P1_NOSDATAT_NORMED0 0xf48100ff
++
++/*P1_NNOSDATA1*/
++#define R0900_P1_NNOSDATA1 0xf482
++#define F0900_P1_NOSDATA_NORMED1 0xf48200ff
++
++/*P1_NNOSDATA0*/
++#define R0900_P1_NNOSDATA0 0xf483
++#define F0900_P1_NOSDATA_NORMED0 0xf48300ff
++
++/*P1_NNOSPLHT1*/
++#define R0900_P1_NNOSPLHT1 0xf484
++#define F0900_P1_NOSPLHT_NORMED1 0xf48400ff
++
++/*P1_NNOSPLHT0*/
++#define R0900_P1_NNOSPLHT0 0xf485
++#define F0900_P1_NOSPLHT_NORMED0 0xf48500ff
++
++/*P1_NNOSPLH1*/
++#define R0900_P1_NNOSPLH1 0xf486
++#define F0900_P1_NOSPLH_NORMED1 0xf48600ff
++
++/*P1_NNOSPLH0*/
++#define R0900_P1_NNOSPLH0 0xf487
++#define F0900_P1_NOSPLH_NORMED0 0xf48700ff
++
++/*P1_NOSDATAT1*/
++#define R0900_P1_NOSDATAT1 0xf488
++#define F0900_P1_NOSDATAT_UNNORMED1 0xf48800ff
++
++/*P1_NOSDATAT0*/
++#define R0900_P1_NOSDATAT0 0xf489
++#define F0900_P1_NOSDATAT_UNNORMED0 0xf48900ff
++
++/*P1_NOSDATA1*/
++#define R0900_P1_NOSDATA1 0xf48a
++#define F0900_P1_NOSDATA_UNNORMED1 0xf48a00ff
++
++/*P1_NOSDATA0*/
++#define R0900_P1_NOSDATA0 0xf48b
++#define F0900_P1_NOSDATA_UNNORMED0 0xf48b00ff
++
++/*P1_NOSPLHT1*/
++#define R0900_P1_NOSPLHT1 0xf48c
++#define F0900_P1_NOSPLHT_UNNORMED1 0xf48c00ff
++
++/*P1_NOSPLHT0*/
++#define R0900_P1_NOSPLHT0 0xf48d
++#define F0900_P1_NOSPLHT_UNNORMED0 0xf48d00ff
++
++/*P1_NOSPLH1*/
++#define R0900_P1_NOSPLH1 0xf48e
++#define F0900_P1_NOSPLH_UNNORMED1 0xf48e00ff
++
++/*P1_NOSPLH0*/
++#define R0900_P1_NOSPLH0 0xf48f
++#define F0900_P1_NOSPLH_UNNORMED0 0xf48f00ff
++
++/*P1_CAR2CFG*/
++#define R0900_P1_CAR2CFG 0xf490
++#define F0900_P1_DESCRAMB_OFF 0xf4900080
++#define F0900_P1_PN4_SELECT 0xf4900040
++#define F0900_P1_CFR2_STOPDVBS1 0xf4900020
++#define F0900_P1_STOP_CFR2UPDATE 0xf4900010
++#define F0900_P1_STOP_NCO2UPDATE 0xf4900008
++#define F0900_P1_ROTA2ON 0xf4900004
++#define F0900_P1_PH_DET_ALGO2 0xf4900003
++
++/*P1_ACLC2*/
++#define R0900_P1_ACLC2 0xf491
++#define F0900_P1_CAR2_PUNCT_ADERAT 0xf4910040
++#define F0900_P1_CAR2_ALPHA_MANT 0xf4910030
++#define F0900_P1_CAR2_ALPHA_EXP 0xf491000f
++
++/*P1_BCLC2*/
++#define R0900_P1_BCLC2 0xf492
++#define F0900_P1_DVBS2_NIP 0xf4920080
++#define F0900_P1_CAR2_PUNCT_BDERAT 0xf4920040
++#define F0900_P1_CAR2_BETA_MANT 0xf4920030
++#define F0900_P1_CAR2_BETA_EXP 0xf492000f
++
++/*P1_CFR22*/
++#define R0900_P1_CFR22 0xf493
++#define F0900_P1_CAR2_FREQ2 0xf49301ff
++
++/*P1_CFR21*/
++#define R0900_P1_CFR21 0xf494
++#define F0900_P1_CAR2_FREQ1 0xf49400ff
++
++/*P1_CFR20*/
++#define R0900_P1_CFR20 0xf495
++#define F0900_P1_CAR2_FREQ0 0xf49500ff
++
++/*P1_ACLC2S2Q*/
++#define R0900_P1_ACLC2S2Q 0xf497
++#define F0900_P1_ENAB_SPSKSYMB 0xf4970080
++#define F0900_P1_CAR2S2_QADERAT 0xf4970040
++#define F0900_P1_CAR2S2_Q_ALPH_M 0xf4970030
++#define F0900_P1_CAR2S2_Q_ALPH_E 0xf497000f
++
++/*P1_ACLC2S28*/
++#define R0900_P1_ACLC2S28 0xf498
++#define F0900_P1_OLDI3Q_MODE 0xf4980080
++#define F0900_P1_CAR2S2_8ADERAT 0xf4980040
++#define F0900_P1_CAR2S2_8_ALPH_M 0xf4980030
++#define F0900_P1_CAR2S2_8_ALPH_E 0xf498000f
++
++/*P1_ACLC2S216A*/
++#define R0900_P1_ACLC2S216A 0xf499
++#define F0900_P1_CAR2S2_16ADERAT 0xf4990040
++#define F0900_P1_CAR2S2_16A_ALPH_M 0xf4990030
++#define F0900_P1_CAR2S2_16A_ALPH_E 0xf499000f
++
++/*P1_ACLC2S232A*/
++#define R0900_P1_ACLC2S232A 0xf49a
++#define F0900_P1_CAR2S2_32ADERAT 0xf49a0040
++#define F0900_P1_CAR2S2_32A_ALPH_M 0xf49a0030
++#define F0900_P1_CAR2S2_32A_ALPH_E 0xf49a000f
++
++/*P1_BCLC2S2Q*/
++#define R0900_P1_BCLC2S2Q 0xf49c
++#define F0900_P1_DVBS2S2Q_NIP 0xf49c0080
++#define F0900_P1_CAR2S2_QBDERAT 0xf49c0040
++#define F0900_P1_CAR2S2_Q_BETA_M 0xf49c0030
++#define F0900_P1_CAR2S2_Q_BETA_E 0xf49c000f
++
++/*P1_BCLC2S28*/
++#define R0900_P1_BCLC2S28 0xf49d
++#define F0900_P1_DVBS2S28_NIP 0xf49d0080
++#define F0900_P1_CAR2S2_8BDERAT 0xf49d0040
++#define F0900_P1_CAR2S2_8_BETA_M 0xf49d0030
++#define F0900_P1_CAR2S2_8_BETA_E 0xf49d000f
++
++/*P1_BCLC2S216A*/
++#define R0900_P1_BCLC2S216A 0xf49e
++#define F0900_P1_DVBS2S216A_NIP 0xf49e0080
++#define F0900_P1_CAR2S2_16BDERAT 0xf49e0040
++#define F0900_P1_CAR2S2_16A_BETA_M 0xf49e0030
++#define F0900_P1_CAR2S2_16A_BETA_E 0xf49e000f
++
++/*P1_BCLC2S232A*/
++#define R0900_P1_BCLC2S232A 0xf49f
++#define F0900_P1_DVBS2S232A_NIP 0xf49f0080
++#define F0900_P1_CAR2S2_32BDERAT 0xf49f0040
++#define F0900_P1_CAR2S2_32A_BETA_M 0xf49f0030
++#define F0900_P1_CAR2S2_32A_BETA_E 0xf49f000f
++
++/*P1_PLROOT2*/
++#define R0900_P1_PLROOT2 0xf4ac
++#define F0900_P1_SHORTFR_DISABLE 0xf4ac0080
++#define F0900_P1_LONGFR_DISABLE 0xf4ac0040
++#define F0900_P1_DUMMYPL_DISABLE 0xf4ac0020
++#define F0900_P1_SHORTFR_AVOID 0xf4ac0010
++#define F0900_P1_PLSCRAMB_MODE 0xf4ac000c
++#define F0900_P1_PLSCRAMB_ROOT2 0xf4ac0003
++
++/*P1_PLROOT1*/
++#define R0900_P1_PLROOT1 0xf4ad
++#define F0900_P1_PLSCRAMB_ROOT1 0xf4ad00ff
++
++/*P1_PLROOT0*/
++#define R0900_P1_PLROOT0 0xf4ae
++#define F0900_P1_PLSCRAMB_ROOT0 0xf4ae00ff
++
++/*P1_MODCODLST0*/
++#define R0900_P1_MODCODLST0 0xf4b0
++#define F0900_P1_EN_TOKEN31 0xf4b00080
++#define F0900_P1_SYNCTAG_SELECT 0xf4b00040
++#define F0900_P1_MODCODRQ_MODE 0xf4b00030
++
++/*P1_MODCODLST1*/
++#define R0900_P1_MODCODLST1 0xf4b1
++#define F0900_P1_DIS_MODCOD29 0xf4b100f0
++#define F0900_P1_DIS_32PSK_9_10 0xf4b1000f
++
++/*P1_MODCODLST2*/
++#define R0900_P1_MODCODLST2 0xf4b2
++#define F0900_P1_DIS_32PSK_8_9 0xf4b200f0
++#define F0900_P1_DIS_32PSK_5_6 0xf4b2000f
++
++/*P1_MODCODLST3*/
++#define R0900_P1_MODCODLST3 0xf4b3
++#define F0900_P1_DIS_32PSK_4_5 0xf4b300f0
++#define F0900_P1_DIS_32PSK_3_4 0xf4b3000f
++
++/*P1_MODCODLST4*/
++#define R0900_P1_MODCODLST4 0xf4b4
++#define F0900_P1_DIS_16PSK_9_10 0xf4b400f0
++#define F0900_P1_DIS_16PSK_8_9 0xf4b4000f
++
++/*P1_MODCODLST5*/
++#define R0900_P1_MODCODLST5 0xf4b5
++#define F0900_P1_DIS_16PSK_5_6 0xf4b500f0
++#define F0900_P1_DIS_16PSK_4_5 0xf4b5000f
++
++/*P1_MODCODLST6*/
++#define R0900_P1_MODCODLST6 0xf4b6
++#define F0900_P1_DIS_16PSK_3_4 0xf4b600f0
++#define F0900_P1_DIS_16PSK_2_3 0xf4b6000f
++
++/*P1_MODCODLST7*/
++#define R0900_P1_MODCODLST7 0xf4b7
++#define F0900_P1_DIS_8P_9_10 0xf4b700f0
++#define F0900_P1_DIS_8P_8_9 0xf4b7000f
++
++/*P1_MODCODLST8*/
++#define R0900_P1_MODCODLST8 0xf4b8
++#define F0900_P1_DIS_8P_5_6 0xf4b800f0
++#define F0900_P1_DIS_8P_3_4 0xf4b8000f
++
++/*P1_MODCODLST9*/
++#define R0900_P1_MODCODLST9 0xf4b9
++#define F0900_P1_DIS_8P_2_3 0xf4b900f0
++#define F0900_P1_DIS_8P_3_5 0xf4b9000f
++
++/*P1_MODCODLSTA*/
++#define R0900_P1_MODCODLSTA 0xf4ba
++#define F0900_P1_DIS_QP_9_10 0xf4ba00f0
++#define F0900_P1_DIS_QP_8_9 0xf4ba000f
++
++/*P1_MODCODLSTB*/
++#define R0900_P1_MODCODLSTB 0xf4bb
++#define F0900_P1_DIS_QP_5_6 0xf4bb00f0
++#define F0900_P1_DIS_QP_4_5 0xf4bb000f
++
++/*P1_MODCODLSTC*/
++#define R0900_P1_MODCODLSTC 0xf4bc
++#define F0900_P1_DIS_QP_3_4 0xf4bc00f0
++#define F0900_P1_DIS_QP_2_3 0xf4bc000f
++
++/*P1_MODCODLSTD*/
++#define R0900_P1_MODCODLSTD 0xf4bd
++#define F0900_P1_DIS_QP_3_5 0xf4bd00f0
++#define F0900_P1_DIS_QP_1_2 0xf4bd000f
++
++/*P1_MODCODLSTE*/
++#define R0900_P1_MODCODLSTE 0xf4be
++#define F0900_P1_DIS_QP_2_5 0xf4be00f0
++#define F0900_P1_DIS_QP_1_3 0xf4be000f
++
++/*P1_MODCODLSTF*/
++#define R0900_P1_MODCODLSTF 0xf4bf
++#define F0900_P1_DIS_QP_1_4 0xf4bf00f0
++#define F0900_P1_DDEMOD_SET 0xf4bf0002
++#define F0900_P1_DDEMOD_MASK 0xf4bf0001
++
++/*P1_DMDRESCFG*/
++#define R0900_P1_DMDRESCFG 0xf4c6
++#define F0900_P1_DMDRES_RESET 0xf4c60080
++#define F0900_P1_DMDRES_NOISESQR 0xf4c60010
++#define F0900_P1_DMDRES_STRALL 0xf4c60008
++#define F0900_P1_DMDRES_NEWONLY 0xf4c60004
++#define F0900_P1_DMDRES_NOSTORE 0xf4c60002
++#define F0900_P1_DMDRES_AGC2MEM 0xf4c60001
++
++/*P1_DMDRESADR*/
++#define R0900_P1_DMDRESADR 0xf4c7
++#define F0900_P1_SUSP_PREDCANAL 0xf4c70080
++#define F0900_P1_DMDRES_VALIDCFR 0xf4c70040
++#define F0900_P1_DMDRES_MEMFULL 0xf4c70030
++#define F0900_P1_DMDRES_RESNBR 0xf4c7000f
++
++/*P1_DMDRESDATA7*/
++#define R0900_P1_DMDRESDATA7 0xf4c8
++#define F0900_P1_DMDRES_DATA7 0xf4c800ff
++
++/*P1_DMDRESDATA6*/
++#define R0900_P1_DMDRESDATA6 0xf4c9
++#define F0900_P1_DMDRES_DATA6 0xf4c900ff
++
++/*P1_DMDRESDATA5*/
++#define R0900_P1_DMDRESDATA5 0xf4ca
++#define F0900_P1_DMDRES_DATA5 0xf4ca00ff
++
++/*P1_DMDRESDATA4*/
++#define R0900_P1_DMDRESDATA4 0xf4cb
++#define F0900_P1_DMDRES_DATA4 0xf4cb00ff
++
++/*P1_DMDRESDATA3*/
++#define R0900_P1_DMDRESDATA3 0xf4cc
++#define F0900_P1_DMDRES_DATA3 0xf4cc00ff
++
++/*P1_DMDRESDATA2*/
++#define R0900_P1_DMDRESDATA2 0xf4cd
++#define F0900_P1_DMDRES_DATA2 0xf4cd00ff
++
++/*P1_DMDRESDATA1*/
++#define R0900_P1_DMDRESDATA1 0xf4ce
++#define F0900_P1_DMDRES_DATA1 0xf4ce00ff
++
++/*P1_DMDRESDATA0*/
++#define R0900_P1_DMDRESDATA0 0xf4cf
++#define F0900_P1_DMDRES_DATA0 0xf4cf00ff
++
++/*P1_FFEI1*/
++#define R0900_P1_FFEI1 0xf4d0
++#define F0900_P1_FFE_ACCI1 0xf4d001ff
++
++/*P1_FFEQ1*/
++#define R0900_P1_FFEQ1 0xf4d1
++#define F0900_P1_FFE_ACCQ1 0xf4d101ff
++
++/*P1_FFEI2*/
++#define R0900_P1_FFEI2 0xf4d2
++#define F0900_P1_FFE_ACCI2 0xf4d201ff
++
++/*P1_FFEQ2*/
++#define R0900_P1_FFEQ2 0xf4d3
++#define F0900_P1_FFE_ACCQ2 0xf4d301ff
++
++/*P1_FFEI3*/
++#define R0900_P1_FFEI3 0xf4d4
++#define F0900_P1_FFE_ACCI3 0xf4d401ff
++
++/*P1_FFEQ3*/
++#define R0900_P1_FFEQ3 0xf4d5
++#define F0900_P1_FFE_ACCQ3 0xf4d501ff
++
++/*P1_FFEI4*/
++#define R0900_P1_FFEI4 0xf4d6
++#define F0900_P1_FFE_ACCI4 0xf4d601ff
++
++/*P1_FFEQ4*/
++#define R0900_P1_FFEQ4 0xf4d7
++#define F0900_P1_FFE_ACCQ4 0xf4d701ff
++
++/*P1_FFECFG*/
++#define R0900_P1_FFECFG 0xf4d8
++#define F0900_P1_EQUALFFE_ON 0xf4d80040
++#define F0900_P1_EQUAL_USEDSYMB 0xf4d80030
++#define F0900_P1_MU_EQUALFFE 0xf4d80007
++
++/*P1_TNRCFG*/
++#define R0900_P1_TNRCFG 0xf4e0
++#define F0900_P1_TUN_ACKFAIL 0xf4e00080
++#define F0900_P1_TUN_TYPE 0xf4e00070
++#define F0900_P1_TUN_SECSTOP 0xf4e00008
++#define F0900_P1_TUN_VCOSRCH 0xf4e00004
++#define F0900_P1_TUN_MADDRESS 0xf4e00003
++
++/*P1_TNRCFG2*/
++#define R0900_P1_TNRCFG2 0xf4e1
++#define F0900_P1_TUN_IQSWAP 0xf4e10080
++#define F0900_P1_STB6110_STEP2MHZ 0xf4e10040
++#define F0900_P1_STB6120_DBLI2C 0xf4e10020
++#define F0900_P1_DIS_FCCK 0xf4e10010
++#define F0900_P1_DIS_LPEN 0xf4e10008
++#define F0900_P1_DIS_BWCALC 0xf4e10004
++#define F0900_P1_SHORT_WAITSTATES 0xf4e10002
++#define F0900_P1_DIS_2BWAGC1 0xf4e10001
++
++/*P1_TNRXTAL*/
++#define R0900_P1_TNRXTAL 0xf4e4
++#define F0900_P1_TUN_MCLKDECIMAL 0xf4e400e0
++#define F0900_P1_TUN_XTALFREQ 0xf4e4001f
++
++/*P1_TNRSTEPS*/
++#define R0900_P1_TNRSTEPS 0xf4e7
++#define F0900_P1_TUNER_BW1P6 0xf4e70080
++#define F0900_P1_BWINC_OFFSET 0xf4e70070
++#define F0900_P1_SOFTSTEP_RNG 0xf4e70008
++#define F0900_P1_TUN_BWOFFSET 0xf4e70107
++
++/*P1_TNRGAIN*/
++#define R0900_P1_TNRGAIN 0xf4e8
++#define F0900_P1_TUN_KDIVEN 0xf4e800c0
++#define F0900_P1_STB6X00_OCK 0xf4e80030
++#define F0900_P1_TUN_GAIN 0xf4e8000f
++
++/*P1_TNRRF1*/
++#define R0900_P1_TNRRF1 0xf4e9
++#define F0900_P1_TUN_RFFREQ2 0xf4e900ff
++
++/*P1_TNRRF0*/
++#define R0900_P1_TNRRF0 0xf4ea
++#define F0900_P1_TUN_RFFREQ1 0xf4ea00ff
++
++/*P1_TNRBW*/
++#define R0900_P1_TNRBW 0xf4eb
++#define F0900_P1_TUN_RFFREQ0 0xf4eb00c0
++#define F0900_P1_TUN_BW 0xf4eb003f
++
++/*P1_TNRADJ*/
++#define R0900_P1_TNRADJ 0xf4ec
++#define F0900_P1_STB61X0_RCLK 0xf4ec0080
++#define F0900_P1_STB61X0_CALTIME 0xf4ec0040
++#define F0900_P1_STB6X00_DLB 0xf4ec0038
++#define F0900_P1_STB6000_FCL 0xf4ec0007
++
++/*P1_TNRCTL2*/
++#define R0900_P1_TNRCTL2 0xf4ed
++#define F0900_P1_STB61X0_LCP1_RCCKOFF 0xf4ed0080
++#define F0900_P1_STB61X0_LCP0 0xf4ed0040
++#define F0900_P1_STB61X0_XTOUT_RFOUTS 0xf4ed0020
++#define F0900_P1_STB61X0_XTON_MCKDV 0xf4ed0010
++#define F0900_P1_STB61X0_CALOFF_DCOFF 0xf4ed0008
++#define F0900_P1_STB6110_LPT 0xf4ed0004
++#define F0900_P1_STB6110_RX 0xf4ed0002
++#define F0900_P1_STB6110_SYN 0xf4ed0001
++
++/*P1_TNRCFG3*/
++#define R0900_P1_TNRCFG3 0xf4ee
++#define F0900_P1_STB6120_DISCTRL1 0xf4ee0080
++#define F0900_P1_STB6120_INVORDER 0xf4ee0040
++#define F0900_P1_STB6120_ENCTRL6 0xf4ee0020
++#define F0900_P1_TUN_PLLFREQ 0xf4ee001c
++#define F0900_P1_TUN_I2CFREQ_MODE 0xf4ee0003
++
++/*P1_TNRLAUNCH*/
++#define R0900_P1_TNRLAUNCH 0xf4f0
++
++/*P1_TNRLD*/
++#define R0900_P1_TNRLD 0xf4f0
++#define F0900_P1_TUNLD_VCOING 0xf4f00080
++#define F0900_P1_TUN_REG1FAIL 0xf4f00040
++#define F0900_P1_TUN_REG2FAIL 0xf4f00020
++#define F0900_P1_TUN_REG3FAIL 0xf4f00010
++#define F0900_P1_TUN_REG4FAIL 0xf4f00008
++#define F0900_P1_TUN_REG5FAIL 0xf4f00004
++#define F0900_P1_TUN_BWING 0xf4f00002
++#define F0900_P1_TUN_LOCKED 0xf4f00001
++
++/*P1_TNROBSL*/
++#define R0900_P1_TNROBSL 0xf4f6
++#define F0900_P1_TUN_I2CABORTED 0xf4f60080
++#define F0900_P1_TUN_LPEN 0xf4f60040
++#define F0900_P1_TUN_FCCK 0xf4f60020
++#define F0900_P1_TUN_I2CLOCKED 0xf4f60010
++#define F0900_P1_TUN_PROGDONE 0xf4f6000c
++#define F0900_P1_TUN_RFRESTE1 0xf4f60003
++
++/*P1_TNRRESTE*/
++#define R0900_P1_TNRRESTE 0xf4f7
++#define F0900_P1_TUN_RFRESTE0 0xf4f700ff
++
++/*P1_SMAPCOEF7*/
++#define R0900_P1_SMAPCOEF7 0xf500
++#define F0900_P1_DIS_QSCALE 0xf5000080
++#define F0900_P1_SMAPCOEF_Q_LLR12 0xf500017f
++
++/*P1_SMAPCOEF6*/
++#define R0900_P1_SMAPCOEF6 0xf501
++#define F0900_P1_DIS_NEWSCALE 0xf5010008
++#define F0900_P1_ADJ_8PSKLLR1 0xf5010004
++#define F0900_P1_OLD_8PSKLLR1 0xf5010002
++#define F0900_P1_DIS_AB8PSK 0xf5010001
++
++/*P1_SMAPCOEF5*/
++#define R0900_P1_SMAPCOEF5 0xf502
++#define F0900_P1_DIS_8SCALE 0xf5020080
++#define F0900_P1_SMAPCOEF_8P_LLR23 0xf502017f
++
++/*P1_DMDPLHSTAT*/
++#define R0900_P1_DMDPLHSTAT 0xf520
++#define F0900_P1_PLH_STATISTIC 0xf52000ff
++
++/*P1_LOCKTIME3*/
++#define R0900_P1_LOCKTIME3 0xf522
++#define F0900_P1_DEMOD_LOCKTIME3 0xf52200ff
++
++/*P1_LOCKTIME2*/
++#define R0900_P1_LOCKTIME2 0xf523
++#define F0900_P1_DEMOD_LOCKTIME2 0xf52300ff
++
++/*P1_LOCKTIME1*/
++#define R0900_P1_LOCKTIME1 0xf524
++#define F0900_P1_DEMOD_LOCKTIME1 0xf52400ff
++
++/*P1_LOCKTIME0*/
++#define R0900_P1_LOCKTIME0 0xf525
++#define F0900_P1_DEMOD_LOCKTIME0 0xf52500ff
++
++/*P1_VITSCALE*/
++#define R0900_P1_VITSCALE 0xf532
++#define F0900_P1_NVTH_NOSRANGE 0xf5320080
++#define F0900_P1_VERROR_MAXMODE 0xf5320040
++#define F0900_P1_KDIV_MODE 0xf5320030
++#define F0900_P1_NSLOWSN_LOCKED 0xf5320008
++#define F0900_P1_DELOCK_PRFLOSS 0xf5320004
++#define F0900_P1_DIS_RSFLOCK 0xf5320002
++
++/*P1_FECM*/
++#define R0900_P1_FECM 0xf533
++#define F0900_P1_DSS_DVB 0xf5330080
++#define F0900_P1_DEMOD_BYPASS 0xf5330040
++#define F0900_P1_CMP_SLOWMODE 0xf5330020
++#define F0900_P1_DSS_SRCH 0xf5330010
++#define F0900_P1_DIFF_MODEVIT 0xf5330004
++#define F0900_P1_SYNCVIT 0xf5330002
++#define F0900_P1_IQINV 0xf5330001
++
++/*P1_VTH12*/
++#define R0900_P1_VTH12 0xf534
++#define F0900_P1_VTH12 0xf53400ff
++
++/*P1_VTH23*/
++#define R0900_P1_VTH23 0xf535
++#define F0900_P1_VTH23 0xf53500ff
++
++/*P1_VTH34*/
++#define R0900_P1_VTH34 0xf536
++#define F0900_P1_VTH34 0xf53600ff
++
++/*P1_VTH56*/
++#define R0900_P1_VTH56 0xf537
++#define F0900_P1_VTH56 0xf53700ff
++
++/*P1_VTH67*/
++#define R0900_P1_VTH67 0xf538
++#define F0900_P1_VTH67 0xf53800ff
++
++/*P1_VTH78*/
++#define R0900_P1_VTH78 0xf539
++#define F0900_P1_VTH78 0xf53900ff
++
++/*P1_VITCURPUN*/
++#define R0900_P1_VITCURPUN 0xf53a
++#define F0900_P1_VIT_MAPPING 0xf53a00e0
++#define F0900_P1_VIT_CURPUN 0xf53a001f
++
++/*P1_VERROR*/
++#define R0900_P1_VERROR 0xf53b
++#define F0900_P1_REGERR_VIT 0xf53b00ff
++
++/*P1_PRVIT*/
++#define R0900_P1_PRVIT 0xf53c
++#define F0900_P1_DIS_VTHLOCK 0xf53c0040
++#define F0900_P1_E7_8VIT 0xf53c0020
++#define F0900_P1_E6_7VIT 0xf53c0010
++#define F0900_P1_E5_6VIT 0xf53c0008
++#define F0900_P1_E3_4VIT 0xf53c0004
++#define F0900_P1_E2_3VIT 0xf53c0002
++#define F0900_P1_E1_2VIT 0xf53c0001
++
++/*P1_VAVSRVIT*/
++#define R0900_P1_VAVSRVIT 0xf53d
++#define F0900_P1_AMVIT 0xf53d0080
++#define F0900_P1_FROZENVIT 0xf53d0040
++#define F0900_P1_SNVIT 0xf53d0030
++#define F0900_P1_TOVVIT 0xf53d000c
++#define F0900_P1_HYPVIT 0xf53d0003
++
++/*P1_VSTATUSVIT*/
++#define R0900_P1_VSTATUSVIT 0xf53e
++#define F0900_P1_VITERBI_ON 0xf53e0080
++#define F0900_P1_END_LOOPVIT 0xf53e0040
++#define F0900_P1_VITERBI_DEPRF 0xf53e0020
++#define F0900_P1_PRFVIT 0xf53e0010
++#define F0900_P1_LOCKEDVIT 0xf53e0008
++#define F0900_P1_VITERBI_DELOCK 0xf53e0004
++#define F0900_P1_VIT_DEMODSEL 0xf53e0002
++#define F0900_P1_VITERBI_COMPOUT 0xf53e0001
++
++/*P1_VTHINUSE*/
++#define R0900_P1_VTHINUSE 0xf53f
++#define F0900_P1_VIT_INUSE 0xf53f00ff
++
++/*P1_KDIV12*/
++#define R0900_P1_KDIV12 0xf540
++#define F0900_P1_KDIV12_MANUAL 0xf5400080
++#define F0900_P1_K_DIVIDER_12 0xf540007f
++
++/*P1_KDIV23*/
++#define R0900_P1_KDIV23 0xf541
++#define F0900_P1_KDIV23_MANUAL 0xf5410080
++#define F0900_P1_K_DIVIDER_23 0xf541007f
++
++/*P1_KDIV34*/
++#define R0900_P1_KDIV34 0xf542
++#define F0900_P1_KDIV34_MANUAL 0xf5420080
++#define F0900_P1_K_DIVIDER_34 0xf542007f
++
++/*P1_KDIV56*/
++#define R0900_P1_KDIV56 0xf543
++#define F0900_P1_KDIV56_MANUAL 0xf5430080
++#define F0900_P1_K_DIVIDER_56 0xf543007f
++
++/*P1_KDIV67*/
++#define R0900_P1_KDIV67 0xf544
++#define F0900_P1_KDIV67_MANUAL 0xf5440080
++#define F0900_P1_K_DIVIDER_67 0xf544007f
++
++/*P1_KDIV78*/
++#define R0900_P1_KDIV78 0xf545
++#define F0900_P1_KDIV78_MANUAL 0xf5450080
++#define F0900_P1_K_DIVIDER_78 0xf545007f
++
++/*P1_PDELCTRL1*/
++#define R0900_P1_PDELCTRL1 0xf550
++#define F0900_P1_INV_MISMASK 0xf5500080
++#define F0900_P1_FORCE_ACCEPTED 0xf5500040
++#define F0900_P1_FILTER_EN 0xf5500020
++#define F0900_P1_FORCE_PKTDELINUSE 0xf5500010
++#define F0900_P1_HYSTEN 0xf5500008
++#define F0900_P1_HYSTSWRST 0xf5500004
++#define F0900_P1_EN_MIS00 0xf5500002
++#define F0900_P1_ALGOSWRST 0xf5500001
++
++/*P1_PDELCTRL2*/
++#define R0900_P1_PDELCTRL2 0xf551
++#define F0900_P1_FORCE_CONTINUOUS 0xf5510080
++#define F0900_P1_RESET_UPKO_COUNT 0xf5510040
++#define F0900_P1_USER_PKTDELIN_NB 0xf5510020
++#define F0900_P1_FORCE_LOCKED 0xf5510010
++#define F0900_P1_DATA_UNBBSCRAM 0xf5510008
++#define F0900_P1_FORCE_LONGPKT 0xf5510004
++#define F0900_P1_FRAME_MODE 0xf5510002
++
++/*P1_HYSTTHRESH*/
++#define R0900_P1_HYSTTHRESH 0xf554
++#define F0900_P1_UNLCK_THRESH 0xf55400f0
++#define F0900_P1_DELIN_LCK_THRESH 0xf554000f
++
++/*P1_ISIENTRY*/
++#define R0900_P1_ISIENTRY 0xf55e
++#define F0900_P1_ISI_ENTRY 0xf55e00ff
++
++/*P1_ISIBITENA*/
++#define R0900_P1_ISIBITENA 0xf55f
++#define F0900_P1_ISI_BIT_EN 0xf55f00ff
++
++/*P1_MATSTR1*/
++#define R0900_P1_MATSTR1 0xf560
++#define F0900_P1_MATYPE_CURRENT1 0xf56000ff
++
++/*P1_MATSTR0*/
++#define R0900_P1_MATSTR0 0xf561
++#define F0900_P1_MATYPE_CURRENT0 0xf56100ff
++
++/*P1_UPLSTR1*/
++#define R0900_P1_UPLSTR1 0xf562
++#define F0900_P1_UPL_CURRENT1 0xf56200ff
++
++/*P1_UPLSTR0*/
++#define R0900_P1_UPLSTR0 0xf563
++#define F0900_P1_UPL_CURRENT0 0xf56300ff
++
++/*P1_DFLSTR1*/
++#define R0900_P1_DFLSTR1 0xf564
++#define F0900_P1_DFL_CURRENT1 0xf56400ff
++
++/*P1_DFLSTR0*/
++#define R0900_P1_DFLSTR0 0xf565
++#define F0900_P1_DFL_CURRENT0 0xf56500ff
++
++/*P1_SYNCSTR*/
++#define R0900_P1_SYNCSTR 0xf566
++#define F0900_P1_SYNC_CURRENT 0xf56600ff
++
++/*P1_SYNCDSTR1*/
++#define R0900_P1_SYNCDSTR1 0xf567
++#define F0900_P1_SYNCD_CURRENT1 0xf56700ff
++
++/*P1_SYNCDSTR0*/
++#define R0900_P1_SYNCDSTR0 0xf568
++#define F0900_P1_SYNCD_CURRENT0 0xf56800ff
++
++/*P1_PDELSTATUS1*/
++#define R0900_P1_PDELSTATUS1 0xf569
++#define F0900_P1_PKTDELIN_DELOCK 0xf5690080
++#define F0900_P1_SYNCDUPDFL_BADDFL 0xf5690040
++#define F0900_P1_CONTINUOUS_STREAM 0xf5690020
++#define F0900_P1_UNACCEPTED_STREAM 0xf5690010
++#define F0900_P1_BCH_ERROR_FLAG 0xf5690008
++#define F0900_P1_BBHCRCKO 0xf5690004
++#define F0900_P1_PKTDELIN_LOCK 0xf5690002
++#define F0900_P1_FIRST_LOCK 0xf5690001
++
++/*P1_PDELSTATUS2*/
++#define R0900_P1_PDELSTATUS2 0xf56a
++#define F0900_P1_PKTDEL_DEMODSEL 0xf56a0080
++#define F0900_P1_FRAME_MODCOD 0xf56a007c
++#define F0900_P1_FRAME_TYPE 0xf56a0003
++
++/*P1_BBFCRCKO1*/
++#define R0900_P1_BBFCRCKO1 0xf56b
++#define F0900_P1_BBHCRC_KOCNT1 0xf56b00ff
++
++/*P1_BBFCRCKO0*/
++#define R0900_P1_BBFCRCKO0 0xf56c
++#define F0900_P1_BBHCRC_KOCNT0 0xf56c00ff
++
++/*P1_UPCRCKO1*/
++#define R0900_P1_UPCRCKO1 0xf56d
++#define F0900_P1_PKTCRC_KOCNT1 0xf56d00ff
++
++/*P1_UPCRCKO0*/
++#define R0900_P1_UPCRCKO0 0xf56e
++#define F0900_P1_PKTCRC_KOCNT0 0xf56e00ff
++
++/*P1_TSSTATEM*/
++#define R0900_P1_TSSTATEM 0xf570
++#define F0900_P1_TSDIL_ON 0xf5700080
++#define F0900_P1_TSSKIPRS_ON 0xf5700040
++#define F0900_P1_TSRS_ON 0xf5700020
++#define F0900_P1_TSDESCRAMB_ON 0xf5700010
++#define F0900_P1_TSFRAME_MODE 0xf5700008
++#define F0900_P1_TS_DISABLE 0xf5700004
++#define F0900_P1_TSACM_MODE 0xf5700002
++#define F0900_P1_TSOUT_NOSYNC 0xf5700001
++
++/*P1_TSCFGH*/
++#define R0900_P1_TSCFGH 0xf572
++#define F0900_P1_TSFIFO_DVBCI 0xf5720080
++#define F0900_P1_TSFIFO_SERIAL 0xf5720040
++#define F0900_P1_TSFIFO_TEIUPDATE 0xf5720020
++#define F0900_P1_TSFIFO_DUTY50 0xf5720010
++#define F0900_P1_TSFIFO_HSGNLOUT 0xf5720008
++#define F0900_P1_TSFIFO_ERRMODE 0xf5720006
++#define F0900_P1_RST_HWARE 0xf5720001
++
++/*P1_TSCFGM*/
++#define R0900_P1_TSCFGM 0xf573
++#define F0900_P1_TSFIFO_MANSPEED 0xf57300c0
++#define F0900_P1_TSFIFO_PERMDATA 0xf5730020
++#define F0900_P1_TSFIFO_NONEWSGNL 0xf5730010
++#define F0900_P1_TSFIFO_BITSPEED 0xf5730008
++#define F0900_P1_NPD_SPECDVBS2 0xf5730004
++#define F0900_P1_TSFIFO_STOPCKDIS 0xf5730002
++#define F0900_P1_TSFIFO_INVDATA 0xf5730001
++
++/*P1_TSCFGL*/
++#define R0900_P1_TSCFGL 0xf574
++#define F0900_P1_TSFIFO_BCLKDEL1CK 0xf57400c0
++#define F0900_P1_BCHERROR_MODE 0xf5740030
++#define F0900_P1_TSFIFO_NSGNL2DATA 0xf5740008
++#define F0900_P1_TSFIFO_EMBINDVB 0xf5740004
++#define F0900_P1_TSFIFO_DPUNACT 0xf5740002
++#define F0900_P1_TSFIFO_NPDOFF 0xf5740001
++
++/*P1_TSINSDELH*/
++#define R0900_P1_TSINSDELH 0xf576
++#define F0900_P1_TSDEL_SYNCBYTE 0xf5760080
++#define F0900_P1_TSDEL_XXHEADER 0xf5760040
++#define F0900_P1_TSDEL_BBHEADER 0xf5760020
++#define F0900_P1_TSDEL_DATAFIELD 0xf5760010
++#define F0900_P1_TSINSDEL_ISCR 0xf5760008
++#define F0900_P1_TSINSDEL_NPD 0xf5760004
++#define F0900_P1_TSINSDEL_RSPARITY 0xf5760002
++#define F0900_P1_TSINSDEL_CRC8 0xf5760001
++
++/*P1_TSSPEED*/
++#define R0900_P1_TSSPEED 0xf580
++#define F0900_P1_TSFIFO_OUTSPEED 0xf58000ff
++
++/*P1_TSSTATUS*/
++#define R0900_P1_TSSTATUS 0xf581
++#define F0900_P1_TSFIFO_LINEOK 0xf5810080
++#define F0900_P1_TSFIFO_ERROR 0xf5810040
++#define F0900_P1_TSFIFO_DATA7 0xf5810020
++#define F0900_P1_TSFIFO_NOSYNC 0xf5810010
++#define F0900_P1_ISCR_INITIALIZED 0xf5810008
++#define F0900_P1_ISCR_UPDATED 0xf5810004
++#define F0900_P1_SOFFIFO_UNREGUL 0xf5810002
++#define F0900_P1_DIL_READY 0xf5810001
++
++/*P1_TSSTATUS2*/
++#define R0900_P1_TSSTATUS2 0xf582
++#define F0900_P1_TSFIFO_DEMODSEL 0xf5820080
++#define F0900_P1_TSFIFOSPEED_STORE 0xf5820040
++#define F0900_P1_DILXX_RESET 0xf5820020
++#define F0900_P1_TSSERIAL_IMPOS 0xf5820010
++#define F0900_P1_TSFIFO_LINENOK 0xf5820008
++#define F0900_P1_BITSPEED_EVENT 0xf5820004
++#define F0900_P1_SCRAMBDETECT 0xf5820002
++#define F0900_P1_ULDTV67_FALSELOCK 0xf5820001
++
++/*P1_TSBITRATE1*/
++#define R0900_P1_TSBITRATE1 0xf583
++#define F0900_P1_TSFIFO_BITRATE1 0xf58300ff
++
++/*P1_TSBITRATE0*/
++#define R0900_P1_TSBITRATE0 0xf584
++#define F0900_P1_TSFIFO_BITRATE0 0xf58400ff
++
++/*P1_ERRCTRL1*/
++#define R0900_P1_ERRCTRL1 0xf598
++#define F0900_P1_ERR_SOURCE1 0xf59800f0
++#define F0900_P1_NUM_EVENT1 0xf5980007
++
++/*P1_ERRCNT12*/
++#define R0900_P1_ERRCNT12 0xf599
++#define F0900_P1_ERRCNT1_OLDVALUE 0xf5990080
++#define F0900_P1_ERR_CNT12 0xf599007f
++
++/*P1_ERRCNT11*/
++#define R0900_P1_ERRCNT11 0xf59a
++#define F0900_P1_ERR_CNT11 0xf59a00ff
++
++/*P1_ERRCNT10*/
++#define R0900_P1_ERRCNT10 0xf59b
++#define F0900_P1_ERR_CNT10 0xf59b00ff
++
++/*P1_ERRCTRL2*/
++#define R0900_P1_ERRCTRL2 0xf59c
++#define F0900_P1_ERR_SOURCE2 0xf59c00f0
++#define F0900_P1_NUM_EVENT2 0xf59c0007
++
++/*P1_ERRCNT22*/
++#define R0900_P1_ERRCNT22 0xf59d
++#define F0900_P1_ERRCNT2_OLDVALUE 0xf59d0080
++#define F0900_P1_ERR_CNT22 0xf59d007f
++
++/*P1_ERRCNT21*/
++#define R0900_P1_ERRCNT21 0xf59e
++#define F0900_P1_ERR_CNT21 0xf59e00ff
++
++/*P1_ERRCNT20*/
++#define R0900_P1_ERRCNT20 0xf59f
++#define F0900_P1_ERR_CNT20 0xf59f00ff
++
++/*P1_FECSPY*/
++#define R0900_P1_FECSPY 0xf5a0
++#define F0900_P1_SPY_ENABLE 0xf5a00080
++#define F0900_P1_NO_SYNCBYTE 0xf5a00040
++#define F0900_P1_SERIAL_MODE 0xf5a00020
++#define F0900_P1_UNUSUAL_PACKET 0xf5a00010
++#define F0900_P1_BER_PACKMODE 0xf5a00008
++#define F0900_P1_BERMETER_LMODE 0xf5a00002
++#define F0900_P1_BERMETER_RESET 0xf5a00001
++
++/*P1_FSPYCFG*/
++#define R0900_P1_FSPYCFG 0xf5a1
++#define F0900_P1_FECSPY_INPUT 0xf5a100c0
++#define F0900_P1_RST_ON_ERROR 0xf5a10020
++#define F0900_P1_ONE_SHOT 0xf5a10010
++#define F0900_P1_I2C_MODE 0xf5a1000c
++#define F0900_P1_SPY_HYSTERESIS 0xf5a10003
++
++/*P1_FSPYDATA*/
++#define R0900_P1_FSPYDATA 0xf5a2
++#define F0900_P1_SPY_STUFFING 0xf5a20080
++#define F0900_P1_NOERROR_PKTJITTER 0xf5a20040
++#define F0900_P1_SPY_CNULLPKT 0xf5a20020
++#define F0900_P1_SPY_OUTDATA_MODE 0xf5a2001f
++
++/*P1_FSPYOUT*/
++#define R0900_P1_FSPYOUT 0xf5a3
++#define F0900_P1_FSPY_DIRECT 0xf5a30080
++#define F0900_P1_SPY_OUTDATA_BUS 0xf5a30038
++#define F0900_P1_STUFF_MODE 0xf5a30007
++
++/*P1_FSTATUS*/
++#define R0900_P1_FSTATUS 0xf5a4
++#define F0900_P1_SPY_ENDSIM 0xf5a40080
++#define F0900_P1_VALID_SIM 0xf5a40040
++#define F0900_P1_FOUND_SIGNAL 0xf5a40020
++#define F0900_P1_DSS_SYNCBYTE 0xf5a40010
++#define F0900_P1_RESULT_STATE 0xf5a4000f
++
++/*P1_FBERCPT4*/
++#define R0900_P1_FBERCPT4 0xf5a8
++#define F0900_P1_FBERMETER_CPT4 0xf5a800ff
++
++/*P1_FBERCPT3*/
++#define R0900_P1_FBERCPT3 0xf5a9
++#define F0900_P1_FBERMETER_CPT3 0xf5a900ff
++
++/*P1_FBERCPT2*/
++#define R0900_P1_FBERCPT2 0xf5aa
++#define F0900_P1_FBERMETER_CPT2 0xf5aa00ff
++
++/*P1_FBERCPT1*/
++#define R0900_P1_FBERCPT1 0xf5ab
++#define F0900_P1_FBERMETER_CPT1 0xf5ab00ff
++
++/*P1_FBERCPT0*/
++#define R0900_P1_FBERCPT0 0xf5ac
++#define F0900_P1_FBERMETER_CPT0 0xf5ac00ff
++
++/*P1_FBERERR2*/
++#define R0900_P1_FBERERR2 0xf5ad
++#define F0900_P1_FBERMETER_ERR2 0xf5ad00ff
++
++/*P1_FBERERR1*/
++#define R0900_P1_FBERERR1 0xf5ae
++#define F0900_P1_FBERMETER_ERR1 0xf5ae00ff
++
++/*P1_FBERERR0*/
++#define R0900_P1_FBERERR0 0xf5af
++#define F0900_P1_FBERMETER_ERR0 0xf5af00ff
++
++/*P1_FSPYBER*/
++#define R0900_P1_FSPYBER 0xf5b2
++#define F0900_P1_FSPYOBS_XORREAD 0xf5b20040
++#define F0900_P1_FSPYBER_OBSMODE 0xf5b20020
++#define F0900_P1_FSPYBER_SYNCBYTE 0xf5b20010
++#define F0900_P1_FSPYBER_UNSYNC 0xf5b20008
++#define F0900_P1_FSPYBER_CTIME 0xf5b20007
++
++/*RCCFGH*/
++#define R0900_RCCFGH 0xf600
++#define F0900_TSRCFIFO_DVBCI 0xf6000080
++#define F0900_TSRCFIFO_SERIAL 0xf6000040
++#define F0900_TSRCFIFO_DISABLE 0xf6000020
++#define F0900_TSFIFO_2TORC 0xf6000010
++#define F0900_TSRCFIFO_HSGNLOUT 0xf6000008
++#define F0900_TSRCFIFO_ERRMODE 0xf6000006
++
++/*TSGENERAL*/
++#define R0900_TSGENERAL 0xf630
++#define F0900_TSFIFO_BCLK1ALL 0xf6300020
++#define F0900_MUXSTREAM_OUTMODE 0xf6300008
++#define F0900_TSFIFO_PERMPARAL 0xf6300006
++#define F0900_RST_REEDSOLO 0xf6300001
++
++/*TSGENERAL1X*/
++#define R0900_TSGENERAL1X 0xf670
++#define F0900_TSFIFO1X_BCLK1ALL 0xf6700020
++#define F0900_MUXSTREAM1X_OUTMODE 0xf6700008
++#define F0900_TSFIFO1X_PERMPARAL 0xf6700006
++#define F0900_RST1X_REEDSOLO 0xf6700001
++
++/*NBITER_NF4*/
++#define R0900_NBITER_NF4 0xfa03
++#define F0900_NBITER_NF_QP_1_2 0xfa0300ff
++
++/*NBITER_NF5*/
++#define R0900_NBITER_NF5 0xfa04
++#define F0900_NBITER_NF_QP_3_5 0xfa0400ff
++
++/*NBITER_NF6*/
++#define R0900_NBITER_NF6 0xfa05
++#define F0900_NBITER_NF_QP_2_3 0xfa0500ff
++
++/*NBITER_NF7*/
++#define R0900_NBITER_NF7 0xfa06
++#define F0900_NBITER_NF_QP_3_4 0xfa0600ff
++
++/*NBITER_NF8*/
++#define R0900_NBITER_NF8 0xfa07
++#define F0900_NBITER_NF_QP_4_5 0xfa0700ff
++
++/*NBITER_NF9*/
++#define R0900_NBITER_NF9 0xfa08
++#define F0900_NBITER_NF_QP_5_6 0xfa0800ff
++
++/*NBITER_NF10*/
++#define R0900_NBITER_NF10 0xfa09
++#define F0900_NBITER_NF_QP_8_9 0xfa0900ff
++
++/*NBITER_NF11*/
++#define R0900_NBITER_NF11 0xfa0a
++#define F0900_NBITER_NF_QP_9_10 0xfa0a00ff
++
++/*NBITER_NF12*/
++#define R0900_NBITER_NF12 0xfa0b
++#define F0900_NBITER_NF_8P_3_5 0xfa0b00ff
++
++/*NBITER_NF13*/
++#define R0900_NBITER_NF13 0xfa0c
++#define F0900_NBITER_NF_8P_2_3 0xfa0c00ff
++
++/*NBITER_NF14*/
++#define R0900_NBITER_NF14 0xfa0d
++#define F0900_NBITER_NF_8P_3_4 0xfa0d00ff
++
++/*NBITER_NF15*/
++#define R0900_NBITER_NF15 0xfa0e
++#define F0900_NBITER_NF_8P_5_6 0xfa0e00ff
++
++/*NBITER_NF16*/
++#define R0900_NBITER_NF16 0xfa0f
++#define F0900_NBITER_NF_8P_8_9 0xfa0f00ff
++
++/*NBITER_NF17*/
++#define R0900_NBITER_NF17 0xfa10
++#define F0900_NBITER_NF_8P_9_10 0xfa1000ff
++
++/*NBITERNOERR*/
++#define R0900_NBITERNOERR 0xfa3f
++#define F0900_NBITER_STOP_CRIT 0xfa3f000f
++
++/*GAINLLR_NF4*/
++#define R0900_GAINLLR_NF4 0xfa43
++#define F0900_GAINLLR_NF_QP_1_2 0xfa43007f
++
++/*GAINLLR_NF5*/
++#define R0900_GAINLLR_NF5 0xfa44
++#define F0900_GAINLLR_NF_QP_3_5 0xfa44007f
++
++/*GAINLLR_NF6*/
++#define R0900_GAINLLR_NF6 0xfa45
++#define F0900_GAINLLR_NF_QP_2_3 0xfa45007f
++
++/*GAINLLR_NF7*/
++#define R0900_GAINLLR_NF7 0xfa46
++#define F0900_GAINLLR_NF_QP_3_4 0xfa46007f
++
++/*GAINLLR_NF8*/
++#define R0900_GAINLLR_NF8 0xfa47
++#define F0900_GAINLLR_NF_QP_4_5 0xfa47007f
++
++/*GAINLLR_NF9*/
++#define R0900_GAINLLR_NF9 0xfa48
++#define F0900_GAINLLR_NF_QP_5_6 0xfa48007f
++
++/*GAINLLR_NF10*/
++#define R0900_GAINLLR_NF10 0xfa49
++#define F0900_GAINLLR_NF_QP_8_9 0xfa49007f
++
++/*GAINLLR_NF11*/
++#define R0900_GAINLLR_NF11 0xfa4a
++#define F0900_GAINLLR_NF_QP_9_10 0xfa4a007f
++
++/*GAINLLR_NF12*/
++#define R0900_GAINLLR_NF12 0xfa4b
++#define F0900_GAINLLR_NF_8P_3_5 0xfa4b007f
++
++/*GAINLLR_NF13*/
++#define R0900_GAINLLR_NF13 0xfa4c
++#define F0900_GAINLLR_NF_8P_2_3 0xfa4c007f
++
++/*GAINLLR_NF14*/
++#define R0900_GAINLLR_NF14 0xfa4d
++#define F0900_GAINLLR_NF_8P_3_4 0xfa4d007f
++
++/*GAINLLR_NF15*/
++#define R0900_GAINLLR_NF15 0xfa4e
++#define F0900_GAINLLR_NF_8P_5_6 0xfa4e007f
++
++/*GAINLLR_NF16*/
++#define R0900_GAINLLR_NF16 0xfa4f
++#define F0900_GAINLLR_NF_8P_8_9 0xfa4f007f
++
++/*GAINLLR_NF17*/
++#define R0900_GAINLLR_NF17 0xfa50
++#define F0900_GAINLLR_NF_8P_9_10 0xfa50007f
++
++/*CFGEXT*/
++#define R0900_CFGEXT 0xfa80
++#define F0900_STAGMODE 0xfa800080
++#define F0900_BYPBCH 0xfa800040
++#define F0900_BYPLDPC 0xfa800020
++#define F0900_LDPCMODE 0xfa800010
++#define F0900_INVLLRSIGN 0xfa800008
++#define F0900_SHORTMULT 0xfa800004
++#define F0900_EXTERNTX 0xfa800001
++
++/*GENCFG*/
++#define R0900_GENCFG 0xfa86
++#define F0900_BROADCAST 0xfa860010
++#define F0900_NOSHFRD2 0xfa860008
++#define F0900_BCHERRFLAG 0xfa860004
++#define F0900_PRIORITY 0xfa860002
++#define F0900_DDEMOD 0xfa860001
++
++/*LDPCERR1*/
++#define R0900_LDPCERR1 0xfa96
++#define F0900_LDPC_ERRORS_COUNTER1 0xfa9600ff
++
++/*LDPCERR0*/
++#define R0900_LDPCERR0 0xfa97
++#define F0900_LDPC_ERRORS_COUNTER0 0xfa9700ff
++
++/*BCHERR*/
++#define R0900_BCHERR 0xfa98
++#define F0900_ERRORFLAG 0xfa980010
++#define F0900_BCH_ERRORS_COUNTER 0xfa98000f
++
++/*TSTRES0*/
++#define R0900_TSTRES0 0xff11
++#define F0900_FRESFEC 0xff110080
++#define F0900_FRESTS 0xff110040
++#define F0900_FRESVIT1 0xff110020
++#define F0900_FRESVIT2 0xff110010
++#define F0900_FRESSYM1 0xff110008
++#define F0900_FRESSYM2 0xff110004
++#define F0900_FRESMAS 0xff110002
++#define F0900_FRESINT 0xff110001
++
++/*P2_TSTDISRX*/
++#define R0900_P2_TSTDISRX 0xff65
++#define F0900_P2_EN_DISRX 0xff650080
++#define F0900_P2_TST_CURRSRC 0xff650040
++#define F0900_P2_IN_DIGSIGNAL 0xff650020
++#define F0900_P2_HIZ_CURRENTSRC 0xff650010
++#define F0900_TST_P2_PIN_SELECT 0xff650008
++#define F0900_P2_TST_DISRX 0xff650007
++
++/*P1_TSTDISRX*/
++#define R0900_P1_TSTDISRX 0xff67
++#define F0900_P1_EN_DISRX 0xff670080
++#define F0900_P1_TST_CURRSRC 0xff670040
++#define F0900_P1_IN_DIGSIGNAL 0xff670020
++#define F0900_P1_HIZ_CURRENTSRC 0xff670010
++#define F0900_TST_P1_PIN_SELECT 0xff670008
++#define F0900_P1_TST_DISRX 0xff670007
++
++#define STV0900_NBREGS 684
++#define STV0900_NBFIELDS 1702
++
++#endif
++
+diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
+new file mode 100644
+index 0000000..a5a3153
+--- /dev/null
++++ b/drivers/media/dvb/frontends/stv0900_sw.c
+@@ -0,0 +1,2847 @@
++/*
++ * stv0900_sw.c
++ *
++ * Driver for ST STV0900 satellite demodulator IC.
++ *
++ * Copyright (C) ST Microelectronics.
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ *
++ * 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 "stv0900.h"
++#include "stv0900_reg.h"
++#include "stv0900_priv.h"
++
++int stv0900_check_signal_presence(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 carr_offset,
++ agc2_integr,
++ max_carrier;
++
++ int no_signal;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ carr_offset = (stv0900_read_reg(i_params, R0900_P1_CFR2) << 8)
++ | stv0900_read_reg(i_params,
++ R0900_P1_CFR1);
++ carr_offset = ge2comp(carr_offset, 16);
++ agc2_integr = (stv0900_read_reg(i_params, R0900_P1_AGC2I1) << 8)
++ | stv0900_read_reg(i_params,
++ R0900_P1_AGC2I0);
++ max_carrier = i_params->dmd1_srch_range / 1000;
++ break;
++ case STV0900_DEMOD_2:
++ carr_offset = (stv0900_read_reg(i_params, R0900_P2_CFR2) << 8)
++ | stv0900_read_reg(i_params,
++ R0900_P2_CFR1);
++ carr_offset = ge2comp(carr_offset, 16);
++ agc2_integr = (stv0900_read_reg(i_params, R0900_P2_AGC2I1) << 8)
++ | stv0900_read_reg(i_params,
++ R0900_P2_AGC2I0);
++ max_carrier = i_params->dmd2_srch_range / 1000;
++ break;
++ }
++
++ max_carrier += (max_carrier / 10);
++ max_carrier = 65536 * (max_carrier / 2);
++ max_carrier /= i_params->mclk / 1000;
++ if (max_carrier > 0x4000)
++ max_carrier = 0x4000;
++
++ if ((agc2_integr > 0x2000)
++ || (carr_offset > + 2*max_carrier)
++ || (carr_offset < -2*max_carrier))
++ no_signal = TRUE;
++ else
++ no_signal = FALSE;
++
++ return no_signal;
++}
++
++static void stv0900_get_sw_loop_params(struct stv0900_internal *i_params,
++ s32 *frequency_inc, s32 *sw_timeout,
++ s32 *steps,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 timeout, freq_inc, max_steps, srate, max_carrier;
++
++ enum fe_stv0900_search_standard standard;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ srate = i_params->dmd1_symbol_rate;
++ max_carrier = i_params->dmd1_srch_range / 1000;
++ max_carrier += max_carrier / 10;
++ standard = i_params->dmd1_srch_standard;
++ break;
++ case STV0900_DEMOD_2:
++ srate = i_params->dmd2_symbol_rate;
++ max_carrier = i_params->dmd2_srch_range / 1000;
++ max_carrier += max_carrier / 10;
++ standard = i_params->dmd2_srch_stndrd;
++ break;
++ }
++
++ max_carrier = 65536 * (max_carrier / 2);
++ max_carrier /= i_params->mclk / 1000;
++
++ if (max_carrier > 0x4000)
++ max_carrier = 0x4000;
++
++ freq_inc = srate;
++ freq_inc /= i_params->mclk >> 10;
++ freq_inc = freq_inc << 6;
++
++ switch (standard) {
++ case STV0900_SEARCH_DVBS1:
++ case STV0900_SEARCH_DSS:
++ freq_inc *= 3;
++ timeout = 20;
++ break;
++ case STV0900_SEARCH_DVBS2:
++ freq_inc *= 4;
++ timeout = 25;
++ break;
++ case STV0900_AUTO_SEARCH:
++ default:
++ freq_inc *= 3;
++ timeout = 25;
++ break;
++ }
++
++ freq_inc /= 100;
++
++ if ((freq_inc > max_carrier) || (freq_inc < 0))
++ freq_inc = max_carrier / 2;
++
++ timeout *= 27500;
++
++ if (srate > 0)
++ timeout /= srate / 1000;
++
++ if ((timeout > 100) || (timeout < 0))
++ timeout = 100;
++
++ max_steps = (max_carrier / freq_inc) + 1;
++
++ if ((max_steps > 100) || (max_steps < 0)) {
++ max_steps = 100;
++ freq_inc = max_carrier / max_steps;
++ }
++
++ *frequency_inc = freq_inc;
++ *sw_timeout = timeout;
++ *steps = max_steps;
++
++}
++
++static int stv0900_search_carr_sw_loop(struct stv0900_internal *i_params,
++ s32 FreqIncr, s32 Timeout, int zigzag,
++ s32 MaxStep, enum fe_stv0900_demod_num demod)
++{
++ int no_signal,
++ lock = FALSE;
++ s32 stepCpt,
++ freqOffset,
++ max_carrier;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ max_carrier = i_params->dmd1_srch_range / 1000;
++ max_carrier += (max_carrier / 10);
++ break;
++ case STV0900_DEMOD_2:
++ max_carrier = i_params->dmd2_srch_range / 1000;
++ max_carrier += (max_carrier / 10);
++ break;
++ }
++
++ max_carrier = 65536 * (max_carrier / 2);
++ max_carrier /= i_params->mclk / 1000;
++
++ if (max_carrier > 0x4000)
++ max_carrier = 0x4000;
++
++ if (zigzag == TRUE)
++ freqOffset = 0;
++ else
++ freqOffset = -max_carrier + FreqIncr;
++
++ stepCpt = 0;
++
++ do {
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1C);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1,
++ (freqOffset / 256) & 0xFF);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0,
++ freqOffset & 0xFF);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
++ stv0900_write_bits(i_params, F0900_P1_ALGOSWRST, 1);
++
++ if (i_params->chip_id == 0x12) {
++ stv0900_write_bits(i_params,
++ F0900_P1_RST_HWARE, 1);
++ stv0900_write_bits(i_params,
++ F0900_P1_RST_HWARE, 0);
++ }
++ break;
++ case STV0900_DEMOD_2:
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1C);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1,
++ (freqOffset / 256) & 0xFF);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0,
++ freqOffset & 0xFF);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
++ stv0900_write_bits(i_params, F0900_P2_ALGOSWRST, 1);
++
++ if (i_params->chip_id == 0x12) {
++ stv0900_write_bits(i_params,
++ F0900_P2_RST_HWARE, 1);
++ stv0900_write_bits(i_params,
++ F0900_P2_RST_HWARE, 0);
++ }
++ break;
++ }
++
++ if (zigzag == TRUE) {
++ if (freqOffset >= 0)
++ freqOffset = -freqOffset - 2 * FreqIncr;
++ else
++ freqOffset = -freqOffset;
++ } else
++ freqOffset += + 2 * FreqIncr;
++
++ stepCpt++;
++ lock = stv0900_get_demod_lock(i_params, demod, Timeout);
++ no_signal = stv0900_check_signal_presence(i_params, demod);
++
++ } while ((lock == FALSE)
++ && (no_signal == FALSE)
++ && ((freqOffset - FreqIncr) < max_carrier)
++ && ((freqOffset + FreqIncr) > -max_carrier)
++ && (stepCpt < MaxStep));
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ stv0900_write_bits(i_params, F0900_P1_ALGOSWRST, 0);
++ break;
++ case STV0900_DEMOD_2:
++ stv0900_write_bits(i_params, F0900_P2_ALGOSWRST, 0);
++ break;
++ }
++
++ return lock;
++}
++
++int stv0900_sw_algo(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ int lock = FALSE;
++
++ int no_signal,
++ zigzag;
++ s32 dvbs2_fly_wheel;
++
++ s32 freqIncrement, softStepTimeout, trialCounter, max_steps;
++
++ stv0900_get_sw_loop_params(i_params, &freqIncrement, &softStepTimeout,
++ &max_steps, demod);
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ switch (i_params->dmd1_srch_standard) {
++ case STV0900_SEARCH_DVBS1:
++ case STV0900_SEARCH_DSS:
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ,
++ 0x3B);
++ else
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ,
++ 0xef);
++
++ stv0900_write_reg(i_params, R0900_P1_DMDCFGMD, 0x49);
++ zigzag = FALSE;
++ break;
++ case STV0900_SEARCH_DVBS2:
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P1_CORRELABS,
++ 0x79);
++ else
++ stv0900_write_reg(i_params, R0900_P1_CORRELABS,
++ 0x68);
++
++ stv0900_write_reg(i_params, R0900_P1_DMDCFGMD,
++ 0x89);
++
++ zigzag = TRUE;
++ break;
++ case STV0900_AUTO_SEARCH:
++ default:
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ,
++ 0x3B);
++ stv0900_write_reg(i_params, R0900_P1_CORRELABS,
++ 0x79);
++ } else {
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ,
++ 0xef);
++ stv0900_write_reg(i_params, R0900_P1_CORRELABS,
++ 0x68);
++ }
++
++ stv0900_write_reg(i_params, R0900_P1_DMDCFGMD,
++ 0xc9);
++ zigzag = FALSE;
++ break;
++ }
++
++ trialCounter = 0;
++ do {
++ lock = stv0900_search_carr_sw_loop(i_params,
++ freqIncrement,
++ softStepTimeout,
++ zigzag,
++ max_steps,
++ demod);
++ no_signal = stv0900_check_signal_presence(i_params,
++ demod);
++ trialCounter++;
++ if ((lock == TRUE)
++ || (no_signal == TRUE)
++ || (trialCounter == 2)) {
++
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params,
++ R0900_P1_CARFREQ,
++ 0x49);
++ stv0900_write_reg(i_params,
++ R0900_P1_CORRELABS,
++ 0x9e);
++ } else {
++ stv0900_write_reg(i_params,
++ R0900_P1_CARFREQ,
++ 0xed);
++ stv0900_write_reg(i_params,
++ R0900_P1_CORRELABS,
++ 0x88);
++ }
++
++ if ((lock == TRUE) && (stv0900_get_bits(i_params, F0900_P1_HEADER_MODE) == STV0900_DVBS2_FOUND)) {
++ msleep(softStepTimeout);
++ dvbs2_fly_wheel = stv0900_get_bits(i_params, F0900_P1_FLYWHEEL_CPT);
++
++ if (dvbs2_fly_wheel < 0xd) {
++ msleep(softStepTimeout);
++ dvbs2_fly_wheel = stv0900_get_bits(i_params, F0900_P1_FLYWHEEL_CPT);
++ }
++
++ if (dvbs2_fly_wheel < 0xd) {
++ lock = FALSE;
++
++ if (trialCounter < 2) {
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P1_CORRELABS, 0x79);
++ else
++ stv0900_write_reg(i_params, R0900_P1_CORRELABS, 0x68);
++
++ stv0900_write_reg(i_params, R0900_P1_DMDCFGMD, 0x89);
++ }
++ }
++ }
++ }
++
++ } while ((lock == FALSE)
++ && (trialCounter < 2)
++ && (no_signal == FALSE));
++
++ break;
++ case STV0900_DEMOD_2:
++ switch (i_params->dmd2_srch_stndrd) {
++ case STV0900_SEARCH_DVBS1:
++ case STV0900_SEARCH_DSS:
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ,
++ 0x3b);
++ else
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ,
++ 0xef);
++
++ stv0900_write_reg(i_params, R0900_P2_DMDCFGMD,
++ 0x49);
++ zigzag = FALSE;
++ break;
++ case STV0900_SEARCH_DVBS2:
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P2_CORRELABS,
++ 0x79);
++ else
++ stv0900_write_reg(i_params, R0900_P2_CORRELABS,
++ 0x68);
++
++ stv0900_write_reg(i_params, R0900_P2_DMDCFGMD, 0x89);
++ zigzag = TRUE;
++ break;
++ case STV0900_AUTO_SEARCH:
++ default:
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ,
++ 0x3b);
++ stv0900_write_reg(i_params, R0900_P2_CORRELABS,
++ 0x79);
++ } else {
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ,
++ 0xef);
++ stv0900_write_reg(i_params, R0900_P2_CORRELABS,
++ 0x68);
++ }
++
++ stv0900_write_reg(i_params, R0900_P2_DMDCFGMD, 0xc9);
++
++ zigzag = FALSE;
++ break;
++ }
++
++ trialCounter = 0;
++
++ do {
++ lock = stv0900_search_carr_sw_loop(i_params,
++ freqIncrement,
++ softStepTimeout,
++ zigzag,
++ max_steps,
++ demod);
++ no_signal = stv0900_check_signal_presence(i_params,
++ demod);
++ trialCounter++;
++ if ((lock == TRUE)
++ || (no_signal == TRUE)
++ || (trialCounter == 2)) {
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params,
++ R0900_P2_CARFREQ,
++ 0x49);
++ stv0900_write_reg(i_params,
++ R0900_P2_CORRELABS,
++ 0x9e);
++ } else {
++ stv0900_write_reg(i_params,
++ R0900_P2_CARFREQ,
++ 0xed);
++ stv0900_write_reg(i_params,
++ R0900_P2_CORRELABS,
++ 0x88);
++ }
++
++ if ((lock == TRUE) && (stv0900_get_bits(i_params, F0900_P2_HEADER_MODE) == STV0900_DVBS2_FOUND)) {
++ msleep(softStepTimeout);
++ dvbs2_fly_wheel = stv0900_get_bits(i_params, F0900_P2_FLYWHEEL_CPT);
++ if (dvbs2_fly_wheel < 0xd) {
++ msleep(softStepTimeout);
++ dvbs2_fly_wheel = stv0900_get_bits(i_params, F0900_P2_FLYWHEEL_CPT);
++ }
++
++ if (dvbs2_fly_wheel < 0xd) {
++ lock = FALSE;
++ if (trialCounter < 2) {
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x79);
++ else
++ stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x68);
++
++ stv0900_write_reg(i_params, R0900_P2_DMDCFGMD, 0x89);
++ }
++ }
++ }
++ }
++
++ } while ((lock == FALSE) && (trialCounter < 2) && (no_signal == FALSE));
++
++ break;
++ }
++
++ return lock;
++}
++
++static u32 stv0900_get_symbol_rate(struct stv0900_internal *i_params,
++ u32 mclk,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 sfr_field3, sfr_field2, sfr_field1, sfr_field0,
++ rem1, rem2, intval1, intval2, srate;
++
++ dmd_reg(sfr_field3, F0900_P1_SYMB_FREQ3, F0900_P2_SYMB_FREQ3);
++ dmd_reg(sfr_field2, F0900_P1_SYMB_FREQ2, F0900_P2_SYMB_FREQ2);
++ dmd_reg(sfr_field1, F0900_P1_SYMB_FREQ1, F0900_P2_SYMB_FREQ1);
++ dmd_reg(sfr_field0, F0900_P1_SYMB_FREQ0, F0900_P2_SYMB_FREQ0);
++
++ srate = (stv0900_get_bits(i_params, sfr_field3) << 24) +
++ (stv0900_get_bits(i_params, sfr_field2) << 16) +
++ (stv0900_get_bits(i_params, sfr_field1) << 8) +
++ (stv0900_get_bits(i_params, sfr_field0));
++ dprintk("lock: srate=%d r0=0x%x r1=0x%x r2=0x%x r3=0x%x \n",
++ srate, stv0900_get_bits(i_params, sfr_field0),
++ stv0900_get_bits(i_params, sfr_field1),
++ stv0900_get_bits(i_params, sfr_field2),
++ stv0900_get_bits(i_params, sfr_field3));
++
++ intval1 = (mclk) >> 16;
++ intval2 = (srate) >> 16;
++
++ rem1 = (mclk) % 0x10000;
++ rem2 = (srate) % 0x10000;
++ srate = (intval1 * intval2) +
++ ((intval1 * rem2) >> 16) +
++ ((intval2 * rem1) >> 16);
++
++ return srate;
++}
++
++static void stv0900_set_symbol_rate(struct stv0900_internal *i_params,
++ u32 mclk, u32 srate,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 sfr_init_reg;
++ u32 symb;
++
++ dprintk(KERN_INFO "%s: Mclk %d, SR %d, Dmd %d\n", __func__, mclk,
++ srate, demod);
++
++ dmd_reg(sfr_init_reg, R0900_P1_SFRINIT1, R0900_P2_SFRINIT1);
++
++ if (srate > 60000000) {
++ symb = srate << 4;
++ symb /= (mclk >> 12);
++ } else if (srate > 6000000) {
++ symb = srate << 6;
++ symb /= (mclk >> 10);
++ } else {
++ symb = srate << 9;
++ symb /= (mclk >> 7);
++ }
++
++ stv0900_write_reg(i_params, sfr_init_reg, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, sfr_init_reg + 1, (symb & 0xFF));
++}
++
++static void stv0900_set_max_symbol_rate(struct stv0900_internal *i_params,
++ u32 mclk, u32 srate,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 sfr_max_reg;
++ u32 symb;
++
++ dmd_reg(sfr_max_reg, R0900_P1_SFRUP1, R0900_P2_SFRUP1);
++
++ srate = 105 * (srate / 100);
++
++ if (srate > 60000000) {
++ symb = srate << 4;
++ symb /= (mclk >> 12);
++ } else if (srate > 6000000) {
++ symb = srate << 6;
++ symb /= (mclk >> 10);
++ } else {
++ symb = srate << 9;
++ symb /= (mclk >> 7);
++ }
++
++ if (symb < 0x7fff) {
++ stv0900_write_reg(i_params, sfr_max_reg, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, sfr_max_reg + 1, (symb & 0xFF));
++ } else {
++ stv0900_write_reg(i_params, sfr_max_reg, 0x7F);
++ stv0900_write_reg(i_params, sfr_max_reg + 1, 0xFF);
++ }
++}
++
++static void stv0900_set_min_symbol_rate(struct stv0900_internal *i_params,
++ u32 mclk, u32 srate,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 sfr_min_reg;
++ u32 symb;
++
++ dmd_reg(sfr_min_reg, R0900_P1_SFRLOW1, R0900_P2_SFRLOW1);
++
++ srate = 95 * (srate / 100);
++ if (srate > 60000000) {
++ symb = srate << 4;
++ symb /= (mclk >> 12);
++
++ } else if (srate > 6000000) {
++ symb = srate << 6;
++ symb /= (mclk >> 10);
++
++ } else {
++ symb = srate << 9;
++ symb /= (mclk >> 7);
++ }
++
++ stv0900_write_reg(i_params, sfr_min_reg, (symb >> 8) & 0xFF);
++ stv0900_write_reg(i_params, sfr_min_reg + 1, (symb & 0xFF));
++}
++
++static s32 stv0900_get_timing_offst(struct stv0900_internal *i_params,
++ u32 srate,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 tmgreg,
++ timingoffset;
++
++ dmd_reg(tmgreg, R0900_P1_TMGREG2, R0900_P2_TMGREG2);
++
++ timingoffset = (stv0900_read_reg(i_params, tmgreg) << 16) +
++ (stv0900_read_reg(i_params, tmgreg + 1) << 8) +
++ (stv0900_read_reg(i_params, tmgreg + 2));
++
++ timingoffset = ge2comp(timingoffset, 24);
++
++
++ if (timingoffset == 0)
++ timingoffset = 1;
++
++ timingoffset = ((s32)srate * 10) / ((s32)0x1000000 / timingoffset);
++ timingoffset /= 320;
++
++ return timingoffset;
++}
++
++static void stv0900_set_dvbs2_rolloff(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 rolloff, man_fld, matstr_reg, rolloff_ctl_fld;
++
++ dmd_reg(man_fld, F0900_P1_MANUAL_ROLLOFF, F0900_P2_MANUAL_ROLLOFF);
++ dmd_reg(matstr_reg, R0900_P1_MATSTR1, R0900_P2_MATSTR1);
++ dmd_reg(rolloff_ctl_fld, F0900_P1_ROLLOFF_CONTROL,
++ F0900_P2_ROLLOFF_CONTROL);
++
++ if (i_params->chip_id == 0x10) {
++ stv0900_write_bits(i_params, man_fld, 1);
++ rolloff = stv0900_read_reg(i_params, matstr_reg) & 0x03;
++ stv0900_write_bits(i_params, rolloff_ctl_fld, rolloff);
++ } else
++ stv0900_write_bits(i_params, man_fld, 0);
++}
++
++static u32 stv0900_carrier_width(u32 srate, enum fe_stv0900_rolloff ro)
++{
++ u32 rolloff;
++
++ switch (ro) {
++ case STV0900_20:
++ rolloff = 20;
++ break;
++ case STV0900_25:
++ rolloff = 25;
++ break;
++ case STV0900_35:
++ default:
++ rolloff = 35;
++ break;
++ }
++
++ return srate + (srate * rolloff) / 100;
++}
++
++static int stv0900_check_timing_lock(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ int timingLock = FALSE;
++ s32 i,
++ timingcpt = 0;
++ u8 carFreq,
++ tmgTHhigh,
++ tmgTHLow;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ carFreq = stv0900_read_reg(i_params, R0900_P1_CARFREQ);
++ tmgTHhigh = stv0900_read_reg(i_params, R0900_P1_TMGTHRISE);
++ tmgTHLow = stv0900_read_reg(i_params, R0900_P1_TMGTHFALL);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, 0x20);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, 0x0);
++ stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
++ stv0900_write_reg(i_params, R0900_P1_RTC, 0x80);
++ stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x40);
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x0);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, 0x0);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, 0x0);
++ stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x65);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
++ msleep(7);
++
++ for (i = 0; i < 10; i++) {
++ if (stv0900_get_bits(i_params, F0900_P1_TMGLOCK_QUALITY) >= 2)
++ timingcpt++;
++
++ msleep(1);
++ }
++
++ if (timingcpt >= 3)
++ timingLock = TRUE;
++
++ stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x38);
++ stv0900_write_reg(i_params, R0900_P1_RTC, 0x88);
++ stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x68);
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, carFreq);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, tmgTHhigh);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, tmgTHLow);
++ break;
++ case STV0900_DEMOD_2:
++ carFreq = stv0900_read_reg(i_params, R0900_P2_CARFREQ);
++ tmgTHhigh = stv0900_read_reg(i_params, R0900_P2_TMGTHRISE);
++ tmgTHLow = stv0900_read_reg(i_params, R0900_P2_TMGTHFALL);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, 0x20);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, 0);
++ stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
++ stv0900_write_reg(i_params, R0900_P2_RTC, 0x80);
++ stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x40);
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x0);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, 0x0);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, 0x0);
++ stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x65);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
++ msleep(5);
++ for (i = 0; i < 10; i++) {
++ if (stv0900_get_bits(i_params, F0900_P2_TMGLOCK_QUALITY) >= 2)
++ timingcpt++;
++
++ msleep(1);
++ }
++
++ if (timingcpt >= 3)
++ timingLock = TRUE;
++
++ stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x38);
++ stv0900_write_reg(i_params, R0900_P2_RTC, 0x88);
++ stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x68);
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, carFreq);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, tmgTHhigh);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, tmgTHLow);
++ break;
++ }
++
++ return timingLock;
++}
++
++static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe,
++ s32 demod_timeout)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++
++ int lock = FALSE;
++ s32 srate, search_range, locktimeout,
++ currier_step, nb_steps, current_step,
++ direction, tuner_freq, timeout;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ srate = i_params->dmd1_symbol_rate;
++ search_range = i_params->dmd1_srch_range;
++ break;
++
++ case STV0900_DEMOD_2:
++ srate = i_params->dmd2_symbol_rate;
++ search_range = i_params->dmd2_srch_range;
++ break;
++ }
++
++ if (srate >= 10000000)
++ locktimeout = demod_timeout / 3;
++ else
++ locktimeout = demod_timeout / 2;
++
++ lock = stv0900_get_demod_lock(i_params, demod, locktimeout);
++
++ if (lock == FALSE) {
++ if (srate >= 10000000) {
++ if (stv0900_check_timing_lock(i_params, demod) == TRUE) {
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1f);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x15);
++ break;
++ case STV0900_DEMOD_2:
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1f);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x15);
++ break;
++ }
++
++ lock = stv0900_get_demod_lock(i_params, demod, demod_timeout);
++ } else
++ lock = FALSE;
++ } else {
++ if (srate <= 4000000)
++ currier_step = 1000;
++ else if (srate <= 7000000)
++ currier_step = 2000;
++ else if (srate <= 10000000)
++ currier_step = 3000;
++ else
++ currier_step = 5000;
++
++ nb_steps = ((search_range / 1000) / currier_step);
++ nb_steps /= 2;
++ nb_steps = (2 * (nb_steps + 1));
++ if (nb_steps < 0)
++ nb_steps = 2;
++ else if (nb_steps > 12)
++ nb_steps = 12;
++
++ current_step = 1;
++ direction = 1;
++ timeout = (demod_timeout / 3);
++ if (timeout > 1000)
++ timeout = 1000;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ if (lock == FALSE) {
++ tuner_freq = i_params->tuner1_freq;
++ i_params->tuner1_bw = stv0900_carrier_width(i_params->dmd1_symbol_rate, i_params->rolloff) + i_params->dmd1_symbol_rate;
++
++ while ((current_step <= nb_steps) && (lock == FALSE)) {
++
++ if (direction > 0)
++ tuner_freq += (current_step * currier_step);
++ else
++ tuner_freq -= (current_step * currier_step);
++
++ stv0900_set_tuner(fe, tuner_freq, i_params->tuner1_bw);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1C);
++ if (i_params->dmd1_srch_standard == STV0900_SEARCH_DVBS2) {
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
++ }
++
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, 0);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, 0);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x15);
++ lock = stv0900_get_demod_lock(i_params, demod, timeout);
++ direction *= -1;
++ current_step++;
++ }
++ }
++ break;
++ case STV0900_DEMOD_2:
++ if (lock == FALSE) {
++ tuner_freq = i_params->tuner2_freq;
++ i_params->tuner2_bw = stv0900_carrier_width(srate, i_params->rolloff) + srate;
++
++ while ((current_step <= nb_steps) && (lock == FALSE)) {
++
++ if (direction > 0)
++ tuner_freq += (current_step * currier_step);
++ else
++ tuner_freq -= (current_step * currier_step);
++
++ stv0900_set_tuner(fe, tuner_freq, i_params->tuner2_bw);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1C);
++ if (i_params->dmd2_srch_stndrd == STV0900_SEARCH_DVBS2) {
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
++ }
++
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, 0);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, 0);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x15);
++ lock = stv0900_get_demod_lock(i_params, demod, timeout);
++ direction *= -1;
++ current_step++;
++ }
++ }
++ break;
++ }
++ }
++ }
++
++ return lock;
++}
++
++static void stv0900_get_lock_timeout(s32 *demod_timeout, s32 *fec_timeout,
++ s32 srate,
++ enum fe_stv0900_search_algo algo)
++{
++ switch (algo) {
++ case STV0900_BLIND_SEARCH:
++ if (srate <= 1500000) {
++ (*demod_timeout) = 1500;
++ (*fec_timeout) = 400;
++ } else if (srate <= 5000000) {
++ (*demod_timeout) = 1000;
++ (*fec_timeout) = 300;
++ } else {
++ (*demod_timeout) = 700;
++ (*fec_timeout) = 100;
++ }
++
++ break;
++ case STV0900_COLD_START:
++ case STV0900_WARM_START:
++ default:
++ if (srate <= 1000000) {
++ (*demod_timeout) = 3000;
++ (*fec_timeout) = 1700;
++ } else if (srate <= 2000000) {
++ (*demod_timeout) = 2500;
++ (*fec_timeout) = 1100;
++ } else if (srate <= 5000000) {
++ (*demod_timeout) = 1000;
++ (*fec_timeout) = 550;
++ } else if (srate <= 10000000) {
++ (*demod_timeout) = 700;
++ (*fec_timeout) = 250;
++ } else if (srate <= 20000000) {
++ (*demod_timeout) = 400;
++ (*fec_timeout) = 130;
++ }
++
++ else {
++ (*demod_timeout) = 300;
++ (*fec_timeout) = 100;
++ }
++
++ break;
++
++ }
++
++ if (algo == STV0900_WARM_START)
++ (*demod_timeout) /= 2;
++}
++
++static void stv0900_set_viterbi_tracq(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++
++ s32 vth_reg;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ dmd_reg(vth_reg, R0900_P1_VTH12, R0900_P2_VTH12);
++
++ stv0900_write_reg(i_params, vth_reg++, 0xd0);
++ stv0900_write_reg(i_params, vth_reg++, 0x7d);
++ stv0900_write_reg(i_params, vth_reg++, 0x53);
++ stv0900_write_reg(i_params, vth_reg++, 0x2F);
++ stv0900_write_reg(i_params, vth_reg++, 0x24);
++ stv0900_write_reg(i_params, vth_reg++, 0x1F);
++}
++
++static void stv0900_set_viterbi_standard(struct stv0900_internal *i_params,
++ enum fe_stv0900_search_standard Standard,
++ enum fe_stv0900_fec PunctureRate,
++ enum fe_stv0900_demod_num demod)
++{
++
++ s32 fecmReg,
++ prvitReg;
++
++ dprintk(KERN_INFO "%s: ViterbiStandard = ", __func__);
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ fecmReg = R0900_P1_FECM;
++ prvitReg = R0900_P1_PRVIT;
++ break;
++ case STV0900_DEMOD_2:
++ fecmReg = R0900_P2_FECM;
++ prvitReg = R0900_P2_PRVIT;
++ break;
++ }
++
++ switch (Standard) {
++ case STV0900_AUTO_SEARCH:
++ dprintk("Auto\n");
++ stv0900_write_reg(i_params, fecmReg, 0x10);
++ stv0900_write_reg(i_params, prvitReg, 0x3F);
++ break;
++ case STV0900_SEARCH_DVBS1:
++ dprintk("DVBS1\n");
++ stv0900_write_reg(i_params, fecmReg, 0x00);
++ switch (PunctureRate) {
++ case STV0900_FEC_UNKNOWN:
++ default:
++ stv0900_write_reg(i_params, prvitReg, 0x2F);
++ break;
++ case STV0900_FEC_1_2:
++ stv0900_write_reg(i_params, prvitReg, 0x01);
++ break;
++ case STV0900_FEC_2_3:
++ stv0900_write_reg(i_params, prvitReg, 0x02);
++ break;
++ case STV0900_FEC_3_4:
++ stv0900_write_reg(i_params, prvitReg, 0x04);
++ break;
++ case STV0900_FEC_5_6:
++ stv0900_write_reg(i_params, prvitReg, 0x08);
++ break;
++ case STV0900_FEC_7_8:
++ stv0900_write_reg(i_params, prvitReg, 0x20);
++ break;
++ }
++
++ break;
++ case STV0900_SEARCH_DSS:
++ dprintk("DSS\n");
++ stv0900_write_reg(i_params, fecmReg, 0x80);
++ switch (PunctureRate) {
++ case STV0900_FEC_UNKNOWN:
++ default:
++ stv0900_write_reg(i_params, prvitReg, 0x13);
++ break;
++ case STV0900_FEC_1_2:
++ stv0900_write_reg(i_params, prvitReg, 0x01);
++ break;
++ case STV0900_FEC_2_3:
++ stv0900_write_reg(i_params, prvitReg, 0x02);
++ break;
++ case STV0900_FEC_6_7:
++ stv0900_write_reg(i_params, prvitReg, 0x10);
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++}
++
++static void stv0900_track_optimization(struct dvb_frontend *fe)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++
++ s32 srate, pilots, aclc, freq1, freq0,
++ i = 0, timed, timef, blindTunSw = 0;
++
++ enum fe_stv0900_rolloff rolloff;
++ enum fe_stv0900_modcode foundModcod;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++ srate += stv0900_get_timing_offst(i_params, srate, demod);
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ switch (i_params->dmd1_rslts.standard) {
++ case STV0900_DVBS1_STANDARD:
++ if (i_params->dmd1_srch_standard == STV0900_AUTO_SEARCH) {
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
++ }
++
++ stv0900_write_bits(i_params, F0900_P1_ROLLOFF_CONTROL, i_params->rolloff);
++ stv0900_write_bits(i_params, F0900_P1_MANUAL_ROLLOFF, 1);
++ stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x75);
++ break;
++ case STV0900_DSS_STANDARD:
++ if (i_params->dmd1_srch_standard == STV0900_AUTO_SEARCH) {
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
++ }
++
++ stv0900_write_bits(i_params, F0900_P1_ROLLOFF_CONTROL, i_params->rolloff);
++ stv0900_write_bits(i_params, F0900_P1_MANUAL_ROLLOFF, 1);
++ stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x75);
++ break;
++ case STV0900_DVBS2_STANDARD:
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
++ stv0900_write_reg(i_params, R0900_P1_ACLC, 0);
++ stv0900_write_reg(i_params, R0900_P1_BCLC, 0);
++ if (i_params->dmd1_rslts.frame_length == STV0900_LONG_FRAME) {
++ foundModcod = stv0900_get_bits(i_params, F0900_P1_DEMOD_MODCOD);
++ pilots = stv0900_get_bits(i_params, F0900_P1_DEMOD_TYPE) & 0x01;
++ aclc = stv0900_get_optim_carr_loop(srate, foundModcod, pilots, i_params->chip_id);
++ if (foundModcod <= STV0900_QPSK_910)
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, aclc);
++ else if (foundModcod <= STV0900_8PSK_910) {
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S28, aclc);
++ }
++
++ if ((i_params->demod_mode == STV0900_SINGLE) && (foundModcod > STV0900_8PSK_910)) {
++ if (foundModcod <= STV0900_16APSK_910) {
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S216A, aclc);
++ } else if (foundModcod <= STV0900_32APSK_910) {
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S232A, aclc);
++ }
++ }
++
++ } else {
++ aclc = stv0900_get_optim_short_carr_loop(srate, i_params->dmd1_rslts.modulation, i_params->chip_id);
++ if (i_params->dmd1_rslts.modulation == STV0900_QPSK)
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, aclc);
++
++ else if (i_params->dmd1_rslts.modulation == STV0900_8PSK) {
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S28, aclc);
++ } else if (i_params->dmd1_rslts.modulation == STV0900_16APSK) {
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S216A, aclc);
++ } else if (i_params->dmd1_rslts.modulation == STV0900_32APSK) {
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P1_ACLC2S232A, aclc);
++ }
++
++ }
++
++ if (i_params->chip_id <= 0x11) {
++ if (i_params->demod_mode != STV0900_SINGLE)
++ stv0900_activate_s2_modcode(i_params, demod);
++
++ }
++
++ stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x67);
++ break;
++ case STV0900_UNKNOWN_STANDARD:
++ default:
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
++ break;
++ }
++
++ freq1 = stv0900_read_reg(i_params, R0900_P1_CFR2);
++ freq0 = stv0900_read_reg(i_params, R0900_P1_CFR1);
++ rolloff = stv0900_get_bits(i_params, F0900_P1_ROLLOFF_STATUS);
++ if (i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) {
++ stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x00);
++ stv0900_write_bits(i_params, F0900_P1_SCAN_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
++ stv0900_write_reg(i_params, R0900_P1_TMGCFG2, 0x01);
++ stv0900_set_symbol_rate(i_params, i_params->mclk, srate, demod);
++ stv0900_set_max_symbol_rate(i_params, i_params->mclk, srate, demod);
++ stv0900_set_min_symbol_rate(i_params, i_params->mclk, srate, demod);
++ blindTunSw = 1;
++ }
++
++ if (i_params->chip_id >= 0x20) {
++ if ((i_params->dmd1_srch_standard == STV0900_SEARCH_DVBS1) || (i_params->dmd1_srch_standard == STV0900_SEARCH_DSS) || (i_params->dmd1_srch_standard == STV0900_AUTO_SEARCH)) {
++ stv0900_write_reg(i_params, R0900_P1_VAVSRVIT, 0x0a);
++ stv0900_write_reg(i_params, R0900_P1_VITSCALE, 0x0);
++ }
++ }
++
++ if (i_params->chip_id < 0x20)
++ stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x08);
++
++ if (i_params->chip_id == 0x10)
++ stv0900_write_reg(i_params, R0900_P1_CORRELEXP, 0x0A);
++
++ stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x38);
++
++ if ((i_params->chip_id >= 0x20) || (blindTunSw == 1) || (i_params->dmd1_symbol_rate < 10000000)) {
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
++ i_params->tuner1_bw = stv0900_carrier_width(srate, i_params->rolloff) + 10000000;
++
++ if ((i_params->chip_id >= 0x20) || (blindTunSw == 1)) {
++ if (i_params->dmd1_srch_algo != STV0900_WARM_START)
++ stv0900_set_bandwidth(fe, i_params->tuner1_bw);
++ }
++
++ if ((i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) || (i_params->dmd1_symbol_rate < 10000000))
++ msleep(50);
++ else
++ msleep(5);
++
++ stv0900_get_lock_timeout(&timed, &timef, srate, STV0900_WARM_START);
++
++ if (stv0900_get_demod_lock(i_params, demod, timed / 2) == FALSE) {
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
++ i = 0;
++ while ((stv0900_get_demod_lock(i_params, demod, timed / 2) == FALSE) && (i <= 2)) {
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
++ i++;
++ }
++ }
++
++ }
++
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x49);
++
++ if ((i_params->dmd1_rslts.standard == STV0900_DVBS1_STANDARD) || (i_params->dmd1_rslts.standard == STV0900_DSS_STANDARD))
++ stv0900_set_viterbi_tracq(i_params, demod);
++
++ break;
++
++ case STV0900_DEMOD_2:
++ switch (i_params->dmd2_rslts.standard) {
++ case STV0900_DVBS1_STANDARD:
++
++ if (i_params->dmd2_srch_stndrd == STV0900_AUTO_SEARCH) {
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
++ }
++
++ stv0900_write_bits(i_params, F0900_P2_ROLLOFF_CONTROL, i_params->rolloff);
++ stv0900_write_bits(i_params, F0900_P2_MANUAL_ROLLOFF, 1);
++ stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x75);
++ break;
++ case STV0900_DSS_STANDARD:
++ if (i_params->dmd2_srch_stndrd == STV0900_AUTO_SEARCH) {
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
++ }
++
++ stv0900_write_bits(i_params, F0900_P2_ROLLOFF_CONTROL, i_params->rolloff);
++ stv0900_write_bits(i_params, F0900_P2_MANUAL_ROLLOFF, 1);
++ stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x75);
++ break;
++ case STV0900_DVBS2_STANDARD:
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
++ stv0900_write_reg(i_params, R0900_P2_ACLC, 0);
++ stv0900_write_reg(i_params, R0900_P2_BCLC, 0);
++ if (i_params->dmd2_rslts.frame_length == STV0900_LONG_FRAME) {
++ foundModcod = stv0900_get_bits(i_params, F0900_P2_DEMOD_MODCOD);
++ pilots = stv0900_get_bits(i_params, F0900_P2_DEMOD_TYPE) & 0x01;
++ aclc = stv0900_get_optim_carr_loop(srate, foundModcod, pilots, i_params->chip_id);
++ if (foundModcod <= STV0900_QPSK_910)
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, aclc);
++ else if (foundModcod <= STV0900_8PSK_910) {
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S28, aclc);
++ }
++
++ if ((i_params->demod_mode == STV0900_SINGLE) && (foundModcod > STV0900_8PSK_910)) {
++ if (foundModcod <= STV0900_16APSK_910) {
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S216A, aclc);
++ } else if (foundModcod <= STV0900_32APSK_910) {
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S232A, aclc);
++ }
++
++ }
++
++ } else {
++ aclc = stv0900_get_optim_short_carr_loop(srate,
++ i_params->dmd2_rslts.modulation,
++ i_params->chip_id);
++
++ if (i_params->dmd2_rslts.modulation == STV0900_QPSK)
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, aclc);
++
++ else if (i_params->dmd2_rslts.modulation == STV0900_8PSK) {
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S28, aclc);
++ } else if (i_params->dmd2_rslts.modulation == STV0900_16APSK) {
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S216A, aclc);
++ } else if (i_params->dmd2_rslts.modulation == STV0900_32APSK) {
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S2Q, 0x2a);
++ stv0900_write_reg(i_params, R0900_P2_ACLC2S232A, aclc);
++ }
++ }
++
++ stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x67);
++
++ break;
++ case STV0900_UNKNOWN_STANDARD:
++ default:
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
++ break;
++ }
++
++ freq1 = stv0900_read_reg(i_params, R0900_P2_CFR2);
++ freq0 = stv0900_read_reg(i_params, R0900_P2_CFR1);
++ rolloff = stv0900_get_bits(i_params, F0900_P2_ROLLOFF_STATUS);
++ if (i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) {
++ stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x00);
++ stv0900_write_bits(i_params, F0900_P2_SCAN_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
++ stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x01);
++ stv0900_set_symbol_rate(i_params, i_params->mclk, srate, demod);
++ stv0900_set_max_symbol_rate(i_params, i_params->mclk, srate, demod);
++ stv0900_set_min_symbol_rate(i_params, i_params->mclk, srate, demod);
++ blindTunSw = 1;
++ }
++
++ if (i_params->chip_id >= 0x20) {
++ if ((i_params->dmd2_srch_stndrd == STV0900_SEARCH_DVBS1) || (i_params->dmd2_srch_stndrd == STV0900_SEARCH_DSS) || (i_params->dmd2_srch_stndrd == STV0900_AUTO_SEARCH)) {
++ stv0900_write_reg(i_params, R0900_P2_VAVSRVIT, 0x0a);
++ stv0900_write_reg(i_params, R0900_P2_VITSCALE, 0x0);
++ }
++ }
++
++ if (i_params->chip_id < 0x20)
++ stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x08);
++
++ if (i_params->chip_id == 0x10)
++ stv0900_write_reg(i_params, R0900_P2_CORRELEXP, 0x0a);
++
++ stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x38);
++ if ((i_params->chip_id >= 0x20) || (blindTunSw == 1) || (i_params->dmd2_symbol_rate < 10000000)) {
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
++ i_params->tuner2_bw = stv0900_carrier_width(srate, i_params->rolloff) + 10000000;
++
++ if ((i_params->chip_id >= 0x20) || (blindTunSw == 1)) {
++ if (i_params->dmd2_srch_algo != STV0900_WARM_START)
++ stv0900_set_bandwidth(fe, i_params->tuner2_bw);
++ }
++
++ if ((i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) || (i_params->dmd2_symbol_rate < 10000000))
++ msleep(50);
++ else
++ msleep(5);
++
++ stv0900_get_lock_timeout(&timed, &timef, srate, STV0900_WARM_START);
++ if (stv0900_get_demod_lock(i_params, demod, timed / 2) == FALSE) {
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
++ i = 0;
++ while ((stv0900_get_demod_lock(i_params, demod, timed / 2) == FALSE) && (i <= 2)) {
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
++ i++;
++ }
++ }
++ }
++
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x49);
++
++ if ((i_params->dmd2_rslts.standard == STV0900_DVBS1_STANDARD) || (i_params->dmd2_rslts.standard == STV0900_DSS_STANDARD))
++ stv0900_set_viterbi_tracq(i_params, demod);
++
++ break;
++ }
++}
++
++static int stv0900_get_fec_lock(struct stv0900_internal *i_params, enum fe_stv0900_demod_num demod, s32 time_out)
++{
++ s32 timer = 0, lock = 0, header_field, pktdelin_field, lock_vit_field;
++
++ enum fe_stv0900_search_state dmd_state;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ dmd_reg(header_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
++ dmd_reg(pktdelin_field, F0900_P1_PKTDELIN_LOCK, F0900_P2_PKTDELIN_LOCK);
++ dmd_reg(lock_vit_field, F0900_P1_LOCKEDVIT, F0900_P2_LOCKEDVIT);
++
++ dmd_state = stv0900_get_bits(i_params, header_field);
++
++ while ((timer < time_out) && (lock == 0)) {
++ switch (dmd_state) {
++ case STV0900_SEARCH:
++ case STV0900_PLH_DETECTED:
++ default:
++ lock = 0;
++ break;
++ case STV0900_DVBS2_FOUND:
++ lock = stv0900_get_bits(i_params, pktdelin_field);
++ break;
++ case STV0900_DVBS_FOUND:
++ lock = stv0900_get_bits(i_params, lock_vit_field);
++ break;
++ }
++
++ if (lock == 0) {
++ msleep(10);
++ timer += 10;
++ }
++ }
++
++ if (lock)
++ dprintk("DEMOD FEC LOCK OK\n");
++ else
++ dprintk("DEMOD FEC LOCK FAIL\n");
++
++ return lock;
++}
++
++static int stv0900_wait_for_lock(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod,
++ s32 dmd_timeout, s32 fec_timeout)
++{
++
++ s32 timer = 0, lock = 0, str_merg_rst_fld, str_merg_lock_fld;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ dmd_reg(str_merg_rst_fld, F0900_P1_RST_HWARE, F0900_P2_RST_HWARE);
++ dmd_reg(str_merg_lock_fld, F0900_P1_TSFIFO_LINEOK, F0900_P2_TSFIFO_LINEOK);
++
++ lock = stv0900_get_demod_lock(i_params, demod, dmd_timeout);
++
++ if (lock)
++ lock = lock && stv0900_get_fec_lock(i_params, demod, fec_timeout);
++
++ if (lock) {
++ lock = 0;
++
++ dprintk(KERN_INFO "%s: Timer = %d, time_out = %d\n", __func__, timer, fec_timeout);
++
++ while ((timer < fec_timeout) && (lock == 0)) {
++ lock = stv0900_get_bits(i_params, str_merg_lock_fld);
++ msleep(1);
++ timer++;
++ }
++ }
++
++ if (lock)
++ dprintk(KERN_INFO "%s: DEMOD LOCK OK\n", __func__);
++ else
++ dprintk(KERN_INFO "%s: DEMOD LOCK FAIL\n", __func__);
++
++ if (lock)
++ return TRUE;
++ else
++ return FALSE;
++}
++
++enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
++ enum fe_stv0900_demod_num demod)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_tracking_standard fnd_standard;
++ s32 state_field,
++ dss_dvb_field;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ dmd_reg(state_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE);
++ dmd_reg(dss_dvb_field, F0900_P1_DSS_DVB, F0900_P2_DSS_DVB);
++
++ if (stv0900_get_bits(i_params, state_field) == 2)
++ fnd_standard = STV0900_DVBS2_STANDARD;
++
++ else if (stv0900_get_bits(i_params, state_field) == 3) {
++ if (stv0900_get_bits(i_params, dss_dvb_field) == 1)
++ fnd_standard = STV0900_DSS_STANDARD;
++ else
++ fnd_standard = STV0900_DVBS1_STANDARD;
++ } else
++ fnd_standard = STV0900_UNKNOWN_STANDARD;
++
++ return fnd_standard;
++}
++
++static s32 stv0900_get_carr_freq(struct stv0900_internal *i_params, u32 mclk,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 cfr_field2, cfr_field1, cfr_field0,
++ derot, rem1, rem2, intval1, intval2;
++
++ dmd_reg(cfr_field2, F0900_P1_CAR_FREQ2, F0900_P2_CAR_FREQ2);
++ dmd_reg(cfr_field1, F0900_P1_CAR_FREQ1, F0900_P2_CAR_FREQ1);
++ dmd_reg(cfr_field0, F0900_P1_CAR_FREQ0, F0900_P2_CAR_FREQ0);
++
++ derot = (stv0900_get_bits(i_params, cfr_field2) << 16) +
++ (stv0900_get_bits(i_params, cfr_field1) << 8) +
++ (stv0900_get_bits(i_params, cfr_field0));
++
++ derot = ge2comp(derot, 24);
++ intval1 = mclk >> 12;
++ intval2 = derot >> 12;
++ rem1 = mclk % 0x1000;
++ rem2 = derot % 0x1000;
++ derot = (intval1 * intval2) +
++ ((intval1 * rem2) >> 12) +
++ ((intval2 * rem1) >> 12);
++
++ return derot;
++}
++
++static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe)
++{
++ struct dvb_frontend_ops *frontend_ops = NULL;
++ struct dvb_tuner_ops *tuner_ops = NULL;
++ u32 frequency = 0;
++
++ if (&fe->ops)
++ frontend_ops = &fe->ops;
++
++ if (&frontend_ops->tuner_ops)
++ tuner_ops = &frontend_ops->tuner_ops;
++
++ if (tuner_ops->get_frequency) {
++ if ((tuner_ops->get_frequency(fe, &frequency)) < 0)
++ dprintk("%s: Invalid parameter\n", __func__);
++ else
++ dprintk("%s: Frequency=%d\n", __func__, frequency);
++
++ }
++
++ return frequency;
++}
++
++static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 rate_fld, vit_curpun_fld;
++ enum fe_stv0900_fec prate;
++
++ dmd_reg(vit_curpun_fld, F0900_P1_VIT_CURPUN, F0900_P2_VIT_CURPUN);
++ rate_fld = stv0900_get_bits(i_params, vit_curpun_fld);
++
++ switch (rate_fld) {
++ case 13:
++ prate = STV0900_FEC_1_2;
++ break;
++ case 18:
++ prate = STV0900_FEC_2_3;
++ break;
++ case 21:
++ prate = STV0900_FEC_3_4;
++ break;
++ case 24:
++ prate = STV0900_FEC_5_6;
++ break;
++ case 25:
++ prate = STV0900_FEC_6_7;
++ break;
++ case 26:
++ prate = STV0900_FEC_7_8;
++ break;
++ default:
++ prate = STV0900_FEC_UNKNOWN;
++ break;
++ }
++
++ return prate;
++}
++
++static enum fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++ enum fe_stv0900_signal_type range = STV0900_OUTOFRANGE;
++ s32 offsetFreq,
++ srate_offset,
++ i = 0;
++
++ u8 timing;
++
++ msleep(5);
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ if (i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) {
++ timing = stv0900_read_reg(i_params, R0900_P1_TMGREG2);
++ i = 0;
++ stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x5c);
++
++ while ((i <= 50) && (timing != 0) && (timing != 0xFF)) {
++ timing = stv0900_read_reg(i_params, R0900_P1_TMGREG2);
++ msleep(5);
++ i += 5;
++ }
++ }
++
++ i_params->dmd1_rslts.standard = stv0900_get_standard(fe, demod);
++ i_params->dmd1_rslts.frequency = stv0900_get_tuner_freq(fe);
++ offsetFreq = stv0900_get_carr_freq(i_params, i_params->mclk, demod) / 1000;
++ i_params->dmd1_rslts.frequency += offsetFreq;
++ i_params->dmd1_rslts.symbol_rate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++ srate_offset = stv0900_get_timing_offst(i_params, i_params->dmd1_rslts.symbol_rate, demod);
++ i_params->dmd1_rslts.symbol_rate += srate_offset;
++ i_params->dmd1_rslts.fec = stv0900_get_vit_fec(i_params, demod);
++ i_params->dmd1_rslts.modcode = stv0900_get_bits(i_params, F0900_P1_DEMOD_MODCOD);
++ i_params->dmd1_rslts.pilot = stv0900_get_bits(i_params, F0900_P1_DEMOD_TYPE) & 0x01;
++ i_params->dmd1_rslts.frame_length = ((u32)stv0900_get_bits(i_params, F0900_P1_DEMOD_TYPE)) >> 1;
++ i_params->dmd1_rslts.rolloff = stv0900_get_bits(i_params, F0900_P1_ROLLOFF_STATUS);
++ switch (i_params->dmd1_rslts.standard) {
++ case STV0900_DVBS2_STANDARD:
++ i_params->dmd1_rslts.spectrum = stv0900_get_bits(i_params, F0900_P1_SPECINV_DEMOD);
++ if (i_params->dmd1_rslts.modcode <= STV0900_QPSK_910)
++ i_params->dmd1_rslts.modulation = STV0900_QPSK;
++ else if (i_params->dmd1_rslts.modcode <= STV0900_8PSK_910)
++ i_params->dmd1_rslts.modulation = STV0900_8PSK;
++ else if (i_params->dmd1_rslts.modcode <= STV0900_16APSK_910)
++ i_params->dmd1_rslts.modulation = STV0900_16APSK;
++ else if (i_params->dmd1_rslts.modcode <= STV0900_32APSK_910)
++ i_params->dmd1_rslts.modulation = STV0900_32APSK;
++ else
++ i_params->dmd1_rslts.modulation = STV0900_UNKNOWN;
++ break;
++ case STV0900_DVBS1_STANDARD:
++ case STV0900_DSS_STANDARD:
++ i_params->dmd1_rslts.spectrum = stv0900_get_bits(i_params, F0900_P1_IQINV);
++ i_params->dmd1_rslts.modulation = STV0900_QPSK;
++ break;
++ default:
++ break;
++ }
++
++ if ((i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) || (i_params->dmd1_symbol_rate < 10000000)) {
++ offsetFreq = i_params->dmd1_rslts.frequency - i_params->tuner1_freq;
++ i_params->tuner1_freq = stv0900_get_tuner_freq(fe);
++ if (ABS(offsetFreq) <= ((i_params->dmd1_srch_range / 2000) + 500))
++ range = STV0900_RANGEOK;
++ else
++ if (ABS(offsetFreq) <= (stv0900_carrier_width(i_params->dmd1_rslts.symbol_rate, i_params->dmd1_rslts.rolloff) / 2000))
++ range = STV0900_RANGEOK;
++ else
++ range = STV0900_OUTOFRANGE;
++
++ } else {
++ if (ABS(offsetFreq) <= ((i_params->dmd1_srch_range / 2000) + 500))
++ range = STV0900_RANGEOK;
++ else
++ range = STV0900_OUTOFRANGE;
++ }
++ break;
++ case STV0900_DEMOD_2:
++ if (i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) {
++ timing = stv0900_read_reg(i_params, R0900_P2_TMGREG2);
++ i = 0;
++ stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x5c);
++
++ while ((i <= 50) && (timing != 0) && (timing != 0xff)) {
++ timing = stv0900_read_reg(i_params, R0900_P2_TMGREG2);
++ msleep(5);
++ i += 5;
++ }
++ }
++
++ i_params->dmd2_rslts.standard = stv0900_get_standard(fe, demod);
++ i_params->dmd2_rslts.frequency = stv0900_get_tuner_freq(fe);
++ offsetFreq = stv0900_get_carr_freq(i_params, i_params->mclk, demod) / 1000;
++ i_params->dmd2_rslts.frequency += offsetFreq;
++ i_params->dmd2_rslts.symbol_rate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++ srate_offset = stv0900_get_timing_offst(i_params, i_params->dmd2_rslts.symbol_rate, demod);
++ i_params->dmd2_rslts.symbol_rate += srate_offset;
++ i_params->dmd2_rslts.fec = stv0900_get_vit_fec(i_params, demod);
++ i_params->dmd2_rslts.modcode = stv0900_get_bits(i_params, F0900_P2_DEMOD_MODCOD);
++ i_params->dmd2_rslts.pilot = stv0900_get_bits(i_params, F0900_P2_DEMOD_TYPE) & 0x01;
++ i_params->dmd2_rslts.frame_length = ((u32)stv0900_get_bits(i_params, F0900_P2_DEMOD_TYPE)) >> 1;
++ i_params->dmd2_rslts.rolloff = stv0900_get_bits(i_params, F0900_P2_ROLLOFF_STATUS);
++ switch (i_params->dmd2_rslts.standard) {
++ case STV0900_DVBS2_STANDARD:
++ i_params->dmd2_rslts.spectrum = stv0900_get_bits(i_params, F0900_P2_SPECINV_DEMOD);
++ if (i_params->dmd2_rslts.modcode <= STV0900_QPSK_910)
++ i_params->dmd2_rslts.modulation = STV0900_QPSK;
++ else if (i_params->dmd2_rslts.modcode <= STV0900_8PSK_910)
++ i_params->dmd2_rslts.modulation = STV0900_8PSK;
++ else if (i_params->dmd2_rslts.modcode <= STV0900_16APSK_910)
++ i_params->dmd2_rslts.modulation = STV0900_16APSK;
++ else if (i_params->dmd2_rslts.modcode <= STV0900_32APSK_910)
++ i_params->dmd2_rslts.modulation = STV0900_32APSK;
++ else
++ i_params->dmd2_rslts.modulation = STV0900_UNKNOWN;
++ break;
++ case STV0900_DVBS1_STANDARD:
++ case STV0900_DSS_STANDARD:
++ i_params->dmd2_rslts.spectrum = stv0900_get_bits(i_params, F0900_P2_IQINV);
++ i_params->dmd2_rslts.modulation = STV0900_QPSK;
++ break;
++ default:
++ break;
++ }
++
++ if ((i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) || (i_params->dmd2_symbol_rate < 10000000)) {
++ offsetFreq = i_params->dmd2_rslts.frequency - i_params->tuner2_freq;
++ i_params->tuner2_freq = stv0900_get_tuner_freq(fe);
++
++ if (ABS(offsetFreq) <= ((i_params->dmd2_srch_range / 2000) + 500))
++ range = STV0900_RANGEOK;
++ else
++ if (ABS(offsetFreq) <= (stv0900_carrier_width(i_params->dmd2_rslts.symbol_rate, i_params->dmd2_rslts.rolloff) / 2000))
++ range = STV0900_RANGEOK;
++ else
++ range = STV0900_OUTOFRANGE;
++ } else {
++ if (ABS(offsetFreq) <= ((i_params->dmd2_srch_range / 2000) + 500))
++ range = STV0900_RANGEOK;
++ else
++ range = STV0900_OUTOFRANGE;
++ }
++
++ break;
++ }
++
++ return range;
++}
++
++static enum fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_frontend *fe)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++
++ s32 srate, demod_timeout,
++ fec_timeout, freq1, freq0;
++ enum fe_stv0900_signal_type signal_type = STV0900_NODATA;;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ i_params->dmd1_rslts.locked = FALSE;
++ if (stv0900_get_bits(i_params, F0900_P1_HEADER_MODE) == STV0900_DVBS_FOUND) {
++ srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++ srate += stv0900_get_timing_offst(i_params, srate, demod);
++ if (i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH)
++ stv0900_set_symbol_rate(i_params, i_params->mclk, srate, demod);
++
++ stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, srate, STV0900_WARM_START);
++ freq1 = stv0900_read_reg(i_params, R0900_P1_CFR2);
++ freq0 = stv0900_read_reg(i_params, R0900_P1_CFR1);
++ stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
++ stv0900_write_bits(i_params, F0900_P1_SPECINV_CONTROL, STV0900_IQ_FORCE_SWAPPED);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1C);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
++ if (stv0900_wait_for_lock(i_params, demod, demod_timeout, fec_timeout) == TRUE) {
++ i_params->dmd1_rslts.locked = TRUE;
++ signal_type = stv0900_get_signal_params(fe);
++ stv0900_track_optimization(fe);
++ } else {
++ stv0900_write_bits(i_params, F0900_P1_SPECINV_CONTROL, STV0900_IQ_FORCE_NORMAL);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1c);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, freq0);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x18);
++ if (stv0900_wait_for_lock(i_params, demod, demod_timeout, fec_timeout) == TRUE) {
++ i_params->dmd1_rslts.locked = TRUE;
++ signal_type = stv0900_get_signal_params(fe);
++ stv0900_track_optimization(fe);
++ }
++
++ }
++
++ } else
++ i_params->dmd1_rslts.locked = FALSE;
++
++ break;
++ case STV0900_DEMOD_2:
++ i_params->dmd2_rslts.locked = FALSE;
++ if (stv0900_get_bits(i_params, F0900_P2_HEADER_MODE) == STV0900_DVBS_FOUND) {
++ srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++ srate += stv0900_get_timing_offst(i_params, srate, demod);
++
++ if (i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH)
++ stv0900_set_symbol_rate(i_params, i_params->mclk, srate, demod);
++
++ stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, srate, STV0900_WARM_START);
++ freq1 = stv0900_read_reg(i_params, R0900_P2_CFR2);
++ freq0 = stv0900_read_reg(i_params, R0900_P2_CFR1);
++ stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
++ stv0900_write_bits(i_params, F0900_P2_SPECINV_CONTROL, STV0900_IQ_FORCE_SWAPPED);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1C);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
++
++ if (stv0900_wait_for_lock(i_params, demod, demod_timeout, fec_timeout) == TRUE) {
++ i_params->dmd2_rslts.locked = TRUE;
++ signal_type = stv0900_get_signal_params(fe);
++ stv0900_track_optimization(fe);
++ } else {
++ stv0900_write_bits(i_params, F0900_P2_SPECINV_CONTROL, STV0900_IQ_FORCE_NORMAL);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1c);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, freq1);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, freq0);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x18);
++
++ if (stv0900_wait_for_lock(i_params, demod, demod_timeout, fec_timeout) == TRUE) {
++ i_params->dmd2_rslts.locked = TRUE;
++ signal_type = stv0900_get_signal_params(fe);
++ stv0900_track_optimization(fe);
++ }
++
++ }
++
++ } else
++ i_params->dmd1_rslts.locked = FALSE;
++
++ break;
++ }
++
++ return signal_type;
++}
++
++static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ u32 minagc2level = 0xffff,
++ agc2level,
++ init_freq, freq_step;
++
++ s32 i, j, nb_steps, direction;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x38);
++ stv0900_write_bits(i_params, F0900_P1_SCAN_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 1);
++
++ stv0900_write_reg(i_params, R0900_P1_SFRUP1, 0x83);
++ stv0900_write_reg(i_params, R0900_P1_SFRUP0, 0xc0);
++
++ stv0900_write_reg(i_params, R0900_P1_SFRLOW1, 0x82);
++ stv0900_write_reg(i_params, R0900_P1_SFRLOW0, 0xa0);
++ stv0900_write_reg(i_params, R0900_P1_DMDT0M, 0x0);
++
++ stv0900_set_symbol_rate(i_params, i_params->mclk, 1000000, demod);
++ nb_steps = -1 + (i_params->dmd1_srch_range / 1000000);
++ nb_steps /= 2;
++ nb_steps = (2 * nb_steps) + 1;
++
++ if (nb_steps < 0)
++ nb_steps = 1;
++
++ direction = 1;
++
++ freq_step = (1000000 << 8) / (i_params->mclk >> 8);
++
++ init_freq = 0;
++
++ for (i = 0; i < nb_steps; i++) {
++ if (direction > 0)
++ init_freq = init_freq + (freq_step * i);
++ else
++ init_freq = init_freq - (freq_step * i);
++
++ direction *= -1;
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x5C);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, (init_freq >> 8) & 0xff);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, init_freq & 0xff);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x58);
++ msleep(10);
++ agc2level = 0;
++
++ for (j = 0; j < 10; j++)
++ agc2level += (stv0900_read_reg(i_params, R0900_P1_AGC2I1) << 8)
++ | stv0900_read_reg(i_params, R0900_P1_AGC2I0);
++
++ agc2level /= 10;
++
++ if (agc2level < minagc2level)
++ minagc2level = agc2level;
++ }
++ break;
++ case STV0900_DEMOD_2:
++ stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x38);
++ stv0900_write_bits(i_params, F0900_P2_SCAN_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 1);
++ stv0900_write_reg(i_params, R0900_P2_SFRUP1, 0x83);
++ stv0900_write_reg(i_params, R0900_P2_SFRUP0, 0xc0);
++ stv0900_write_reg(i_params, R0900_P2_SFRLOW1, 0x82);
++ stv0900_write_reg(i_params, R0900_P2_SFRLOW0, 0xa0);
++ stv0900_write_reg(i_params, R0900_P2_DMDT0M, 0x0);
++ stv0900_set_symbol_rate(i_params, i_params->mclk, 1000000, demod);
++ nb_steps = -1 + (i_params->dmd2_srch_range / 1000000);
++ nb_steps /= 2;
++ nb_steps = (2 * nb_steps) + 1;
++
++ if (nb_steps < 0)
++ nb_steps = 1;
++
++ direction = 1;
++ freq_step = (1000000 << 8) / (i_params->mclk >> 8);
++ init_freq = 0;
++ for (i = 0; i < nb_steps; i++) {
++ if (direction > 0)
++ init_freq = init_freq + (freq_step * i);
++ else
++ init_freq = init_freq - (freq_step * i);
++
++ direction *= -1;
++
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5C);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, (init_freq >> 8) & 0xff);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, init_freq & 0xff);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x58);
++
++ msleep(10);
++ agc2level = 0;
++ for (j = 0; j < 10; j++)
++ agc2level += (stv0900_read_reg(i_params, R0900_P2_AGC2I1) << 8)
++ | stv0900_read_reg(i_params, R0900_P2_AGC2I0);
++
++ agc2level /= 10;
++
++ if (agc2level < minagc2level)
++ minagc2level = agc2level;
++ }
++ break;
++ }
++
++ return (u16)minagc2level;
++}
++
++static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++ int timingLock = FALSE;
++ s32 i, timingcpt = 0,
++ direction = 1,
++ nb_steps,
++ current_step = 0,
++ tuner_freq;
++
++ u32 coarse_srate = 0, agc2_integr = 0, currier_step = 1200;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ stv0900_write_bits(i_params, F0900_P1_I2C_DEMOD_MODE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P1_TMGCFG, 0x12);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, 0xf0);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, 0xe0);
++ stv0900_write_bits(i_params, F0900_P1_SCAN_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 1);
++ stv0900_write_reg(i_params, R0900_P1_SFRUP1, 0x83);
++ stv0900_write_reg(i_params, R0900_P1_SFRUP0, 0xc0);
++ stv0900_write_reg(i_params, R0900_P1_SFRLOW1, 0x82);
++ stv0900_write_reg(i_params, R0900_P1_SFRLOW0, 0xa0);
++ stv0900_write_reg(i_params, R0900_P1_DMDT0M, 0x0);
++ stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x50);
++
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x6a);
++ stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x95);
++ } else {
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xed);
++ stv0900_write_reg(i_params, R0900_P1_SFRSTEP, 0x73);
++ }
++
++ if (i_params->dmd1_symbol_rate <= 2000000)
++ currier_step = 1000;
++ else if (i_params->dmd1_symbol_rate <= 5000000)
++ currier_step = 2000;
++ else if (i_params->dmd1_symbol_rate <= 12000000)
++ currier_step = 3000;
++ else
++ currier_step = 5000;
++
++ nb_steps = -1 + ((i_params->dmd1_srch_range / 1000) / currier_step);
++ nb_steps /= 2;
++ nb_steps = (2 * nb_steps) + 1;
++
++ if (nb_steps < 0)
++ nb_steps = 1;
++
++ else if (nb_steps > 10) {
++ nb_steps = 11;
++ currier_step = (i_params->dmd1_srch_range / 1000) / 10;
++ }
++
++ current_step = 0;
++
++ direction = 1;
++ tuner_freq = i_params->tuner1_freq;
++
++ while ((timingLock == FALSE) && (current_step < nb_steps)) {
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x5F);
++ stv0900_write_bits(i_params, F0900_P1_I2C_DEMOD_MODE, 0x0);
++
++ msleep(50);
++
++ for (i = 0; i < 10; i++) {
++ if (stv0900_get_bits(i_params, F0900_P1_TMGLOCK_QUALITY) >= 2)
++ timingcpt++;
++
++ agc2_integr += (stv0900_read_reg(i_params, R0900_P1_AGC2I1) << 8) | stv0900_read_reg(i_params, R0900_P1_AGC2I0);
++
++ }
++
++ agc2_integr /= 10;
++ coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++ current_step++;
++ direction *= -1;
++
++ dprintk("lock: I2C_DEMOD_MODE_FIELD =0. Search started. tuner freq=%d agc2=0x%x srate_coarse=%d tmg_cpt=%d\n", tuner_freq, agc2_integr, coarse_srate, timingcpt);
++
++ if ((timingcpt >= 5) && (agc2_integr < 0x1F00) && (coarse_srate < 55000000) && (coarse_srate > 850000)) {
++ timingLock = TRUE;
++ }
++
++ else if (current_step < nb_steps) {
++ if (direction > 0)
++ tuner_freq += (current_step * currier_step);
++ else
++ tuner_freq -= (current_step * currier_step);
++
++ stv0900_set_tuner(fe, tuner_freq, i_params->tuner1_bw);
++ }
++ }
++
++ if (timingLock == FALSE)
++ coarse_srate = 0;
++ else
++ coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++ break;
++ case STV0900_DEMOD_2:
++ stv0900_write_bits(i_params, F0900_P2_I2C_DEMOD_MODE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P2_TMGCFG, 0x12);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, 0xf0);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, 0xe0);
++ stv0900_write_bits(i_params, F0900_P2_SCAN_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 1);
++ stv0900_write_reg(i_params, R0900_P2_SFRUP1, 0x83);
++ stv0900_write_reg(i_params, R0900_P2_SFRUP0, 0xc0);
++ stv0900_write_reg(i_params, R0900_P2_SFRLOW1, 0x82);
++ stv0900_write_reg(i_params, R0900_P2_SFRLOW0, 0xa0);
++ stv0900_write_reg(i_params, R0900_P2_DMDT0M, 0x0);
++ stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x50);
++
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x6a);
++ stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x95);
++ } else {
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0xed);
++ stv0900_write_reg(i_params, R0900_P2_SFRSTEP, 0x73);
++ }
++
++ if (i_params->dmd2_symbol_rate <= 2000000)
++ currier_step = 1000;
++ else if (i_params->dmd2_symbol_rate <= 5000000)
++ currier_step = 2000;
++ else if (i_params->dmd2_symbol_rate <= 12000000)
++ currier_step = 3000;
++ else
++ currier_step = 5000;
++
++
++ nb_steps = -1 + ((i_params->dmd2_srch_range / 1000) / currier_step);
++ nb_steps /= 2;
++ nb_steps = (2 * nb_steps) + 1;
++
++ if (nb_steps < 0)
++ nb_steps = 1;
++ else if (nb_steps > 10) {
++ nb_steps = 11;
++ currier_step = (i_params->dmd2_srch_range / 1000) / 10;
++ }
++
++ current_step = 0;
++ direction = 1;
++ tuner_freq = i_params->tuner2_freq;
++
++ while ((timingLock == FALSE) && (current_step < nb_steps)) {
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5F);
++ stv0900_write_bits(i_params, F0900_P2_I2C_DEMOD_MODE, 0x0);
++
++ msleep(50);
++ timingcpt = 0;
++
++ for (i = 0; i < 20; i++) {
++ if (stv0900_get_bits(i_params, F0900_P2_TMGLOCK_QUALITY) >= 2)
++ timingcpt++;
++ agc2_integr += (stv0900_read_reg(i_params, R0900_P2_AGC2I1) << 8)
++ | stv0900_read_reg(i_params, R0900_P2_AGC2I0);
++ }
++
++ agc2_integr /= 20;
++ coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++ if ((timingcpt >= 10) && (agc2_integr < 0x1F00) && (coarse_srate < 55000000) && (coarse_srate > 850000))
++ timingLock = TRUE;
++ else {
++ current_step++;
++ direction *= -1;
++
++ if (direction > 0)
++ tuner_freq += (current_step * currier_step);
++ else
++ tuner_freq -= (current_step * currier_step);
++
++ stv0900_set_tuner(fe, tuner_freq, i_params->tuner2_bw);
++ }
++ }
++
++ if (timingLock == FALSE)
++ coarse_srate = 0;
++ else
++ coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++ break;
++ }
++
++ return coarse_srate;
++}
++
++static u32 stv0900_search_srate_fine(struct dvb_frontend *fe)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++ u32 coarse_srate,
++ coarse_freq,
++ symb;
++
++ coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ coarse_freq = (stv0900_read_reg(i_params, R0900_P1_CFR2) << 8)
++ | stv0900_read_reg(i_params, R0900_P1_CFR1);
++ symb = 13 * (coarse_srate / 10);
++
++ if (symb < i_params->dmd1_symbol_rate)
++ coarse_srate = 0;
++ else {
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P1_TMGCFG2, 0x01);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHRISE, 0x20);
++ stv0900_write_reg(i_params, R0900_P1_TMGTHFALL, 0x00);
++ stv0900_write_reg(i_params, R0900_P1_TMGCFG, 0xd2);
++ stv0900_write_bits(i_params, F0900_P1_CFR_AUTOSCAN, 0);
++
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x49);
++ else
++ stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xed);
++
++ if (coarse_srate > 3000000) {
++ symb = 13 * (coarse_srate / 10);
++ symb = (symb / 1000) * 65536;
++ symb /= (i_params->mclk / 1000);
++ stv0900_write_reg(i_params, R0900_P1_SFRUP1, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, R0900_P1_SFRUP0, (symb & 0xFF));
++
++ symb = 10 * (coarse_srate / 13);
++ symb = (symb / 1000) * 65536;
++ symb /= (i_params->mclk / 1000);
++
++ stv0900_write_reg(i_params, R0900_P1_SFRLOW1, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, R0900_P1_SFRLOW0, (symb & 0xFF));
++
++ symb = (coarse_srate / 1000) * 65536;
++ symb /= (i_params->mclk / 1000);
++ stv0900_write_reg(i_params, R0900_P1_SFRINIT1, (symb >> 8) & 0xFF);
++ stv0900_write_reg(i_params, R0900_P1_SFRINIT0, (symb & 0xFF));
++ } else {
++ symb = 13 * (coarse_srate / 10);
++ symb = (symb / 100) * 65536;
++ symb /= (i_params->mclk / 100);
++ stv0900_write_reg(i_params, R0900_P1_SFRUP1, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, R0900_P1_SFRUP0, (symb & 0xFF));
++
++ symb = 10 * (coarse_srate / 14);
++ symb = (symb / 100) * 65536;
++ symb /= (i_params->mclk / 100);
++ stv0900_write_reg(i_params, R0900_P1_SFRLOW1, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, R0900_P1_SFRLOW0, (symb & 0xFF));
++
++ symb = (coarse_srate / 100) * 65536;
++ symb /= (i_params->mclk / 100);
++ stv0900_write_reg(i_params, R0900_P1_SFRINIT1, (symb >> 8) & 0xFF);
++ stv0900_write_reg(i_params, R0900_P1_SFRINIT0, (symb & 0xFF));
++ }
++
++ stv0900_write_reg(i_params, R0900_P1_DMDT0M, 0x20);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT1, (coarse_freq >> 8) & 0xff);
++ stv0900_write_reg(i_params, R0900_P1_CFRINIT0, coarse_freq & 0xff);
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x15);
++ }
++ break;
++ case STV0900_DEMOD_2:
++ coarse_freq = (stv0900_read_reg(i_params, R0900_P2_CFR2) << 8)
++ | stv0900_read_reg(i_params, R0900_P2_CFR1);
++
++ symb = 13 * (coarse_srate / 10);
++
++ if (symb < i_params->dmd2_symbol_rate)
++ coarse_srate = 0;
++ else {
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x1F);
++ stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x01);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHRISE, 0x20);
++ stv0900_write_reg(i_params, R0900_P2_TMGTHFALL, 0x00);
++ stv0900_write_reg(i_params, R0900_P2_TMGCFG, 0xd2);
++ stv0900_write_bits(i_params, F0900_P2_CFR_AUTOSCAN, 0);
++
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0x49);
++ else
++ stv0900_write_reg(i_params, R0900_P2_CARFREQ, 0xed);
++
++ if (coarse_srate > 3000000) {
++ symb = 13 * (coarse_srate / 10);
++ symb = (symb / 1000) * 65536;
++ symb /= (i_params->mclk / 1000);
++ stv0900_write_reg(i_params, R0900_P2_SFRUP1, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, R0900_P2_SFRUP0, (symb & 0xFF));
++
++ symb = 10 * (coarse_srate / 13);
++ symb = (symb / 1000) * 65536;
++ symb /= (i_params->mclk / 1000);
++
++ stv0900_write_reg(i_params, R0900_P2_SFRLOW1, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, R0900_P2_SFRLOW0, (symb & 0xFF));
++
++ symb = (coarse_srate / 1000) * 65536;
++ symb /= (i_params->mclk / 1000);
++ stv0900_write_reg(i_params, R0900_P2_SFRINIT1, (symb >> 8) & 0xFF);
++ stv0900_write_reg(i_params, R0900_P2_SFRINIT0, (symb & 0xFF));
++ } else {
++ symb = 13 * (coarse_srate / 10);
++ symb = (symb / 100) * 65536;
++ symb /= (i_params->mclk / 100);
++ stv0900_write_reg(i_params, R0900_P2_SFRUP1, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, R0900_P2_SFRUP0, (symb & 0xFF));
++
++ symb = 10 * (coarse_srate / 14);
++ symb = (symb / 100) * 65536;
++ symb /= (i_params->mclk / 100);
++ stv0900_write_reg(i_params, R0900_P2_SFRLOW1, (symb >> 8) & 0x7F);
++ stv0900_write_reg(i_params, R0900_P2_SFRLOW0, (symb & 0xFF));
++
++ symb = (coarse_srate / 100) * 65536;
++ symb /= (i_params->mclk / 100);
++ stv0900_write_reg(i_params, R0900_P2_SFRINIT1, (symb >> 8) & 0xFF);
++ stv0900_write_reg(i_params, R0900_P2_SFRINIT0, (symb & 0xFF));
++ }
++
++ stv0900_write_reg(i_params, R0900_P2_DMDT0M, 0x20);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT1, (coarse_freq >> 8) & 0xff);
++ stv0900_write_reg(i_params, R0900_P2_CFRINIT0, coarse_freq & 0xff);
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x15);
++ }
++
++ break;
++ }
++
++ return coarse_srate;
++}
++
++static int stv0900_blind_search_algo(struct dvb_frontend *fe)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++ u8 k_ref_tmg, k_ref_tmg_max, k_ref_tmg_min;
++ u32 coarse_srate;
++ int lock = FALSE, coarse_fail = FALSE;
++ s32 demod_timeout = 500, fec_timeout = 50, kref_tmg_reg, fail_cpt, i, agc2_overflow;
++ u16 agc2_integr;
++ u8 dstatus2;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ if (i_params->chip_id < 0x20) {
++ k_ref_tmg_max = 233;
++ k_ref_tmg_min = 143;
++ } else {
++ k_ref_tmg_max = 120;
++ k_ref_tmg_min = 30;
++ }
++
++ agc2_integr = stv0900_blind_check_agc2_min_level(i_params, demod);
++
++ if (agc2_integr > STV0900_BLIND_SEARCH_AGC2_TH) {
++ lock = FALSE;
++
++ } else {
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ if (i_params->chip_id == 0x10)
++ stv0900_write_reg(i_params, R0900_P1_CORRELEXP, 0xAA);
++
++ if (i_params->chip_id < 0x20)
++ stv0900_write_reg(i_params, R0900_P1_CARHDR, 0x55);
++
++ stv0900_write_reg(i_params, R0900_P1_CARCFG, 0xC4);
++ stv0900_write_reg(i_params, R0900_P1_RTCS2, 0x44);
++
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P1_EQUALCFG, 0x41);
++ stv0900_write_reg(i_params, R0900_P1_FFECFG, 0x41);
++ stv0900_write_reg(i_params, R0900_P1_VITSCALE, 0x82);
++ stv0900_write_reg(i_params, R0900_P1_VAVSRVIT, 0x0);
++ }
++
++ kref_tmg_reg = R0900_P1_KREFTMG;
++ break;
++ case STV0900_DEMOD_2:
++ if (i_params->chip_id == 0x10)
++ stv0900_write_reg(i_params, R0900_P2_CORRELEXP, 0xAA);
++
++ if (i_params->chip_id < 0x20)
++ stv0900_write_reg(i_params, R0900_P2_CARHDR, 0x55);
++
++ stv0900_write_reg(i_params, R0900_P2_CARCFG, 0xC4);
++ stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x44);
++
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P2_EQUALCFG, 0x41);
++ stv0900_write_reg(i_params, R0900_P2_FFECFG, 0x41);
++ stv0900_write_reg(i_params, R0900_P2_VITSCALE, 0x82);
++ stv0900_write_reg(i_params, R0900_P2_VAVSRVIT, 0x0);
++ }
++
++ kref_tmg_reg = R0900_P2_KREFTMG;
++ break;
++ }
++
++ k_ref_tmg = k_ref_tmg_max;
++
++ do {
++ stv0900_write_reg(i_params, kref_tmg_reg, k_ref_tmg);
++ if (stv0900_search_srate_coarse(fe) != 0) {
++ coarse_srate = stv0900_search_srate_fine(fe);
++
++ if (coarse_srate != 0) {
++ stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, coarse_srate, STV0900_BLIND_SEARCH);
++ lock = stv0900_get_demod_lock(i_params, demod, demod_timeout);
++ } else
++ lock = FALSE;
++ } else {
++ fail_cpt = 0;
++ agc2_overflow = 0;
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ for (i = 0; i < 10; i++) {
++ agc2_integr = (stv0900_read_reg(i_params, R0900_P1_AGC2I1) << 8)
++ | stv0900_read_reg(i_params, R0900_P1_AGC2I0);
++
++ if (agc2_integr >= 0xff00)
++ agc2_overflow++;
++
++ dstatus2 = stv0900_read_reg(i_params, R0900_P1_DSTATUS2);
++
++ if (((dstatus2 & 0x1) == 0x1) && ((dstatus2 >> 7) == 1))
++ fail_cpt++;
++ }
++ break;
++ case STV0900_DEMOD_2:
++ for (i = 0; i < 10; i++) {
++ agc2_integr = (stv0900_read_reg(i_params, R0900_P2_AGC2I1) << 8)
++ | stv0900_read_reg(i_params, R0900_P2_AGC2I0);
++
++ if (agc2_integr >= 0xff00)
++ agc2_overflow++;
++
++ dstatus2 = stv0900_read_reg(i_params, R0900_P2_DSTATUS2);
++
++ if (((dstatus2 & 0x1) == 0x1) && ((dstatus2 >> 7) == 1))
++ fail_cpt++;
++ }
++ break;
++ }
++
++ if ((fail_cpt > 7) || (agc2_overflow > 7))
++ coarse_fail = TRUE;
++
++ lock = FALSE;
++ }
++ k_ref_tmg -= 30;
++ } while ((k_ref_tmg >= k_ref_tmg_min) && (lock == FALSE) && (coarse_fail == FALSE));
++ }
++
++ return lock;
++}
++
++static void stv0900_set_viterbi_acq(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++ s32 vth_reg;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ dmd_reg(vth_reg, R0900_P1_VTH12, R0900_P2_VTH12);
++
++ stv0900_write_reg(i_params, vth_reg++, 0x96);
++ stv0900_write_reg(i_params, vth_reg++, 0x64);
++ stv0900_write_reg(i_params, vth_reg++, 0x36);
++ stv0900_write_reg(i_params, vth_reg++, 0x23);
++ stv0900_write_reg(i_params, vth_reg++, 0x1E);
++ stv0900_write_reg(i_params, vth_reg++, 0x19);
++}
++
++static void stv0900_set_search_standard(struct stv0900_internal *i_params,
++ enum fe_stv0900_demod_num demod)
++{
++
++ int sstndrd;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ sstndrd = i_params->dmd1_srch_standard;
++ if (demod == 1)
++ sstndrd = i_params->dmd2_srch_stndrd;
++
++ switch (sstndrd) {
++ case STV0900_SEARCH_DVBS1:
++ dprintk("Search Standard = DVBS1\n");
++ break;
++ case STV0900_SEARCH_DSS:
++ dprintk("Search Standard = DSS\n");
++ case STV0900_SEARCH_DVBS2:
++ break;
++ dprintk("Search Standard = DVBS2\n");
++ case STV0900_AUTO_SEARCH:
++ default:
++ dprintk("Search Standard = AUTO\n");
++ break;
++ }
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ switch (i_params->dmd1_srch_standard) {
++ case STV0900_SEARCH_DVBS1:
++ case STV0900_SEARCH_DSS:
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
++
++ stv0900_write_bits(i_params, F0900_STOP_CLKVIT1, 0);
++ stv0900_write_reg(i_params, R0900_P1_ACLC, 0x1a);
++ stv0900_write_reg(i_params, R0900_P1_BCLC, 0x09);
++ stv0900_write_reg(i_params, R0900_P1_CAR2CFG, 0x22);
++
++ stv0900_set_viterbi_acq(i_params, demod);
++ stv0900_set_viterbi_standard(i_params,
++ i_params->dmd1_srch_standard,
++ i_params->dmd1_fec, demod);
++
++ break;
++ case STV0900_SEARCH_DVBS2:
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_STOP_CLKVIT1, 1);
++ stv0900_write_reg(i_params, R0900_P1_ACLC, 0x1a);
++ stv0900_write_reg(i_params, R0900_P1_BCLC, 0x09);
++ stv0900_write_reg(i_params, R0900_P1_CAR2CFG, 0x26);
++ if (i_params->demod_mode != STV0900_SINGLE) {
++ if (i_params->chip_id <= 0x11)
++ stv0900_stop_all_s2_modcod(i_params, demod);
++ else
++ stv0900_activate_s2_modcode(i_params, demod);
++
++ } else
++ stv0900_activate_s2_modcode_single(i_params, demod);
++
++ stv0900_set_viterbi_tracq(i_params, demod);
++
++ break;
++ case STV0900_AUTO_SEARCH:
++ default:
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P1_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P1_DVBS2_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_STOP_CLKVIT1, 0);
++ stv0900_write_reg(i_params, R0900_P1_ACLC, 0x1a);
++ stv0900_write_reg(i_params, R0900_P1_BCLC, 0x09);
++ stv0900_write_reg(i_params, R0900_P1_CAR2CFG, 0x26);
++ if (i_params->demod_mode != STV0900_SINGLE) {
++ if (i_params->chip_id <= 0x11)
++ stv0900_stop_all_s2_modcod(i_params, demod);
++ else
++ stv0900_activate_s2_modcode(i_params, demod);
++
++ } else
++ stv0900_activate_s2_modcode_single(i_params, demod);
++
++ if (i_params->dmd1_symbol_rate >= 2000000)
++ stv0900_set_viterbi_acq(i_params, demod);
++ else
++ stv0900_set_viterbi_tracq(i_params, demod);
++
++ stv0900_set_viterbi_standard(i_params, i_params->dmd1_srch_standard, i_params->dmd1_fec, demod);
++
++ break;
++ }
++ break;
++ case STV0900_DEMOD_2:
++ switch (i_params->dmd2_srch_stndrd) {
++ case STV0900_SEARCH_DVBS1:
++ case STV0900_SEARCH_DSS:
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_STOP_CLKVIT2, 0);
++ stv0900_write_reg(i_params, R0900_P2_ACLC, 0x1a);
++ stv0900_write_reg(i_params, R0900_P2_BCLC, 0x09);
++ stv0900_write_reg(i_params, R0900_P2_CAR2CFG, 0x22);
++ stv0900_set_viterbi_acq(i_params, demod);
++ stv0900_set_viterbi_standard(i_params, i_params->dmd2_srch_stndrd, i_params->dmd2_fec, demod);
++ break;
++ case STV0900_SEARCH_DVBS2:
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_STOP_CLKVIT2, 1);
++ stv0900_write_reg(i_params, R0900_P2_ACLC, 0x1a);
++ stv0900_write_reg(i_params, R0900_P2_BCLC, 0x09);
++ stv0900_write_reg(i_params, R0900_P2_CAR2CFG, 0x26);
++ if (i_params->demod_mode != STV0900_SINGLE)
++ stv0900_activate_s2_modcode(i_params, demod);
++ else
++ stv0900_activate_s2_modcode_single(i_params, demod);
++
++ stv0900_set_viterbi_tracq(i_params, demod);
++ break;
++ case STV0900_AUTO_SEARCH:
++ default:
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 0);
++ stv0900_write_bits(i_params, F0900_P2_DVBS1_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_P2_DVBS2_ENABLE, 1);
++ stv0900_write_bits(i_params, F0900_STOP_CLKVIT2, 0);
++ stv0900_write_reg(i_params, R0900_P2_ACLC, 0x1a);
++ stv0900_write_reg(i_params, R0900_P2_BCLC, 0x09);
++ stv0900_write_reg(i_params, R0900_P2_CAR2CFG, 0x26);
++ if (i_params->demod_mode != STV0900_SINGLE)
++ stv0900_activate_s2_modcode(i_params, demod);
++ else
++ stv0900_activate_s2_modcode_single(i_params, demod);
++
++ if (i_params->dmd2_symbol_rate >= 2000000)
++ stv0900_set_viterbi_acq(i_params, demod);
++ else
++ stv0900_set_viterbi_tracq(i_params, demod);
++
++ stv0900_set_viterbi_standard(i_params, i_params->dmd2_srch_stndrd, i_params->dmd2_fec, demod);
++
++ break;
++ }
++
++ break;
++ }
++}
++
++enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
++{
++ struct stv0900_state *state = fe->demodulator_priv;
++ struct stv0900_internal *i_params = state->internal;
++ enum fe_stv0900_demod_num demod = state->demod;
++
++ s32 demod_timeout = 500, fec_timeout = 50, stream_merger_field;
++
++ int lock = FALSE, low_sr = FALSE;
++
++ enum fe_stv0900_signal_type signal_type = STV0900_NOCARRIER;
++ enum fe_stv0900_search_algo algo;
++ int no_signal = FALSE;
++
++ dprintk(KERN_INFO "%s\n", __func__);
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ algo = i_params->dmd1_srch_algo;
++
++ stv0900_write_bits(i_params, F0900_P1_RST_HWARE, 1);
++ stream_merger_field = F0900_P1_RST_HWARE;
++
++ stv0900_write_reg(i_params, R0900_P1_DMDISTATE, 0x5C);
++
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P1_CORRELABS, 0x9e);
++ else
++ stv0900_write_reg(i_params, R0900_P1_CORRELABS, 0x88);
++
++ stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, i_params->dmd1_symbol_rate, i_params->dmd1_srch_algo);
++
++ if (i_params->dmd1_srch_algo == STV0900_BLIND_SEARCH) {
++ i_params->tuner1_bw = 2 * 36000000;
++
++ stv0900_write_reg(i_params, R0900_P1_TMGCFG2, 0x00);
++ stv0900_write_reg(i_params, R0900_P1_CORRELMANT, 0x70);
++
++ stv0900_set_symbol_rate(i_params, i_params->mclk, 1000000, demod);
++ } else {
++ stv0900_write_reg(i_params, R0900_P1_DMDT0M, 0x20);
++ stv0900_write_reg(i_params, R0900_P1_TMGCFG, 0xd2);
++
++ if (i_params->dmd1_symbol_rate < 2000000)
++ stv0900_write_reg(i_params, R0900_P1_CORRELMANT, 0x63);
++ else
++ stv0900_write_reg(i_params, R0900_P1_CORRELMANT, 0x70);
++
++ stv0900_write_reg(i_params, R0900_P1_AGC2REF, 0x38);
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P1_KREFTMG, 0x5a);
++
++ if (i_params->dmd1_srch_algo == STV0900_COLD_START)
++ i_params->tuner1_bw = (15 * (stv0900_carrier_width(i_params->dmd1_symbol_rate, i_params->rolloff) + 10000000)) / 10;
++ else if (i_params->dmd1_srch_algo == STV0900_WARM_START)
++ i_params->tuner1_bw = stv0900_carrier_width(i_params->dmd1_symbol_rate, i_params->rolloff) + 10000000;
++ } else {
++ stv0900_write_reg(i_params, R0900_P1_KREFTMG, 0xc1);
++ i_params->tuner1_bw = (15 * (stv0900_carrier_width(i_params->dmd1_symbol_rate, i_params->rolloff) + 10000000)) / 10;
++ }
++
++ stv0900_write_reg(i_params, R0900_P1_TMGCFG2, 0x01);
++
++ stv0900_set_symbol_rate(i_params, i_params->mclk, i_params->dmd1_symbol_rate, demod);
++ stv0900_set_max_symbol_rate(i_params, i_params->mclk, i_params->dmd1_symbol_rate, demod);
++ stv0900_set_min_symbol_rate(i_params, i_params->mclk, i_params->dmd1_symbol_rate, demod);
++ if (i_params->dmd1_symbol_rate >= 10000000)
++ low_sr = FALSE;
++ else
++ low_sr = TRUE;
++
++ }
++
++ stv0900_set_tuner(fe, i_params->tuner1_freq, i_params->tuner1_bw);
++
++ stv0900_write_bits(i_params, F0900_P1_SPECINV_CONTROL, i_params->dmd1_srch_iq_inv);
++ stv0900_write_bits(i_params, F0900_P1_MANUAL_ROLLOFF, 1);
++
++ stv0900_set_search_standard(i_params, demod);
++
++ if (i_params->dmd1_srch_algo != STV0900_BLIND_SEARCH)
++ stv0900_start_search(i_params, demod);
++ break;
++ case STV0900_DEMOD_2:
++ algo = i_params->dmd2_srch_algo;
++
++ stv0900_write_bits(i_params, F0900_P2_RST_HWARE, 1);
++
++ stream_merger_field = F0900_P2_RST_HWARE;
++
++ stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5C);
++
++ if (i_params->chip_id >= 0x20)
++ stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x9e);
++ else
++ stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x88);
++
++ stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, i_params->dmd2_symbol_rate, i_params->dmd2_srch_algo);
++
++ if (i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) {
++ i_params->tuner2_bw = 2 * 36000000;
++
++ stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x00);
++ stv0900_write_reg(i_params, R0900_P2_CORRELMANT, 0x70);
++
++ stv0900_set_symbol_rate(i_params, i_params->mclk, 1000000, demod);
++ } else {
++ stv0900_write_reg(i_params, R0900_P2_DMDT0M, 0x20);
++ stv0900_write_reg(i_params, R0900_P2_TMGCFG, 0xd2);
++
++ if (i_params->dmd2_symbol_rate < 2000000)
++ stv0900_write_reg(i_params, R0900_P2_CORRELMANT, 0x63);
++ else
++ stv0900_write_reg(i_params, R0900_P2_CORRELMANT, 0x70);
++
++ if (i_params->dmd2_symbol_rate >= 10000000)
++ stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x38);
++ else
++ stv0900_write_reg(i_params, R0900_P2_AGC2REF, 0x60);
++
++ if (i_params->chip_id >= 0x20) {
++ stv0900_write_reg(i_params, R0900_P2_KREFTMG, 0x5a);
++
++ if (i_params->dmd2_srch_algo == STV0900_COLD_START)
++ i_params->tuner2_bw = (15 * (stv0900_carrier_width(i_params->dmd2_symbol_rate,
++ i_params->rolloff) + 10000000)) / 10;
++ else if (i_params->dmd2_srch_algo == STV0900_WARM_START)
++ i_params->tuner2_bw = stv0900_carrier_width(i_params->dmd2_symbol_rate,
++ i_params->rolloff) + 10000000;
++ } else {
++ stv0900_write_reg(i_params, R0900_P2_KREFTMG, 0xc1);
++ i_params->tuner2_bw = (15 * (stv0900_carrier_width(i_params->dmd2_symbol_rate,
++ i_params->rolloff) + 10000000)) / 10;
++ }
++
++ stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x01);
++
++ stv0900_set_symbol_rate(i_params, i_params->mclk, i_params->dmd2_symbol_rate, demod);
++ stv0900_set_max_symbol_rate(i_params, i_params->mclk, i_params->dmd2_symbol_rate, demod);
++ stv0900_set_min_symbol_rate(i_params, i_params->mclk, i_params->dmd2_symbol_rate, demod);
++ if (i_params->dmd2_symbol_rate >= 10000000)
++ low_sr = FALSE;
++ else
++ low_sr = TRUE;
++
++ }
++
++ stv0900_set_tuner(fe, i_params->tuner2_freq, i_params->tuner2_bw);
++
++ stv0900_write_bits(i_params, F0900_P2_SPECINV_CONTROL, i_params->dmd2_srch_iq_inv);
++ stv0900_write_bits(i_params, F0900_P2_MANUAL_ROLLOFF, 1);
++
++ stv0900_set_search_standard(i_params, demod);
++
++ if (i_params->dmd2_srch_algo != STV0900_BLIND_SEARCH)
++ stv0900_start_search(i_params, demod);
++ break;
++ }
++
++ if (i_params->chip_id == 0x12) {
++ stv0900_write_bits(i_params, stream_merger_field, 0);
++ msleep(3);
++ stv0900_write_bits(i_params, stream_merger_field, 1);
++ stv0900_write_bits(i_params, stream_merger_field, 0);
++ }
++
++ if (algo == STV0900_BLIND_SEARCH)
++ lock = stv0900_blind_search_algo(fe);
++ else if (algo == STV0900_COLD_START)
++ lock = stv0900_get_demod_cold_lock(fe, demod_timeout);
++ else if (algo == STV0900_WARM_START)
++ lock = stv0900_get_demod_lock(i_params, demod, demod_timeout);
++
++ if ((lock == FALSE) && (algo == STV0900_COLD_START)) {
++ if (low_sr == FALSE) {
++ if (stv0900_check_timing_lock(i_params, demod) == TRUE)
++ lock = stv0900_sw_algo(i_params, demod);
++ }
++ }
++
++ if (lock == TRUE)
++ signal_type = stv0900_get_signal_params(fe);
++
++ if ((lock == TRUE) && (signal_type == STV0900_RANGEOK)) {
++ stv0900_track_optimization(fe);
++ if (i_params->chip_id <= 0x11) {
++ if ((stv0900_get_standard(fe, STV0900_DEMOD_1) == STV0900_DVBS1_STANDARD) && (stv0900_get_standard(fe, STV0900_DEMOD_2) == STV0900_DVBS1_STANDARD)) {
++ msleep(20);
++ stv0900_write_bits(i_params, stream_merger_field, 0);
++ } else {
++ stv0900_write_bits(i_params, stream_merger_field, 0);
++ msleep(3);
++ stv0900_write_bits(i_params, stream_merger_field, 1);
++ stv0900_write_bits(i_params, stream_merger_field, 0);
++ }
++ } else if (i_params->chip_id == 0x20) {
++ stv0900_write_bits(i_params, stream_merger_field, 0);
++ msleep(3);
++ stv0900_write_bits(i_params, stream_merger_field, 1);
++ stv0900_write_bits(i_params, stream_merger_field, 0);
++ }
++
++ if (stv0900_wait_for_lock(i_params, demod, fec_timeout, fec_timeout) == TRUE) {
++ lock = TRUE;
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ i_params->dmd1_rslts.locked = TRUE;
++ if (i_params->dmd1_rslts.standard == STV0900_DVBS2_STANDARD) {
++ stv0900_set_dvbs2_rolloff(i_params, demod);
++ stv0900_write_reg(i_params, R0900_P1_PDELCTRL2, 0x40);
++ stv0900_write_reg(i_params, R0900_P1_PDELCTRL2, 0);
++ stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x67);
++ } else {
++ stv0900_write_reg(i_params, R0900_P1_ERRCTRL1, 0x75);
++ }
++
++ stv0900_write_reg(i_params, R0900_P1_FBERCPT4, 0);
++ stv0900_write_reg(i_params, R0900_P1_ERRCTRL2, 0xc1);
++ break;
++ case STV0900_DEMOD_2:
++ i_params->dmd2_rslts.locked = TRUE;
++
++ if (i_params->dmd2_rslts.standard == STV0900_DVBS2_STANDARD) {
++ stv0900_set_dvbs2_rolloff(i_params, demod);
++ stv0900_write_reg(i_params, R0900_P2_PDELCTRL2, 0x60);
++ stv0900_write_reg(i_params, R0900_P2_PDELCTRL2, 0x20);
++ stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x67);
++ } else {
++ stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x75);
++ }
++
++ stv0900_write_reg(i_params, R0900_P2_FBERCPT4, 0);
++
++ stv0900_write_reg(i_params, R0900_P2_ERRCTRL2, 0xc1);
++ break;
++ }
++ } else {
++ lock = FALSE;
++ signal_type = STV0900_NODATA;
++ no_signal = stv0900_check_signal_presence(i_params, demod);
++
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ i_params->dmd1_rslts.locked = FALSE;
++ break;
++ case STV0900_DEMOD_2:
++ i_params->dmd2_rslts.locked = FALSE;
++ break;
++ }
++ }
++ }
++
++ if ((signal_type == STV0900_NODATA) && (no_signal == FALSE)) {
++ switch (demod) {
++ case STV0900_DEMOD_1:
++ default:
++ if (i_params->chip_id <= 0x11) {
++ if ((stv0900_get_bits(i_params, F0900_P1_HEADER_MODE) == STV0900_DVBS_FOUND) &&
++ (i_params->dmd1_srch_iq_inv <= STV0900_IQ_AUTO_NORMAL_FIRST))
++ signal_type = stv0900_dvbs1_acq_workaround(fe);
++ } else
++ i_params->dmd1_rslts.locked = FALSE;
++
++ break;
++ case STV0900_DEMOD_2:
++ if (i_params->chip_id <= 0x11) {
++ if ((stv0900_get_bits(i_params, F0900_P2_HEADER_MODE) == STV0900_DVBS_FOUND) &&
++ (i_params->dmd2_srch_iq_inv <= STV0900_IQ_AUTO_NORMAL_FIRST))
++ signal_type = stv0900_dvbs1_acq_workaround(fe);
++ } else
++ i_params->dmd2_rslts.locked = FALSE;
++ break;
++ }
++ }
++
++ return signal_type;
++}
++
+diff --git a/drivers/media/dvb/frontends/stv6110.c b/drivers/media/dvb/frontends/stv6110.c
+new file mode 100644
+index 0000000..70efac8
+--- /dev/null
++++ b/drivers/media/dvb/frontends/stv6110.c
+@@ -0,0 +1,456 @@
++/*
++ * stv6110.c
++ *
++ * Driver for ST STV6110 satellite tuner IC.
++ *
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ *
++ * 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/module.h>
++#include <linux/dvb/frontend.h>
++
++#include <linux/types.h>
++
++#include "stv6110.h"
++
++static int debug;
++
++struct stv6110_priv {
++ int i2c_address;
++ struct i2c_adapter *i2c;
++
++ u32 mclk;
++ u8 regs[8];
++};
++
++#define dprintk(args...) \
++ do { \
++ if (debug) \
++ printk(KERN_DEBUG args); \
++ } while (0)
++
++static s32 abssub(s32 a, s32 b)
++{
++ if (a > b)
++ return a - b;
++ else
++ return b - a;
++};
++
++static int stv6110_release(struct dvb_frontend *fe)
++{
++ kfree(fe->tuner_priv);
++ fe->tuner_priv = NULL;
++ return 0;
++}
++
++static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[],
++ int start, int len)
++{
++ struct stv6110_priv *priv = fe->tuner_priv;
++ int rc;
++ u8 cmdbuf[len + 1];
++ struct i2c_msg msg = {
++ .addr = priv->i2c_address,
++ .flags = 0,
++ .buf = cmdbuf,
++ .len = len + 1
++ };
++
++ dprintk("%s\n", __func__);
++
++ if (start + len > 8)
++ return -EINVAL;
++
++ memcpy(&cmdbuf[1], buf, len);
++ cmdbuf[0] = start;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++
++ rc = i2c_transfer(priv->i2c, &msg, 1);
++ if (rc != 1)
++ dprintk("%s: i2c error\n", __func__);
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ return 0;
++}
++
++static int stv6110_read_regs(struct dvb_frontend *fe, u8 regs[],
++ int start, int len)
++{
++ struct stv6110_priv *priv = fe->tuner_priv;
++ int rc;
++ u8 reg[] = { start };
++ struct i2c_msg msg_wr = {
++ .addr = priv->i2c_address,
++ .flags = 0,
++ .buf = reg,
++ .len = 1,
++ };
++
++ struct i2c_msg msg_rd = {
++ .addr = priv->i2c_address,
++ .flags = I2C_M_RD,
++ .buf = regs,
++ .len = len,
++ };
++ /* write subaddr */
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++
++ rc = i2c_transfer(priv->i2c, &msg_wr, 1);
++ if (rc != 1)
++ dprintk("%s: i2c error\n", __func__);
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++ /* read registers */
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++
++ rc = i2c_transfer(priv->i2c, &msg_rd, 1);
++ if (rc != 1)
++ dprintk("%s: i2c error\n", __func__);
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ memcpy(&priv->regs[start], regs, len);
++
++ return 0;
++}
++
++static int stv6110_read_reg(struct dvb_frontend *fe, int start)
++{
++ u8 buf[] = { 0 };
++ stv6110_read_regs(fe, buf, start, 1);
++
++ return buf[0];
++}
++
++static int stv6110_sleep(struct dvb_frontend *fe)
++{
++ u8 reg[] = { 0 };
++ stv6110_write_regs(fe, reg, 0, 1);
++
++ return 0;
++}
++
++static u32 carrier_width(u32 symbol_rate, fe_rolloff_t rolloff)
++{
++ u32 rlf;
++
++ switch (rolloff) {
++ case ROLLOFF_20:
++ rlf = 20;
++ break;
++ case ROLLOFF_25:
++ rlf = 25;
++ break;
++ default:
++ rlf = 35;
++ break;
++ }
++
++ return symbol_rate + ((symbol_rate * rlf) / 100);
++}
++
++static int stv6110_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
++{
++ struct stv6110_priv *priv = fe->tuner_priv;
++ u8 r8, ret = 0x04;
++ int i;
++
++ if ((bandwidth / 2) > 36000000) /*BW/2 max=31+5=36 mhz for r8=31*/
++ r8 = 31;
++ else if ((bandwidth / 2) < 5000000) /* BW/2 min=5Mhz for F=0 */
++ r8 = 0;
++ else /*if 5 < BW/2 < 36*/
++ r8 = (bandwidth / 2) / 1000000 - 5;
++
++ /* ctrl3, RCCLKOFF = 0 Activate the calibration Clock */
++ /* ctrl3, CF = r8 Set the LPF value */
++ priv->regs[RSTV6110_CTRL3] &= ~((1 << 6) | 0x1f);
++ priv->regs[RSTV6110_CTRL3] |= (r8 & 0x1f);
++ stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1);
++ /* stat1, CALRCSTRT = 1 Start LPF auto calibration*/
++ priv->regs[RSTV6110_STAT1] |= 0x02;
++ stv6110_write_regs(fe, &priv->regs[RSTV6110_STAT1], RSTV6110_STAT1, 1);
++
++ i = 0;
++ /* Wait for CALRCSTRT == 0 */
++ while ((i < 10) && (ret != 0)) {
++ ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x02);
++ mdelay(1); /* wait for LPF auto calibration */
++ i++;
++ }
++
++ /* RCCLKOFF = 1 calibration done, desactivate the calibration Clock */
++ priv->regs[RSTV6110_CTRL3] |= (1 << 6);
++ stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1);
++ return 0;
++}
++
++static int stv6110_init(struct dvb_frontend *fe)
++{
++ struct stv6110_priv *priv = fe->tuner_priv;
++ u8 buf0[] = { 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e };
++
++ memcpy(priv->regs, buf0, 8);
++ /* K = (Reference / 1000000) - 16 */
++ priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3);
++ priv->regs[RSTV6110_CTRL1] |=
++ ((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
++
++ stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], RSTV6110_CTRL1, 8);
++ msleep(1);
++ stv6110_set_bandwidth(fe, 72000000);
++
++ return 0;
++}
++
++static int stv6110_get_frequency(struct dvb_frontend *fe, u32 *frequency)
++{
++ struct stv6110_priv *priv = fe->tuner_priv;
++ u32 nbsteps, divider, psd2, freq;
++ u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
++
++ stv6110_read_regs(fe, regs, 0, 8);
++ /*N*/
++ divider = (priv->regs[RSTV6110_TUNING2] & 0x0f) << 8;
++ divider += priv->regs[RSTV6110_TUNING1];
++
++ /*R*/
++ nbsteps = (priv->regs[RSTV6110_TUNING2] >> 6) & 3;
++ /*p*/
++ psd2 = (priv->regs[RSTV6110_TUNING2] >> 4) & 1;
++
++ freq = divider * (priv->mclk / 1000);
++ freq /= (1 << (nbsteps + psd2));
++ freq /= 4;
++
++ *frequency = freq;
++
++ return 0;
++}
++
++static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
++{
++ struct stv6110_priv *priv = fe->tuner_priv;
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ u8 ret = 0x04;
++ u32 divider, ref, p, presc, i, result_freq, vco_freq;
++ s32 p_calc, p_calc_opt = 1000, r_div, r_div_opt = 0, p_val;
++ s32 srate; u8 gain;
++
++ dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__,
++ frequency, priv->mclk);
++
++ /* K = (Reference / 1000000) - 16 */
++ priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3);
++ priv->regs[RSTV6110_CTRL1] |=
++ ((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
++
++ /* BB_GAIN = db/2 */
++ if (fe->ops.set_property && fe->ops.get_property) {
++ srate = c->symbol_rate;
++ dprintk("%s: Get Frontend parameters: srate=%d\n",
++ __func__, srate);
++ } else
++ srate = 15000000;
++
++ if (srate >= 15000000)
++ gain = 3; /* +6 dB */
++ else if (srate >= 5000000)
++ gain = 3; /* +6 dB */
++ else
++ gain = 3; /* +6 dB */
++
++ priv->regs[RSTV6110_CTRL2] &= ~0x0f;
++ priv->regs[RSTV6110_CTRL2] |= (gain & 0x0f);
++
++ if (frequency <= 1023000) {
++ p = 1;
++ presc = 0;
++ } else if (frequency <= 1300000) {
++ p = 1;
++ presc = 1;
++ } else if (frequency <= 2046000) {
++ p = 0;
++ presc = 0;
++ } else {
++ p = 0;
++ presc = 1;
++ }
++ /* DIV4SEL = p*/
++ priv->regs[RSTV6110_TUNING2] &= ~(1 << 4);
++ priv->regs[RSTV6110_TUNING2] |= (p << 4);
++
++ /* PRESC32ON = presc */
++ priv->regs[RSTV6110_TUNING2] &= ~(1 << 5);
++ priv->regs[RSTV6110_TUNING2] |= (presc << 5);
++
++ p_val = (int)(1 << (p + 1)) * 10;/* P = 2 or P = 4 */
++ for (r_div = 0; r_div <= 3; r_div++) {
++ p_calc = (priv->mclk / 100000);
++ p_calc /= (1 << (r_div + 1));
++ if ((abssub(p_calc, p_val)) < (abssub(p_calc_opt, p_val)))
++ r_div_opt = r_div;
++
++ p_calc_opt = (priv->mclk / 100000);
++ p_calc_opt /= (1 << (r_div_opt + 1));
++ }
++
++ ref = priv->mclk / ((1 << (r_div_opt + 1)) * (1 << (p + 1)));
++ divider = (((frequency * 1000) + (ref >> 1)) / ref);
++
++ /* RDIV = r_div_opt */
++ priv->regs[RSTV6110_TUNING2] &= ~(3 << 6);
++ priv->regs[RSTV6110_TUNING2] |= (((r_div_opt) & 3) << 6);
++
++ /* NDIV_MSB = MSB(divider) */
++ priv->regs[RSTV6110_TUNING2] &= ~0x0f;
++ priv->regs[RSTV6110_TUNING2] |= (((divider) >> 8) & 0x0f);
++
++ /* NDIV_LSB, LSB(divider) */
++ priv->regs[RSTV6110_TUNING1] = (divider & 0xff);
++
++ /* CALVCOSTRT = 1 VCO Auto Calibration */
++ priv->regs[RSTV6110_STAT1] |= 0x04;
++ stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1],
++ RSTV6110_CTRL1, 8);
++
++ i = 0;
++ /* Wait for CALVCOSTRT == 0 */
++ while ((i < 10) && (ret != 0)) {
++ ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x04);
++ msleep(1); /* wait for VCO auto calibration */
++ i++;
++ }
++
++ ret = stv6110_read_reg(fe, RSTV6110_STAT1);
++ stv6110_get_frequency(fe, &result_freq);
++
++ vco_freq = divider * ((priv->mclk / 1000) / ((1 << (r_div_opt + 1))));
++ dprintk("%s, stat1=%x, lo_freq=%d kHz, vco_frec=%d kHz\n", __func__,
++ ret, result_freq, vco_freq);
++
++ return 0;
++}
++
++static int stv6110_set_params(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *params)
++{
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff);
++
++ stv6110_set_frequency(fe, c->frequency);
++ stv6110_set_bandwidth(fe, bandwidth);
++
++ return 0;
++}
++
++static int stv6110_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
++{
++ struct stv6110_priv *priv = fe->tuner_priv;
++ u8 r8 = 0;
++ u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
++ stv6110_read_regs(fe, regs, 0, 8);
++
++ /* CF */
++ r8 = priv->regs[RSTV6110_CTRL3] & 0x1f;
++ *bandwidth = (r8 + 5) * 2000000;/* x2 for ZIF tuner BW/2 = F+5 Mhz */
++
++ return 0;
++}
++
++static struct dvb_tuner_ops stv6110_tuner_ops = {
++ .info = {
++ .name = "ST STV6110",
++ .frequency_min = 950000,
++ .frequency_max = 2150000,
++ .frequency_step = 1000,
++ },
++ .init = stv6110_init,
++ .release = stv6110_release,
++ .sleep = stv6110_sleep,
++ .set_params = stv6110_set_params,
++ .get_frequency = stv6110_get_frequency,
++ .set_frequency = stv6110_set_frequency,
++ .get_bandwidth = stv6110_get_bandwidth,
++ .set_bandwidth = stv6110_set_bandwidth,
++
++};
++
++struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
++ const struct stv6110_config *config,
++ struct i2c_adapter *i2c)
++{
++ struct stv6110_priv *priv = NULL;
++ u8 reg0[] = { 0x00, 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e };
++
++ struct i2c_msg msg[] = {
++ {
++ .addr = config->i2c_address,
++ .flags = 0,
++ .buf = reg0,
++ .len = 9
++ }
++ };
++ int ret;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1);
++
++ ret = i2c_transfer(i2c, msg, 1);
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0);
++
++ if (ret != 1)
++ return NULL;
++
++ priv = kzalloc(sizeof(struct stv6110_priv), GFP_KERNEL);
++ if (priv == NULL)
++ return NULL;
++
++ priv->i2c_address = config->i2c_address;
++ priv->i2c = i2c;
++ priv->mclk = config->mclk;
++
++ memcpy(&priv->regs, &reg0[1], 8);
++
++ memcpy(&fe->ops.tuner_ops, &stv6110_tuner_ops,
++ sizeof(struct dvb_tuner_ops));
++ fe->tuner_priv = priv;
++ printk(KERN_INFO "STV6110 attached on addr=%x!\n", priv->i2c_address);
++
++ return fe;
++}
++EXPORT_SYMBOL(stv6110_attach);
++
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
++
++MODULE_DESCRIPTION("ST STV6110 driver");
++MODULE_AUTHOR("Igor M. Liplianin");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/stv6110.h b/drivers/media/dvb/frontends/stv6110.h
+new file mode 100644
+index 0000000..1c0314d
+--- /dev/null
++++ b/drivers/media/dvb/frontends/stv6110.h
+@@ -0,0 +1,62 @@
++/*
++ * stv6110.h
++ *
++ * Driver for ST STV6110 satellite tuner IC.
++ *
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ *
++ * 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 __DVB_STV6110_H__
++#define __DVB_STV6110_H__
++
++#include <linux/i2c.h>
++#include "dvb_frontend.h"
++
++/* registers */
++#define RSTV6110_CTRL1 0
++#define RSTV6110_CTRL2 1
++#define RSTV6110_TUNING1 2
++#define RSTV6110_TUNING2 3
++#define RSTV6110_CTRL3 4
++#define RSTV6110_STAT1 5
++#define RSTV6110_STAT2 6
++#define RSTV6110_STAT3 7
++
++struct stv6110_config {
++ u8 i2c_address;
++ u32 mclk;
++ int iq_wiring;
++};
++
++#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \
++ && defined(MODULE))
++extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
++ const struct stv6110_config *config,
++ struct i2c_adapter *i2c);
++#else
++static inline struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
++ const struct stv6110_config *config,
++ struct i2c_adapter *i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif
++
++#endif
+diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
+index 1465ff7..4981cef 100644
+--- a/drivers/media/dvb/frontends/tda1004x.c
++++ b/drivers/media/dvb/frontends/tda1004x.c
+@@ -162,7 +162,7 @@ static int tda1004x_read_byte(struct tda1004x_state *state, int reg)
+ if (ret != 2) {
+ dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
+ ret);
+- return -1;
++ return -EINVAL;
+ }
+
+ dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
+@@ -481,16 +481,18 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
+ static int tda10046_fwupload(struct dvb_frontend* fe)
+ {
+ struct tda1004x_state* state = fe->demodulator_priv;
+- int ret;
++ int ret, confc4;
+ const struct firmware *fw;
+
+ /* reset + wake up chip */
+ if (state->config->xtal_freq == TDA10046_XTAL_4M) {
+- tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
++ confc4 = 0;
+ } else {
+ dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__);
+- tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
++ confc4 = 0x80;
+ }
++ tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
++
+ tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
+ /* set GPIO 1 and 3 */
+ if (state->config->gpio_config != TDA10046_GPTRI) {
+@@ -508,13 +510,29 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
+ if (tda1004x_check_upload_ok(state) == 0)
+ return 0;
+
++ /*
++ For i2c normal work, we need to slow down the bus speed.
++ However, the slow down breaks the eeprom firmware load.
++ So, use normal speed for eeprom booting and then restore the
++ i2c speed after that. Tested with MSI TV @nyware A/D board,
++ that comes with firmware version 29 inside their eeprom.
++
++ It should also be noticed that no other I2C transfer should
++ be in course while booting from eeprom, otherwise, tda10046
++ goes into an instable state. So, proper locking are needed
++ at the i2c bus master.
++ */
+ printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
+- tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
++ tda1004x_write_byteI(state, TDA1004X_CONFC4, 4);
+ msleep(300);
+- /* don't re-upload unless necessary */
++ tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
++
++ /* Checks if eeprom firmware went without troubles */
+ if (tda1004x_check_upload_ok(state) == 0)
+ return 0;
+
++ /* eeprom firmware didn't work. Load one manually. */
++
+ if (state->config->request_firmware != NULL) {
+ /* request the firmware, this will block until someone uploads it */
+ printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
+diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c
+new file mode 100644
+index 0000000..e22a0b3
+--- /dev/null
++++ b/drivers/media/dvb/frontends/zl10036.c
+@@ -0,0 +1,519 @@
++/**
++ * Driver for Zarlink zl10036 DVB-S silicon tuner
++ *
++ * Copyright (C) 2006 Tino Reichardt
++ * Copyright (C) 2007-2009 Matthias Schwarzott <zzam@gentoo.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License Version 2, as
++ * published by the Free Software Foundation.
++ *
++ * 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.
++ *
++ **
++ * The data sheet for this tuner can be found at:
++ * http://www.mcmilk.de/projects/dvb-card/datasheets/ZL10036.pdf
++ *
++ * This one is working: (at my Avermedia DVB-S Pro)
++ * - zl10036 (40pin, FTA)
++ *
++ * A driver for zl10038 should be very similar.
++ */
++
++#include <linux/module.h>
++#include <linux/dvb/frontend.h>
++#include <asm/types.h>
++
++#include "zl10036.h"
++
++static int zl10036_debug;
++#define dprintk(level, args...) \
++ do { if (zl10036_debug & level) printk(KERN_DEBUG "zl10036: " args); \
++ } while (0)
++
++#define deb_info(args...) dprintk(0x01, args)
++#define deb_i2c(args...) dprintk(0x02, args)
++
++struct zl10036_state {
++ struct i2c_adapter *i2c;
++ const struct zl10036_config *config;
++ u32 frequency;
++ u8 br, bf;
++};
++
++
++/* This driver assumes the tuner is driven by a 10.111MHz Cristal */
++#define _XTAL 10111
++
++/* Some of the possible dividers:
++ * 64, (write 0x05 to reg), freq step size 158kHz
++ * 10, (write 0x0a to reg), freq step size 1.011kHz (used here)
++ * 5, (write 0x09 to reg), freq step size 2.022kHz
++ */
++
++#define _RDIV 10
++#define _RDIV_REG 0x0a
++#define _FR (_XTAL/_RDIV)
++
++#define STATUS_POR 0x80 /* Power on Reset */
++#define STATUS_FL 0x40 /* Frequency & Phase Lock */
++
++/* read/write for zl10036 and zl10038 */
++
++static int zl10036_read_status_reg(struct zl10036_state *state)
++{
++ u8 status;
++ struct i2c_msg msg[1] = {
++ { .addr = state->config->tuner_address, .flags = I2C_M_RD,
++ .buf = &status, .len = sizeof(status) },
++ };
++
++ if (i2c_transfer(state->i2c, msg, 1) != 1) {
++ printk(KERN_ERR "%s: i2c read failed at addr=%02x\n",
++ __func__, state->config->tuner_address);
++ return -EIO;
++ }
++
++ deb_i2c("R(status): %02x [FL=%d]\n", status,
++ (status & STATUS_FL) ? 1 : 0);
++ if (status & STATUS_POR)
++ deb_info("%s: Power-On-Reset bit enabled - "
++ "need to initialize the tuner\n", __func__);
++
++ return status;
++}
++
++static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count)
++{
++ struct i2c_msg msg[1] = {
++ { .addr = state->config->tuner_address, .flags = 0,
++ .buf = buf, .len = count },
++ };
++ u8 reg = 0;
++ int ret;
++
++ if (zl10036_debug & 0x02) {
++ /* every 8bit-value satisifes this!
++ * so only check for debug log */
++ if ((buf[0] & 0x80) == 0x00)
++ reg = 2;
++ else if ((buf[0] & 0xc0) == 0x80)
++ reg = 4;
++ else if ((buf[0] & 0xf0) == 0xc0)
++ reg = 6;
++ else if ((buf[0] & 0xf0) == 0xd0)
++ reg = 8;
++ else if ((buf[0] & 0xf0) == 0xe0)
++ reg = 10;
++ else if ((buf[0] & 0xf0) == 0xf0)
++ reg = 12;
++
++ deb_i2c("W(%d):", reg);
++ {
++ int i;
++ for (i = 0; i < count; i++)
++ printk(KERN_CONT " %02x", buf[i]);
++ printk(KERN_CONT "\n");
++ }
++ }
++
++ ret = i2c_transfer(state->i2c, msg, 1);
++ if (ret != 1) {
++ printk(KERN_ERR "%s: i2c error, ret=%d\n", __func__, ret);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int zl10036_release(struct dvb_frontend *fe)
++{
++ struct zl10036_state *state = fe->tuner_priv;
++
++ fe->tuner_priv = NULL;
++ kfree(state);
++
++ return 0;
++}
++
++static int zl10036_sleep(struct dvb_frontend *fe)
++{
++ struct zl10036_state *state = fe->tuner_priv;
++ u8 buf[] = { 0xf0, 0x80 }; /* regs 12/13 */
++ int ret;
++
++ deb_info("%s\n", __func__);
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
++
++ ret = zl10036_write(state, buf, sizeof(buf));
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
++
++ return ret;
++}
++
++/**
++ * register map of the ZL10036/ZL10038
++ *
++ * reg[default] content
++ * 2[0x00]: 0 | N14 | N13 | N12 | N11 | N10 | N9 | N8
++ * 3[0x00]: N7 | N6 | N5 | N4 | N3 | N2 | N1 | N0
++ * 4[0x80]: 1 | 0 | RFG | BA1 | BA0 | BG1 | BG0 | LEN
++ * 5[0x00]: P0 | C1 | C0 | R4 | R3 | R2 | R1 | R0
++ * 6[0xc0]: 1 | 1 | 0 | 0 | RSD | 0 | 0 | 0
++ * 7[0x20]: P1 | BF6 | BF5 | BF4 | BF3 | BF2 | BF1 | 0
++ * 8[0xdb]: 1 | 1 | 0 | 1 | 0 | CC | 1 | 1
++ * 9[0x30]: VSD | V2 | V1 | V0 | S3 | S2 | S1 | S0
++ * 10[0xe1]: 1 | 1 | 1 | 0 | 0 | LS2 | LS1 | LS0
++ * 11[0xf5]: WS | WH2 | WH1 | WH0 | WL2 | WL1 | WL0 | WRE
++ * 12[0xf0]: 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0
++ * 13[0x28]: PD | BR4 | BR3 | BR2 | BR1 | BR0 | CLR | TL
++ */
++
++static int zl10036_set_frequency(struct zl10036_state *state, u32 frequency)
++{
++ u8 buf[2];
++ u32 div, foffset;
++
++ div = (frequency + _FR/2) / _FR;
++ state->frequency = div * _FR;
++
++ foffset = frequency - state->frequency;
++
++ buf[0] = (div >> 8) & 0x7f;
++ buf[1] = (div >> 0) & 0xff;
++
++ deb_info("%s: ftodo=%u fpriv=%u ferr=%d div=%u\n", __func__,
++ frequency, state->frequency, foffset, div);
++
++ return zl10036_write(state, buf, sizeof(buf));
++}
++
++static int zl10036_set_bandwidth(struct zl10036_state *state, u32 fbw)
++{
++ /* fbw is measured in kHz */
++ u8 br, bf;
++ int ret;
++ u8 buf_bf[] = {
++ 0xc0, 0x00, /* 6/7: rsd=0 bf=0 */
++ };
++ u8 buf_br[] = {
++ 0xf0, 0x00, /* 12/13: br=0xa clr=0 tl=0*/
++ };
++ u8 zl10036_rsd_off[] = { 0xc8 }; /* set RSD=1 */
++
++ /* ensure correct values */
++ if (fbw > 35000)
++ fbw = 35000;
++ if (fbw < 8000)
++ fbw = 8000;
++
++#define _BR_MAXIMUM (_XTAL/575) /* _XTAL / 575kHz = 17 */
++
++ /* <= 28,82 MHz */
++ if (fbw <= 28820) {
++ br = _BR_MAXIMUM;
++ } else {
++ /**
++ * f(bw)=34,6MHz f(xtal)=10.111MHz
++ * br = (10111/34600) * 63 * 1/K = 14;
++ */
++ br = ((_XTAL * 21 * 1000) / (fbw * 419));
++ }
++
++ /* ensure correct values */
++ if (br < 4)
++ br = 4;
++ if (br > _BR_MAXIMUM)
++ br = _BR_MAXIMUM;
++
++ /*
++ * k = 1.257
++ * bf = fbw/_XTAL * br * k - 1 */
++
++ bf = (fbw * br * 1257) / (_XTAL * 1000) - 1;
++
++ /* ensure correct values */
++ if (bf > 62)
++ bf = 62;
++
++ buf_bf[1] = (bf << 1) & 0x7e;
++ buf_br[1] = (br << 2) & 0x7c;
++ deb_info("%s: BW=%d br=%u bf=%u\n", __func__, fbw, br, bf);
++
++ if (br != state->br) {
++ ret = zl10036_write(state, buf_br, sizeof(buf_br));
++ if (ret < 0)
++ return ret;
++ }
++
++ if (bf != state->bf) {
++ ret = zl10036_write(state, buf_bf, sizeof(buf_bf));
++ if (ret < 0)
++ return ret;
++
++ /* time = br/(32* fxtal) */
++ /* minimal sleep time to be calculated
++ * maximum br is 63 -> max time = 2 /10 MHz = 2e-7 */
++ msleep(1);
++
++ ret = zl10036_write(state, zl10036_rsd_off,
++ sizeof(zl10036_rsd_off));
++ if (ret < 0)
++ return ret;
++ }
++
++ state->br = br;
++ state->bf = bf;
++
++ return 0;
++}
++
++static int zl10036_set_gain_params(struct zl10036_state *state,
++ int c)
++{
++ u8 buf[2];
++ u8 rfg, ba, bg;
++
++ /* default values */
++ rfg = 0; /* enable when using an lna */
++ ba = 1;
++ bg = 1;
++
++ /* reg 4 */
++ buf[0] = 0x80 | ((rfg << 5) & 0x20)
++ | ((ba << 3) & 0x18) | ((bg << 1) & 0x06);
++
++ if (!state->config->rf_loop_enable)
++ buf[0] |= 0x01;
++
++ /* P0=0 */
++ buf[1] = _RDIV_REG | ((c << 5) & 0x60);
++
++ deb_info("%s: c=%u rfg=%u ba=%u bg=%u\n", __func__, c, rfg, ba, bg);
++ return zl10036_write(state, buf, sizeof(buf));
++}
++
++static int zl10036_set_params(struct dvb_frontend *fe,
++ struct dvb_frontend_parameters *params)
++{
++ struct zl10036_state *state = fe->tuner_priv;
++ int ret = 0;
++ u32 frequency = params->frequency;
++ u32 fbw;
++ int i;
++ u8 c;
++
++ /* ensure correct values
++ * maybe redundant as core already checks this */
++ if ((frequency < fe->ops.info.frequency_min)
++ || (frequency > fe->ops.info.frequency_max))
++ return -EINVAL;
++
++ /**
++ * alpha = 1.35 for dvb-s
++ * fBW = (alpha*symbolrate)/(2*0.8)
++ * 1.35 / (2*0.8) = 27 / 32
++ */
++ fbw = (27 * params->u.qpsk.symbol_rate) / 32;
++
++ /* scale to kHz */
++ fbw /= 1000;
++
++ /* Add safe margin of 3MHz */
++ fbw += 3000;
++
++ /* setting the charge pump - guessed values */
++ if (frequency < 950000)
++ return -EINVAL;
++ else if (frequency < 1250000)
++ c = 0;
++ else if (frequency < 1750000)
++ c = 1;
++ else if (frequency < 2175000)
++ c = 2;
++ else
++ return -EINVAL;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
++
++ ret = zl10036_set_gain_params(state, c);
++ if (ret < 0)
++ goto error;
++
++ ret = zl10036_set_frequency(state, params->frequency);
++ if (ret < 0)
++ goto error;
++
++ ret = zl10036_set_bandwidth(state, fbw);
++ if (ret < 0)
++ goto error;
++
++ /* wait for tuner lock - no idea if this is really needed */
++ for (i = 0; i < 20; i++) {
++ ret = zl10036_read_status_reg(state);
++ if (ret < 0)
++ goto error;
++
++ /* check Frequency & Phase Lock Bit */
++ if (ret & STATUS_FL)
++ break;
++
++ msleep(10);
++ }
++
++error:
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
++
++ return ret;
++}
++
++static int zl10036_get_frequency(struct dvb_frontend *fe, u32 *frequency)
++{
++ struct zl10036_state *state = fe->tuner_priv;
++
++ *frequency = state->frequency;
++
++ return 0;
++}
++
++static int zl10036_init_regs(struct zl10036_state *state)
++{
++ int ret;
++ int i;
++
++ /* could also be one block from reg 2 to 13 and additional 10/11 */
++ u8 zl10036_init_tab[][2] = {
++ { 0x04, 0x00 }, /* 2/3: div=0x400 - arbitrary value */
++ { 0x8b, _RDIV_REG }, /* 4/5: rfg=0 ba=1 bg=1 len=? */
++ /* p0=0 c=0 r=_RDIV_REG */
++ { 0xc0, 0x20 }, /* 6/7: rsd=0 bf=0x10 */
++ { 0xd3, 0x40 }, /* 8/9: from datasheet */
++ { 0xe3, 0x5b }, /* 10/11: lock window level */
++ { 0xf0, 0x28 }, /* 12/13: br=0xa clr=0 tl=0*/
++ { 0xe3, 0xf9 }, /* 10/11: unlock window level */
++ };
++
++ /* invalid values to trigger writing */
++ state->br = 0xff;
++ state->bf = 0xff;
++
++ if (!state->config->rf_loop_enable)
++ zl10036_init_tab[1][2] |= 0x01;
++
++ deb_info("%s\n", __func__);
++
++ for (i = 0; i < ARRAY_SIZE(zl10036_init_tab); i++) {
++ ret = zl10036_write(state, zl10036_init_tab[i], 2);
++ if (ret < 0)
++ return ret;
++ }
++
++ return 0;
++}
++
++static int zl10036_init(struct dvb_frontend *fe)
++{
++ struct zl10036_state *state = fe->tuner_priv;
++ int ret = 0;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
++
++ ret = zl10036_read_status_reg(state);
++ if (ret < 0)
++ return ret;
++
++ /* Only init if Power-on-Reset bit is set? */
++ ret = zl10036_init_regs(state);
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
++
++ return ret;
++}
++
++static struct dvb_tuner_ops zl10036_tuner_ops = {
++ .info = {
++ .name = "Zarlink ZL10036",
++ .frequency_min = 950000,
++ .frequency_max = 2175000
++ },
++ .init = zl10036_init,
++ .release = zl10036_release,
++ .sleep = zl10036_sleep,
++ .set_params = zl10036_set_params,
++ .get_frequency = zl10036_get_frequency,
++};
++
++struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
++ const struct zl10036_config *config,
++ struct i2c_adapter *i2c)
++{
++ struct zl10036_state *state = NULL;
++ int ret;
++
++ if (NULL == config) {
++ printk(KERN_ERR "%s: no config specified", __func__);
++ goto error;
++ }
++
++ state = kzalloc(sizeof(struct zl10036_state), GFP_KERNEL);
++ if (NULL == state)
++ return NULL;
++
++ state->config = config;
++ state->i2c = i2c;
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
++
++ ret = zl10036_read_status_reg(state);
++ if (ret < 0) {
++ printk(KERN_ERR "%s: No zl10036 found\n", __func__);
++ goto error;
++ }
++
++ ret = zl10036_init_regs(state);
++ if (ret < 0) {
++ printk(KERN_ERR "%s: tuner initialization failed\n",
++ __func__);
++ goto error;
++ }
++
++ if (fe->ops.i2c_gate_ctrl)
++ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
++
++ fe->tuner_priv = state;
++
++ memcpy(&fe->ops.tuner_ops, &zl10036_tuner_ops,
++ sizeof(struct dvb_tuner_ops));
++ printk(KERN_INFO "%s: tuner initialization (%s addr=0x%02x) ok\n",
++ __func__, fe->ops.tuner_ops.info.name, config->tuner_address);
++
++ return fe;
++
++error:
++ zl10036_release(fe);
++ return NULL;
++}
++EXPORT_SYMBOL(zl10036_attach);
++
++module_param_named(debug, zl10036_debug, int, 0644);
++MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
++MODULE_DESCRIPTION("DVB ZL10036 driver");
++MODULE_AUTHOR("Tino Reichardt");
++MODULE_AUTHOR("Matthias Schwarzott");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/zl10036.h b/drivers/media/dvb/frontends/zl10036.h
+new file mode 100644
+index 0000000..d84b8f8
+--- /dev/null
++++ b/drivers/media/dvb/frontends/zl10036.h
+@@ -0,0 +1,53 @@
++/**
++ * Driver for Zarlink ZL10036 DVB-S silicon tuner
++ *
++ * Copyright (C) 2006 Tino Reichardt
++ * Copyright (C) 2007-2009 Matthias Schwarzott <zzam@gentoo.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License Version 2, as
++ * published by the Free Software Foundation.
++ *
++ * 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 DVB_ZL10036_H
++#define DVB_ZL10036_H
++
++#include <linux/i2c.h>
++#include "dvb_frontend.h"
++
++/**
++ * Attach a zl10036 tuner to the supplied frontend structure.
++ *
++ * @param fe Frontend to attach to.
++ * @param config zl10036_config structure
++ * @return FE pointer on success, NULL on failure.
++ */
++
++struct zl10036_config {
++ u8 tuner_address;
++ int rf_loop_enable;
++};
++
++#if defined(CONFIG_DVB_ZL10036) || \
++ (defined(CONFIG_DVB_ZL10036_MODULE) && defined(MODULE))
++extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
++ const struct zl10036_config *config, struct i2c_adapter *i2c);
++#else
++static inline struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
++ const struct zl10036_config *config, struct i2c_adapter *i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif
++
++#endif /* DVB_ZL10036_H */
+diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
+index b150ed3..148b6f7 100644
+--- a/drivers/media/dvb/frontends/zl10353.c
++++ b/drivers/media/dvb/frontends/zl10353.c
+@@ -572,6 +572,10 @@ static int zl10353_init(struct dvb_frontend *fe)
+ zl10353_dump_regs(fe);
+ if (state->config.parallel_ts)
+ zl10353_reset_attach[2] &= ~0x20;
++ if (state->config.clock_ctl_1)
++ zl10353_reset_attach[3] = state->config.clock_ctl_1;
++ if (state->config.pll_0)
++ zl10353_reset_attach[4] = state->config.pll_0;
+
+ /* Do a "hard" reset if not already done */
+ if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
+@@ -614,6 +618,7 @@ struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
+ struct i2c_adapter *i2c)
+ {
+ struct zl10353_state *state = NULL;
++ int id;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL);
+@@ -625,7 +630,8 @@ struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
+ memcpy(&state->config, config, sizeof(struct zl10353_config));
+
+ /* check if the demod is there */
+- if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
++ id = zl10353_read_register(state, CHIP_ID);
++ if ((id != ID_ZL10353) && (id != ID_CE6230) && (id != ID_CE6231))
+ goto error;
+
+ /* create dvb_frontend */
+diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
+index 2287bac..6e3ca9e 100644
+--- a/drivers/media/dvb/frontends/zl10353.h
++++ b/drivers/media/dvb/frontends/zl10353.h
+@@ -41,6 +41,10 @@ struct zl10353_config
+
+ /* set if i2c_gate_ctrl disable is required */
+ u8 disable_i2c_gate_ctrl:1;
++
++ /* clock control registers (0x51-0x54) */
++ u8 clock_ctl_1; /* default: 0x46 */
++ u8 pll_0; /* default: 0x15 */
+ };
+
+ #if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE))
+diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
+index 055ff1f..e0dd1d3 100644
+--- a/drivers/media/dvb/frontends/zl10353_priv.h
++++ b/drivers/media/dvb/frontends/zl10353_priv.h
+@@ -22,7 +22,9 @@
+ #ifndef _ZL10353_PRIV_
+ #define _ZL10353_PRIV_
+
+-#define ID_ZL10353 0x14
++#define ID_ZL10353 0x14 /* Zarlink ZL10353 */
++#define ID_CE6230 0x18 /* Intel CE6230 */
++#define ID_CE6231 0x19 /* Intel CE6231 */
+
+ #define msb(x) (((x) >> 8) & 0xff)
+ #define lsb(x) ((x) & 0xff)
+@@ -50,6 +52,10 @@ enum zl10353_reg_addr {
+ TPS_RECEIVED_0 = 0x1E,
+ TPS_CURRENT_1 = 0x1F,
+ TPS_CURRENT_0 = 0x20,
++ CLOCK_CTL_0 = 0x51,
++ CLOCK_CTL_1 = 0x52,
++ PLL_0 = 0x53,
++ PLL_1 = 0x54,
+ RESET = 0x55,
+ AGC_TARGET = 0x56,
+ MCLK_RATIO = 0x5C,
+diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
+index d101b30..ee89623 100644
+--- a/drivers/media/dvb/pluto2/pluto2.c
++++ b/drivers/media/dvb/pluto2/pluto2.c
+@@ -116,6 +116,7 @@ struct pluto {
+
+ /* irq */
+ unsigned int overflow;
++ unsigned int dead;
+
+ /* dma */
+ dma_addr_t dma_addr;
+@@ -336,8 +337,10 @@ static irqreturn_t pluto_irq(int irq, void *dev_id)
+ return IRQ_NONE;
+
+ if (tscr == 0xffffffff) {
+- // FIXME: maybe recover somehow
+- dev_err(&pluto->pdev->dev, "card hung up :(\n");
++ if (pluto->dead == 0)
++ dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n");
++ /* It's dead Jim */
++ pluto->dead = 1;
+ return IRQ_HANDLED;
+ }
+
+diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile
+index ee0737a..bcf93f4 100644
+--- a/drivers/media/dvb/siano/Makefile
++++ b/drivers/media/dvb/siano/Makefile
+@@ -1,6 +1,8 @@
+-sms1xxx-objs := smscoreapi.o smsusb.o smsdvb.o sms-cards.o
++sms1xxx-objs := smscoreapi.o sms-cards.o
+
+ obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
++obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o
++obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsdvb.o
+
+ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+
+diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
+index 4307e4e..63e4d0e 100644
+--- a/drivers/media/dvb/siano/sms-cards.c
++++ b/drivers/media/dvb/siano/sms-cards.c
+@@ -19,50 +19,9 @@
+
+ #include "sms-cards.h"
+
+-struct usb_device_id smsusb_id_table[] = {
+-#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
+- { USB_DEVICE(0x187f, 0x0010),
+- .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+- { USB_DEVICE(0x187f, 0x0100),
+- .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+- { USB_DEVICE(0x187f, 0x0200),
+- .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
+- { USB_DEVICE(0x187f, 0x0201),
+- .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
+- { USB_DEVICE(0x187f, 0x0300),
+- .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
+-#endif
+- { USB_DEVICE(0x2040, 0x1700),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
+- { USB_DEVICE(0x2040, 0x1800),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
+- { USB_DEVICE(0x2040, 0x1801),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
+- { USB_DEVICE(0x2040, 0x2000),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+- { USB_DEVICE(0x2040, 0x2009),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
+- { USB_DEVICE(0x2040, 0x200a),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+- { USB_DEVICE(0x2040, 0x2010),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+- { USB_DEVICE(0x2040, 0x2019),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+- { USB_DEVICE(0x2040, 0x5500),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+- { USB_DEVICE(0x2040, 0x5510),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+- { USB_DEVICE(0x2040, 0x5520),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+- { USB_DEVICE(0x2040, 0x5530),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+- { USB_DEVICE(0x2040, 0x5580),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+- { USB_DEVICE(0x2040, 0x5590),
+- .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+- { } /* Terminating entry */
+-};
+-MODULE_DEVICE_TABLE(usb, smsusb_id_table);
++static int sms_dbg;
++module_param_named(cards_dbg, sms_dbg, int, 0644);
++MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
+
+ static struct sms_board sms_boards[] = {
+ [SMS_BOARD_UNKNOWN] = {
+@@ -115,6 +74,7 @@ static struct sms_board sms_boards[] = {
+ .type = SMS_NOVA_B0,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .lna_ctrl = 29,
++ .rf_switch = 17,
+ },
+ [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
+ .name = "Hauppauge WinTV MiniCard",
+@@ -130,6 +90,7 @@ struct sms_board *sms_get_board(int id)
+
+ return &sms_boards[id];
+ }
++EXPORT_SYMBOL_GPL(sms_get_board);
+
+ static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
+ {
+@@ -182,6 +143,7 @@ int sms_board_setup(struct smscore_device_t *coredev)
+ }
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(sms_board_setup);
+
+ int sms_board_power(struct smscore_device_t *coredev, int onoff)
+ {
+@@ -197,12 +159,13 @@ int sms_board_power(struct smscore_device_t *coredev, int onoff)
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+ /* LNA */
+- sms_set_gpio(coredev,
+- board->lna_ctrl, onoff ? 1 : 0);
++ if (!onoff)
++ sms_set_gpio(coredev, board->lna_ctrl, 0);
+ break;
+ }
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(sms_board_power);
+
+ int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
+ {
+@@ -225,3 +188,40 @@ int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
+ }
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(sms_board_led_feedback);
++
++int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
++{
++ int board_id = smscore_get_board_id(coredev);
++ struct sms_board *board = sms_get_board(board_id);
++
++ sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled");
++
++ switch (board_id) {
++ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
++ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
++ sms_set_gpio(coredev,
++ board->rf_switch, onoff ? 1 : 0);
++ return sms_set_gpio(coredev,
++ board->lna_ctrl, onoff ? 1 : 0);
++ }
++ return -EINVAL;
++}
++EXPORT_SYMBOL_GPL(sms_board_lna_control);
++
++int sms_board_load_modules(int id)
++{
++ switch (id) {
++ case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT:
++ case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
++ case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
++ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
++ request_module("smsdvb");
++ break;
++ default:
++ /* do nothing */
++ break;
++ }
++ return 0;
++}
++EXPORT_SYMBOL_GPL(sms_board_load_modules);
+diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
+index 8e0fe9f..64d74c5 100644
+--- a/drivers/media/dvb/siano/sms-cards.h
++++ b/drivers/media/dvb/siano/sms-cards.h
+@@ -40,7 +40,7 @@ struct sms_board {
+ char *name, *fw[DEVICE_MODE_MAX];
+
+ /* gpios */
+- int led_power, led_hi, led_lo, lna_ctrl;
++ int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
+ };
+
+ struct sms_board *sms_get_board(int id);
+@@ -52,7 +52,8 @@ int sms_board_setup(struct smscore_device_t *coredev);
+ #define SMS_LED_HI 2
+ int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
+ int sms_board_power(struct smscore_device_t *coredev, int onoff);
++int sms_board_lna_control(struct smscore_device_t *coredev, int onoff);
+
+-extern struct usb_device_id smsusb_id_table[];
++extern int sms_board_load_modules(int id);
+
+ #endif /* __SMS_CARDS_H__ */
+diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
+index cf613f2..7bd4d1d 100644
+--- a/drivers/media/dvb/siano/smscoreapi.c
++++ b/drivers/media/dvb/siano/smscoreapi.c
+@@ -3,7 +3,7 @@
+ *
+ * This file contains implementation for the interface to sms core component
+ *
+- * author: Anatoly Greenblat
++ * author: Uri Shkolnik
+ *
+ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+@@ -34,8 +34,8 @@
+ #include "smscoreapi.h"
+ #include "sms-cards.h"
+
+-int sms_debug;
+-module_param_named(debug, sms_debug, int, 0644);
++static int sms_dbg;
++module_param_named(debug, sms_dbg, int, 0644);
+ MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+ struct smscore_device_notifyee_t {
+@@ -105,11 +105,13 @@ int smscore_led_state(struct smscore_device_t *core, int led)
+ core->led_state = led;
+ return core->led_state;
+ }
++EXPORT_SYMBOL_GPL(smscore_set_board_id);
+
+ int smscore_get_board_id(struct smscore_device_t *core)
+ {
+ return core->board_id;
+ }
++EXPORT_SYMBOL_GPL(smscore_get_board_id);
+
+ struct smscore_registry_entry_t {
+ struct list_head entry;
+@@ -170,6 +172,7 @@ int smscore_registry_getmode(char *devpath)
+
+ return default_mode;
+ }
++EXPORT_SYMBOL_GPL(smscore_registry_getmode);
+
+ static enum sms_device_type_st smscore_registry_gettype(char *devpath)
+ {
+@@ -261,6 +264,7 @@ int smscore_register_hotplug(hotplug_t hotplug)
+
+ return rc;
+ }
++EXPORT_SYMBOL_GPL(smscore_register_hotplug);
+
+ /**
+ * unregister a client callback that called when device plugged in/unplugged
+@@ -289,6 +293,7 @@ void smscore_unregister_hotplug(hotplug_t hotplug)
+
+ kmutex_unlock(&g_smscore_deviceslock);
+ }
++EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
+
+ static void smscore_notify_clients(struct smscore_device_t *coredev)
+ {
+@@ -432,6 +437,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
+
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(smscore_register_device);
+
+ /**
+ * sets initial device mode and notifies client hotplugs that device is ready
+@@ -460,6 +466,7 @@ int smscore_start_device(struct smscore_device_t *coredev)
+
+ return rc;
+ }
++EXPORT_SYMBOL_GPL(smscore_start_device);
+
+ static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+ void *buffer, size_t size,
+@@ -688,6 +695,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
+
+ sms_info("device %p destroyed", coredev);
+ }
++EXPORT_SYMBOL_GPL(smscore_unregister_device);
+
+ static int smscore_detect_mode(struct smscore_device_t *coredev)
+ {
+@@ -732,7 +740,7 @@ static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
+ /*DVBH*/
+ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+ /*TDMB*/
+- {"none", "tdmb_nova_12mhz.inp", "none", "none"},
++ {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
+ /*DABIP*/
+ {"none", "none", "none", "none"},
+ /*BDA*/
+@@ -879,6 +887,7 @@ int smscore_get_device_mode(struct smscore_device_t *coredev)
+ {
+ return coredev->mode;
+ }
++EXPORT_SYMBOL_GPL(smscore_get_device_mode);
+
+ /**
+ * find client by response id & type within the clients list.
+@@ -1006,6 +1015,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
+ smscore_putbuffer(coredev, cb);
+ }
+ }
++EXPORT_SYMBOL_GPL(smscore_onresponse);
+
+ /**
+ * return pointer to next free buffer descriptor from core pool
+@@ -1031,6 +1041,7 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+
+ return cb;
+ }
++EXPORT_SYMBOL_GPL(smscore_getbuffer);
+
+ /**
+ * return buffer descriptor to a pool
+@@ -1045,6 +1056,7 @@ void smscore_putbuffer(struct smscore_device_t *coredev,
+ {
+ list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
+ }
++EXPORT_SYMBOL_GPL(smscore_putbuffer);
+
+ static int smscore_validate_client(struct smscore_device_t *coredev,
+ struct smscore_client_t *client,
+@@ -1124,6 +1136,7 @@ int smscore_register_client(struct smscore_device_t *coredev,
+
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(smscore_register_client);
+
+ /**
+ * frees smsclient object and all subclients associated with it
+@@ -1154,6 +1167,7 @@ void smscore_unregister_client(struct smscore_client_t *client)
+
+ spin_unlock_irqrestore(&coredev->clientslock, flags);
+ }
++EXPORT_SYMBOL_GPL(smscore_unregister_client);
+
+ /**
+ * verifies that source id is not taken by another client,
+@@ -1193,6 +1207,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
+
+ return coredev->sendrequest_handler(coredev->context, buffer, size);
+ }
++EXPORT_SYMBOL_GPL(smsclient_sendrequest);
+
+
+ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
+@@ -1276,12 +1291,12 @@ static int __init smscore_module_init(void)
+ INIT_LIST_HEAD(&g_smscore_registry);
+ kmutex_init(&g_smscore_registrylock);
+
+- /* USB Register */
+- rc = smsusb_register();
+
+- /* DVB Register */
+- rc = smsdvb_register();
+
++
++
++
++ return rc;
+ sms_debug("rc %d", rc);
+
+ return rc;
+@@ -1290,6 +1305,10 @@ static int __init smscore_module_init(void)
+ static void __exit smscore_module_exit(void)
+ {
+
++
++
++
++
+ kmutex_lock(&g_smscore_deviceslock);
+ while (!list_empty(&g_smscore_notifyees)) {
+ struct smscore_device_notifyee_t *notifyee =
+@@ -1312,18 +1331,12 @@ static void __exit smscore_module_exit(void)
+ }
+ kmutex_unlock(&g_smscore_registrylock);
+
+- /* DVB UnRegister */
+- smsdvb_unregister();
+-
+- /* Unregister USB */
+- smsusb_unregister();
+-
+ sms_debug("");
+ }
+
+ module_init(smscore_module_init);
+ module_exit(smscore_module_exit);
+
+-MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
+-MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
++MODULE_DESCRIPTION("Siano MDTV Core module");
++MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
+index 760e233..548de90 100644
+--- a/drivers/media/dvb/siano/smscoreapi.h
++++ b/drivers/media/dvb/siano/smscoreapi.h
+@@ -29,13 +29,13 @@
+ #include <linux/scatterlist.h>
+ #include <linux/types.h>
+ #include <asm/page.h>
++#include <linux/mutex.h>
+
+ #include "dmxdev.h"
+ #include "dvbdev.h"
+ #include "dvb_demux.h"
+ #include "dvb_frontend.h"
+
+-#include <linux/mutex.h>
+
+ #define kmutex_init(_p_) mutex_init(_p_)
+ #define kmutex_lock(_p_) mutex_lock(_p_)
+@@ -369,27 +369,6 @@ struct smscore_gpio_config {
+ u8 outputdriving;
+ };
+
+-struct smsdvb_client_t {
+- struct list_head entry;
+-
+- struct smscore_device_t *coredev;
+- struct smscore_client_t *smsclient;
+-
+- struct dvb_adapter adapter;
+- struct dvb_demux demux;
+- struct dmxdev dmxdev;
+- struct dvb_frontend frontend;
+-
+- fe_status_t fe_status;
+- int fe_ber, fe_snr, fe_unc, fe_signal_strength;
+-
+- struct completion tune_done, stat_done;
+-
+- /* todo: save freq/band instead whole struct */
+- struct dvb_frontend_parameters fe_params;
+-
+-};
+-
+ extern void smscore_registry_setmode(char *devpath, int mode);
+ extern int smscore_registry_getmode(char *devpath);
+
+@@ -418,6 +397,13 @@ extern int smsclient_sendrequest(struct smscore_client_t *client,
+ extern void smscore_onresponse(struct smscore_device_t *coredev,
+ struct smscore_buffer_t *cb);
+
++extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
++extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
++ struct vm_area_struct *vma);
++extern int smscore_get_fw_filename(struct smscore_device_t *coredev,
++ int mode, char *filename);
++extern int smscore_send_fw_file(struct smscore_device_t *coredev,
++ u8 *ufwbuf, int size);
+
+ extern
+ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
+@@ -433,18 +419,9 @@ int smscore_get_board_id(struct smscore_device_t *core);
+
+ int smscore_led_state(struct smscore_device_t *core, int led);
+
+-/* smsdvb.c */
+-int smsdvb_register(void);
+-void smsdvb_unregister(void);
+-
+-/* smsusb.c */
+-int smsusb_register(void);
+-void smsusb_unregister(void);
+
+ /* ------------------------------------------------------------------------ */
+
+-extern int sms_debug;
+-
+ #define DBG_INFO 1
+ #define DBG_ADV 2
+
+@@ -452,7 +429,7 @@ extern int sms_debug;
+ printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+ #define dprintk(kern, lvl, fmt, arg...) do {\
+- if (sms_debug & lvl) \
++ if (sms_dbg & lvl) \
+ sms_printk(kern, fmt, ##arg); } while (0)
+
+ #define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
+diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
+index 2da953a..ba080b9 100644
+--- a/drivers/media/dvb/siano/smsdvb.c
++++ b/drivers/media/dvb/siano/smsdvb.c
+@@ -1,7 +1,7 @@
+ /*
+ * Driver for the Siano SMS1xxx USB dongle
+ *
+- * author: Anatoly Greenblat
++ * Author: Uri Shkolni
+ *
+ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+@@ -27,9 +27,33 @@
+
+ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
++struct smsdvb_client_t {
++ struct list_head entry;
++
++ struct smscore_device_t *coredev;
++ struct smscore_client_t *smsclient;
++
++ struct dvb_adapter adapter;
++ struct dvb_demux demux;
++ struct dmxdev dmxdev;
++ struct dvb_frontend frontend;
++
++ fe_status_t fe_status;
++ int fe_ber, fe_snr, fe_unc, fe_signal_strength;
++
++ struct completion tune_done, stat_done;
++
++ /* todo: save freq/band instead whole struct */
++ struct dvb_frontend_parameters fe_params;
++};
++
+ static struct list_head g_smsdvb_clients;
+ static struct mutex g_smsdvb_clientslock;
+
++static int sms_dbg;
++module_param_named(debug, sms_dbg, int, 0644);
++MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
++
+ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
+ {
+ struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
+@@ -262,6 +286,7 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
+ struct SmsMsgHdr_ST Msg;
+ u32 Data[3];
+ } Msg;
++ int ret;
+
+ Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ Msg.Msg.msgDstId = HIF_TASK;
+@@ -282,6 +307,24 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
+ default: return -EINVAL;
+ }
+
++ /* Disable LNA, if any. An error is returned if no LNA is present */
++ ret = sms_board_lna_control(client->coredev, 0);
++ if (ret == 0) {
++ fe_status_t status;
++
++ /* tune with LNA off at first */
++ ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
++ &client->tune_done);
++
++ smsdvb_read_status(fe, &status);
++
++ if (status & FE_HAS_LOCK)
++ return ret;
++
++ /* previous tune didnt lock - enable LNA and tune again */
++ sms_board_lna_control(client->coredev, 1);
++ }
++
+ return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+ &client->tune_done);
+ }
+@@ -329,7 +372,7 @@ static void smsdvb_release(struct dvb_frontend *fe)
+
+ static struct dvb_frontend_ops smsdvb_fe_ops = {
+ .info = {
+- .name = "Siano Mobile Digital SMS1xxx",
++ .name = "Siano Mobile Digital MDTV Receiver",
+ .type = FE_OFDM,
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+@@ -371,7 +414,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
+ if (!arrival)
+ return 0;
+
+- if (smscore_get_device_mode(coredev) != 4) {
++ if (smscore_get_device_mode(coredev) != DEVICE_MODE_DVBT_BDA) {
+ sms_err("SMS Device mode is not set for "
+ "DVB operation.");
+ return 0;
+@@ -473,7 +516,7 @@ adapter_error:
+ return rc;
+ }
+
+-int smsdvb_register(void)
++int smsdvb_module_init(void)
+ {
+ int rc;
+
+@@ -487,7 +530,7 @@ int smsdvb_register(void)
+ return rc;
+ }
+
+-void smsdvb_unregister(void)
++void smsdvb_module_exit(void)
+ {
+ smscore_unregister_hotplug(smsdvb_hotplug);
+
+@@ -499,3 +542,10 @@ void smsdvb_unregister(void)
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+ }
++
++module_init(smsdvb_module_init);
++module_exit(smsdvb_module_exit);
++
++MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
++MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
+index 5d7ca34..71c65f5 100644
+--- a/drivers/media/dvb/siano/smsusb.c
++++ b/drivers/media/dvb/siano/smsusb.c
+@@ -27,6 +27,10 @@
+ #include "smscoreapi.h"
+ #include "sms-cards.h"
+
++static int sms_dbg;
++module_param_named(debug, sms_dbg, int, 0644);
++MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
++
+ #define USB1_BUFFER_SIZE 0x1000
+ #define USB2_BUFFER_SIZE 0x4000
+
+@@ -424,6 +428,7 @@ static int smsusb_probe(struct usb_interface *intf,
+
+ rc = smsusb_init_device(intf, id->driver_info);
+ sms_info("rc %d", rc);
++ sms_board_load_modules(id->driver_info);
+ return rc;
+ }
+
+@@ -436,7 +441,7 @@ static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
+ {
+ struct smsusb_device_t *dev =
+ (struct smsusb_device_t *)usb_get_intfdata(intf);
+- printk(KERN_INFO "%s Entering status %d.\n", __func__, msg.event);
++ printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event);
+ smsusb_stop_streaming(dev);
+ return 0;
+ }
+@@ -448,7 +453,7 @@ static int smsusb_resume(struct usb_interface *intf)
+ (struct smsusb_device_t *)usb_get_intfdata(intf);
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+- printk(KERN_INFO "%s Entering.\n", __func__);
++ printk(KERN_INFO "%s: Entering.\n", __func__);
+ usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
+ usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
+
+@@ -463,9 +468,8 @@ static int smsusb_resume(struct usb_interface *intf)
+ intf->cur_altsetting->desc.
+ bInterfaceNumber, 0);
+ if (rc < 0) {
+- printk(KERN_INFO
+- "%s usb_set_interface failed, rc %d\n",
+- __func__, rc);
++ printk(KERN_INFO "%s usb_set_interface failed, "
++ "rc %d\n", __func__, rc);
+ return rc;
+ }
+ }
+@@ -474,8 +478,55 @@ static int smsusb_resume(struct usb_interface *intf)
+ return 0;
+ }
+
++struct usb_device_id smsusb_id_table[] = {
++#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
++ { USB_DEVICE(0x187f, 0x0010),
++ .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
++ { USB_DEVICE(0x187f, 0x0100),
++ .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
++ { USB_DEVICE(0x187f, 0x0200),
++ .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
++ { USB_DEVICE(0x187f, 0x0201),
++ .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
++ { USB_DEVICE(0x187f, 0x0300),
++ .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
++#endif
++ { USB_DEVICE(0x2040, 0x1700),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
++ { USB_DEVICE(0x2040, 0x1800),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
++ { USB_DEVICE(0x2040, 0x1801),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
++ { USB_DEVICE(0x2040, 0x2000),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
++ { USB_DEVICE(0x2040, 0x2009),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
++ { USB_DEVICE(0x2040, 0x200a),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
++ { USB_DEVICE(0x2040, 0x2010),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
++ { USB_DEVICE(0x2040, 0x2011),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
++ { USB_DEVICE(0x2040, 0x2019),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
++ { USB_DEVICE(0x2040, 0x5500),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
++ { USB_DEVICE(0x2040, 0x5510),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
++ { USB_DEVICE(0x2040, 0x5520),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
++ { USB_DEVICE(0x2040, 0x5530),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
++ { USB_DEVICE(0x2040, 0x5580),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
++ { USB_DEVICE(0x2040, 0x5590),
++ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
++ { } /* Terminating entry */
++};
++MODULE_DEVICE_TABLE(usb, smsusb_id_table);
++
+ static struct usb_driver smsusb_driver = {
+- .name = "sms1xxx",
++ .name = "smsusb",
+ .probe = smsusb_probe,
+ .disconnect = smsusb_disconnect,
+ .id_table = smsusb_id_table,
+@@ -484,7 +535,7 @@ static struct usb_driver smsusb_driver = {
+ .resume = smsusb_resume,
+ };
+
+-int smsusb_register(void)
++int smsusb_module_init(void)
+ {
+ int rc = usb_register(&smsusb_driver);
+ if (rc)
+@@ -495,10 +546,16 @@ int smsusb_register(void)
+ return rc;
+ }
+
+-void smsusb_unregister(void)
++void smsusb_module_exit(void)
+ {
+ sms_debug("");
+ /* Regular USB Cleanup */
+ usb_deregister(&smsusb_driver);
+ }
+
++module_init(smsusb_module_init);
++module_exit(smsusb_module_exit);
++
++MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
++MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
+index ab0bcd2..7729904 100644
+--- a/drivers/media/dvb/ttpci/Kconfig
++++ b/drivers/media/dvb/ttpci/Kconfig
+@@ -108,7 +108,7 @@ config DVB_BUDGET_CI
+ select DVB_STB6100 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+ select VIDEO_IR
+ help
+ Support for simple SAA7146 based DVB cards
+diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
+index aa1ff52..4624cee 100644
+--- a/drivers/media/dvb/ttpci/av7110.c
++++ b/drivers/media/dvb/ttpci/av7110.c
+@@ -725,7 +725,7 @@ static int dvb_osd_ioctl(struct inode *inode, struct file *file,
+ }
+
+
+-static struct file_operations dvb_osd_fops = {
++static const struct file_operations dvb_osd_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = dvb_generic_ioctl,
+ .open = dvb_generic_open,
+diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
+index bdc62ac..e4d0900 100644
+--- a/drivers/media/dvb/ttpci/av7110_av.c
++++ b/drivers/media/dvb/ttpci/av7110_av.c
+@@ -1456,7 +1456,7 @@ static int dvb_audio_release(struct inode *inode, struct file *file)
+ * driver registration
+ ******************************************************************************/
+
+-static struct file_operations dvb_video_fops = {
++static const struct file_operations dvb_video_fops = {
+ .owner = THIS_MODULE,
+ .write = dvb_video_write,
+ .ioctl = dvb_generic_ioctl,
+@@ -1474,7 +1474,7 @@ static struct dvb_device dvbdev_video = {
+ .kernel_ioctl = dvb_video_ioctl,
+ };
+
+-static struct file_operations dvb_audio_fops = {
++static const struct file_operations dvb_audio_fops = {
+ .owner = THIS_MODULE,
+ .write = dvb_audio_write,
+ .ioctl = dvb_generic_ioctl,
+diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
+index 261135d..c7a65b1 100644
+--- a/drivers/media/dvb/ttpci/av7110_ca.c
++++ b/drivers/media/dvb/ttpci/av7110_ca.c
+@@ -345,7 +345,7 @@ static ssize_t dvb_ca_read(struct file *file, char __user *buf,
+ return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
+ }
+
+-static struct file_operations dvb_ca_fops = {
++static const struct file_operations dvb_ca_fops = {
+ .owner = THIS_MODULE,
+ .read = dvb_ca_read,
+ .write = dvb_ca_write,
+diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
+index c5b9c70..2210cff 100644
+--- a/drivers/media/dvb/ttpci/av7110_v4l.c
++++ b/drivers/media/dvb/ttpci/av7110_v4l.c
+@@ -316,253 +316,261 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
+ return 0;
+ }
+
+-static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
++static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+ {
+- struct saa7146_dev *dev = fh->dev;
+- struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+- dprintk(4, "saa7146_dev: %p\n", dev);
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
++ u16 stereo_det;
++ s8 stereo;
+
+- switch (cmd) {
+- case VIDIOC_G_TUNER:
+- {
+- struct v4l2_tuner *t = arg;
+- u16 stereo_det;
+- s8 stereo;
++ dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
+
+- dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
++ if (!av7110->analog_tuner_flags || t->index != 0)
++ return -EINVAL;
+
+- if (!av7110->analog_tuner_flags || t->index != 0)
+- return -EINVAL;
++ memset(t, 0, sizeof(*t));
++ strcpy((char *)t->name, "Television");
++
++ t->type = V4L2_TUNER_ANALOG_TV;
++ t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
++ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
++ t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
++ t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
++ /* FIXME: add the real signal strength here */
++ t->signal = 0xffff;
++ t->afc = 0;
++
++ /* FIXME: standard / stereo detection is still broken */
++ msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
++ dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
++ msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
++ dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
++ stereo = (s8)(stereo_det >> 8);
++ if (stereo > 0x10) {
++ /* stereo */
++ t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
++ t->audmode = V4L2_TUNER_MODE_STEREO;
++ } else if (stereo < -0x10) {
++ /* bilingual */
++ t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
++ t->audmode = V4L2_TUNER_MODE_LANG1;
++ } else /* mono */
++ t->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+- memset(t, 0, sizeof(*t));
+- strcpy((char *)t->name, "Television");
+-
+- t->type = V4L2_TUNER_ANALOG_TV;
+- t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
+- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+- t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
+- t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
+- /* FIXME: add the real signal strength here */
+- t->signal = 0xffff;
+- t->afc = 0;
+-
+- // FIXME: standard / stereo detection is still broken
+- msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
+- dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
+- msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
+- dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
+- stereo = (s8)(stereo_det >> 8);
+- if (stereo > 0x10) {
+- /* stereo */
+- t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+- t->audmode = V4L2_TUNER_MODE_STEREO;
+- }
+- else if (stereo < -0x10) {
+- /* bilingual */
+- t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+- t->audmode = V4L2_TUNER_MODE_LANG1;
+- }
+- else /* mono */
+- t->rxsubchans = V4L2_TUNER_SUB_MONO;
++ return 0;
++}
+
+- return 0;
+- }
+- case VIDIOC_S_TUNER:
+- {
+- struct v4l2_tuner *t = arg;
+- u16 fm_matrix, src;
+- dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
++static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
++ u16 fm_matrix, src;
++ dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
+
+- if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+- return -EINVAL;
++ if (!av7110->analog_tuner_flags || av7110->current_input != 1)
++ return -EINVAL;
+
+- switch (t->audmode) {
+- case V4L2_TUNER_MODE_STEREO:
+- dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
+- fm_matrix = 0x3001; // stereo
+- src = 0x0020;
+- break;
+- case V4L2_TUNER_MODE_LANG1_LANG2:
+- dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
+- fm_matrix = 0x3000; // bilingual
+- src = 0x0020;
+- break;
+- case V4L2_TUNER_MODE_LANG1:
+- dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
+- fm_matrix = 0x3000; // mono
+- src = 0x0000;
+- break;
+- case V4L2_TUNER_MODE_LANG2:
+- dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
+- fm_matrix = 0x3000; // mono
+- src = 0x0010;
+- break;
+- default: /* case V4L2_TUNER_MODE_MONO: */
+- dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
+- fm_matrix = 0x3000; // mono
+- src = 0x0030;
+- break;
+- }
+- msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
+- msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
+- msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
+- msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
+- return 0;
++ switch (t->audmode) {
++ case V4L2_TUNER_MODE_STEREO:
++ dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
++ fm_matrix = 0x3001; /* stereo */
++ src = 0x0020;
++ break;
++ case V4L2_TUNER_MODE_LANG1_LANG2:
++ dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
++ fm_matrix = 0x3000; /* bilingual */
++ src = 0x0020;
++ break;
++ case V4L2_TUNER_MODE_LANG1:
++ dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
++ fm_matrix = 0x3000; /* mono */
++ src = 0x0000;
++ break;
++ case V4L2_TUNER_MODE_LANG2:
++ dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
++ fm_matrix = 0x3000; /* mono */
++ src = 0x0010;
++ break;
++ default: /* case V4L2_TUNER_MODE_MONO: */
++ dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
++ fm_matrix = 0x3000; /* mono */
++ src = 0x0030;
++ break;
+ }
+- case VIDIOC_G_FREQUENCY:
+- {
+- struct v4l2_frequency *f = arg;
++ msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
++ msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
++ msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
++ msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
++ return 0;
++}
+
+- dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
++static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+- if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+- return -EINVAL;
++ dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
+
+- memset(f, 0, sizeof(*f));
+- f->type = V4L2_TUNER_ANALOG_TV;
+- f->frequency = av7110->current_freq;
+- return 0;
+- }
+- case VIDIOC_S_FREQUENCY:
+- {
+- struct v4l2_frequency *f = arg;
++ if (!av7110->analog_tuner_flags || av7110->current_input != 1)
++ return -EINVAL;
+
+- dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
++ memset(f, 0, sizeof(*f));
++ f->type = V4L2_TUNER_ANALOG_TV;
++ f->frequency = av7110->current_freq;
++ return 0;
++}
+
+- if (!av7110->analog_tuner_flags || av7110->current_input != 1)
+- return -EINVAL;
++static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+- if (V4L2_TUNER_ANALOG_TV != f->type)
+- return -EINVAL;
++ dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
+
+- msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); // fast mute
+- msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
++ if (!av7110->analog_tuner_flags || av7110->current_input != 1)
++ return -EINVAL;
+
+- /* tune in desired frequency */
+- if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
+- ves1820_set_tv_freq(dev, f->frequency);
+- } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
+- stv0297_set_tv_freq(dev, f->frequency);
+- }
+- av7110->current_freq = f->frequency;
++ if (V4L2_TUNER_ANALOG_TV != f->type)
++ return -EINVAL;
+
+- msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); // start stereo detection
+- msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
+- msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
+- msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
+- return 0;
+- }
+- case VIDIOC_ENUMINPUT:
+- {
+- struct v4l2_input *i = arg;
++ msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
++ msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
+
+- dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
++ /* tune in desired frequency */
++ if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820)
++ ves1820_set_tv_freq(dev, f->frequency);
++ else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297)
++ stv0297_set_tv_freq(dev, f->frequency);
++ av7110->current_freq = f->frequency;
+
+- if (av7110->analog_tuner_flags) {
+- if (i->index < 0 || i->index >= 4)
+- return -EINVAL;
+- } else {
+- if (i->index != 0)
+- return -EINVAL;
+- }
++ msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */
++ msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
++ msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */
++ msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */
++ return 0;
++}
+
+- memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
++static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
+- return 0;
++ dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
++
++ if (av7110->analog_tuner_flags) {
++ if (i->index < 0 || i->index >= 4)
++ return -EINVAL;
++ } else {
++ if (i->index != 0)
++ return -EINVAL;
+ }
+- case VIDIOC_G_INPUT:
+- {
+- int *input = (int *)arg;
+- *input = av7110->current_input;
+- dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
++
++ memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
++
++ return 0;
++}
++
++static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
++
++ *input = av7110->current_input;
++ dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
++ return 0;
++}
++
++static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
++
++ dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
++
++ if (!av7110->analog_tuner_flags)
+ return 0;
+- }
+- case VIDIOC_S_INPUT:
+- {
+- int input = *(int *)arg;
+
+- dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
++ if (input < 0 || input >= 4)
++ return -EINVAL;
+
+- if (!av7110->analog_tuner_flags)
+- return 0;
++ av7110->current_input = input;
++ return av7110_dvb_c_switch(fh);
++}
+
+- if (input < 0 || input >= 4)
+- return -EINVAL;
++static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
++{
++ dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
++ if (a->index != 0)
++ return -EINVAL;
++ memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
++ return 0;
++}
+
+- av7110->current_input = input;
+- return av7110_dvb_c_switch(fh);
+- }
+- case VIDIOC_G_AUDIO:
+- {
+- struct v4l2_audio *a = arg;
++static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
++{
++ dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
++ return 0;
++}
+
+- dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
+- if (a->index != 0)
+- return -EINVAL;
+- memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
+- break;
+- }
+- case VIDIOC_S_AUDIO:
+- {
+- struct v4l2_audio *a = arg;
+- dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
+- break;
+- }
+- case VIDIOC_G_SLICED_VBI_CAP:
+- {
+- struct v4l2_sliced_vbi_cap *cap = arg;
+- dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
+- memset(cap, 0, sizeof *cap);
+- if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+- cap->service_set = V4L2_SLICED_WSS_625;
+- cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+- }
+- break;
+- }
+- case VIDIOC_G_FMT:
+- {
+- struct v4l2_format *f = arg;
+- dprintk(2, "VIDIOC_G_FMT:\n");
+- if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+- FW_VERSION(av7110->arm_app) < 0x2623)
+- return -EAGAIN; /* handled by core driver */
+- memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+- if (av7110->wssMode) {
+- f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+- f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+- f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+- }
+- break;
++static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
++ struct v4l2_sliced_vbi_cap *cap)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
++
++ dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
++ if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
++ return -EINVAL;
++ if (FW_VERSION(av7110->arm_app) >= 0x2623) {
++ cap->service_set = V4L2_SLICED_WSS_625;
++ cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+ }
+- case VIDIOC_S_FMT:
+- {
+- struct v4l2_format *f = arg;
+- dprintk(2, "VIDIOC_S_FMT\n");
+- if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+- FW_VERSION(av7110->arm_app) < 0x2623)
+- return -EAGAIN; /* handled by core driver */
+- if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
+- f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
+- memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+- /* WSS controlled by firmware */
+- av7110->wssMode = 0;
+- av7110->wssData = 0;
+- return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
+- SetWSSConfig, 1, 0);
+- } else {
+- memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+- f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+- f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+- f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+- /* WSS controlled by userspace */
+- av7110->wssMode = 1;
+- av7110->wssData = 0;
+- }
+- break;
++ return 0;
++}
++
++static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
++ struct v4l2_format *f)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
++
++ dprintk(2, "VIDIOC_G_FMT:\n");
++ if (FW_VERSION(av7110->arm_app) < 0x2623)
++ return -EINVAL;
++ memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
++ if (av7110->wssMode) {
++ f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
++ f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
++ f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
+ }
+- default:
+- printk("no such ioctl\n");
+- return -ENOIOCTLCMD;
++ return 0;
++}
++
++static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
++ struct v4l2_format *f)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
++
++ dprintk(2, "VIDIOC_S_FMT\n");
++ if (FW_VERSION(av7110->arm_app) < 0x2623)
++ return -EINVAL;
++ if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
++ f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
++ memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
++ /* WSS controlled by firmware */
++ av7110->wssMode = 0;
++ av7110->wssData = 0;
++ return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
++ SetWSSConfig, 1, 0);
++ } else {
++ memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
++ f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
++ f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
++ f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
++ /* WSS controlled by userspace */
++ av7110->wssMode = 1;
++ av7110->wssData = 0;
+ }
+ return 0;
+ }
+@@ -609,22 +617,6 @@ static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size
+ * INITIALIZATION
+ ****************************************************************************/
+
+-static struct saa7146_extension_ioctls ioctls[] = {
+- { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
+- { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
+- { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
+- { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
+- { VIDIOC_G_FMT, SAA7146_BEFORE },
+- { VIDIOC_S_FMT, SAA7146_BEFORE },
+- { 0, 0 }
+-};
+-
+ static u8 saa7113_init_regs[] = {
+ 0x02, 0xd0,
+ 0x03, 0x23,
+@@ -788,20 +780,34 @@ int av7110_init_analog_module(struct av7110 *av7110)
+ int av7110_init_v4l(struct av7110 *av7110)
+ {
+ struct saa7146_dev* dev = av7110->dev;
++ struct saa7146_ext_vv *vv_data;
+ int ret;
+
+ /* special case DVB-C: these cards have an analog tuner
+ plus need some special handling, so we have separate
+ saa7146_ext_vv data for these... */
+ if (av7110->analog_tuner_flags)
+- ret = saa7146_vv_init(dev, &av7110_vv_data_c);
++ vv_data = &av7110_vv_data_c;
+ else
+- ret = saa7146_vv_init(dev, &av7110_vv_data_st);
++ vv_data = &av7110_vv_data_st;
++ ret = saa7146_vv_init(dev, vv_data);
+
+ if (ret) {
+ ERR(("cannot init capture device. skipping.\n"));
+ return -ENODEV;
+ }
++ vv_data->ops.vidioc_enum_input = vidioc_enum_input;
++ vv_data->ops.vidioc_g_input = vidioc_g_input;
++ vv_data->ops.vidioc_s_input = vidioc_s_input;
++ vv_data->ops.vidioc_g_tuner = vidioc_g_tuner;
++ vv_data->ops.vidioc_s_tuner = vidioc_s_tuner;
++ vv_data->ops.vidioc_g_frequency = vidioc_g_frequency;
++ vv_data->ops.vidioc_s_frequency = vidioc_s_frequency;
++ vv_data->ops.vidioc_g_audio = vidioc_g_audio;
++ vv_data->ops.vidioc_s_audio = vidioc_s_audio;
++ vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
++ vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
++ vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
+
+ if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
+ ERR(("cannot register capture device. skipping.\n"));
+@@ -900,9 +906,6 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
+ .num_stds = ARRAY_SIZE(standard),
+ .std_callback = &std_callback,
+
+- .ioctls = &ioctls[0],
+- .ioctl = av7110_ioctl,
+-
+ .vbi_fops.open = av7110_vbi_reset,
+ .vbi_fops.release = av7110_vbi_reset,
+ .vbi_fops.write = av7110_vbi_write,
+@@ -918,9 +921,6 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
+ .num_stds = ARRAY_SIZE(standard),
+ .std_callback = &std_callback,
+
+- .ioctls = &ioctls[0],
+- .ioctl = av7110_ioctl,
+-
+ .vbi_fops.open = av7110_vbi_reset,
+ .vbi_fops.release = av7110_vbi_reset,
+ .vbi_fops.write = av7110_vbi_write,
+diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
+index 4182121..855fe74 100644
+--- a/drivers/media/dvb/ttpci/budget-av.c
++++ b/drivers/media/dvb/ttpci/budget-av.c
+@@ -1404,6 +1404,41 @@ static int budget_av_detach(struct saa7146_dev *dev)
+ return err;
+ }
+
++#define KNC1_INPUTS 2
++static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
++ {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
++ {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
++};
++
++static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
++{
++ dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
++ if (i->index < 0 || i->index >= KNC1_INPUTS)
++ return -EINVAL;
++ memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
++ return 0;
++}
++
++static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
++
++ *i = budget_av->cur_input;
++
++ dprintk(1, "VIDIOC_G_INPUT %d.\n", *i);
++ return 0;
++}
++
++static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
++
++ dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
++ return saa7113_setinput(budget_av, input);
++}
++
+ static struct saa7146_ext_vv vv_data;
+
+ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
+@@ -1442,6 +1477,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
+ ERR(("cannot init vv subsystem.\n"));
+ return err;
+ }
++ vv_data.ops.vidioc_enum_input = vidioc_enum_input;
++ vv_data.ops.vidioc_g_input = vidioc_g_input;
++ vv_data.ops.vidioc_s_input = vidioc_s_input;
+
+ if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
+ /* fixme: proper cleanup here */
+@@ -1480,54 +1518,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
+ return 0;
+ }
+
+-#define KNC1_INPUTS 2
+-static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
+- {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
+- {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
+-};
+-
+-static struct saa7146_extension_ioctls ioctls[] = {
+- {VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE},
+- {VIDIOC_G_INPUT, SAA7146_EXCLUSIVE},
+- {VIDIOC_S_INPUT, SAA7146_EXCLUSIVE},
+- {0, 0}
+-};
+-
+-static long av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+-{
+- struct saa7146_dev *dev = fh->dev;
+- struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
+-
+- switch (cmd) {
+- case VIDIOC_ENUMINPUT:{
+- struct v4l2_input *i = arg;
+-
+- dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
+- if (i->index < 0 || i->index >= KNC1_INPUTS) {
+- return -EINVAL;
+- }
+- memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
+- return 0;
+- }
+- case VIDIOC_G_INPUT:{
+- int *input = (int *) arg;
+-
+- *input = budget_av->cur_input;
+-
+- dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
+- return 0;
+- }
+- case VIDIOC_S_INPUT:{
+- int input = *(int *) arg;
+- dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
+- return saa7113_setinput(budget_av, input);
+- }
+- default:
+- return -ENOIOCTLCMD;
+- }
+- return 0;
+-}
+-
+ static struct saa7146_standard standard[] = {
+ {.name = "PAL",.id = V4L2_STD_PAL,
+ .v_offset = 0x17,.v_field = 288,
+@@ -1546,8 +1536,6 @@ static struct saa7146_ext_vv vv_data = {
+ .flags = 0,
+ .stds = &standard[0],
+ .num_stds = ARRAY_SIZE(standard),
+- .ioctls = &ioctls[0],
+- .ioctl = av_ioctl,
+ };
+
+ static struct saa7146_extension budget_extension;
+diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
+index bcbc5d4..371a716 100644
+--- a/drivers/media/dvb/ttpci/budget-ci.c
++++ b/drivers/media/dvb/ttpci/budget-ci.c
+@@ -1076,6 +1076,10 @@ static struct tda10023_config tda10023_config = {
+ .deltaf = 0xa511,
+ };
+
++static struct tda827x_config tda827x_config = {
++ .config = 0,
++};
++
+ /* TT S2-3200 DVB-S (STB0899) Inittab */
+ static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
+
+@@ -1414,7 +1418,7 @@ static void frontend_init(struct budget_ci *budget_ci)
+ case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
+ budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
+ if (budget_ci->budget.dvb_frontend) {
+- if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
++ if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) {
+ printk(KERN_ERR "%s: No tda827x found!\n", __func__);
+ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+ budget_ci->budget.dvb_frontend = NULL;
+diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
+index 2014ebc..cc54ed4 100644
+--- a/drivers/media/radio/dsbr100.c
++++ b/drivers/media/radio/dsbr100.c
+@@ -390,9 +390,11 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
+ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+ {
++ struct dsbr100_device *radio = video_drvdata(file);
++
+ strlcpy(v->driver, "dsbr100", sizeof(v->driver));
+ strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
+- sprintf(v->bus_info, "USB");
++ usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+ return 0;
+@@ -450,7 +452,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
+ if (radio->removed)
+ return -EIO;
+
++ mutex_lock(&radio->lock);
+ radio->curfreq = f->frequency;
++ mutex_unlock(&radio->lock);
++
+ retval = dsbr100_setfreq(radio, radio->curfreq);
+ if (retval < 0)
+ dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
+@@ -601,7 +606,10 @@ static int usb_dsbr100_close(struct file *file)
+ if (!radio)
+ return -ENODEV;
+
++ mutex_lock(&radio->lock);
+ radio->users = 0;
++ mutex_unlock(&radio->lock);
++
+ if (!radio->removed) {
+ retval = dsbr100_stop(radio);
+ if (retval < 0) {
+diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
+index bfa13b8..ac82e33 100644
+--- a/drivers/media/radio/radio-aimslab.c
++++ b/drivers/media/radio/radio-aimslab.c
+@@ -32,14 +32,15 @@
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay */
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/videodev2.h> /* kernel radio structs */
+-#include <media/v4l2-common.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#include <linux/io.h> /* outb, outb_p */
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++MODULE_AUTHOR("M.Kirkwood");
++MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
++MODULE_LICENSE("GPL");
+
+ #ifndef CONFIG_RADIO_RTRACK_PORT
+ #define CONFIG_RADIO_RTRACK_PORT -1
+@@ -47,86 +48,95 @@
+
+ static int io = CONFIG_RADIO_RTRACK_PORT;
+ static int radio_nr = -1;
+-static struct mutex lock;
+
+-struct rt_device
++module_param(io, int, 0);
++MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
++module_param(radio_nr, int, 0);
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
++
++struct rtrack
+ {
+- unsigned long in_use;
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
+ int port;
+ int curvol;
+ unsigned long curfreq;
+ int muted;
++ int io;
++ struct mutex lock;
+ };
+
++static struct rtrack rtrack_card;
+
+ /* local things */
+
+ static void sleep_delay(long n)
+ {
+ /* Sleep nicely for 'n' uS */
+- int d=n/msecs_to_jiffies(1000);
+- if(!d)
++ int d = n / msecs_to_jiffies(1000);
++ if (!d)
+ udelay(n);
+ else
+ msleep(jiffies_to_msecs(d));
+ }
+
+-static void rt_decvol(void)
++static void rt_decvol(struct rtrack *rt)
+ {
+- outb(0x58, io); /* volume down + sigstr + on */
++ outb(0x58, rt->io); /* volume down + sigstr + on */
+ sleep_delay(100000);
+- outb(0xd8, io); /* volume steady + sigstr + on */
++ outb(0xd8, rt->io); /* volume steady + sigstr + on */
+ }
+
+-static void rt_incvol(void)
++static void rt_incvol(struct rtrack *rt)
+ {
+- outb(0x98, io); /* volume up + sigstr + on */
++ outb(0x98, rt->io); /* volume up + sigstr + on */
+ sleep_delay(100000);
+- outb(0xd8, io); /* volume steady + sigstr + on */
++ outb(0xd8, rt->io); /* volume steady + sigstr + on */
+ }
+
+-static void rt_mute(struct rt_device *dev)
++static void rt_mute(struct rtrack *rt)
+ {
+- dev->muted = 1;
+- mutex_lock(&lock);
+- outb(0xd0, io); /* volume steady, off */
+- mutex_unlock(&lock);
++ rt->muted = 1;
++ mutex_lock(&rt->lock);
++ outb(0xd0, rt->io); /* volume steady, off */
++ mutex_unlock(&rt->lock);
+ }
+
+-static int rt_setvol(struct rt_device *dev, int vol)
++static int rt_setvol(struct rtrack *rt, int vol)
+ {
+ int i;
+
+- mutex_lock(&lock);
++ mutex_lock(&rt->lock);
+
+- if(vol == dev->curvol) { /* requested volume = current */
+- if (dev->muted) { /* user is unmuting the card */
+- dev->muted = 0;
+- outb (0xd8, io); /* enable card */
++ if (vol == rt->curvol) { /* requested volume = current */
++ if (rt->muted) { /* user is unmuting the card */
++ rt->muted = 0;
++ outb(0xd8, rt->io); /* enable card */
+ }
+- mutex_unlock(&lock);
++ mutex_unlock(&rt->lock);
+ return 0;
+ }
+
+- if(vol == 0) { /* volume = 0 means mute the card */
+- outb(0x48, io); /* volume down but still "on" */
++ if (vol == 0) { /* volume = 0 means mute the card */
++ outb(0x48, rt->io); /* volume down but still "on" */
+ sleep_delay(2000000); /* make sure it's totally down */
+- outb(0xd0, io); /* volume steady, off */
+- dev->curvol = 0; /* track the volume state! */
+- mutex_unlock(&lock);
++ outb(0xd0, rt->io); /* volume steady, off */
++ rt->curvol = 0; /* track the volume state! */
++ mutex_unlock(&rt->lock);
+ return 0;
+ }
+
+- dev->muted = 0;
+- if(vol > dev->curvol)
+- for(i = dev->curvol; i < vol; i++)
+- rt_incvol();
++ rt->muted = 0;
++ if (vol > rt->curvol)
++ for (i = rt->curvol; i < vol; i++)
++ rt_incvol(rt);
+ else
+- for(i = dev->curvol; i > vol; i--)
+- rt_decvol();
++ for (i = rt->curvol; i > vol; i--)
++ rt_decvol(rt);
+
+- dev->curvol = vol;
+- mutex_unlock(&lock);
++ rt->curvol = vol;
++ mutex_unlock(&rt->lock);
+ return 0;
+ }
+
+@@ -135,155 +145,137 @@ static int rt_setvol(struct rt_device *dev, int vol)
+ * and bit 4 (+16) is to keep the signal strength meter enabled
+ */
+
+-static void send_0_byte(int port, struct rt_device *dev)
++static void send_0_byte(struct rtrack *rt)
+ {
+- if ((dev->curvol == 0) || (dev->muted)) {
+- outb_p(128+64+16+ 1, port); /* wr-enable + data low */
+- outb_p(128+64+16+2+1, port); /* clock */
++ if (rt->curvol == 0 || rt->muted) {
++ outb_p(128+64+16+ 1, rt->io); /* wr-enable + data low */
++ outb_p(128+64+16+2+1, rt->io); /* clock */
+ }
+ else {
+- outb_p(128+64+16+8+ 1, port); /* on + wr-enable + data low */
+- outb_p(128+64+16+8+2+1, port); /* clock */
++ outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */
++ outb_p(128+64+16+8+2+1, rt->io); /* clock */
+ }
+ sleep_delay(1000);
+ }
+
+-static void send_1_byte(int port, struct rt_device *dev)
++static void send_1_byte(struct rtrack *rt)
+ {
+- if ((dev->curvol == 0) || (dev->muted)) {
+- outb_p(128+64+16+4 +1, port); /* wr-enable+data high */
+- outb_p(128+64+16+4+2+1, port); /* clock */
++ if (rt->curvol == 0 || rt->muted) {
++ outb_p(128+64+16+4 +1, rt->io); /* wr-enable+data high */
++ outb_p(128+64+16+4+2+1, rt->io); /* clock */
+ }
+ else {
+- outb_p(128+64+16+8+4 +1, port); /* on+wr-enable+data high */
+- outb_p(128+64+16+8+4+2+1, port); /* clock */
++ outb_p(128+64+16+8+4 +1, rt->io); /* on+wr-enable+data high */
++ outb_p(128+64+16+8+4+2+1, rt->io); /* clock */
+ }
+
+ sleep_delay(1000);
+ }
+
+-static int rt_setfreq(struct rt_device *dev, unsigned long freq)
++static int rt_setfreq(struct rtrack *rt, unsigned long freq)
+ {
+ int i;
+
+- /* adapted from radio-aztech.c */
++ mutex_lock(&rt->lock); /* Stop other ops interfering */
++
++ rt->curfreq = freq;
+
+ /* now uses VIDEO_TUNER_LOW for fine tuning */
+
+ freq += 171200; /* Add 10.7 MHz IF */
+ freq /= 800; /* Convert to 50 kHz units */
+
+- mutex_lock(&lock); /* Stop other ops interfering */
+-
+- send_0_byte (io, dev); /* 0: LSB of frequency */
++ send_0_byte(rt); /* 0: LSB of frequency */
+
+ for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
+ if (freq & (1 << i))
+- send_1_byte (io, dev);
++ send_1_byte(rt);
+ else
+- send_0_byte (io, dev);
++ send_0_byte(rt);
+
+- send_0_byte (io, dev); /* 14: test bit - always 0 */
+- send_0_byte (io, dev); /* 15: test bit - always 0 */
++ send_0_byte(rt); /* 14: test bit - always 0 */
++ send_0_byte(rt); /* 15: test bit - always 0 */
+
+- send_0_byte (io, dev); /* 16: band data 0 - always 0 */
+- send_0_byte (io, dev); /* 17: band data 1 - always 0 */
+- send_0_byte (io, dev); /* 18: band data 2 - always 0 */
+- send_0_byte (io, dev); /* 19: time base - always 0 */
++ send_0_byte(rt); /* 16: band data 0 - always 0 */
++ send_0_byte(rt); /* 17: band data 1 - always 0 */
++ send_0_byte(rt); /* 18: band data 2 - always 0 */
++ send_0_byte(rt); /* 19: time base - always 0 */
+
+- send_0_byte (io, dev); /* 20: spacing (0 = 25 kHz) */
+- send_1_byte (io, dev); /* 21: spacing (1 = 25 kHz) */
+- send_0_byte (io, dev); /* 22: spacing (0 = 25 kHz) */
+- send_1_byte (io, dev); /* 23: AM/FM (FM = 1, always) */
++ send_0_byte(rt); /* 20: spacing (0 = 25 kHz) */
++ send_1_byte(rt); /* 21: spacing (1 = 25 kHz) */
++ send_0_byte(rt); /* 22: spacing (0 = 25 kHz) */
++ send_1_byte(rt); /* 23: AM/FM (FM = 1, always) */
+
+- if ((dev->curvol == 0) || (dev->muted))
+- outb (0xd0, io); /* volume steady + sigstr */
++ if (rt->curvol == 0 || rt->muted)
++ outb(0xd0, rt->io); /* volume steady + sigstr */
+ else
+- outb (0xd8, io); /* volume steady + sigstr + on */
++ outb(0xd8, rt->io); /* volume steady + sigstr + on */
+
+- mutex_unlock(&lock);
++ mutex_unlock(&rt->lock);
+
+ return 0;
+ }
+
+-static int rt_getsigstr(struct rt_device *dev)
++static int rt_getsigstr(struct rtrack *rt)
+ {
+- if (inb(io) & 2) /* bit set = no signal present */
+- return 0;
+- return 1; /* signal present */
+-}
++ int sig = 1;
+
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- },{
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 0xff,
+- .step = 1,
+- .default_value = 0xff,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- }
+-};
++ mutex_lock(&rt->lock);
++ if (inb(rt->io) & 2) /* bit set = no signal present */
++ sig = 0;
++ mutex_unlock(&rt->lock);
++ return sig;
++}
+
+ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+ {
+ strlcpy(v->driver, "radio-aimslab", sizeof(v->driver));
+ strlcpy(v->card, "RadioTrack", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack *rt = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+- v->rangelow = (87*16000);
+- v->rangehigh = (108*16000);
++ v->rangelow = 87 * 16000;
++ v->rangehigh = 108 * 16000;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v->capability = V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
+- v->signal = 0xffff*rt_getsigstr(rt);
++ v->signal = 0xffff * rt_getsigstr(rt);
+ return 0;
+ }
+
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack *rt = video_drvdata(file);
+
+- rt->curfreq = f->frequency;
+- rt_setfreq(rt, rt->curfreq);
++ rt_setfreq(rt, f->frequency);
+ return 0;
+ }
+
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack *rt = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = rt->curfreq;
+@@ -293,14 +285,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
+ }
+ return -EINVAL;
+ }
+@@ -308,14 +297,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack *rt = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = rt->muted;
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+- ctrl->value = rt->curvol * 6554;
++ ctrl->value = rt->curvol;
+ return 0;
+ }
+ return -EINVAL;
+@@ -324,33 +313,22 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack *rt = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value)
+ rt_mute(rt);
+ else
+- rt_setvol(rt,rt->curvol);
++ rt_setvol(rt, rt->curvol);
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+- rt_setvol(rt,ctrl->value);
++ rt_setvol(rt, ctrl->value);
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+-static int vidioc_g_audio (struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -359,36 +337,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
+- return 0;
++ return i ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_audio(struct file *file, void *priv,
++static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+-static struct rt_device rtrack_unit;
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ return a->index ? -EINVAL : 0;
++}
+
+-static int rtrack_exclusive_open(struct file *file)
++static int rtrack_open(struct file *file)
+ {
+- return test_and_set_bit(0, &rtrack_unit.in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int rtrack_exclusive_release(struct file *file)
++static int rtrack_release(struct file *file)
+ {
+- clear_bit(0, &rtrack_unit.in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations rtrack_fops = {
+ .owner = THIS_MODULE,
+- .open = rtrack_exclusive_open,
+- .release = rtrack_exclusive_release,
++ .open = rtrack_open,
++ .release = rtrack_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -407,64 +387,69 @@ static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ };
+
+-static struct video_device rtrack_radio = {
+- .name = "RadioTrack radio",
+- .fops = &rtrack_fops,
+- .ioctl_ops = &rtrack_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ static int __init rtrack_init(void)
+ {
+- if(io==-1)
+- {
+- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
++ struct rtrack *rt = &rtrack_card;
++ struct v4l2_device *v4l2_dev = &rt->v4l2_dev;
++ int res;
++
++ strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name));
++ rt->io = io;
++
++ if (rt->io == -1) {
++ v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n");
+ return -EINVAL;
+ }
+
+- if (!request_region(io, 2, "rtrack"))
+- {
+- printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
++ if (!request_region(rt->io, 2, "rtrack")) {
++ v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io);
+ return -EBUSY;
+ }
+
+- video_set_drvdata(&rtrack_radio, &rtrack_unit);
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(rt->io, 2);
++ v4l2_err(v4l2_dev, "could not register v4l2_device\n");
++ return res;
++ }
+
+- if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io, 2);
++ strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name));
++ rt->vdev.v4l2_dev = v4l2_dev;
++ rt->vdev.fops = &rtrack_fops;
++ rt->vdev.ioctl_ops = &rtrack_ioctl_ops;
++ rt->vdev.release = video_device_release_empty;
++ video_set_drvdata(&rt->vdev, rt);
++
++ if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(&rt->v4l2_dev);
++ release_region(rt->io, 2);
+ return -EINVAL;
+ }
+- printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n");
++ v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
+
+ /* Set up the I/O locking */
+
+- mutex_init(&lock);
++ mutex_init(&rt->lock);
+
+ /* mute card - prevents noisy bootups */
+
+ /* this ensures that the volume is all the way down */
+- outb(0x48, io); /* volume down but still "on" */
++ outb(0x48, rt->io); /* volume down but still "on" */
+ sleep_delay(2000000); /* make sure it's totally down */
+- outb(0xc0, io); /* steady volume, mute card */
+- rtrack_unit.curvol = 0;
++ outb(0xc0, rt->io); /* steady volume, mute card */
+
+ return 0;
+ }
+
+-MODULE_AUTHOR("M.Kirkwood");
+-MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
+-MODULE_LICENSE("GPL");
+-
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
+-module_param(radio_nr, int, 0);
+-
+-static void __exit cleanup_rtrack_module(void)
++static void __exit rtrack_exit(void)
+ {
+- video_unregister_device(&rtrack_radio);
+- release_region(io,2);
++ struct rtrack *rt = &rtrack_card;
++
++ video_unregister_device(&rt->vdev);
++ v4l2_device_unregister(&rt->v4l2_dev);
++ release_region(rt->io, 2);
+ }
+
+ module_init(rtrack_init);
+-module_exit(cleanup_rtrack_module);
++module_exit(rtrack_exit);
+
+diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
+index 5604e88..49299f7 100644
+--- a/drivers/media/radio/radio-aztech.c
++++ b/drivers/media/radio/radio-aztech.c
+@@ -29,33 +29,15 @@
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay */
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/videodev2.h> /* kernel radio structs */
+-#include <media/v4l2-common.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#include <linux/io.h> /* outb, outb_p */
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+-
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- },{
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 0xff,
+- .step = 1,
+- .default_value = 0xff,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- }
+-};
++MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
++MODULE_DESCRIPTION("A driver for the Aztech radio card.");
++MODULE_LICENSE("GPL");
+
+ /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
+
+@@ -66,55 +48,64 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+ static int io = CONFIG_RADIO_AZTECH_PORT;
+ static int radio_nr = -1;
+ static int radio_wait_time = 1000;
+-static struct mutex lock;
+
+-struct az_device
++module_param(io, int, 0);
++module_param(radio_nr, int, 0);
++MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
++
++struct aztech
+ {
+- unsigned long in_use;
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ int io;
+ int curvol;
+ unsigned long curfreq;
+ int stereo;
++ struct mutex lock;
+ };
+
++static struct aztech aztech_card;
++
+ static int volconvert(int level)
+ {
+- level>>=14; /* Map 16bits down to 2 bit */
+- level&=3;
++ level >>= 14; /* Map 16bits down to 2 bit */
++ level &= 3;
+
+ /* convert to card-friendly values */
+- switch (level)
+- {
+- case 0:
+- return 0;
+- case 1:
+- return 1;
+- case 2:
+- return 4;
+- case 3:
+- return 5;
++ switch (level) {
++ case 0:
++ return 0;
++ case 1:
++ return 1;
++ case 2:
++ return 4;
++ case 3:
++ return 5;
+ }
+ return 0; /* Quieten gcc */
+ }
+
+-static void send_0_byte (struct az_device *dev)
++static void send_0_byte(struct aztech *az)
+ {
+ udelay(radio_wait_time);
+- outb_p(2+volconvert(dev->curvol), io);
+- outb_p(64+2+volconvert(dev->curvol), io);
++ outb_p(2 + volconvert(az->curvol), az->io);
++ outb_p(64 + 2 + volconvert(az->curvol), az->io);
+ }
+
+-static void send_1_byte (struct az_device *dev)
++static void send_1_byte(struct aztech *az)
+ {
+ udelay (radio_wait_time);
+- outb_p(128+2+volconvert(dev->curvol), io);
+- outb_p(128+64+2+volconvert(dev->curvol), io);
++ outb_p(128 + 2 + volconvert(az->curvol), az->io);
++ outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io);
+ }
+
+-static int az_setvol(struct az_device *dev, int vol)
++static int az_setvol(struct aztech *az, int vol)
+ {
+- mutex_lock(&lock);
+- outb (volconvert(vol), io);
+- mutex_unlock(&lock);
++ mutex_lock(&az->lock);
++ outb(volconvert(vol), az->io);
++ mutex_unlock(&az->lock);
+ return 0;
+ }
+
+@@ -126,116 +117,110 @@ static int az_setvol(struct az_device *dev, int vol)
+ *
+ */
+
+-static int az_getsigstr(struct az_device *dev)
++static int az_getsigstr(struct aztech *az)
+ {
+- if (inb(io) & 2) /* bit set = no signal present */
+- return 0;
+- return 1; /* signal present */
++ int sig = 1;
++
++ mutex_lock(&az->lock);
++ if (inb(az->io) & 2) /* bit set = no signal present */
++ sig = 0;
++ mutex_unlock(&az->lock);
++ return sig;
+ }
+
+-static int az_getstereo(struct az_device *dev)
++static int az_getstereo(struct aztech *az)
+ {
+- if (inb(io) & 1) /* bit set = mono */
+- return 0;
+- return 1; /* stereo */
++ int stereo = 1;
++
++ mutex_lock(&az->lock);
++ if (inb(az->io) & 1) /* bit set = mono */
++ stereo = 0;
++ mutex_unlock(&az->lock);
++ return stereo;
+ }
+
+-static int az_setfreq(struct az_device *dev, unsigned long frequency)
++static int az_setfreq(struct aztech *az, unsigned long frequency)
+ {
+ int i;
+
++ mutex_lock(&az->lock);
++
++ az->curfreq = frequency;
+ frequency += 171200; /* Add 10.7 MHz IF */
+ frequency /= 800; /* Convert to 50 kHz units */
+
+- mutex_lock(&lock);
+-
+- send_0_byte (dev); /* 0: LSB of frequency */
++ send_0_byte(az); /* 0: LSB of frequency */
+
+ for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
+ if (frequency & (1 << i))
+- send_1_byte (dev);
++ send_1_byte(az);
+ else
+- send_0_byte (dev);
++ send_0_byte(az);
+
+- send_0_byte (dev); /* 14: test bit - always 0 */
+- send_0_byte (dev); /* 15: test bit - always 0 */
+- send_0_byte (dev); /* 16: band data 0 - always 0 */
+- if (dev->stereo) /* 17: stereo (1 to enable) */
+- send_1_byte (dev);
++ send_0_byte(az); /* 14: test bit - always 0 */
++ send_0_byte(az); /* 15: test bit - always 0 */
++ send_0_byte(az); /* 16: band data 0 - always 0 */
++ if (az->stereo) /* 17: stereo (1 to enable) */
++ send_1_byte(az);
+ else
+- send_0_byte (dev);
++ send_0_byte(az);
+
+- send_1_byte (dev); /* 18: band data 1 - unknown */
+- send_0_byte (dev); /* 19: time base - always 0 */
+- send_0_byte (dev); /* 20: spacing (0 = 25 kHz) */
+- send_1_byte (dev); /* 21: spacing (1 = 25 kHz) */
+- send_0_byte (dev); /* 22: spacing (0 = 25 kHz) */
+- send_1_byte (dev); /* 23: AM/FM (FM = 1, always) */
++ send_1_byte(az); /* 18: band data 1 - unknown */
++ send_0_byte(az); /* 19: time base - always 0 */
++ send_0_byte(az); /* 20: spacing (0 = 25 kHz) */
++ send_1_byte(az); /* 21: spacing (1 = 25 kHz) */
++ send_0_byte(az); /* 22: spacing (0 = 25 kHz) */
++ send_1_byte(az); /* 23: AM/FM (FM = 1, always) */
+
+ /* latch frequency */
+
+- udelay (radio_wait_time);
+- outb_p(128+64+volconvert(dev->curvol), io);
++ udelay(radio_wait_time);
++ outb_p(128 + 64 + volconvert(az->curvol), az->io);
+
+- mutex_unlock(&lock);
++ mutex_unlock(&az->lock);
+
+ return 0;
+ }
+
+-static int vidioc_querycap (struct file *file, void *priv,
++static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+ {
+- strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
+- strlcpy(v->card, "Aztech Radio", sizeof (v->card));
+- sprintf(v->bus_info,"ISA");
++ strlcpy(v->driver, "radio-aztech", sizeof(v->driver));
++ strlcpy(v->card, "Aztech Radio", sizeof(v->card));
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+-static int vidioc_g_tuner (struct file *file, void *priv,
++static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- struct az_device *az = video_drvdata(file);
++ struct aztech *az = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+
+- v->rangelow=(87*16000);
+- v->rangehigh=(108*16000);
+- v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+- v->capability=V4L2_TUNER_CAP_LOW;
+- if(az_getstereo(az))
++ v->rangelow = 87 * 16000;
++ v->rangehigh = 108 * 16000;
++ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
++ v->capability = V4L2_TUNER_CAP_LOW;
++ if (az_getstereo(az))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+- v->signal=0xFFFF*az_getsigstr(az);
++ v->signal = 0xFFFF * az_getsigstr(az);
+
+ return 0;
+ }
+
+-
+-static int vidioc_s_tuner (struct file *file, void *priv,
++static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+-
+- return 0;
+-}
+-
+-static int vidioc_g_audio (struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+@@ -246,113 +231,107 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
+- return 0;
++ return i ? -EINVAL : 0;
+ }
+
+-
+-static int vidioc_s_audio (struct file *file, void *priv,
++static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
+-
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+-static int vidioc_s_frequency (struct file *file, void *priv,
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ return a->index ? -EINVAL : 0;
++}
++
++static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct az_device *az = video_drvdata(file);
++ struct aztech *az = video_drvdata(file);
+
+- az->curfreq = f->frequency;
+- az_setfreq(az, az->curfreq);
++ az_setfreq(az, f->frequency);
+ return 0;
+ }
+
+-static int vidioc_g_frequency (struct file *file, void *priv,
++static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct az_device *az = video_drvdata(file);
++ struct aztech *az = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = az->curfreq;
+-
+ return 0;
+ }
+
+-static int vidioc_queryctrl (struct file *file, void *priv,
++static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return (0);
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
+ }
+ return -EINVAL;
+ }
+
+-static int vidioc_g_ctrl (struct file *file, void *priv,
++static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct az_device *az = video_drvdata(file);
++ struct aztech *az = video_drvdata(file);
+
+ switch (ctrl->id) {
+- case V4L2_CID_AUDIO_MUTE:
+- if (az->curvol==0)
+- ctrl->value=1;
+- else
+- ctrl->value=0;
+- return (0);
+- case V4L2_CID_AUDIO_VOLUME:
+- ctrl->value=az->curvol * 6554;
+- return (0);
++ case V4L2_CID_AUDIO_MUTE:
++ if (az->curvol == 0)
++ ctrl->value = 1;
++ else
++ ctrl->value = 0;
++ return 0;
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value = az->curvol * 6554;
++ return 0;
+ }
+ return -EINVAL;
+ }
+
+-static int vidioc_s_ctrl (struct file *file, void *priv,
++static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct az_device *az = video_drvdata(file);
++ struct aztech *az = video_drvdata(file);
+
+ switch (ctrl->id) {
+- case V4L2_CID_AUDIO_MUTE:
+- if (ctrl->value) {
+- az_setvol(az,0);
+- } else {
+- az_setvol(az,az->curvol);
+- }
+- return (0);
+- case V4L2_CID_AUDIO_VOLUME:
+- az_setvol(az,ctrl->value);
+- return (0);
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value)
++ az_setvol(az, 0);
++ else
++ az_setvol(az, az->curvol);
++ return 0;
++ case V4L2_CID_AUDIO_VOLUME:
++ az_setvol(az, ctrl->value);
++ return 0;
+ }
+ return -EINVAL;
+ }
+
+-static struct az_device aztech_unit;
+-
+-static int aztech_exclusive_open(struct file *file)
++static int aztech_open(struct file *file)
+ {
+- return test_and_set_bit(0, &aztech_unit.in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int aztech_exclusive_release(struct file *file)
++static int aztech_release(struct file *file)
+ {
+- clear_bit(0, &aztech_unit.in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations aztech_fops = {
+ .owner = THIS_MODULE,
+- .open = aztech_exclusive_open,
+- .release = aztech_exclusive_release,
++ .open = aztech_open,
++ .release = aztech_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -371,57 +350,60 @@ static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ };
+
+-static struct video_device aztech_radio = {
+- .name = "Aztech radio",
+- .fops = &aztech_fops,
+- .ioctl_ops = &aztech_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+-module_param_named(debug,aztech_radio.debug, int, 0644);
+-MODULE_PARM_DESC(debug,"activates debug info");
+-
+ static int __init aztech_init(void)
+ {
+- if(io==-1)
+- {
+- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
++ struct aztech *az = &aztech_card;
++ struct v4l2_device *v4l2_dev = &az->v4l2_dev;
++ int res;
++
++ strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name));
++ az->io = io;
++
++ if (az->io == -1) {
++ v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n");
+ return -EINVAL;
+ }
+
+- if (!request_region(io, 2, "aztech"))
+- {
+- printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
++ if (!request_region(az->io, 2, "aztech")) {
++ v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io);
+ return -EBUSY;
+ }
+
+- mutex_init(&lock);
+- video_set_drvdata(&aztech_radio, &aztech_unit);
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(az->io, 2);
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ return res;
++ }
+
+- if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io,2);
++ mutex_init(&az->lock);
++ strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name));
++ az->vdev.v4l2_dev = v4l2_dev;
++ az->vdev.fops = &aztech_fops;
++ az->vdev.ioctl_ops = &aztech_ioctl_ops;
++ az->vdev.release = video_device_release_empty;
++ video_set_drvdata(&az->vdev, az);
++
++ if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(v4l2_dev);
++ release_region(az->io, 2);
+ return -EINVAL;
+ }
+
+- printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
++ v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
+ /* mute card - prevents noisy bootups */
+- outb (0, io);
++ outb(0, az->io);
+ return 0;
+ }
+
+-MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
+-MODULE_DESCRIPTION("A driver for the Aztech radio card.");
+-MODULE_LICENSE("GPL");
+-
+-module_param(io, int, 0);
+-module_param(radio_nr, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
+-
+-static void __exit aztech_cleanup(void)
++static void __exit aztech_exit(void)
+ {
+- video_unregister_device(&aztech_radio);
+- release_region(io,2);
++ struct aztech *az = &aztech_card;
++
++ video_unregister_device(&az->vdev);
++ v4l2_device_unregister(&az->v4l2_dev);
++ release_region(az->io, 2);
+ }
+
+ module_init(aztech_init);
+-module_exit(aztech_cleanup);
++module_exit(aztech_exit);
+diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
+index cb3075a..d30fc0c 100644
+--- a/drivers/media/radio/radio-cadet.c
++++ b/drivers/media/radio/radio-cadet.c
+@@ -35,333 +35,318 @@
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay */
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/videodev2.h> /* V4L2 API defs */
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-ioctl.h>
+ #include <linux/param.h>
+ #include <linux/pnp.h>
++#include <linux/io.h> /* outb, outb_p */
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
++
++MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
++MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
++MODULE_LICENSE("GPL");
++
++static int io = -1; /* default to isapnp activation */
++static int radio_nr = -1;
++
++module_param(io, int, 0);
++MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
++module_param(radio_nr, int, 0);
++
++#define CADET_VERSION KERNEL_VERSION(0, 3, 3)
+
+ #define RDS_BUFFER 256
+ #define RDS_RX_FLAG 1
+ #define MBS_RX_FLAG 2
+
+-#define CADET_VERSION KERNEL_VERSION(0,3,3)
+-
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- },{
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 0xff,
+- .step = 1,
+- .default_value = 0xff,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- }
++struct cadet {
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ int io;
++ int users;
++ int curtuner;
++ int tunestat;
++ int sigstrength;
++ wait_queue_head_t read_queue;
++ struct timer_list readtimer;
++ __u8 rdsin, rdsout, rdsstat;
++ unsigned char rdsbuf[RDS_BUFFER];
++ struct mutex lock;
++ int reading;
+ };
+
+-static int io=-1; /* default to isapnp activation */
+-static int radio_nr = -1;
+-static int users;
+-static int curtuner;
+-static int tunestat;
+-static int sigstrength;
+-static wait_queue_head_t read_queue;
+-static struct timer_list readtimer;
+-static __u8 rdsin, rdsout, rdsstat;
+-static unsigned char rdsbuf[RDS_BUFFER];
+-static spinlock_t cadet_io_lock;
+-
+-static int cadet_probe(void);
++static struct cadet cadet_card;
+
+ /*
+ * Signal Strength Threshold Values
+ * The V4L API spec does not define any particular unit for the signal
+ * strength value. These values are in microvolts of RF at the tuner's input.
+ */
+-static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
++static __u16 sigtable[2][4] = {
++ { 5, 10, 30, 150 },
++ { 28, 40, 63, 1000 }
++};
+
+
+-static int
+-cadet_getstereo(void)
++static int cadet_getstereo(struct cadet *dev)
+ {
+ int ret = V4L2_TUNER_SUB_MONO;
+- if(curtuner != 0) /* Only FM has stereo capability! */
++
++ if (dev->curtuner != 0) /* Only FM has stereo capability! */
+ return V4L2_TUNER_SUB_MONO;
+
+- spin_lock(&cadet_io_lock);
+- outb(7,io); /* Select tuner control */
+- if( (inb(io+1) & 0x40) == 0)
++ mutex_lock(&dev->lock);
++ outb(7, dev->io); /* Select tuner control */
++ if ((inb(dev->io + 1) & 0x40) == 0)
+ ret = V4L2_TUNER_SUB_STEREO;
+- spin_unlock(&cadet_io_lock);
++ mutex_unlock(&dev->lock);
+ return ret;
+ }
+
+-static unsigned
+-cadet_gettune(void)
++static unsigned cadet_gettune(struct cadet *dev)
+ {
+- int curvol,i;
+- unsigned fifo=0;
++ int curvol, i;
++ unsigned fifo = 0;
+
+ /*
+ * Prepare for read
+ */
+
+- spin_lock(&cadet_io_lock);
++ mutex_lock(&dev->lock);
+
+- outb(7,io); /* Select tuner control */
+- curvol=inb(io+1); /* Save current volume/mute setting */
+- outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */
+- tunestat=0xffff;
++ outb(7, dev->io); /* Select tuner control */
++ curvol = inb(dev->io + 1); /* Save current volume/mute setting */
++ outb(0x00, dev->io + 1); /* Ensure WRITE-ENABLE is LOW */
++ dev->tunestat = 0xffff;
+
+ /*
+ * Read the shift register
+ */
+- for(i=0;i<25;i++) {
+- fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
+- if(i<24) {
+- outb(0x01,io+1);
+- tunestat&=inb(io+1);
+- outb(0x00,io+1);
++ for (i = 0; i < 25; i++) {
++ fifo = (fifo << 1) | ((inb(dev->io + 1) >> 7) & 0x01);
++ if (i < 24) {
++ outb(0x01, dev->io + 1);
++ dev->tunestat &= inb(dev->io + 1);
++ outb(0x00, dev->io + 1);
+ }
+ }
+
+ /*
+ * Restore volume/mute setting
+ */
+- outb(curvol,io+1);
+- spin_unlock(&cadet_io_lock);
++ outb(curvol, dev->io + 1);
++ mutex_unlock(&dev->lock);
+
+ return fifo;
+ }
+
+-static unsigned
+-cadet_getfreq(void)
++static unsigned cadet_getfreq(struct cadet *dev)
+ {
+ int i;
+- unsigned freq=0,test,fifo=0;
++ unsigned freq = 0, test, fifo = 0;
+
+ /*
+ * Read current tuning
+ */
+- fifo=cadet_gettune();
++ fifo = cadet_gettune(dev);
+
+ /*
+ * Convert to actual frequency
+ */
+- if(curtuner==0) { /* FM */
+- test=12500;
+- for(i=0;i<14;i++) {
+- if((fifo&0x01)!=0) {
+- freq+=test;
+- }
+- test=test<<1;
+- fifo=fifo>>1;
++ if (dev->curtuner == 0) { /* FM */
++ test = 12500;
++ for (i = 0; i < 14; i++) {
++ if ((fifo & 0x01) != 0)
++ freq += test;
++ test = test << 1;
++ fifo = fifo >> 1;
+ }
+- freq-=10700000; /* IF frequency is 10.7 MHz */
+- freq=(freq*16)/1000000; /* Make it 1/16 MHz */
+- }
+- if(curtuner==1) { /* AM */
+- freq=((fifo&0x7fff)-2010)*16;
++ freq -= 10700000; /* IF frequency is 10.7 MHz */
++ freq = (freq * 16) / 1000000; /* Make it 1/16 MHz */
+ }
++ if (dev->curtuner == 1) /* AM */
++ freq = ((fifo & 0x7fff) - 2010) * 16;
+
+ return freq;
+ }
+
+-static void
+-cadet_settune(unsigned fifo)
++static void cadet_settune(struct cadet *dev, unsigned fifo)
+ {
+ int i;
+ unsigned test;
+
+- spin_lock(&cadet_io_lock);
++ mutex_lock(&dev->lock);
+
+- outb(7,io); /* Select tuner control */
++ outb(7, dev->io); /* Select tuner control */
+ /*
+ * Write the shift register
+ */
+- test=0;
+- test=(fifo>>23)&0x02; /* Align data for SDO */
+- test|=0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */
+- outb(7,io); /* Select tuner control */
+- outb(test,io+1); /* Initialize for write */
+- for(i=0;i<25;i++) {
+- test|=0x01; /* Toggle SCK High */
+- outb(test,io+1);
+- test&=0xfe; /* Toggle SCK Low */
+- outb(test,io+1);
+- fifo=fifo<<1; /* Prepare the next bit */
+- test=0x1c|((fifo>>23)&0x02);
+- outb(test,io+1);
++ test = 0;
++ test = (fifo >> 23) & 0x02; /* Align data for SDO */
++ test |= 0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */
++ outb(7, dev->io); /* Select tuner control */
++ outb(test, dev->io + 1); /* Initialize for write */
++ for (i = 0; i < 25; i++) {
++ test |= 0x01; /* Toggle SCK High */
++ outb(test, dev->io + 1);
++ test &= 0xfe; /* Toggle SCK Low */
++ outb(test, dev->io + 1);
++ fifo = fifo << 1; /* Prepare the next bit */
++ test = 0x1c | ((fifo >> 23) & 0x02);
++ outb(test, dev->io + 1);
+ }
+- spin_unlock(&cadet_io_lock);
++ mutex_unlock(&dev->lock);
+ }
+
+-static void
+-cadet_setfreq(unsigned freq)
++static void cadet_setfreq(struct cadet *dev, unsigned freq)
+ {
+ unsigned fifo;
+- int i,j,test;
++ int i, j, test;
+ int curvol;
+
+ /*
+ * Formulate a fifo command
+ */
+- fifo=0;
+- if(curtuner==0) { /* FM */
+- test=102400;
+- freq=(freq*1000)/16; /* Make it kHz */
+- freq+=10700; /* IF is 10700 kHz */
+- for(i=0;i<14;i++) {
+- fifo=fifo<<1;
+- if(freq>=test) {
+- fifo|=0x01;
+- freq-=test;
++ fifo = 0;
++ if (dev->curtuner == 0) { /* FM */
++ test = 102400;
++ freq = (freq * 1000) / 16; /* Make it kHz */
++ freq += 10700; /* IF is 10700 kHz */
++ for (i = 0; i < 14; i++) {
++ fifo = fifo << 1;
++ if (freq >= test) {
++ fifo |= 0x01;
++ freq -= test;
+ }
+- test=test>>1;
++ test = test >> 1;
+ }
+ }
+- if(curtuner==1) { /* AM */
+- fifo=(freq/16)+2010; /* Make it kHz */
+- fifo|=0x100000; /* Select AM Band */
++ if (dev->curtuner == 1) { /* AM */
++ fifo = (freq / 16) + 2010; /* Make it kHz */
++ fifo |= 0x100000; /* Select AM Band */
+ }
+
+ /*
+ * Save current volume/mute setting
+ */
+
+- spin_lock(&cadet_io_lock);
+- outb(7,io); /* Select tuner control */
+- curvol=inb(io+1);
+- spin_unlock(&cadet_io_lock);
++ mutex_lock(&dev->lock);
++ outb(7, dev->io); /* Select tuner control */
++ curvol = inb(dev->io + 1);
++ mutex_unlock(&dev->lock);
+
+ /*
+ * Tune the card
+ */
+- for(j=3;j>-1;j--) {
+- cadet_settune(fifo|(j<<16));
++ for (j = 3; j > -1; j--) {
++ cadet_settune(dev, fifo | (j << 16));
+
+- spin_lock(&cadet_io_lock);
+- outb(7,io); /* Select tuner control */
+- outb(curvol,io+1);
+- spin_unlock(&cadet_io_lock);
++ mutex_lock(&dev->lock);
++ outb(7, dev->io); /* Select tuner control */
++ outb(curvol, dev->io + 1);
++ mutex_unlock(&dev->lock);
+
+ msleep(100);
+
+- cadet_gettune();
+- if((tunestat & 0x40) == 0) { /* Tuned */
+- sigstrength=sigtable[curtuner][j];
++ cadet_gettune(dev);
++ if ((dev->tunestat & 0x40) == 0) { /* Tuned */
++ dev->sigstrength = sigtable[dev->curtuner][j];
+ return;
+ }
+ }
+- sigstrength=0;
++ dev->sigstrength = 0;
+ }
+
+
+-static int
+-cadet_getvol(void)
++static int cadet_getvol(struct cadet *dev)
+ {
+ int ret = 0;
+
+- spin_lock(&cadet_io_lock);
++ mutex_lock(&dev->lock);
+
+- outb(7,io); /* Select tuner control */
+- if((inb(io + 1) & 0x20) != 0)
++ outb(7, dev->io); /* Select tuner control */
++ if ((inb(dev->io + 1) & 0x20) != 0)
+ ret = 0xffff;
+
+- spin_unlock(&cadet_io_lock);
++ mutex_unlock(&dev->lock);
+ return ret;
+ }
+
+
+-static void
+-cadet_setvol(int vol)
++static void cadet_setvol(struct cadet *dev, int vol)
+ {
+- spin_lock(&cadet_io_lock);
+- outb(7,io); /* Select tuner control */
+- if(vol>0)
+- outb(0x20,io+1);
++ mutex_lock(&dev->lock);
++ outb(7, dev->io); /* Select tuner control */
++ if (vol > 0)
++ outb(0x20, dev->io + 1);
+ else
+- outb(0x00,io+1);
+- spin_unlock(&cadet_io_lock);
++ outb(0x00, dev->io + 1);
++ mutex_unlock(&dev->lock);
+ }
+
+-static void
+-cadet_handler(unsigned long data)
++static void cadet_handler(unsigned long data)
+ {
+- /*
+- * Service the RDS fifo
+- */
++ struct cadet *dev = (void *)data;
+
+- if(spin_trylock(&cadet_io_lock))
+- {
+- outb(0x3,io); /* Select RDS Decoder Control */
+- if((inb(io+1)&0x20)!=0) {
++ /* Service the RDS fifo */
++ if (mutex_trylock(&dev->lock)) {
++ outb(0x3, dev->io); /* Select RDS Decoder Control */
++ if ((inb(dev->io + 1) & 0x20) != 0)
+ printk(KERN_CRIT "cadet: RDS fifo overflow\n");
+- }
+- outb(0x80,io); /* Select RDS fifo */
+- while((inb(io)&0x80)!=0) {
+- rdsbuf[rdsin]=inb(io+1);
+- if(rdsin==rdsout)
++ outb(0x80, dev->io); /* Select RDS fifo */
++ while ((inb(dev->io) & 0x80) != 0) {
++ dev->rdsbuf[dev->rdsin] = inb(dev->io + 1);
++ if (dev->rdsin == dev->rdsout)
+ printk(KERN_WARNING "cadet: RDS buffer overflow\n");
+ else
+- rdsin++;
++ dev->rdsin++;
+ }
+- spin_unlock(&cadet_io_lock);
++ mutex_unlock(&dev->lock);
+ }
+
+ /*
+ * Service pending read
+ */
+- if( rdsin!=rdsout)
+- wake_up_interruptible(&read_queue);
++ if (dev->rdsin != dev->rdsout)
++ wake_up_interruptible(&dev->read_queue);
+
+ /*
+ * Clean up and exit
+ */
+- init_timer(&readtimer);
+- readtimer.function=cadet_handler;
+- readtimer.data=(unsigned long)0;
+- readtimer.expires=jiffies+msecs_to_jiffies(50);
+- add_timer(&readtimer);
++ init_timer(&dev->readtimer);
++ dev->readtimer.function = cadet_handler;
++ dev->readtimer.data = (unsigned long)0;
++ dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
++ add_timer(&dev->readtimer);
+ }
+
+
+-
+-static ssize_t
+-cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
++static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+ {
+- int i=0;
++ struct cadet *dev = video_drvdata(file);
+ unsigned char readbuf[RDS_BUFFER];
+-
+- if(rdsstat==0) {
+- spin_lock(&cadet_io_lock);
+- rdsstat=1;
+- outb(0x80,io); /* Select RDS fifo */
+- spin_unlock(&cadet_io_lock);
+- init_timer(&readtimer);
+- readtimer.function=cadet_handler;
+- readtimer.data=(unsigned long)0;
+- readtimer.expires=jiffies+msecs_to_jiffies(50);
+- add_timer(&readtimer);
++ int i = 0;
++
++ if (dev->rdsstat == 0) {
++ mutex_lock(&dev->lock);
++ dev->rdsstat = 1;
++ outb(0x80, dev->io); /* Select RDS fifo */
++ mutex_unlock(&dev->lock);
++ init_timer(&dev->readtimer);
++ dev->readtimer.function = cadet_handler;
++ dev->readtimer.data = (unsigned long)dev;
++ dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
++ add_timer(&dev->readtimer);
+ }
+- if(rdsin==rdsout) {
++ if (dev->rdsin == dev->rdsout) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+- interruptible_sleep_on(&read_queue);
++ interruptible_sleep_on(&dev->read_queue);
+ }
+- while( i<count && rdsin!=rdsout)
+- readbuf[i++]=rdsbuf[rdsout++];
++ while (i < count && dev->rdsin != dev->rdsout)
++ readbuf[i++] = dev->rdsbuf[dev->rdsout++];
+
+- if (copy_to_user(data,readbuf,i))
++ if (copy_to_user(data, readbuf, i))
+ return -EFAULT;
+ return i;
+ }
+@@ -370,38 +355,40 @@ cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+ {
+- v->capabilities =
+- V4L2_CAP_TUNER |
+- V4L2_CAP_READWRITE;
++ strlcpy(v->driver, "ADS Cadet", sizeof(v->driver));
++ strlcpy(v->card, "ADS Cadet", sizeof(v->card));
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = CADET_VERSION;
+- strcpy(v->driver, "ADS Cadet");
+- strcpy(v->card, "ADS Cadet");
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_READWRITE;
+ return 0;
+ }
+
+ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
++ struct cadet *dev = video_drvdata(file);
++
+ v->type = V4L2_TUNER_RADIO;
+ switch (v->index) {
+ case 0:
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->capability = V4L2_TUNER_CAP_STEREO;
+ v->rangelow = 1400; /* 87.5 MHz */
+ v->rangehigh = 1728; /* 108.0 MHz */
+- v->rxsubchans=cadet_getstereo();
+- switch (v->rxsubchans){
++ v->rxsubchans = cadet_getstereo(dev);
++ switch (v->rxsubchans) {
+ case V4L2_TUNER_SUB_MONO:
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ break;
+ case V4L2_TUNER_SUB_STEREO:
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ break;
+- default: ;
++ default:
++ break;
+ }
+ break;
+ case 1:
+- strcpy(v->name, "AM");
++ strlcpy(v->name, "AM", sizeof(v->name));
+ v->capability = V4L2_TUNER_CAP_LOW;
+ v->rangelow = 8320; /* 520 kHz */
+ v->rangehigh = 26400; /* 1650 kHz */
+@@ -411,25 +398,29 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ default:
+ return -EINVAL;
+ }
+- v->signal = sigstrength; /* We might need to modify scaling of this */
++ v->signal = dev->sigstrength; /* We might need to modify scaling of this */
+ return 0;
+ }
+
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if((v->index != 0)&&(v->index != 1))
++ struct cadet *dev = video_drvdata(file);
++
++ if (v->index != 0 && v->index != 1)
+ return -EINVAL;
+- curtuner = v->index;
++ dev->curtuner = v->index;
+ return 0;
+ }
+
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- f->tuner = curtuner;
++ struct cadet *dev = video_drvdata(file);
++
++ f->tuner = dev->curtuner;
+ f->type = V4L2_TUNER_RADIO;
+- f->frequency = cadet_getfreq();
++ f->frequency = cadet_getfreq(dev);
+ return 0;
+ }
+
+@@ -437,27 +428,26 @@ static int vidioc_g_frequency(struct file *file, void *priv,
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
++ struct cadet *dev = video_drvdata(file);
++
+ if (f->type != V4L2_TUNER_RADIO)
+ return -EINVAL;
+- if((curtuner==0)&&((f->frequency<1400)||(f->frequency>1728)))
++ if (dev->curtuner == 0 && (f->frequency < 1400 || f->frequency > 1728))
+ return -EINVAL;
+- if((curtuner==1)&&((f->frequency<8320)||(f->frequency>26400)))
++ if (dev->curtuner == 1 && (f->frequency < 8320 || f->frequency > 26400))
+ return -EINVAL;
+- cadet_setfreq(f->frequency);
++ cadet_setfreq(dev, f->frequency);
+ return 0;
+ }
+
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
+ }
+ return -EINVAL;
+ }
+@@ -465,12 +455,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- switch (ctrl->id){
++ struct cadet *dev = video_drvdata(file);
++
++ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
+- ctrl->value = (cadet_getvol() == 0);
++ ctrl->value = (cadet_getvol(dev) == 0);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+- ctrl->value = cadet_getvol();
++ ctrl->value = cadet_getvol(dev);
+ break;
+ default:
+ return -EINVAL;
+@@ -481,15 +473,17 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
++ struct cadet *dev = video_drvdata(file);
++
+ switch (ctrl->id){
+ case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
+ if (ctrl->value)
+- cadet_setvol(0);
++ cadet_setvol(dev, 0);
+ else
+- cadet_setvol(0xffff);
++ cadet_setvol(dev, 0xffff);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+- cadet_setvol(ctrl->value);
++ cadet_setvol(dev, ctrl->value);
+ break;
+ default:
+ return -EINVAL;
+@@ -497,16 +491,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ return 0;
+ }
+
+-static int vidioc_g_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -515,43 +499,52 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
++ return i ? -EINVAL : 0;
++}
++
++static int vidioc_g_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+ static int vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
+- return 0;
++ return a->index ? -EINVAL : 0;
+ }
+
+-static int
+-cadet_open(struct file *file)
++static int cadet_open(struct file *file)
+ {
+- users++;
+- if (1 == users) init_waitqueue_head(&read_queue);
++ struct cadet *dev = video_drvdata(file);
++
++ dev->users++;
++ if (1 == dev->users)
++ init_waitqueue_head(&dev->read_queue);
+ return 0;
+ }
+
+-static int
+-cadet_release(struct file *file)
++static int cadet_release(struct file *file)
+ {
+- users--;
+- if (0 == users){
+- del_timer_sync(&readtimer);
+- rdsstat=0;
++ struct cadet *dev = video_drvdata(file);
++
++ dev->users--;
++ if (0 == dev->users) {
++ del_timer_sync(&dev->readtimer);
++ dev->rdsstat = 0;
+ }
+ return 0;
+ }
+
+-static unsigned int
+-cadet_poll(struct file *file, struct poll_table_struct *wait)
++static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait)
+ {
+- poll_wait(file,&read_queue,wait);
+- if(rdsin != rdsout)
++ struct cadet *dev = video_drvdata(file);
++
++ poll_wait(file, &dev->read_queue, wait);
++ if (dev->rdsin != dev->rdsout)
+ return POLLIN | POLLRDNORM;
+ return 0;
+ }
+@@ -581,13 +574,6 @@ static const struct v4l2_ioctl_ops cadet_ioctl_ops = {
+ .vidioc_s_input = vidioc_s_input,
+ };
+
+-static struct video_device cadet_radio = {
+- .name = "Cadet radio",
+- .fops = &cadet_fops,
+- .ioctl_ops = &cadet_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ #ifdef CONFIG_PNP
+
+ static struct pnp_device_id cadet_pnp_devices[] = {
+@@ -598,7 +584,7 @@ static struct pnp_device_id cadet_pnp_devices[] = {
+
+ MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices);
+
+-static int cadet_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
++static int cadet_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+ {
+ if (!dev)
+ return -ENODEV;
+@@ -606,13 +592,12 @@ static int cadet_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev
+ if (io > 0)
+ return -EBUSY;
+
+- if (!pnp_port_valid(dev, 0)) {
++ if (!pnp_port_valid(dev, 0))
+ return -ENODEV;
+- }
+
+ io = pnp_port_start(dev, 0);
+
+- printk ("radio-cadet: PnP reports device at %#x\n", io);
++ printk(KERN_INFO "radio-cadet: PnP reports device at %#x\n", io);
+
+ return io;
+ }
+@@ -628,23 +613,23 @@ static struct pnp_driver cadet_pnp_driver = {
+ static struct pnp_driver cadet_pnp_driver;
+ #endif
+
+-static int cadet_probe(void)
++static void cadet_probe(struct cadet *dev)
+ {
+- static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
++ static int iovals[8] = { 0x330, 0x332, 0x334, 0x336, 0x338, 0x33a, 0x33c, 0x33e };
+ int i;
+
+- for(i=0;i<8;i++) {
+- io=iovals[i];
+- if (request_region(io, 2, "cadet-probe")) {
+- cadet_setfreq(1410);
+- if(cadet_getfreq()==1410) {
+- release_region(io, 2);
+- return io;
++ for (i = 0; i < 8; i++) {
++ dev->io = iovals[i];
++ if (request_region(dev->io, 2, "cadet-probe")) {
++ cadet_setfreq(dev, 1410);
++ if (cadet_getfreq(dev) == 1410) {
++ release_region(dev->io, 2);
++ return;
+ }
+- release_region(io, 2);
++ release_region(dev->io, 2);
+ }
+ }
+- return -1;
++ dev->io = -1;
+ }
+
+ /*
+@@ -654,59 +639,69 @@ static int cadet_probe(void)
+
+ static int __init cadet_init(void)
+ {
+- spin_lock_init(&cadet_io_lock);
++ struct cadet *dev = &cadet_card;
++ struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
++ int res;
+
+- /*
+- * If a probe was requested then probe ISAPnP first (safest)
+- */
++ strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name));
++ mutex_init(&dev->lock);
++
++ /* If a probe was requested then probe ISAPnP first (safest) */
+ if (io < 0)
+ pnp_register_driver(&cadet_pnp_driver);
+- /*
+- * If that fails then probe unsafely if probe is requested
+- */
+- if(io < 0)
+- io = cadet_probe ();
++ dev->io = io;
+
+- /*
+- * Else we bail out
+- */
++ /* If that fails then probe unsafely if probe is requested */
++ if (dev->io < 0)
++ cadet_probe(dev);
+
+- if(io < 0) {
++ /* Else we bail out */
++ if (dev->io < 0) {
+ #ifdef MODULE
+- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
++ v4l2_err(v4l2_dev, "you must set an I/O address with io=0x330, 0x332, 0x334,\n");
++ v4l2_err(v4l2_dev, "0x336, 0x338, 0x33a, 0x33c or 0x33e\n");
+ #endif
+ goto fail;
+ }
+- if (!request_region(io,2,"cadet"))
++ if (!request_region(dev->io, 2, "cadet"))
++ goto fail;
++
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(dev->io, 2);
++ v4l2_err(v4l2_dev, "could not register v4l2_device\n");
+ goto fail;
+- if (video_register_device(&cadet_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io,2);
++ }
++
++ strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
++ dev->vdev.v4l2_dev = v4l2_dev;
++ dev->vdev.fops = &cadet_fops;
++ dev->vdev.ioctl_ops = &cadet_ioctl_ops;
++ dev->vdev.release = video_device_release_empty;
++ video_set_drvdata(&dev->vdev, dev);
++
++ if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(v4l2_dev);
++ release_region(dev->io, 2);
+ goto fail;
+ }
+- printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
++ v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io);
+ return 0;
+ fail:
+ pnp_unregister_driver(&cadet_pnp_driver);
+- return -1;
++ return -ENODEV;
+ }
+
+-
+-
+-MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
+-MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
+-MODULE_LICENSE("GPL");
+-
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
+-module_param(radio_nr, int, 0);
+-
+-static void __exit cadet_cleanup_module(void)
++static void __exit cadet_exit(void)
+ {
+- video_unregister_device(&cadet_radio);
+- release_region(io,2);
++ struct cadet *dev = &cadet_card;
++
++ video_unregister_device(&dev->vdev);
++ v4l2_device_unregister(&dev->v4l2_dev);
++ release_region(dev->io, 2);
+ pnp_unregister_driver(&cadet_pnp_driver);
+ }
+
+ module_init(cadet_init);
+-module_exit(cadet_cleanup_module);
++module_exit(cadet_exit);
+
+diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
+index 0c96bf8..09265d2 100644
+--- a/drivers/media/radio/radio-gemtek-pci.c
++++ b/drivers/media/radio/radio-gemtek-pci.c
+@@ -45,34 +45,25 @@
+ #include <linux/init.h>
+ #include <linux/pci.h>
+ #include <linux/videodev2.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-ioctl.h>
+ #include <linux/errno.h>
+-
+ #include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+-
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- },{
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 65535,
+- .step = 65535,
+- .default_value = 0xff,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- }
+-};
++#include <linux/io.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
+
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
++MODULE_AUTHOR("Vladimir Shebordaev <vshebordaev@mail.ru>");
++MODULE_DESCRIPTION("The video4linux driver for the Gemtek PCI Radio Card");
++MODULE_LICENSE("GPL");
++
++static int nr_radio = -1;
++static int mx = 1;
++
++module_param(mx, bool, 0);
++MODULE_PARM_DESC(mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not");
++module_param(nr_radio, int, 0);
++MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
+
+ #ifndef PCI_VENDOR_ID_GEMTEK
+ #define PCI_VENDOR_ID_GEMTEK 0x5046
+@@ -90,8 +81,11 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+ #define GEMTEK_PCI_RANGE_HIGH (108*16000)
+ #endif
+
+-struct gemtek_pci_card {
+- struct video_device *videodev;
++struct gemtek_pci {
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ struct mutex lock;
++ struct pci_dev *pdev;
+
+ u32 iobase;
+ u32 length;
+@@ -100,116 +94,133 @@ struct gemtek_pci_card {
+ u8 mute;
+ };
+
+-static int nr_radio = -1;
+-static unsigned long in_use;
++static inline struct gemtek_pci *to_gemtek_pci(struct v4l2_device *v4l2_dev)
++{
++ return container_of(v4l2_dev, struct gemtek_pci, v4l2_dev);
++}
+
+-static inline u8 gemtek_pci_out( u16 value, u32 port )
++static inline u8 gemtek_pci_out(u16 value, u32 port)
+ {
+- outw( value, port );
++ outw(value, port);
+
+ return (u8)value;
+ }
+
+-#define _b0( v ) *((u8 *)&v)
+-static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
++#define _b0(v) (*((u8 *)&v))
++
++static void __gemtek_pci_cmd(u16 value, u32 port, u8 *last_byte, int keep)
+ {
+- register u8 byte = *last_byte;
++ u8 byte = *last_byte;
+
+- if ( !value ) {
+- if ( !keep )
++ if (!value) {
++ if (!keep)
+ value = (u16)port;
+ byte &= 0xfd;
+ } else
+ byte |= 2;
+
+- _b0( value ) = byte;
+- outw( value, port );
++ _b0(value) = byte;
++ outw(value, port);
+ byte |= 1;
+- _b0( value ) = byte;
+- outw( value, port );
++ _b0(value) = byte;
++ outw(value, port);
+ byte &= 0xfe;
+- _b0( value ) = byte;
+- outw( value, port );
++ _b0(value) = byte;
++ outw(value, port);
+
+ *last_byte = byte;
+ }
+
+-static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
++static inline void gemtek_pci_nil(u32 port, u8 *last_byte)
+ {
+- __gemtek_pci_cmd( 0x00, port, last_byte, false );
++ __gemtek_pci_cmd(0x00, port, last_byte, false);
+ }
+
+-static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
++static inline void gemtek_pci_cmd(u16 cmd, u32 port, u8 *last_byte)
+ {
+- __gemtek_pci_cmd( cmd, port, last_byte, true );
++ __gemtek_pci_cmd(cmd, port, last_byte, true);
+ }
+
+-static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
++static void gemtek_pci_setfrequency(struct gemtek_pci *card, unsigned long frequency)
+ {
+- register int i;
+- register u32 value = frequency / 200 + 856;
+- register u16 mask = 0x8000;
++ int i;
++ u32 value = frequency / 200 + 856;
++ u16 mask = 0x8000;
+ u8 last_byte;
+ u32 port = card->iobase;
+
+- last_byte = gemtek_pci_out( 0x06, port );
++ mutex_lock(&card->lock);
++ card->current_frequency = frequency;
++ last_byte = gemtek_pci_out(0x06, port);
+
+ i = 0;
+ do {
+- gemtek_pci_nil( port, &last_byte );
++ gemtek_pci_nil(port, &last_byte);
+ i++;
+- } while ( i < 9 );
++ } while (i < 9);
+
+ i = 0;
+ do {
+- gemtek_pci_cmd( value & mask, port, &last_byte );
++ gemtek_pci_cmd(value & mask, port, &last_byte);
+ mask >>= 1;
+ i++;
+- } while ( i < 16 );
++ } while (i < 16);
+
+- outw( 0x10, port );
++ outw(0x10, port);
++ mutex_unlock(&card->lock);
+ }
+
+
+-static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
++static void gemtek_pci_mute(struct gemtek_pci *card)
+ {
+- outb( 0x1f, card->iobase );
++ mutex_lock(&card->lock);
++ outb(0x1f, card->iobase);
+ card->mute = true;
++ mutex_unlock(&card->lock);
+ }
+
+-static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
++static void gemtek_pci_unmute(struct gemtek_pci *card)
+ {
+- if ( card->mute ) {
+- gemtek_pci_setfrequency( card, card->current_frequency );
++ mutex_lock(&card->lock);
++ if (card->mute) {
++ gemtek_pci_setfrequency(card, card->current_frequency);
+ card->mute = false;
+ }
++ mutex_unlock(&card->lock);
+ }
+
+-static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card )
++static int gemtek_pci_getsignal(struct gemtek_pci *card)
+ {
+- return ( inb( card->iobase ) & 0x08 ) ? 0 : 1;
++ int sig;
++
++ mutex_lock(&card->lock);
++ sig = (inb(card->iobase) & 0x08) ? 0 : 1;
++ mutex_unlock(&card->lock);
++ return sig;
+ }
+
+ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+ {
++ struct gemtek_pci *card = video_drvdata(file);
++
+ strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver));
+ strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(card->pdev));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- struct gemtek_pci_card *card = video_drvdata(file);
++ struct gemtek_pci *card = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+ v->rangelow = GEMTEK_PCI_RANGE_LOW;
+ v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
+@@ -223,21 +234,18 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct gemtek_pci_card *card = video_drvdata(file);
++ struct gemtek_pci *card = video_drvdata(file);
+
+- if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
+- (f->frequency > GEMTEK_PCI_RANGE_HIGH) )
++ if (f->frequency < GEMTEK_PCI_RANGE_LOW ||
++ f->frequency > GEMTEK_PCI_RANGE_HIGH)
+ return -EINVAL;
+ gemtek_pci_setfrequency(card, f->frequency);
+- card->current_frequency = f->frequency;
+ card->mute = false;
+ return 0;
+ }
+@@ -245,7 +253,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct gemtek_pci_card *card = video_drvdata(file);
++ struct gemtek_pci *card = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = card->current_frequency;
+@@ -255,13 +263,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
+ }
+ return -EINVAL;
+ }
+@@ -269,7 +275,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct gemtek_pci_card *card = video_drvdata(file);
++ struct gemtek_pci *card = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -288,7 +294,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct gemtek_pci_card *card = video_drvdata(file);
++ struct gemtek_pci *card = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -307,17 +313,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ return -EINVAL;
+ }
+
+-static int vidioc_g_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -326,17 +321,22 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
++ return i ? -EINVAL : 0;
++}
++
++static int vidioc_g_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+ static int vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
+- return 0;
++ return a->index ? -EINVAL : 0;
+ }
+
+ enum {
+@@ -354,25 +354,22 @@ static struct pci_device_id gemtek_pci_id[] =
+ { 0 }
+ };
+
+-MODULE_DEVICE_TABLE( pci, gemtek_pci_id );
+-
+-static int mx = 1;
++MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
+
+-static int gemtek_pci_exclusive_open(struct file *file)
++static int gemtek_pci_open(struct file *file)
+ {
+- return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int gemtek_pci_exclusive_release(struct file *file)
++static int gemtek_pci_release(struct file *file)
+ {
+- clear_bit(0, &in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations gemtek_pci_fops = {
+ .owner = THIS_MODULE,
+- .open = gemtek_pci_exclusive_open,
+- .release = gemtek_pci_exclusive_release,
++ .open = gemtek_pci_open,
++ .release = gemtek_pci_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -391,108 +388,100 @@ static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ };
+
+-static struct video_device vdev_template = {
+- .name = "Gemtek PCI Radio",
+- .fops = &gemtek_pci_fops,
+- .ioctl_ops = &gemtek_pci_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+-static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
++static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+ {
+- struct gemtek_pci_card *card;
+- struct video_device *devradio;
++ struct gemtek_pci *card;
++ struct v4l2_device *v4l2_dev;
++ int res;
+
+- if ( (card = kzalloc( sizeof( struct gemtek_pci_card ), GFP_KERNEL )) == NULL ) {
+- printk( KERN_ERR "gemtek_pci: out of memory\n" );
++ card = kzalloc(sizeof(struct gemtek_pci), GFP_KERNEL);
++ if (card == NULL) {
++ dev_err(&pdev->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+
+- if ( pci_enable_device( pci_dev ) )
+- goto err_pci;
++ v4l2_dev = &card->v4l2_dev;
++ mutex_init(&card->lock);
++ card->pdev = pdev;
+
+- card->iobase = pci_resource_start( pci_dev, 0 );
+- card->length = pci_resource_len( pci_dev, 0 );
++ strlcpy(v4l2_dev->name, "gemtek_pci", sizeof(v4l2_dev->name));
+
+- if ( request_region( card->iobase, card->length, card_names[pci_id->driver_data] ) == NULL ) {
+- printk( KERN_ERR "gemtek_pci: i/o port already in use\n" );
+- goto err_pci;
++ res = v4l2_device_register(&pdev->dev, v4l2_dev);
++ if (res < 0) {
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ kfree(card);
++ return res;
+ }
+
+- pci_set_drvdata( pci_dev, card );
++ if (pci_enable_device(pdev))
++ goto err_pci;
+
+- if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
+- printk( KERN_ERR "gemtek_pci: out of memory\n" );
+- goto err_video;
++ card->iobase = pci_resource_start(pdev, 0);
++ card->length = pci_resource_len(pdev, 0);
++
++ if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) {
++ v4l2_err(v4l2_dev, "i/o port already in use\n");
++ goto err_pci;
+ }
+- *devradio = vdev_template;
+
+- if (video_register_device(devradio, VFL_TYPE_RADIO, nr_radio) < 0) {
+- kfree( devradio );
++ strlcpy(card->vdev.name, v4l2_dev->name, sizeof(card->vdev.name));
++ card->vdev.v4l2_dev = v4l2_dev;
++ card->vdev.fops = &gemtek_pci_fops;
++ card->vdev.ioctl_ops = &gemtek_pci_ioctl_ops;
++ card->vdev.release = video_device_release_empty;
++ video_set_drvdata(&card->vdev, card);
++
++ if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
+ goto err_video;
+- }
+
+- card->videodev = devradio;
+- video_set_drvdata(devradio, card);
+- gemtek_pci_mute( card );
++ gemtek_pci_mute(card);
+
+- printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
+- pci_dev->revision, card->iobase, card->iobase + card->length - 1 );
++ v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
++ pdev->revision, card->iobase, card->iobase + card->length - 1);
+
+ return 0;
+
+ err_video:
+- release_region( card->iobase, card->length );
++ release_region(card->iobase, card->length);
+
+ err_pci:
+- kfree( card );
++ v4l2_device_unregister(v4l2_dev);
++ kfree(card);
+ return -ENODEV;
+ }
+
+-static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
++static void __devexit gemtek_pci_remove(struct pci_dev *pdev)
+ {
+- struct gemtek_pci_card *card = pci_get_drvdata( pci_dev );
++ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
++ struct gemtek_pci *card = to_gemtek_pci(v4l2_dev);
+
+- video_unregister_device( card->videodev );
+- kfree( card->videodev );
++ video_unregister_device(&card->vdev);
++ v4l2_device_unregister(v4l2_dev);
+
+- release_region( card->iobase, card->length );
++ release_region(card->iobase, card->length);
+
+- if ( mx )
+- gemtek_pci_mute( card );
++ if (mx)
++ gemtek_pci_mute(card);
+
+- kfree( card );
+-
+- pci_set_drvdata( pci_dev, NULL );
++ kfree(card);
+ }
+
+-static struct pci_driver gemtek_pci_driver =
+-{
++static struct pci_driver gemtek_pci_driver = {
+ .name = "gemtek_pci",
+ .id_table = gemtek_pci_id,
+ .probe = gemtek_pci_probe,
+ .remove = __devexit_p(gemtek_pci_remove),
+ };
+
+-static int __init gemtek_pci_init_module( void )
++static int __init gemtek_pci_init(void)
+ {
+- return pci_register_driver( &gemtek_pci_driver );
++ return pci_register_driver(&gemtek_pci_driver);
+ }
+
+-static void __exit gemtek_pci_cleanup_module( void )
++static void __exit gemtek_pci_exit(void)
+ {
+ pci_unregister_driver(&gemtek_pci_driver);
+ }
+
+-MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev@mail.ru>" );
+-MODULE_DESCRIPTION( "The video4linux driver for the Gemtek PCI Radio Card" );
+-MODULE_LICENSE("GPL");
+-
+-module_param(mx, bool, 0);
+-MODULE_PARM_DESC( mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not" );
+-module_param(nr_radio, int, 0);
+-MODULE_PARM_DESC( nr_radio, "video4linux device number to use");
+-
+-module_init( gemtek_pci_init_module );
+-module_exit( gemtek_pci_cleanup_module );
+-
++module_init(gemtek_pci_init);
++module_exit(gemtek_pci_exit);
+diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
+index 2b68be7..1504644 100644
+--- a/drivers/media/radio/radio-gemtek.c
++++ b/drivers/media/radio/radio-gemtek.c
+@@ -20,16 +20,14 @@
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay */
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/videodev2.h> /* kernel radio structs */
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#include <linux/mutex.h>
++#include <linux/io.h> /* outb, outb_p */
+ #include <media/v4l2-ioctl.h>
+-#include <media/v4l2-common.h>
+-#include <linux/spinlock.h>
++#include <media/v4l2-device.h>
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,0,3)
+-#define RADIO_BANNER "GemTek Radio card driver: v0.0.3"
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 3)
+
+ /*
+ * Module info.
+@@ -57,7 +55,6 @@ static int shutdown = 1;
+ static int keepmuted = 1;
+ static int initmute = 1;
+ static int radio_nr = -1;
+-static unsigned long in_use;
+
+ module_param(io, int, 0444);
+ MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
+@@ -112,12 +109,19 @@ module_param(radio_nr, int, 0444);
+ #define SHORT_DELAY 5 /* usec */
+ #define LONG_DELAY 75 /* usec */
+
+-struct gemtek_device {
++struct gemtek {
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ struct mutex lock;
+ unsigned long lastfreq;
+ int muted;
++ int verified;
++ int io;
+ u32 bu2614data;
+ };
+
++static struct gemtek gemtek_card;
++
+ #define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */
+ #define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */
+ #define BU2614_VOID_BITS 4 /* unused */
+@@ -153,10 +157,6 @@ struct gemtek_device {
+ #define BU2614_FMUN_MASK MKMASK(FMUN)
+ #define BU2614_TEST_MASK MKMASK(TEST)
+
+-static struct gemtek_device gemtek_unit;
+-
+-static spinlock_t lock;
+-
+ /*
+ * Set data which will be sent to BU2614FS.
+ */
+@@ -166,33 +166,33 @@ static spinlock_t lock;
+ /*
+ * Transmit settings to BU2614FS over GemTek IC.
+ */
+-static void gemtek_bu2614_transmit(struct gemtek_device *dev)
++static void gemtek_bu2614_transmit(struct gemtek *gt)
+ {
+ int i, bit, q, mute;
+
+- spin_lock(&lock);
++ mutex_lock(&gt->lock);
+
+- mute = dev->muted ? GEMTEK_MT : 0x00;
++ mute = gt->muted ? GEMTEK_MT : 0x00;
+
+- outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
++ outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
+ udelay(SHORT_DELAY);
+- outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
++ outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
+ udelay(LONG_DELAY);
+
+- for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) {
+- bit = (q & 1) ? GEMTEK_DA : 0;
+- outb_p(mute | GEMTEK_CE | bit, io);
+- udelay(SHORT_DELAY);
+- outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io);
+- udelay(SHORT_DELAY);
++ for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) {
++ bit = (q & 1) ? GEMTEK_DA : 0;
++ outb_p(mute | GEMTEK_CE | bit, gt->io);
++ udelay(SHORT_DELAY);
++ outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io);
++ udelay(SHORT_DELAY);
+ }
+
+- outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
++ outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
+ udelay(SHORT_DELAY);
+- outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
++ outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
+ udelay(LONG_DELAY);
+
+- spin_unlock(&lock);
++ mutex_unlock(&gt->lock);
+ }
+
+ /*
+@@ -206,107 +206,109 @@ static unsigned long gemtek_convfreq(unsigned long freq)
+ /*
+ * Set FM-frequency.
+ */
+-static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
++static void gemtek_setfreq(struct gemtek *gt, unsigned long freq)
+ {
+-
+- if (keepmuted && hardmute && dev->muted)
++ if (keepmuted && hardmute && gt->muted)
+ return;
+
+- if (freq < GEMTEK_LOWFREQ)
+- freq = GEMTEK_LOWFREQ;
+- else if (freq > GEMTEK_HIGHFREQ)
+- freq = GEMTEK_HIGHFREQ;
++ freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ);
+
+- dev->lastfreq = freq;
+- dev->muted = 0;
++ gt->lastfreq = freq;
++ gt->muted = 0;
+
+- gemtek_bu2614_set(dev, BU2614_PORT, 0);
+- gemtek_bu2614_set(dev, BU2614_FMES, 0);
+- gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */
+- gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+- gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set */
+- gemtek_bu2614_set(dev, BU2614_TEST, 0);
++ gemtek_bu2614_set(gt, BU2614_PORT, 0);
++ gemtek_bu2614_set(gt, BU2614_FMES, 0);
++ gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */
++ gemtek_bu2614_set(gt, BU2614_SWAL, 0);
++ gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */
++ gemtek_bu2614_set(gt, BU2614_TEST, 0);
+
+- gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
+- gemtek_bu2614_set(dev, BU2614_FREQ, gemtek_convfreq(freq));
++ gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
++ gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq));
+
+- gemtek_bu2614_transmit(dev);
++ gemtek_bu2614_transmit(gt);
+ }
+
+ /*
+ * Set mute flag.
+ */
+-static void gemtek_mute(struct gemtek_device *dev)
++static void gemtek_mute(struct gemtek *gt)
+ {
+ int i;
+- dev->muted = 1;
++
++ gt->muted = 1;
+
+ if (hardmute) {
+ /* Turn off PLL, disable data output */
+- gemtek_bu2614_set(dev, BU2614_PORT, 0);
+- gemtek_bu2614_set(dev, BU2614_FMES, 0); /* CT bit off */
+- gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */
+- gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+- gemtek_bu2614_set(dev, BU2614_FMUN, 0); /* GT bit off */
+- gemtek_bu2614_set(dev, BU2614_TEST, 0);
+- gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF);
+- gemtek_bu2614_set(dev, BU2614_FREQ, 0);
+- gemtek_bu2614_transmit(dev);
+- } else {
+- spin_lock(&lock);
++ gemtek_bu2614_set(gt, BU2614_PORT, 0);
++ gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */
++ gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */
++ gemtek_bu2614_set(gt, BU2614_SWAL, 0);
++ gemtek_bu2614_set(gt, BU2614_FMUN, 0); /* GT bit off */
++ gemtek_bu2614_set(gt, BU2614_TEST, 0);
++ gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF);
++ gemtek_bu2614_set(gt, BU2614_FREQ, 0);
++ gemtek_bu2614_transmit(gt);
++ return;
++ }
+
+- /* Read bus contents (CE, CK and DA). */
+- i = inb_p(io);
+- /* Write it back with mute flag set. */
+- outb_p((i >> 5) | GEMTEK_MT, io);
+- udelay(SHORT_DELAY);
++ mutex_lock(&gt->lock);
+
+- spin_unlock(&lock);
+- }
++ /* Read bus contents (CE, CK and DA). */
++ i = inb_p(gt->io);
++ /* Write it back with mute flag set. */
++ outb_p((i >> 5) | GEMTEK_MT, gt->io);
++ udelay(SHORT_DELAY);
++
++ mutex_unlock(&gt->lock);
+ }
+
+ /*
+ * Unset mute flag.
+ */
+-static void gemtek_unmute(struct gemtek_device *dev)
++static void gemtek_unmute(struct gemtek *gt)
+ {
+ int i;
+- dev->muted = 0;
+
++ gt->muted = 0;
+ if (hardmute) {
+ /* Turn PLL back on. */
+- gemtek_setfreq(dev, dev->lastfreq);
+- } else {
+- spin_lock(&lock);
++ gemtek_setfreq(gt, gt->lastfreq);
++ return;
++ }
++ mutex_lock(&gt->lock);
+
+- i = inb_p(io);
+- outb_p(i >> 5, io);
+- udelay(SHORT_DELAY);
++ i = inb_p(gt->io);
++ outb_p(i >> 5, gt->io);
++ udelay(SHORT_DELAY);
+
+- spin_unlock(&lock);
+- }
++ mutex_unlock(&gt->lock);
+ }
+
+ /*
+ * Get signal strength (= stereo status).
+ */
+-static inline int gemtek_getsigstr(void)
++static inline int gemtek_getsigstr(struct gemtek *gt)
+ {
+- return inb_p(io) & GEMTEK_NS ? 0 : 1;
++ int sig;
++
++ mutex_lock(&gt->lock);
++ sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1;
++ mutex_unlock(&gt->lock);
++ return sig;
+ }
+
+ /*
+ * Check if requested card acts like GemTek Radio card.
+ */
+-static int gemtek_verify(int port)
++static int gemtek_verify(struct gemtek *gt, int port)
+ {
+- static int verified = -1;
+ int i, q;
+
+- if (verified == port)
++ if (gt->verified == port)
+ return 1;
+
+- spin_lock(&lock);
++ mutex_lock(&gt->lock);
+
+ q = inb_p(port); /* Read bus contents before probing. */
+ /* Try to turn on CE, CK and DA respectively and check if card responds
+@@ -316,15 +318,15 @@ static int gemtek_verify(int port)
+ udelay(SHORT_DELAY);
+
+ if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
+- spin_unlock(&lock);
++ mutex_unlock(&gt->lock);
+ return 0;
+ }
+ }
+ outb_p(q >> 5, port); /* Write bus contents back. */
+ udelay(SHORT_DELAY);
+
+- spin_unlock(&lock);
+- verified = port;
++ mutex_unlock(&gt->lock);
++ gt->verified = port;
+
+ return 1;
+ }
+@@ -332,83 +334,61 @@ static int gemtek_verify(int port)
+ /*
+ * Automatic probing for card.
+ */
+-static int gemtek_probe(void)
++static int gemtek_probe(struct gemtek *gt)
+ {
++ struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
+ int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
+ int i;
+
+ if (!probe) {
+- printk(KERN_INFO "Automatic device probing disabled.\n");
++ v4l2_info(v4l2_dev, "Automatic device probing disabled.\n");
+ return -1;
+ }
+
+- printk(KERN_INFO "Automatic device probing enabled.\n");
++ v4l2_info(v4l2_dev, "Automatic device probing enabled.\n");
+
+ for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
+- printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]);
++ v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]);
+
+ if (!request_region(ioports[i], 1, "gemtek-probe")) {
+- printk(KERN_WARNING "I/O port 0x%x busy!\n",
++ v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n",
+ ioports[i]);
+ continue;
+ }
+
+- if (gemtek_verify(ioports[i])) {
+- printk(KERN_INFO "Card found from I/O port "
++ if (gemtek_verify(gt, ioports[i])) {
++ v4l2_info(v4l2_dev, "Card found from I/O port "
+ "0x%x!\n", ioports[i]);
+
+ release_region(ioports[i], 1);
+-
+- io = ioports[i];
+- return io;
++ gt->io = ioports[i];
++ return gt->io;
+ }
+
+ release_region(ioports[i], 1);
+ }
+
+- printk(KERN_ERR "Automatic probing failed!\n");
+-
++ v4l2_err(v4l2_dev, "Automatic probing failed!\n");
+ return -1;
+ }
+
+ /*
+ * Video 4 Linux stuff.
+ */
+-
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- }, {
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 65535,
+- .step = 65535,
+- .default_value = 0xff,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- }
+-};
+-
+-static int gemtek_exclusive_open(struct file *file)
++static int gemtek_open(struct file *file)
+ {
+- return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int gemtek_exclusive_release(struct file *file)
++static int gemtek_release(struct file *file)
+ {
+- clear_bit(0, &in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations gemtek_fops = {
+ .owner = THIS_MODULE,
+- .open = gemtek_exclusive_open,
+- .release = gemtek_exclusive_release,
++ .open = gemtek_open,
++ .release = gemtek_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -417,23 +397,25 @@ static int vidioc_querycap(struct file *file, void *priv,
+ {
+ strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
+ strlcpy(v->card, "GemTek", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
+ {
++ struct gemtek *gt = video_drvdata(file);
++
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+ v->rangelow = GEMTEK_LOWFREQ;
+ v->rangehigh = GEMTEK_HIGHFREQ;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+- v->signal = 0xffff * gemtek_getsigstr();
++ v->signal = 0xffff * gemtek_getsigstr(gt);
+ if (v->signal) {
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+@@ -441,65 +423,56 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO;
+ }
+-
+ return 0;
+ }
+
+ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+- return 0;
++ return (v->index != 0) ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_frequency(struct file *file, void *priv,
++static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct gemtek_device *rt = video_drvdata(file);
+-
+- gemtek_setfreq(rt, f->frequency);
++ struct gemtek *gt = video_drvdata(file);
+
++ if (f->tuner != 0)
++ return -EINVAL;
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = gt->lastfreq;
+ return 0;
+ }
+
+-static int vidioc_g_frequency(struct file *file, void *priv,
++static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct gemtek_device *rt = video_drvdata(file);
++ struct gemtek *gt = video_drvdata(file);
+
+- f->type = V4L2_TUNER_RADIO;
+- f->frequency = rt->lastfreq;
++ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
++ return -EINVAL;
++ gemtek_setfreq(gt, f->frequency);
+ return 0;
+ }
+
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
++ default:
++ return -EINVAL;
+ }
+- return -EINVAL;
+ }
+
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct gemtek_device *rt = video_drvdata(file);
++ struct gemtek *gt = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+- ctrl->value = rt->muted;
+- return 0;
+- case V4L2_CID_AUDIO_VOLUME:
+- if (rt->muted)
+- ctrl->value = 0;
+- else
+- ctrl->value = 65535;
++ ctrl->value = gt->muted;
+ return 0;
+ }
+ return -EINVAL;
+@@ -508,35 +481,19 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct gemtek_device *rt = video_drvdata(file);
++ struct gemtek *gt = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value)
+- gemtek_mute(rt);
+- else
+- gemtek_unmute(rt);
+- return 0;
+- case V4L2_CID_AUDIO_VOLUME:
+- if (ctrl->value)
+- gemtek_unmute(rt);
++ gemtek_mute(gt);
+ else
+- gemtek_mute(rt);
++ gemtek_unmute(gt);
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -545,16 +502,20 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
++ return (i != 0) ? -EINVAL : 0;
++}
++
++static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
++{
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
+- return 0;
++ return (a->index != 0) ? -EINVAL : 0;
+ }
+
+ static const struct v4l2_ioctl_ops gemtek_ioctl_ops = {
+@@ -572,62 +533,73 @@ static const struct v4l2_ioctl_ops gemtek_ioctl_ops = {
+ .vidioc_s_ctrl = vidioc_s_ctrl
+ };
+
+-static struct video_device gemtek_radio = {
+- .name = "GemTek Radio card",
+- .fops = &gemtek_fops,
+- .ioctl_ops = &gemtek_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ /*
+ * Initialization / cleanup related stuff.
+ */
+
+-/*
+- * Initilize card.
+- */
+ static int __init gemtek_init(void)
+ {
+- printk(KERN_INFO RADIO_BANNER "\n");
++ struct gemtek *gt = &gemtek_card;
++ struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
++ int res;
+
+- spin_lock_init(&lock);
++ strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name));
+
+- gemtek_probe();
+- if (io) {
+- if (!request_region(io, 1, "gemtek")) {
+- printk(KERN_ERR "I/O port 0x%x already in use.\n", io);
++ v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n");
++
++ mutex_init(&gt->lock);
++
++ gt->verified = -1;
++ gt->io = io;
++ gemtek_probe(gt);
++ if (gt->io) {
++ if (!request_region(gt->io, 1, "gemtek")) {
++ v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io);
+ return -EBUSY;
+ }
+
+- if (!gemtek_verify(io))
+- printk(KERN_WARNING "Card at I/O port 0x%x does not "
++ if (!gemtek_verify(gt, gt->io))
++ v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not "
+ "respond properly, check your "
+- "configuration.\n", io);
++ "configuration.\n", gt->io);
+ else
+- printk(KERN_INFO "Using I/O port 0x%x.\n", io);
++ v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io);
+ } else if (probe) {
+- printk(KERN_ERR "Automatic probing failed and no "
++ v4l2_err(v4l2_dev, "Automatic probing failed and no "
+ "fixed I/O port defined.\n");
+ return -ENODEV;
+ } else {
+- printk(KERN_ERR "Automatic probing disabled but no fixed "
++ v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed "
+ "I/O port defined.");
+ return -EINVAL;
+ }
+
+- video_set_drvdata(&gemtek_radio, &gemtek_unit);
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ release_region(gt->io, 1);
++ return res;
++ }
+
+- if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io, 1);
++ strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name));
++ gt->vdev.v4l2_dev = v4l2_dev;
++ gt->vdev.fops = &gemtek_fops;
++ gt->vdev.ioctl_ops = &gemtek_ioctl_ops;
++ gt->vdev.release = video_device_release_empty;
++ video_set_drvdata(&gt->vdev, gt);
++
++ if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(v4l2_dev);
++ release_region(gt->io, 1);
+ return -EBUSY;
+ }
+
+ /* Set defaults */
+- gemtek_unit.lastfreq = GEMTEK_LOWFREQ;
+- gemtek_unit.bu2614data = 0;
++ gt->lastfreq = GEMTEK_LOWFREQ;
++ gt->bu2614data = 0;
+
+ if (initmute)
+- gemtek_mute(&gemtek_unit);
++ gemtek_mute(gt);
+
+ return 0;
+ }
+@@ -637,15 +609,19 @@ static int __init gemtek_init(void)
+ */
+ static void __exit gemtek_exit(void)
+ {
++ struct gemtek *gt = &gemtek_card;
++ struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
++
+ if (shutdown) {
+ hardmute = 1; /* Turn off PLL */
+- gemtek_mute(&gemtek_unit);
++ gemtek_mute(gt);
+ } else {
+- printk(KERN_INFO "Module unloaded but card not muted!\n");
++ v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n");
+ }
+
+- video_unregister_device(&gemtek_radio);
+- release_region(io, 1);
++ video_unregister_device(&gt->vdev);
++ v4l2_device_unregister(&gt->v4l2_dev);
++ release_region(gt->io, 1);
+ }
+
+ module_init(gemtek_init);
+diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
+index ba3a13a..01a6d22 100644
+--- a/drivers/media/radio/radio-maestro.c
++++ b/drivers/media/radio/radio-maestro.c
+@@ -22,27 +22,22 @@
+ #include <linux/init.h>
+ #include <linux/ioport.h>
+ #include <linux/delay.h>
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+ #include <linux/pci.h>
+ #include <linux/videodev2.h>
+-#include <media/v4l2-common.h>
++#include <linux/io.h>
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,0,6)
+-#define DRIVER_VERSION "0.06"
++MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
++MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
++MODULE_LICENSE("GPL");
+
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- }
+-};
++static int radio_nr = -1;
++module_param(radio_nr, int, 0);
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 6)
++#define DRIVER_VERSION "0.06"
+
+ #define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */
+
+@@ -72,62 +67,27 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+
+ #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
+
+-static int radio_nr = -1;
+-module_param(radio_nr, int, 0);
++struct maestro {
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ struct pci_dev *pdev;
++ struct mutex lock;
+
+-static unsigned long in_use;
+-
+-static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
++ u16 io; /* base of Maestro card radio io (GPIO_DATA)*/
++ u16 muted; /* VIDEO_AUDIO_MUTE */
++ u16 stereo; /* VIDEO_TUNER_STEREO_ON */
++ u16 tuned; /* signal strength (0 or 0xffff) */
++};
+
+-static int maestro_exclusive_open(struct file *file)
++static inline struct maestro *to_maestro(struct v4l2_device *v4l2_dev)
+ {
+- return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
++ return container_of(v4l2_dev, struct maestro, v4l2_dev);
+ }
+
+-static int maestro_exclusive_release(struct file *file)
++static u32 radio_bits_get(struct maestro *dev)
+ {
+- clear_bit(0, &in_use);
+- return 0;
+-}
+-
+-static void maestro_remove(struct pci_dev *pdev);
+-
+-static struct pci_device_id maestro_r_pci_tbl[] = {
+- { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968),
+- .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+- .class_mask = 0xffff00 },
+- { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978),
+- .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+- .class_mask = 0xffff00 },
+- { 0 }
+-};
+-MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl);
+-
+-static struct pci_driver maestro_r_driver = {
+- .name = "maestro_radio",
+- .id_table = maestro_r_pci_tbl,
+- .probe = maestro_probe,
+- .remove = __devexit_p(maestro_remove),
+-};
+-
+-static const struct v4l2_file_operations maestro_fops = {
+- .owner = THIS_MODULE,
+- .open = maestro_exclusive_open,
+- .release = maestro_exclusive_release,
+- .ioctl = video_ioctl2,
+-};
+-
+-struct radio_device {
+- u16 io, /* base of Maestro card radio io (GPIO_DATA)*/
+- muted, /* VIDEO_AUDIO_MUTE */
+- stereo, /* VIDEO_TUNER_STEREO_ON */
+- tuned; /* signal strength (0 or 0xffff) */
+-};
+-
+-static u32 radio_bits_get(struct radio_device *dev)
+-{
+- register u16 io=dev->io, l, rdata;
+- register u32 data=0;
++ u16 io = dev->io, l, rdata;
++ u32 data = 0;
+ u16 omask;
+
+ omask = inw(io + IO_MASK);
+@@ -135,25 +95,23 @@ static u32 radio_bits_get(struct radio_device *dev)
+ outw(0, io);
+ udelay(16);
+
+- for (l=24;l--;) {
++ for (l = 24; l--;) {
+ outw(STR_CLK, io); /* HI state */
+ udelay(2);
+- if(!l)
++ if (!l)
+ dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
+ outw(0, io); /* LO state */
+ udelay(2);
+ data <<= 1; /* shift data */
+ rdata = inw(io);
+- if(!l)
+- dev->stereo = rdata & STR_MOST ?
+- 0 : 1;
+- else
+- if(rdata & STR_DATA)
+- data++;
++ if (!l)
++ dev->stereo = (rdata & STR_MOST) ? 0 : 1;
++ else if (rdata & STR_DATA)
++ data++;
+ udelay(2);
+ }
+
+- if(dev->muted)
++ if (dev->muted)
+ outw(STR_WREN, io);
+
+ udelay(4);
+@@ -162,18 +120,18 @@ static u32 radio_bits_get(struct radio_device *dev)
+ return data & 0x3ffe;
+ }
+
+-static void radio_bits_set(struct radio_device *dev, u32 data)
++static void radio_bits_set(struct maestro *dev, u32 data)
+ {
+- register u16 io=dev->io, l, bits;
++ u16 io = dev->io, l, bits;
+ u16 omask, odir;
+
+ omask = inw(io + IO_MASK);
+- odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
++ odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
+ outw(odir | STR_DATA, io + IO_DIR);
+ outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
+ udelay(16);
+- for (l=25;l;l--) {
+- bits = ((data >> 18) & STR_DATA) | STR_WREN ;
++ for (l = 25; l; l--) {
++ bits = ((data >> 18) & STR_DATA) | STR_WREN;
+ data <<= 1; /* shift data */
+ outw(bits, io); /* start strobe */
+ udelay(2);
+@@ -183,7 +141,7 @@ static void radio_bits_set(struct radio_device *dev, u32 data)
+ udelay(4);
+ }
+
+- if(!dev->muted)
++ if (!dev->muted)
+ outw(0, io);
+
+ udelay(4);
+@@ -195,78 +153,79 @@ static void radio_bits_set(struct radio_device *dev, u32 data)
+ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+ {
++ struct maestro *dev = video_drvdata(file);
++
+ strlcpy(v->driver, "radio-maestro", sizeof(v->driver));
+ strlcpy(v->card, "Maestro Radio", sizeof(v->card));
+- sprintf(v->bus_info, "PCI");
++ snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- struct radio_device *card = video_drvdata(file);
++ struct maestro *dev = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- (void)radio_bits_get(card);
++ mutex_lock(&dev->lock);
++ radio_bits_get(dev);
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+ v->rangelow = FREQ_LO;
+ v->rangehigh = FREQ_HI;
+- v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ v->capability = V4L2_TUNER_CAP_LOW;
+- if(card->stereo)
++ if (dev->stereo)
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+- v->signal = card->tuned;
++ v->signal = dev->tuned;
++ mutex_unlock(&dev->lock);
+ return 0;
+ }
+
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct radio_device *card = video_drvdata(file);
++ struct maestro *dev = video_drvdata(file);
+
+ if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
+ return -EINVAL;
+- radio_bits_set(card, FREQ2BITS(f->frequency));
++ mutex_lock(&dev->lock);
++ radio_bits_set(dev, FREQ2BITS(f->frequency));
++ mutex_unlock(&dev->lock);
+ return 0;
+ }
+
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct radio_device *card = video_drvdata(file);
++ struct maestro *dev = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+- f->frequency = BITS2FREQ(radio_bits_get(card));
++ mutex_lock(&dev->lock);
++ f->frequency = BITS2FREQ(radio_bits_get(dev));
++ mutex_unlock(&dev->lock);
+ return 0;
+ }
+
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+ }
+ return -EINVAL;
+ }
+@@ -274,11 +233,11 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct radio_device *card = video_drvdata(file);
++ struct maestro *dev = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+- ctrl->value = card->muted;
++ ctrl->value = dev->muted;
+ return 0;
+ }
+ return -EINVAL;
+@@ -287,56 +246,85 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct radio_device *card = video_drvdata(file);
+- register u16 io = card->io;
+- register u16 omask = inw(io + IO_MASK);
++ struct maestro *dev = video_drvdata(file);
++ u16 io = dev->io;
++ u16 omask;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
++ mutex_lock(&dev->lock);
++ omask = inw(io + IO_MASK);
+ outw(~STR_WREN, io + IO_MASK);
+- outw((card->muted = ctrl->value ) ?
+- STR_WREN : 0, io);
++ dev->muted = ctrl->value;
++ outw(dev->muted ? STR_WREN : 0, io);
+ udelay(4);
+ outw(omask, io + IO_MASK);
+ msleep(125);
++ mutex_unlock(&dev->lock);
+ return 0;
+ }
+ return -EINVAL;
+ }
+
++static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
++{
++ *i = 0;
++ return 0;
++}
++
++static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
++{
++ return i ? -EINVAL : 0;
++}
++
+ static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
+ {
+- *i = 0;
+- return 0;
++ return a->index ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
++static int maestro_open(struct file *file)
+ {
+- if (i != 0)
+- return -EINVAL;
+ return 0;
+ }
+
+-static int vidioc_s_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
++static int maestro_release(struct file *file)
+ {
+- if (a->index != 0)
+- return -EINVAL;
+ return 0;
+ }
+
+-static u16 __devinit radio_power_on(struct radio_device *dev)
++static const struct v4l2_file_operations maestro_fops = {
++ .owner = THIS_MODULE,
++ .open = maestro_open,
++ .release = maestro_release,
++ .ioctl = video_ioctl2,
++};
++
++static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_g_tuner = vidioc_g_tuner,
++ .vidioc_s_tuner = vidioc_s_tuner,
++ .vidioc_g_audio = vidioc_g_audio,
++ .vidioc_s_audio = vidioc_s_audio,
++ .vidioc_g_input = vidioc_g_input,
++ .vidioc_s_input = vidioc_s_input,
++ .vidioc_g_frequency = vidioc_g_frequency,
++ .vidioc_s_frequency = vidioc_s_frequency,
++ .vidioc_queryctrl = vidioc_queryctrl,
++ .vidioc_g_ctrl = vidioc_g_ctrl,
++ .vidioc_s_ctrl = vidioc_s_ctrl,
++};
++
++static u16 __devinit radio_power_on(struct maestro *dev)
+ {
+ register u16 io = dev->io;
+ register u32 ofreq;
+@@ -360,33 +348,11 @@ static u16 __devinit radio_power_on(struct radio_device *dev)
+ return (ofreq == radio_bits_get(dev));
+ }
+
+-static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
+- .vidioc_querycap = vidioc_querycap,
+- .vidioc_g_tuner = vidioc_g_tuner,
+- .vidioc_s_tuner = vidioc_s_tuner,
+- .vidioc_g_audio = vidioc_g_audio,
+- .vidioc_s_audio = vidioc_s_audio,
+- .vidioc_g_input = vidioc_g_input,
+- .vidioc_s_input = vidioc_s_input,
+- .vidioc_g_frequency = vidioc_g_frequency,
+- .vidioc_s_frequency = vidioc_s_frequency,
+- .vidioc_queryctrl = vidioc_queryctrl,
+- .vidioc_g_ctrl = vidioc_g_ctrl,
+- .vidioc_s_ctrl = vidioc_s_ctrl,
+-};
+-
+-static struct video_device maestro_radio = {
+- .name = "Maestro radio",
+- .fops = &maestro_fops,
+- .ioctl_ops = &maestro_ioctl_ops,
+- .release = video_device_release,
+-};
+-
+ static int __devinit maestro_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+ {
+- struct radio_device *radio_unit;
+- struct video_device *maestro_radio_inst;
++ struct maestro *dev;
++ struct v4l2_device *v4l2_dev;
+ int retval;
+
+ retval = pci_enable_device(pdev);
+@@ -397,46 +363,53 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
+
+ retval = -ENOMEM;
+
+- radio_unit = kzalloc(sizeof(*radio_unit), GFP_KERNEL);
+- if (radio_unit == NULL) {
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (dev == NULL) {
+ dev_err(&pdev->dev, "not enough memory\n");
+ goto err;
+ }
+
+- radio_unit->io = pci_resource_start(pdev, 0) + GPIO_DATA;
++ v4l2_dev = &dev->v4l2_dev;
++ mutex_init(&dev->lock);
++ dev->pdev = pdev;
+
+- maestro_radio_inst = video_device_alloc();
+- if (maestro_radio_inst == NULL) {
+- dev_err(&pdev->dev, "not enough memory\n");
++ strlcpy(v4l2_dev->name, "maestro", sizeof(v4l2_dev->name));
++
++ retval = v4l2_device_register(&pdev->dev, v4l2_dev);
++ if (retval < 0) {
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+ goto errfr;
+ }
+
+- memcpy(maestro_radio_inst, &maestro_radio, sizeof(maestro_radio));
+- video_set_drvdata(maestro_radio_inst, radio_unit);
+- pci_set_drvdata(pdev, maestro_radio_inst);
++ dev->io = pci_resource_start(pdev, 0) + GPIO_DATA;
+
+- retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, radio_nr);
++ strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
++ dev->vdev.v4l2_dev = v4l2_dev;
++ dev->vdev.fops = &maestro_fops;
++ dev->vdev.ioctl_ops = &maestro_ioctl_ops;
++ dev->vdev.release = video_device_release_empty;
++ video_set_drvdata(&dev->vdev, dev);
++
++ retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
+ if (retval) {
+- printk(KERN_ERR "can't register video device!\n");
++ v4l2_err(v4l2_dev, "can't register video device!\n");
+ goto errfr1;
+ }
+
+- if (!radio_power_on(radio_unit)) {
++ if (!radio_power_on(dev)) {
+ retval = -EIO;
+ goto errunr;
+ }
+
+- dev_info(&pdev->dev, "version " DRIVER_VERSION " time " __TIME__ " "
+- __DATE__ "\n");
+- dev_info(&pdev->dev, "radio chip initialized\n");
++ v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
+
+ return 0;
+ errunr:
+- video_unregister_device(maestro_radio_inst);
++ video_unregister_device(&dev->vdev);
+ errfr1:
+- video_device_release(maestro_radio_inst);
++ v4l2_device_unregister(v4l2_dev);
+ errfr:
+- kfree(radio_unit);
++ kfree(dev);
+ err:
+ return retval;
+
+@@ -444,11 +417,31 @@ err:
+
+ static void __devexit maestro_remove(struct pci_dev *pdev)
+ {
+- struct video_device *vdev = pci_get_drvdata(pdev);
++ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
++ struct maestro *dev = to_maestro(v4l2_dev);
+
+- video_unregister_device(vdev);
++ video_unregister_device(&dev->vdev);
++ v4l2_device_unregister(&dev->v4l2_dev);
+ }
+
++static struct pci_device_id maestro_r_pci_tbl[] = {
++ { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968),
++ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
++ .class_mask = 0xffff00 },
++ { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978),
++ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
++ .class_mask = 0xffff00 },
++ { 0 }
++};
++MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl);
++
++static struct pci_driver maestro_r_driver = {
++ .name = "maestro_radio",
++ .id_table = maestro_r_pci_tbl,
++ .probe = maestro_probe,
++ .remove = __devexit_p(maestro_remove),
++};
++
+ static int __init maestro_radio_init(void)
+ {
+ int retval = pci_register_driver(&maestro_r_driver);
+@@ -466,7 +459,3 @@ static void __exit maestro_radio_exit(void)
+
+ module_init(maestro_radio_init);
+ module_exit(maestro_radio_exit);
+-
+-MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
+-MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
+index c5dc00a..2606f0b 100644
+--- a/drivers/media/radio/radio-maxiradio.c
++++ b/drivers/media/radio/radio-maxiradio.c
+@@ -37,38 +37,32 @@
+ #include <linux/init.h>
+ #include <linux/ioport.h>
+ #include <linux/delay.h>
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
+ #include <linux/mutex.h>
+-
+ #include <linux/pci.h>
+ #include <linux/videodev2.h>
+-#include <media/v4l2-common.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#include <linux/io.h>
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+
++MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
++MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
++MODULE_LICENSE("GPL");
++
++static int radio_nr = -1;
++module_param(radio_nr, int, 0);
++
++static int debug;
++
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "activates debug info");
++
+ #define DRIVER_VERSION "0.77"
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,7,7)
+-
+-static struct video_device maxiradio_radio;
+-
+-#define dprintk(num, fmt, arg...) \
+- do { \
+- if (maxiradio_radio.debug >= num) \
+- printk(KERN_DEBUG "%s: " fmt, \
+- maxiradio_radio.name, ## arg); } while (0)
+-
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- }
+-};
++#define RADIO_VERSION KERNEL_VERSION(0, 7, 7)
++
++#define dprintk(dev, num, fmt, arg...) \
++ v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg)
+
+ #ifndef PCI_VENDOR_ID_GUILLEMOT
+ #define PCI_VENDOR_ID_GUILLEMOT 0x5046
+@@ -80,90 +74,70 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+
+
+ /* TEA5757 pin mappings */
+-static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ;
+-
+-static int radio_nr = -1;
+-module_param(radio_nr, int, 0);
++static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
+
+-static unsigned long in_use;
+-
+-#define FREQ_LO 50*16000
+-#define FREQ_HI 150*16000
++#define FREQ_LO (50 * 16000)
++#define FREQ_HI (150 * 16000)
+
+ #define FREQ_IF 171200 /* 10.7*16000 */
+ #define FREQ_STEP 200 /* 12.5*16 */
+
+ /* (x==fmhz*16*1000) -> bits */
+-#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1)) \
+- /(FREQ_STEP<<2))<<2)
++#define FREQ2BITS(x) \
++ ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2)
+
+ #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
+
+
+-static int maxiradio_exclusive_open(struct file *file)
++struct maxiradio
+ {
+- return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
+-}
+-
+-static int maxiradio_exclusive_release(struct file *file)
+-{
+- clear_bit(0, &in_use);
+- return 0;
+-}
+-
+-static const struct v4l2_file_operations maxiradio_fops = {
+- .owner = THIS_MODULE,
+- .open = maxiradio_exclusive_open,
+- .release = maxiradio_exclusive_release,
+- .ioctl = video_ioctl2,
+-};
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ struct pci_dev *pdev;
+
+-static struct radio_device
+-{
+- __u16 io, /* base of radio io */
+- muted, /* VIDEO_AUDIO_MUTE */
+- stereo, /* VIDEO_TUNER_STEREO_ON */
+- tuned; /* signal strength (0 or 0xffff) */
++ u16 io; /* base of radio io */
++ u16 muted; /* VIDEO_AUDIO_MUTE */
++ u16 stereo; /* VIDEO_TUNER_STEREO_ON */
++ u16 tuned; /* signal strength (0 or 0xffff) */
+
+ unsigned long freq;
+
+ struct mutex lock;
+-} radio_unit = {
+- .muted =1,
+- .freq = FREQ_LO,
+ };
+
+-static void outbit(unsigned long bit, __u16 io)
++static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev)
+ {
+- if (bit != 0)
+- {
+- outb( power|wren|data ,io); udelay(4);
+- outb( power|wren|data|clk ,io); udelay(4);
+- outb( power|wren|data ,io); udelay(4);
+- }
+- else
+- {
+- outb( power|wren ,io); udelay(4);
+- outb( power|wren|clk ,io); udelay(4);
+- outb( power|wren ,io); udelay(4);
+- }
++ return container_of(v4l2_dev, struct maxiradio, v4l2_dev);
+ }
+
+-static void turn_power(__u16 io, int p)
++static void outbit(unsigned long bit, u16 io)
++{
++ int val = power | wren | (bit ? data : 0);
++
++ outb(val, io);
++ udelay(4);
++ outb(val | clk, io);
++ udelay(4);
++ outb(val, io);
++ udelay(4);
++}
++
++static void turn_power(struct maxiradio *dev, int p)
+ {
+ if (p != 0) {
+- dprintk(1, "Radio powered on\n");
+- outb(power, io);
++ dprintk(dev, 1, "Radio powered on\n");
++ outb(power, dev->io);
+ } else {
+- dprintk(1, "Radio powered off\n");
+- outb(0,io);
++ dprintk(dev, 1, "Radio powered off\n");
++ outb(0, dev->io);
+ }
+ }
+
+-static void set_freq(__u16 io, __u32 freq)
++static void set_freq(struct maxiradio *dev, u32 freq)
+ {
+ unsigned long int si;
+ int bl;
++ int io = dev->io;
+ int val = FREQ2BITS(freq);
+
+ /* TEA5757 shift register bits (see pdf) */
+@@ -188,14 +162,14 @@ static void set_freq(__u16 io, __u32 freq)
+ si >>= 1;
+ }
+
+- dprintk(1, "Radio freq set to %d.%02d MHz\n",
++ dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n",
+ freq / 16000,
+ freq % 16000 * 100 / 16000);
+
+- turn_power(io, 1);
++ turn_power(dev, 1);
+ }
+
+-static int get_stereo(__u16 io)
++static int get_stereo(u16 io)
+ {
+ outb(power,io);
+ udelay(4);
+@@ -203,7 +177,7 @@ static int get_stereo(__u16 io)
+ return !(inb(io) & mo_st);
+ }
+
+-static int get_tune(__u16 io)
++static int get_tune(u16 io)
+ {
+ outb(power+clk,io);
+ udelay(4);
+@@ -212,95 +186,84 @@ static int get_tune(__u16 io)
+ }
+
+
+-static int vidioc_querycap (struct file *file, void *priv,
++static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+ {
+- strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
+- strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
+- sprintf(v->bus_info,"ISA");
+- v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ struct maxiradio *dev = video_drvdata(file);
+
++ strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver));
++ strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card));
++ snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+-static int vidioc_g_tuner (struct file *file, void *priv,
++static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- struct radio_device *card = video_drvdata(file);
++ struct maxiradio *dev = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- memset(v,0,sizeof(*v));
+- strcpy(v->name, "FM");
++ mutex_lock(&dev->lock);
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+-
+- v->rangelow=FREQ_LO;
+- v->rangehigh=FREQ_HI;
+- v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+- v->capability=V4L2_TUNER_CAP_LOW;
+- if(get_stereo(card->io))
++ v->rangelow = FREQ_LO;
++ v->rangehigh = FREQ_HI;
++ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
++ v->capability = V4L2_TUNER_CAP_LOW;
++ if (get_stereo(dev->io))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+- v->signal=0xffff*get_tune(card->io);
++ v->signal = 0xffff * get_tune(dev->io);
++ mutex_unlock(&dev->lock);
+
+ return 0;
+ }
+
+-static int vidioc_s_tuner (struct file *file, void *priv,
++static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+-
+- return 0;
+-}
+-
+-static int vidioc_g_audio (struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "FM");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+-
+ return 0;
+ }
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
++ return i ? -EINVAL : 0;
++}
+
++static int vidioc_g_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+
+-static int vidioc_s_audio (struct file *file, void *priv,
++static int vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
+-
+- return 0;
++ return a->index ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_frequency (struct file *file, void *priv,
++static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct radio_device *card = video_drvdata(file);
++ struct maxiradio *dev = video_drvdata(file);
+
+ if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
+- dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
++ dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
+ f->frequency / 16000,
+ f->frequency % 16000 * 100 / 16000,
+ FREQ_LO / 16000, FREQ_HI / 16000);
+@@ -308,75 +271,91 @@ static int vidioc_s_frequency (struct file *file, void *priv,
+ return -EINVAL;
+ }
+
+- card->freq = f->frequency;
+- set_freq(card->io, card->freq);
++ mutex_lock(&dev->lock);
++ dev->freq = f->frequency;
++ set_freq(dev, dev->freq);
+ msleep(125);
++ mutex_unlock(&dev->lock);
+
+ return 0;
+ }
+
+-static int vidioc_g_frequency (struct file *file, void *priv,
++static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct radio_device *card = video_drvdata(file);
++ struct maxiradio *dev = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+- f->frequency = card->freq;
++ f->frequency = dev->freq;
+
+- dprintk(4, "radio freq is %d.%02d MHz",
++ dprintk(dev, 4, "radio freq is %d.%02d MHz",
+ f->frequency / 16000,
+ f->frequency % 16000 * 100 / 16000);
+
+ return 0;
+ }
+
+-static int vidioc_queryctrl (struct file *file, void *priv,
++static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
+- return (0);
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+ }
+-
+ return -EINVAL;
+ }
+
+-static int vidioc_g_ctrl (struct file *file, void *priv,
+- struct v4l2_control *ctrl)
++static int vidioc_g_ctrl(struct file *file, void *priv,
++ struct v4l2_control *ctrl)
+ {
+- struct radio_device *card = video_drvdata(file);
++ struct maxiradio *dev = video_drvdata(file);
+
+ switch (ctrl->id) {
+- case V4L2_CID_AUDIO_MUTE:
+- ctrl->value=card->muted;
+- return (0);
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value = dev->muted;
++ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+-static int vidioc_s_ctrl (struct file *file, void *priv,
+- struct v4l2_control *ctrl)
++static int vidioc_s_ctrl(struct file *file, void *priv,
++ struct v4l2_control *ctrl)
+ {
+- struct radio_device *card = video_drvdata(file);
++ struct maxiradio *dev = video_drvdata(file);
+
+ switch (ctrl->id) {
+- case V4L2_CID_AUDIO_MUTE:
+- card->muted = ctrl->value;
+- if(card->muted)
+- turn_power(card->io, 0);
+- else
+- set_freq(card->io, card->freq);
+- return 0;
++ case V4L2_CID_AUDIO_MUTE:
++ mutex_lock(&dev->lock);
++ dev->muted = ctrl->value;
++ if (dev->muted)
++ turn_power(dev, 0);
++ else
++ set_freq(dev, dev->freq);
++ mutex_unlock(&dev->lock);
++ return 0;
+ }
+
+ return -EINVAL;
+ }
+
++static int maxiradio_open(struct file *file)
++{
++ return 0;
++}
++
++static int maxiradio_release(struct file *file)
++{
++ return 0;
++}
++
++static const struct v4l2_file_operations maxiradio_fops = {
++ .owner = THIS_MODULE,
++ .open = maxiradio_open,
++ .release = maxiradio_release,
++ .ioctl = video_ioctl2,
++};
++
+ static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+@@ -392,60 +371,84 @@ static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ };
+
+-static struct video_device maxiradio_radio = {
+- .name = "Maxi Radio FM2000 radio",
+- .fops = &maxiradio_fops,
+- .ioctl_ops = &maxiradio_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+ {
+- if(!request_region(pci_resource_start(pdev, 0),
++ struct maxiradio *dev;
++ struct v4l2_device *v4l2_dev;
++ int retval = -ENOMEM;
++
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (dev == NULL) {
++ dev_err(&pdev->dev, "not enough memory\n");
++ return -ENOMEM;
++ }
++
++ v4l2_dev = &dev->v4l2_dev;
++ mutex_init(&dev->lock);
++ dev->pdev = pdev;
++ dev->muted = 1;
++ dev->freq = FREQ_LO;
++
++ strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name));
++
++ retval = v4l2_device_register(&pdev->dev, v4l2_dev);
++ if (retval < 0) {
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ goto errfr;
++ }
++
++ if (!request_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
+- printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
++ v4l2_err(v4l2_dev, "can't reserve I/O ports\n");
+ goto err_out;
+ }
+
+ if (pci_enable_device(pdev))
+ goto err_out_free_region;
+
+- radio_unit.io = pci_resource_start(pdev, 0);
+- mutex_init(&radio_unit.lock);
+- video_set_drvdata(&maxiradio_radio, &radio_unit);
++ dev->io = pci_resource_start(pdev, 0);
++ strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
++ dev->vdev.v4l2_dev = v4l2_dev;
++ dev->vdev.fops = &maxiradio_fops;
++ dev->vdev.ioctl_ops = &maxiradio_ioctl_ops;
++ dev->vdev.release = video_device_release_empty;
++ video_set_drvdata(&dev->vdev, dev);
+
+- if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- printk("radio-maxiradio: can't register device!");
++ if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_err(v4l2_dev, "can't register device!");
+ goto err_out_free_region;
+ }
+
+- printk(KERN_INFO "radio-maxiradio: version "
+- DRIVER_VERSION
+- " time "
+- __TIME__ " "
+- __DATE__
+- "\n");
++ v4l2_info(v4l2_dev, "version " DRIVER_VERSION
++ " time " __TIME__ " " __DATE__ "\n");
+
+- printk(KERN_INFO "radio-maxiradio: found Guillemot MAXI Radio device (io = 0x%x)\n",
+- radio_unit.io);
++ v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n",
++ dev->io);
+ return 0;
+
+ err_out_free_region:
+ release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ err_out:
++ v4l2_device_unregister(v4l2_dev);
++errfr:
++ kfree(dev);
+ return -ENODEV;
+ }
+
+ static void __devexit maxiradio_remove_one(struct pci_dev *pdev)
+ {
+- video_unregister_device(&maxiradio_radio);
++ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
++ struct maxiradio *dev = to_maxiradio(v4l2_dev);
++
++ video_unregister_device(&dev->vdev);
++ v4l2_device_unregister(&dev->v4l2_dev);
+ release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ }
+
+ static struct pci_device_id maxiradio_pci_tbl[] = {
+ { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO,
+ PCI_ANY_ID, PCI_ANY_ID, },
+- { 0,}
++ { 0 }
+ };
+
+ MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl);
+@@ -469,10 +472,3 @@ static void __exit maxiradio_radio_exit(void)
+
+ module_init(maxiradio_radio_init);
+ module_exit(maxiradio_radio_exit);
+-
+-MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
+-MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
+-MODULE_LICENSE("GPL");
+-
+-module_param_named(debug,maxiradio_radio.debug, int, 0644);
+-MODULE_PARM_DESC(debug,"activates debug info");
+diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
+index fdfc7bf..ded25bf 100644
+--- a/drivers/media/radio/radio-mr800.c
++++ b/drivers/media/radio/radio-mr800.c
+@@ -22,7 +22,7 @@
+ */
+
+ /*
+- * Big thanks to authors of dsbr100.c and radio-si470x.c
++ * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c
+ *
+ * When work was looked pretty good, i discover this:
+ * http://av-usbradio.sourceforge.net/index.php
+@@ -30,18 +30,23 @@
+ * Latest release of theirs project was in 2005.
+ * Probably, this driver could be improved trough using their
+ * achievements (specifications given).
+- * So, we have smth to begin with.
++ * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio
++ * in 2007. He allowed to use his driver to improve current mr800 radio driver.
++ * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492
+ *
+- * History:
+ * Version 0.01: First working version.
+ * It's required to blacklist AverMedia USB Radio
+ * in usbhid/hid-quirks.c
++ * Version 0.10: A lot of cleanups and fixes: unpluging the device,
++ * few mutex locks were added, codinstyle issues, etc.
++ * Added stereo support. Thanks to
++ * Douglas Schilling Landgraf <dougsland@gmail.com> and
++ * David Ellingsworth <david@identd.dyndns.org>
++ * for discussion, help and support.
+ *
+ * Many things to do:
+ * - Correct power managment of device (suspend & resume)
+- * - Make x86 independance (little-endian and big-endian stuff)
+ * - Add code for scanning and smooth tuning
+- * - Checked and add stereo&mono stuff
+ * - Add code for sensitivity value
+ * - Correct mistakes
+ * - In Japan another FREQ_MIN and FREQ_MAX
+@@ -62,8 +67,8 @@
+ /* driver and module definitions */
+ #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
+ #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
+-#define DRIVER_VERSION "0.01"
+-#define RADIO_VERSION KERNEL_VERSION(0, 0, 1)
++#define DRIVER_VERSION "0.10"
++#define RADIO_VERSION KERNEL_VERSION(0, 1, 0)
+
+ MODULE_AUTHOR(DRIVER_AUTHOR);
+ MODULE_DESCRIPTION(DRIVER_DESC);
+@@ -87,6 +92,22 @@ devices, that would be 76 and 91. */
+ #define FREQ_MAX 108.0
+ #define FREQ_MUL 16000
+
++/*
++ * Commands that device should understand
++ * List isnt full and will be updated with implementation of new functions
++ */
++#define AMRADIO_SET_FREQ 0xa4
++#define AMRADIO_SET_MUTE 0xab
++#define AMRADIO_SET_MONO 0xae
++
++/* Comfortable defines for amradio_set_mute */
++#define AMRADIO_START 0x00
++#define AMRADIO_STOP 0x01
++
++/* Comfortable defines for amradio_set_stereo */
++#define WANT_STEREO 0x00
++#define WANT_MONO 0x01
++
+ /* module parameter */
+ static int radio_nr = -1;
+ module_param(radio_nr, int, 0);
+@@ -169,43 +190,48 @@ static struct usb_driver usb_amradio_driver = {
+ .supports_autosuspend = 0,
+ };
+
+-/* switch on radio. Send 8 bytes to device. */
+-static int amradio_start(struct amradio_device *radio)
++/* switch on/off the radio. Send 8 bytes to device */
++static int amradio_set_mute(struct amradio_device *radio, char argument)
+ {
+ int retval;
+ int size;
+
++ /* safety check */
++ if (radio->removed)
++ return -EIO;
++
+ mutex_lock(&radio->lock);
+
+ radio->buffer[0] = 0x00;
+ radio->buffer[1] = 0x55;
+ radio->buffer[2] = 0xaa;
+ radio->buffer[3] = 0x00;
+- radio->buffer[4] = 0xab;
+- radio->buffer[5] = 0x00;
++ radio->buffer[4] = AMRADIO_SET_MUTE;
++ radio->buffer[5] = argument;
+ radio->buffer[6] = 0x00;
+ radio->buffer[7] = 0x00;
+
+ retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+ (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+- if (retval) {
++ if (retval < 0 || size != BUFFER_LENGTH) {
+ mutex_unlock(&radio->lock);
+ return retval;
+ }
+
+- radio->muted = 0;
++ radio->muted = argument;
+
+ mutex_unlock(&radio->lock);
+
+ return retval;
+ }
+
+-/* switch off radio */
+-static int amradio_stop(struct amradio_device *radio)
++/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
++static int amradio_setfreq(struct amradio_device *radio, int freq)
+ {
+ int retval;
+ int size;
++ unsigned short freq_send = 0x10 + (freq >> 3) / 25;
+
+ /* safety check */
+ if (radio->removed)
+@@ -216,33 +242,46 @@ static int amradio_stop(struct amradio_device *radio)
+ radio->buffer[0] = 0x00;
+ radio->buffer[1] = 0x55;
+ radio->buffer[2] = 0xaa;
+- radio->buffer[3] = 0x00;
+- radio->buffer[4] = 0xab;
+- radio->buffer[5] = 0x01;
++ radio->buffer[3] = 0x03;
++ radio->buffer[4] = AMRADIO_SET_FREQ;
++ radio->buffer[5] = 0x00;
+ radio->buffer[6] = 0x00;
+- radio->buffer[7] = 0x00;
++ radio->buffer[7] = 0x08;
+
+ retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+ (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+- if (retval) {
++ if (retval < 0 || size != BUFFER_LENGTH) {
+ mutex_unlock(&radio->lock);
+ return retval;
+ }
+
+- radio->muted = 1;
++ /* frequency is calculated from freq_send and placed in first 2 bytes */
++ radio->buffer[0] = (freq_send >> 8) & 0xff;
++ radio->buffer[1] = freq_send & 0xff;
++ radio->buffer[2] = 0x01;
++ radio->buffer[3] = 0x00;
++ radio->buffer[4] = 0x00;
++ /* 5 and 6 bytes of buffer already = 0x00 */
++ radio->buffer[7] = 0x00;
++
++ retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
++ (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
++
++ if (retval < 0 || size != BUFFER_LENGTH) {
++ mutex_unlock(&radio->lock);
++ return retval;
++ }
+
+ mutex_unlock(&radio->lock);
+
+ return retval;
+ }
+
+-/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+-static int amradio_setfreq(struct amradio_device *radio, int freq)
++static int amradio_set_stereo(struct amradio_device *radio, char argument)
+ {
+ int retval;
+ int size;
+- unsigned short freq_send = 0x13 + (freq >> 3) / 25;
+
+ /* safety check */
+ if (radio->removed)
+@@ -253,50 +292,33 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
+ radio->buffer[0] = 0x00;
+ radio->buffer[1] = 0x55;
+ radio->buffer[2] = 0xaa;
+- radio->buffer[3] = 0x03;
+- radio->buffer[4] = 0xa4;
+- radio->buffer[5] = 0x00;
+- radio->buffer[6] = 0x00;
+- radio->buffer[7] = 0x08;
+-
+- retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+- (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+-
+- if (retval) {
+- mutex_unlock(&radio->lock);
+- return retval;
+- }
+-
+- /* frequency is calculated from freq_send and placed in first 2 bytes */
+- radio->buffer[0] = (freq_send >> 8) & 0xff;
+- radio->buffer[1] = freq_send & 0xff;
+- radio->buffer[2] = 0x01;
+ radio->buffer[3] = 0x00;
+- radio->buffer[4] = 0x00;
+- /* 5 and 6 bytes of buffer already = 0x00 */
++ radio->buffer[4] = AMRADIO_SET_MONO;
++ radio->buffer[5] = argument;
++ radio->buffer[6] = 0x00;
+ radio->buffer[7] = 0x00;
+
+ retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+ (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+- if (retval) {
++ if (retval < 0 || size != BUFFER_LENGTH) {
++ radio->stereo = -1;
+ mutex_unlock(&radio->lock);
+ return retval;
+ }
+
+- radio->stereo = 0;
++ radio->stereo = 1;
+
+ mutex_unlock(&radio->lock);
+
+ return retval;
+ }
+
+-/* USB subsystem interface begins here */
+-
+-/* handle unplugging of the device, release data structures
+-if nothing keeps us from doing it. If something is still
+-keeping us busy, the release callback of v4l will take care
+-of releasing it. */
++/* Handle unplugging the device.
++ * We call video_unregister_device in any case.
++ * The last function called in this procedure is
++ * usb_amradio_device_release.
++ */
+ static void usb_amradio_disconnect(struct usb_interface *intf)
+ {
+ struct amradio_device *radio = usb_get_intfdata(intf);
+@@ -313,9 +335,11 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
+ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+ {
++ struct amradio_device *radio = video_drvdata(file);
++
+ strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
+ strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
+- sprintf(v->bus_info, "USB");
++ usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+ return 0;
+@@ -326,6 +350,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+ struct amradio_device *radio = video_get_drvdata(video_devdata(file));
++ int retval;
+
+ /* safety check */
+ if (radio->removed)
+@@ -337,7 +362,16 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ /* TODO: Add function which look is signal stereo or not
+ * amradio_getstat(radio);
+ */
+- radio->stereo = -1;
++
++/* we call amradio_set_stereo to set radio->stereo
++ * Honestly, amradio_getstat should cover this in future and
++ * amradio_set_stereo shouldn't be here
++ */
++ retval = amradio_set_stereo(radio, WANT_STEREO);
++ if (retval < 0)
++ amradio_dev_warn(&radio->videodev->dev,
++ "set stereo failed\n");
++
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+ v->rangelow = FREQ_MIN * FREQ_MUL;
+@@ -358,6 +392,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+ struct amradio_device *radio = video_get_drvdata(video_devdata(file));
++ int retval;
+
+ /* safety check */
+ if (radio->removed)
+@@ -365,6 +400,25 @@ static int vidioc_s_tuner(struct file *file, void *priv,
+
+ if (v->index > 0)
+ return -EINVAL;
++
++ /* mono/stereo selector */
++ switch (v->audmode) {
++ case V4L2_TUNER_MODE_MONO:
++ retval = amradio_set_stereo(radio, WANT_MONO);
++ if (retval < 0)
++ amradio_dev_warn(&radio->videodev->dev,
++ "set mono failed\n");
++ break;
++ case V4L2_TUNER_MODE_STEREO:
++ retval = amradio_set_stereo(radio, WANT_STEREO);
++ if (retval < 0)
++ amradio_dev_warn(&radio->videodev->dev,
++ "set stereo failed\n");
++ break;
++ default:
++ return -EINVAL;
++ }
++
+ return 0;
+ }
+
+@@ -373,13 +427,18 @@ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+ struct amradio_device *radio = video_get_drvdata(video_devdata(file));
++ int retval;
+
+ /* safety check */
+ if (radio->removed)
+ return -EIO;
+
++ mutex_lock(&radio->lock);
+ radio->curfreq = f->frequency;
+- if (amradio_setfreq(radio, radio->curfreq) < 0)
++ mutex_unlock(&radio->lock);
++
++ retval = amradio_setfreq(radio, radio->curfreq);
++ if (retval < 0)
+ amradio_dev_warn(&radio->videodev->dev,
+ "set frequency failed\n");
+ return 0;
+@@ -438,6 +497,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+ struct amradio_device *radio = video_get_drvdata(video_devdata(file));
++ int retval;
+
+ /* safety check */
+ if (radio->removed)
+@@ -446,13 +506,15 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+- if (amradio_stop(radio) < 0) {
++ retval = amradio_set_mute(radio, AMRADIO_STOP);
++ if (retval < 0) {
+ amradio_dev_warn(&radio->videodev->dev,
+ "amradio_stop failed\n");
+ return -1;
+ }
+ } else {
+- if (amradio_start(radio) < 0) {
++ retval = amradio_set_mute(radio, AMRADIO_START);
++ if (retval < 0) {
+ amradio_dev_warn(&radio->videodev->dev,
+ "amradio_start failed\n");
+ return -1;
+@@ -503,20 +565,29 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ static int usb_amradio_open(struct file *file)
+ {
+ struct amradio_device *radio = video_get_drvdata(video_devdata(file));
++ int retval;
+
+ lock_kernel();
+
+ radio->users = 1;
+ radio->muted = 1;
+
+- if (amradio_start(radio) < 0) {
++ retval = amradio_set_mute(radio, AMRADIO_START);
++ if (retval < 0) {
+ amradio_dev_warn(&radio->videodev->dev,
+ "radio did not start up properly\n");
+ radio->users = 0;
+ unlock_kernel();
+ return -EIO;
+ }
+- if (amradio_setfreq(radio, radio->curfreq) < 0)
++
++ retval = amradio_set_stereo(radio, WANT_STEREO);
++ if (retval < 0)
++ amradio_dev_warn(&radio->videodev->dev,
++ "set stereo failed\n");
++
++ retval = amradio_setfreq(radio, radio->curfreq);
++ if (retval < 0)
+ amradio_dev_warn(&radio->videodev->dev,
+ "set frequency failed\n");
+
+@@ -533,10 +604,12 @@ static int usb_amradio_close(struct file *file)
+ if (!radio)
+ return -ENODEV;
+
++ mutex_lock(&radio->lock);
+ radio->users = 0;
++ mutex_unlock(&radio->lock);
+
+ if (!radio->removed) {
+- retval = amradio_stop(radio);
++ retval = amradio_set_mute(radio, AMRADIO_STOP);
+ if (retval < 0)
+ amradio_dev_warn(&radio->videodev->dev,
+ "amradio_stop failed\n");
+@@ -549,8 +622,10 @@ static int usb_amradio_close(struct file *file)
+ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
+ {
+ struct amradio_device *radio = usb_get_intfdata(intf);
++ int retval;
+
+- if (amradio_stop(radio) < 0)
++ retval = amradio_set_mute(radio, AMRADIO_STOP);
++ if (retval < 0)
+ dev_warn(&intf->dev, "amradio_stop failed\n");
+
+ dev_info(&intf->dev, "going into suspend..\n");
+@@ -562,8 +637,10 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
+ static int usb_amradio_resume(struct usb_interface *intf)
+ {
+ struct amradio_device *radio = usb_get_intfdata(intf);
++ int retval;
+
+- if (amradio_start(radio) < 0)
++ retval = amradio_set_mute(radio, AMRADIO_START);
++ if (retval < 0)
+ dev_warn(&intf->dev, "amradio_start failed\n");
+
+ dev_info(&intf->dev, "coming out of suspend..\n");
+@@ -614,28 +691,32 @@ static struct video_device amradio_videodev_template = {
+ .release = usb_amradio_device_release,
+ };
+
+-/* check if the device is present and register with v4l and
+-usb if it is */
++/* check if the device is present and register with v4l and usb if it is */
+ static int usb_amradio_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+ {
+ struct amradio_device *radio;
++ int retval;
+
+ radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL);
+
+- if (!(radio))
++ if (!radio) {
++ dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
+ return -ENOMEM;
++ }
+
+ radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+
+- if (!(radio->buffer)) {
++ if (!radio->buffer) {
++ dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
+ kfree(radio);
+ return -ENOMEM;
+ }
+
+ radio->videodev = video_device_alloc();
+
+- if (!(radio->videodev)) {
++ if (!radio->videodev) {
++ dev_err(&intf->dev, "video_device_alloc failed\n");
+ kfree(radio->buffer);
+ kfree(radio);
+ return -ENOMEM;
+@@ -648,12 +729,14 @@ static int usb_amradio_probe(struct usb_interface *intf,
+ radio->users = 0;
+ radio->usbdev = interface_to_usbdev(intf);
+ radio->curfreq = 95.16 * FREQ_MUL;
++ radio->stereo = -1;
+
+ mutex_init(&radio->lock);
+
+ video_set_drvdata(radio->videodev, radio);
+- if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+- dev_warn(&intf->dev, "could not register video device\n");
++ retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
++ if (retval < 0) {
++ dev_err(&intf->dev, "could not register video device\n");
+ video_device_release(radio->videodev);
+ kfree(radio->buffer);
+ kfree(radio);
+diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
+index 2587227..d1e6b01 100644
+--- a/drivers/media/radio/radio-rtrack2.c
++++ b/drivers/media/radio/radio-rtrack2.c
+@@ -13,34 +13,16 @@
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay */
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/videodev2.h> /* kernel radio structs */
+-#include <media/v4l2-common.h>
++#include <linux/mutex.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#include <linux/io.h> /* outb, outb_p */
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+-#include <linux/spinlock.h>
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+-
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- },{
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 65535,
+- .step = 65535,
+- .default_value = 0xff,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- }
+-};
++MODULE_AUTHOR("Ben Pfaff");
++MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
++MODULE_LICENSE("GPL");
+
+ #ifndef CONFIG_RADIO_RTRACK2_PORT
+ #define CONFIG_RADIO_RTRACK2_PORT -1
+@@ -48,79 +30,88 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+
+ static int io = CONFIG_RADIO_RTRACK2_PORT;
+ static int radio_nr = -1;
+-static spinlock_t lock;
+
+-struct rt_device
++module_param(io, int, 0);
++MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
++module_param(radio_nr, int, 0);
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
++
++struct rtrack2
+ {
+- unsigned long in_use;
+- int port;
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ int io;
+ unsigned long curfreq;
+ int muted;
++ struct mutex lock;
+ };
+
++static struct rtrack2 rtrack2_card;
++
+
+ /* local things */
+
+-static void rt_mute(struct rt_device *dev)
++static void rt_mute(struct rtrack2 *dev)
+ {
+- if(dev->muted)
++ if (dev->muted)
+ return;
+- spin_lock(&lock);
+- outb(1, io);
+- spin_unlock(&lock);
++ mutex_lock(&dev->lock);
++ outb(1, dev->io);
++ mutex_unlock(&dev->lock);
+ dev->muted = 1;
+ }
+
+-static void rt_unmute(struct rt_device *dev)
++static void rt_unmute(struct rtrack2 *dev)
+ {
+ if(dev->muted == 0)
+ return;
+- spin_lock(&lock);
+- outb(0, io);
+- spin_unlock(&lock);
++ mutex_lock(&dev->lock);
++ outb(0, dev->io);
++ mutex_unlock(&dev->lock);
+ dev->muted = 0;
+ }
+
+-static void zero(void)
++static void zero(struct rtrack2 *dev)
+ {
+- outb_p(1, io);
+- outb_p(3, io);
+- outb_p(1, io);
++ outb_p(1, dev->io);
++ outb_p(3, dev->io);
++ outb_p(1, dev->io);
+ }
+
+-static void one(void)
++static void one(struct rtrack2 *dev)
+ {
+- outb_p(5, io);
+- outb_p(7, io);
+- outb_p(5, io);
++ outb_p(5, dev->io);
++ outb_p(7, dev->io);
++ outb_p(5, dev->io);
+ }
+
+-static int rt_setfreq(struct rt_device *dev, unsigned long freq)
++static int rt_setfreq(struct rtrack2 *dev, unsigned long freq)
+ {
+ int i;
+
++ mutex_lock(&dev->lock);
++ dev->curfreq = freq;
+ freq = freq / 200 + 856;
+
+- spin_lock(&lock);
+-
+- outb_p(0xc8, io);
+- outb_p(0xc9, io);
+- outb_p(0xc9, io);
++ outb_p(0xc8, dev->io);
++ outb_p(0xc9, dev->io);
++ outb_p(0xc9, dev->io);
+
+ for (i = 0; i < 10; i++)
+- zero ();
++ zero(dev);
+
+ for (i = 14; i >= 0; i--)
+ if (freq & (1 << i))
+- one ();
++ one(dev);
+ else
+- zero ();
++ zero(dev);
+
+- outb_p(0xc8, io);
++ outb_p(0xc8, dev->io);
+ if (!dev->muted)
+- outb_p(0, io);
++ outb_p(0, dev->io);
+
+- spin_unlock(&lock);
++ mutex_unlock(&dev->lock);
+ return 0;
+ }
+
+@@ -129,61 +120,61 @@ static int vidioc_querycap(struct file *file, void *priv,
+ {
+ strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
+ strlcpy(v->card, "RadioTrack II", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+-
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+-static int rt_getsigstr(struct rt_device *dev)
++static int rt_getsigstr(struct rtrack2 *dev)
+ {
+- if (inb(io) & 2) /* bit set = no signal present */
+- return 0;
+- return 1; /* signal present */
++ int sig = 1;
++
++ mutex_lock(&dev->lock);
++ if (inb(dev->io) & 2) /* bit set = no signal present */
++ sig = 0;
++ mutex_unlock(&dev->lock);
++ return sig;
+ }
+
+ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack2 *rt = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+- v->rangelow = (88*16000);
+- v->rangehigh = (108*16000);
++ v->rangelow = 88 * 16000;
++ v->rangehigh = 108 * 16000;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v->capability = V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
+- v->signal = 0xFFFF*rt_getsigstr(rt);
++ v->signal = 0xFFFF * rt_getsigstr(rt);
+ return 0;
+ }
+
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack2 *rt = video_drvdata(file);
+
+- rt->curfreq = f->frequency;
+- rt_setfreq(rt, rt->curfreq);
++ rt_setfreq(rt, f->frequency);
+ return 0;
+ }
+
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack2 *rt = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = rt->curfreq;
+@@ -193,14 +184,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
+ }
+ return -EINVAL;
+ }
+@@ -208,7 +196,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack2 *rt = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -227,7 +215,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct rt_device *rt = video_drvdata(file);
++ struct rtrack2 *rt = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -246,17 +234,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ return -EINVAL;
+ }
+
+-static int vidioc_g_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -265,36 +242,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
+- return 0;
++ return i ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_audio(struct file *file, void *priv,
++static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+-static struct rt_device rtrack2_unit;
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ return a->index ? -EINVAL : 0;
++}
+
+-static int rtrack2_exclusive_open(struct file *file)
++static int rtrack2_open(struct file *file)
+ {
+- return test_and_set_bit(0, &rtrack2_unit.in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int rtrack2_exclusive_release(struct file *file)
++static int rtrack2_release(struct file *file)
+ {
+- clear_bit(0, &rtrack2_unit.in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations rtrack2_fops = {
+ .owner = THIS_MODULE,
+- .open = rtrack2_exclusive_open,
+- .release = rtrack2_exclusive_release,
++ .open = rtrack2_open,
++ .release = rtrack2_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -313,62 +292,61 @@ static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
+ .vidioc_s_input = vidioc_s_input,
+ };
+
+-static struct video_device rtrack2_radio = {
+- .name = "RadioTrack II radio",
+- .fops = &rtrack2_fops,
+- .ioctl_ops = &rtrack2_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ static int __init rtrack2_init(void)
+ {
+- if(io==-1)
+- {
+- printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
++ struct rtrack2 *dev = &rtrack2_card;
++ struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
++ int res;
++
++ strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name));
++ dev->io = io;
++ if (dev->io == -1) {
++ v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n");
+ return -EINVAL;
+ }
+- if (!request_region(io, 4, "rtrack2"))
+- {
+- printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
++ if (!request_region(dev->io, 4, "rtrack2")) {
++ v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io);
+ return -EBUSY;
+ }
+
+- video_set_drvdata(&rtrack2_radio, &rtrack2_unit);
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(dev->io, 4);
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ return res;
++ }
+
+- spin_lock_init(&lock);
+- if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io, 4);
++ strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
++ dev->vdev.v4l2_dev = v4l2_dev;
++ dev->vdev.fops = &rtrack2_fops;
++ dev->vdev.ioctl_ops = &rtrack2_ioctl_ops;
++ dev->vdev.release = video_device_release_empty;
++ video_set_drvdata(&dev->vdev, dev);
++
++ mutex_init(&dev->lock);
++ if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(v4l2_dev);
++ release_region(dev->io, 4);
+ return -EINVAL;
+ }
+
+- printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n");
++ v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
+
+ /* mute card - prevents noisy bootups */
+- outb(1, io);
+- rtrack2_unit.muted = 1;
++ outb(1, dev->io);
++ dev->muted = 1;
+
+ return 0;
+ }
+
+-MODULE_AUTHOR("Ben Pfaff");
+-MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
+-MODULE_LICENSE("GPL");
+-
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
+-module_param(radio_nr, int, 0);
+-
+-static void __exit rtrack2_cleanup_module(void)
++static void __exit rtrack2_exit(void)
+ {
+- video_unregister_device(&rtrack2_radio);
+- release_region(io,4);
++ struct rtrack2 *dev = &rtrack2_card;
++
++ video_unregister_device(&dev->vdev);
++ v4l2_device_unregister(&dev->v4l2_dev);
++ release_region(dev->io, 4);
+ }
+
+ module_init(rtrack2_init);
+-module_exit(rtrack2_cleanup_module);
+-
+-/*
+- Local variables:
+- compile-command: "mmake"
+- End:
+-*/
++module_exit(rtrack2_exit);
+diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
+index d358e48..f4784f0 100644
+--- a/drivers/media/radio/radio-sf16fmi.c
++++ b/drivers/media/radio/radio-sf16fmi.c
+@@ -22,113 +22,109 @@
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay */
+-#include <linux/videodev2.h> /* kernel radio structs */
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-ioctl.h>
+ #include <linux/isapnp.h>
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/mutex.h>
++#include <linux/videodev2.h> /* kernel radio structs */
++#include <linux/io.h> /* outb, outb_p */
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
+
+-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
++MODULE_DESCRIPTION("A driver for the SF16MI radio.");
++MODULE_LICENSE("GPL");
+
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- }
+-};
++static int io = -1;
++static int radio_nr = -1;
++
++module_param(io, int, 0);
++MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
++module_param(radio_nr, int, 0);
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
+
+-struct fmi_device
++struct fmi
+ {
+- unsigned long in_use;
+- int port;
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ int io;
+ int curvol; /* 1 or 0 */
+ unsigned long curfreq; /* freq in kHz */
+ __u32 flags;
++ struct mutex lock;
+ };
+
+-static int io = -1;
+-static int radio_nr = -1;
+-static struct pnp_dev *dev = NULL;
+-static struct mutex lock;
++static struct fmi fmi_card;
++static struct pnp_dev *dev;
+
+ /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
+ /* It is only useful to give freq in intervall of 800 (=0.05Mhz),
+ * other bits will be truncated, e.g 92.7400016 -> 92.7, but
+ * 92.7400017 -> 92.75
+ */
+-#define RSF16_ENCODE(x) ((x)/800+214)
+-#define RSF16_MINFREQ 87*16000
+-#define RSF16_MAXFREQ 108*16000
++#define RSF16_ENCODE(x) ((x) / 800 + 214)
++#define RSF16_MINFREQ (87 * 16000)
++#define RSF16_MAXFREQ (108 * 16000)
+
+-static void outbits(int bits, unsigned int data, int port)
++static void outbits(int bits, unsigned int data, int io)
+ {
+- while(bits--) {
+- if(data & 1) {
+- outb(5, port);
++ while (bits--) {
++ if (data & 1) {
++ outb(5, io);
+ udelay(6);
+- outb(7, port);
++ outb(7, io);
+ udelay(6);
+ } else {
+- outb(1, port);
++ outb(1, io);
+ udelay(6);
+- outb(3, port);
++ outb(3, io);
+ udelay(6);
+ }
+- data>>=1;
++ data >>= 1;
+ }
+ }
+
+-static inline void fmi_mute(int port)
++static inline void fmi_mute(struct fmi *fmi)
+ {
+- mutex_lock(&lock);
+- outb(0x00, port);
+- mutex_unlock(&lock);
++ mutex_lock(&fmi->lock);
++ outb(0x00, fmi->io);
++ mutex_unlock(&fmi->lock);
+ }
+
+-static inline void fmi_unmute(int port)
++static inline void fmi_unmute(struct fmi *fmi)
+ {
+- mutex_lock(&lock);
+- outb(0x08, port);
+- mutex_unlock(&lock);
++ mutex_lock(&fmi->lock);
++ outb(0x08, fmi->io);
++ mutex_unlock(&fmi->lock);
+ }
+
+-static inline int fmi_setfreq(struct fmi_device *dev)
++static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq)
+ {
+- int myport = dev->port;
+- unsigned long freq = dev->curfreq;
++ mutex_lock(&fmi->lock);
++ fmi->curfreq = freq;
+
+- mutex_lock(&lock);
+-
+- outbits(16, RSF16_ENCODE(freq), myport);
+- outbits(8, 0xC0, myport);
++ outbits(16, RSF16_ENCODE(freq), fmi->io);
++ outbits(8, 0xC0, fmi->io);
+ msleep(143); /* was schedule_timeout(HZ/7) */
+- mutex_unlock(&lock);
+- if (dev->curvol) fmi_unmute(myport);
++ mutex_unlock(&fmi->lock);
++ if (fmi->curvol)
++ fmi_unmute(fmi);
+ return 0;
+ }
+
+-static inline int fmi_getsigstr(struct fmi_device *dev)
++static inline int fmi_getsigstr(struct fmi *fmi)
+ {
+ int val;
+ int res;
+- int myport = dev->port;
+-
+
+- mutex_lock(&lock);
+- val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */
+- outb(val, myport);
+- outb(val | 0x10, myport);
++ mutex_lock(&fmi->lock);
++ val = fmi->curvol ? 0x08 : 0x00; /* unmute/mute */
++ outb(val, fmi->io);
++ outb(val | 0x10, fmi->io);
+ msleep(143); /* was schedule_timeout(HZ/7) */
+- res = (int)inb(myport+1);
+- outb(val, myport);
++ res = (int)inb(fmi->io + 1);
++ outb(val, fmi->io);
+
+- mutex_unlock(&lock);
++ mutex_unlock(&fmi->lock);
+ return (res & 2) ? 0 : 0xFFFF;
+ }
+
+@@ -137,9 +133,9 @@ static int vidioc_querycap(struct file *file, void *priv,
+ {
+ strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
+ strlcpy(v->card, "SF16-FMx radio", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+@@ -147,18 +143,18 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+ int mult;
+- struct fmi_device *fmi = video_drvdata(file);
++ struct fmi *fmi = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+ mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
+- v->rangelow = RSF16_MINFREQ/mult;
+- v->rangehigh = RSF16_MAXFREQ/mult;
++ v->rangelow = RSF16_MINFREQ / mult;
++ v->rangehigh = RSF16_MAXFREQ / mult;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
+- v->capability = fmi->flags&V4L2_TUNER_CAP_LOW;
++ v->capability = fmi->flags & V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ v->signal = fmi_getsigstr(fmi);
+ return 0;
+@@ -167,32 +163,29 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct fmi_device *fmi = video_drvdata(file);
++ struct fmi *fmi = video_drvdata(file);
+
+ if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
+ f->frequency *= 1000;
+ if (f->frequency < RSF16_MINFREQ ||
+- f->frequency > RSF16_MAXFREQ )
++ f->frequency > RSF16_MAXFREQ)
+ return -EINVAL;
+- /*rounding in steps of 800 to match th freq
+- that will be used */
+- fmi->curfreq = (f->frequency/800)*800;
+- fmi_setfreq(fmi);
++ /* rounding in steps of 800 to match the freq
++ that will be used */
++ fmi_setfreq(fmi, (f->frequency / 800) * 800);
+ return 0;
+ }
+
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct fmi_device *fmi = video_drvdata(file);
++ struct fmi *fmi = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = fmi->curfreq;
+@@ -204,14 +197,9 @@ static int vidioc_g_frequency(struct file *file, void *priv,
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+ }
+ return -EINVAL;
+ }
+@@ -219,7 +207,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct fmi_device *fmi = video_drvdata(file);
++ struct fmi *fmi = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -232,31 +220,20 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct fmi_device *fmi = video_drvdata(file);
++ struct fmi *fmi = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value)
+- fmi_mute(fmi->port);
++ fmi_mute(fmi);
+ else
+- fmi_unmute(fmi->port);
++ fmi_unmute(fmi);
+ fmi->curvol = ctrl->value;
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+-static int vidioc_g_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -265,36 +242,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
+- return 0;
++ return i ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_audio(struct file *file, void *priv,
++static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+-static struct fmi_device fmi_unit;
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ return a->index ? -EINVAL : 0;
++}
+
+-static int fmi_exclusive_open(struct file *file)
++static int fmi_open(struct file *file)
+ {
+- return test_and_set_bit(0, &fmi_unit.in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int fmi_exclusive_release(struct file *file)
++static int fmi_release(struct file *file)
+ {
+- clear_bit(0, &fmi_unit.in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations fmi_fops = {
+ .owner = THIS_MODULE,
+- .open = fmi_exclusive_open,
+- .release = fmi_exclusive_release,
++ .open = fmi_open,
++ .release = fmi_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -313,13 +292,6 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ };
+
+-static struct video_device fmi_radio = {
+- .name = "SF16FMx radio",
+- .fops = &fmi_fops,
+- .ioctl_ops = &fmi_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ /* ladis: this is my card. does any other types exist? */
+ static struct isapnp_device_id id_table[] __devinitdata = {
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+@@ -344,7 +316,7 @@ static int __init isapnp_fmi_probe(void)
+ if (pnp_device_attach(dev) < 0)
+ return -EAGAIN;
+ if (pnp_activate_dev(dev) < 0) {
+- printk ("radio-sf16fmi: PnP configure failed (out of resources?)\n");
++ printk(KERN_ERR "radio-sf16fmi: PnP configure failed (out of resources?)\n");
+ pnp_device_detach(dev);
+ return -ENOMEM;
+ }
+@@ -354,59 +326,72 @@ static int __init isapnp_fmi_probe(void)
+ }
+
+ i = pnp_port_start(dev, 0);
+- printk ("radio-sf16fmi: PnP reports card at %#x\n", i);
++ printk(KERN_INFO "radio-sf16fmi: PnP reports card at %#x\n", i);
+
+ return i;
+ }
+
+ static int __init fmi_init(void)
+ {
++ struct fmi *fmi = &fmi_card;
++ struct v4l2_device *v4l2_dev = &fmi->v4l2_dev;
++ int res;
++
+ if (io < 0)
+ io = isapnp_fmi_probe();
+- if (io < 0) {
+- printk(KERN_ERR "radio-sf16fmi: No PnP card found.\n");
+- return io;
++ strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name));
++ fmi->io = io;
++ if (fmi->io < 0) {
++ v4l2_err(v4l2_dev, "No PnP card found.\n");
++ return fmi->io;
+ }
+ if (!request_region(io, 2, "radio-sf16fmi")) {
+- printk(KERN_ERR "radio-sf16fmi: port 0x%x already in use\n", io);
++ v4l2_err(v4l2_dev, "port 0x%x already in use\n", fmi->io);
+ pnp_device_detach(dev);
+ return -EBUSY;
+ }
+
+- fmi_unit.port = io;
+- fmi_unit.curvol = 0;
+- fmi_unit.curfreq = 0;
+- fmi_unit.flags = V4L2_TUNER_CAP_LOW;
+- video_set_drvdata(&fmi_radio, &fmi_unit);
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(fmi->io, 2);
++ pnp_device_detach(dev);
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ return res;
++ }
++
++ fmi->flags = V4L2_TUNER_CAP_LOW;
++ strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
++ fmi->vdev.v4l2_dev = v4l2_dev;
++ fmi->vdev.fops = &fmi_fops;
++ fmi->vdev.ioctl_ops = &fmi_ioctl_ops;
++ fmi->vdev.release = video_device_release_empty;
++ video_set_drvdata(&fmi->vdev, fmi);
+
+- mutex_init(&lock);
++ mutex_init(&fmi->lock);
+
+- if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io, 2);
++ if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(v4l2_dev);
++ release_region(fmi->io, 2);
++ pnp_device_detach(dev);
+ return -EINVAL;
+ }
+
+- printk(KERN_INFO "SF16FMx radio card driver at 0x%x\n", io);
++ v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io);
+ /* mute card - prevents noisy bootups */
+- fmi_mute(io);
++ fmi_mute(fmi);
+ return 0;
+ }
+
+-MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
+-MODULE_DESCRIPTION("A driver for the SF16MI radio.");
+-MODULE_LICENSE("GPL");
+-
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
+-module_param(radio_nr, int, 0);
+-
+-static void __exit fmi_cleanup_module(void)
++static void __exit fmi_exit(void)
+ {
+- video_unregister_device(&fmi_radio);
+- release_region(io, 2);
++ struct fmi *fmi = &fmi_card;
++
++ video_unregister_device(&fmi->vdev);
++ v4l2_device_unregister(&fmi->v4l2_dev);
++ release_region(fmi->io, 2);
+ if (dev)
+ pnp_device_detach(dev);
+ }
+
+ module_init(fmi_init);
+-module_exit(fmi_cleanup_module);
++module_exit(fmi_exit);
+diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
+index 92f17a3..0ba9d88 100644
+--- a/drivers/media/radio/radio-sf16fmr2.c
++++ b/drivers/media/radio/radio-sf16fmr2.c
+@@ -18,40 +18,28 @@
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay */
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/videodev2.h> /* kernel radio structs */
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-ioctl.h>
+ #include <linux/mutex.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#include <linux/io.h> /* outb, outb_p */
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
+
+-static struct mutex lock;
++MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
++MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
++MODULE_LICENSE("GPL");
++
++static int io = 0x384;
++static int radio_nr = -1;
++
++module_param(io, int, 0);
++MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
++module_param(radio_nr, int, 0);
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+ #define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+ #define AUD_VOL_INDEX 1
+
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- },
+- [AUD_VOL_INDEX] = {
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 15,
+- .step = 1,
+- .default_value = 0,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- }
+-};
+-
+ #undef DEBUG
+ //#define DEBUG 1
+
+@@ -62,156 +50,160 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+ #endif
+
+ /* this should be static vars for module size */
+-struct fmr2_device
++struct fmr2
+ {
+- unsigned long in_use;
+- int port;
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ struct mutex lock;
++ int io;
+ int curvol; /* 0-15 */
+ int mute;
+ int stereo; /* card is producing stereo audio */
+ unsigned long curfreq; /* freq in kHz */
+ int card_type;
+- __u32 flags;
++ u32 flags;
+ };
+
+-static int io = 0x384;
+-static int radio_nr = -1;
++static struct fmr2 fmr2_card;
+
+ /* hw precision is 12.5 kHz
+ * It is only useful to give freq in intervall of 200 (=0.0125Mhz),
+ * other bits will be truncated
+ */
+-#define RSF16_ENCODE(x) ((x)/200+856)
+-#define RSF16_MINFREQ 87*16000
+-#define RSF16_MAXFREQ 108*16000
++#define RSF16_ENCODE(x) ((x) / 200 + 856)
++#define RSF16_MINFREQ (87 * 16000)
++#define RSF16_MAXFREQ (108 * 16000)
+
+-static inline void wait(int n,int port)
++static inline void wait(int n, int io)
+ {
+- for (;n;--n) inb(port);
++ for (; n; --n)
++ inb(io);
+ }
+
+-static void outbits(int bits, unsigned int data, int nWait, int port)
++static void outbits(int bits, unsigned int data, int nWait, int io)
+ {
+ int bit;
+- for(;--bits>=0;) {
+- bit = (data>>bits) & 1;
+- outb(bit,port);
+- wait(nWait,port);
+- outb(bit|2,port);
+- wait(nWait,port);
+- outb(bit,port);
+- wait(nWait,port);
++
++ for (; --bits >= 0;) {
++ bit = (data >> bits) & 1;
++ outb(bit, io);
++ wait(nWait, io);
++ outb(bit | 2, io);
++ wait(nWait, io);
++ outb(bit, io);
++ wait(nWait, io);
+ }
+ }
+
+-static inline void fmr2_mute(int port)
++static inline void fmr2_mute(int io)
+ {
+- outb(0x00, port);
+- wait(4,port);
++ outb(0x00, io);
++ wait(4, io);
+ }
+
+-static inline void fmr2_unmute(int port)
++static inline void fmr2_unmute(int io)
+ {
+- outb(0x04, port);
+- wait(4,port);
++ outb(0x04, io);
++ wait(4, io);
+ }
+
+-static inline int fmr2_stereo_mode(int port)
++static inline int fmr2_stereo_mode(int io)
+ {
+- int n = inb(port);
+- outb(6,port);
+- inb(port);
+- n = ((n>>3)&1)^1;
++ int n = inb(io);
++
++ outb(6, io);
++ inb(io);
++ n = ((n >> 3) & 1) ^ 1;
+ debug_print((KERN_DEBUG "stereo: %d\n", n));
+ return n;
+ }
+
+-static int fmr2_product_info(struct fmr2_device *dev)
++static int fmr2_product_info(struct fmr2 *dev)
+ {
+- int n = inb(dev->port);
++ int n = inb(dev->io);
++
+ n &= 0xC1;
+- if (n == 0)
+- {
++ if (n == 0) {
+ /* this should support volume set */
+ dev->card_type = 12;
+ return 0;
+ }
+ /* not volume (mine is 11) */
+- dev->card_type = (n==128)?11:0;
++ dev->card_type = (n == 128) ? 11 : 0;
+ return n;
+ }
+
+-static inline int fmr2_getsigstr(struct fmr2_device *dev)
++static inline int fmr2_getsigstr(struct fmr2 *dev)
+ {
+- /* !!! work only if scanning freq */
+- int port = dev->port, res = 0xffff;
+- outb(5,port);
+- wait(4,port);
+- if (!(inb(port)&1)) res = 0;
++ /* !!! works only if scanning freq */
++ int res = 0xffff;
++
++ outb(5, dev->io);
++ wait(4, dev->io);
++ if (!(inb(dev->io) & 1))
++ res = 0;
+ debug_print((KERN_DEBUG "signal: %d\n", res));
+ return res;
+ }
+
+ /* set frequency and unmute card */
+-static int fmr2_setfreq(struct fmr2_device *dev)
++static int fmr2_setfreq(struct fmr2 *dev)
+ {
+- int port = dev->port;
+ unsigned long freq = dev->curfreq;
+
+- fmr2_mute(port);
++ fmr2_mute(dev->io);
+
+ /* 0x42 for mono output
+ * 0x102 forward scanning
+ * 0x182 scansione avanti
+ */
+- outbits(9,0x2,3,port);
+- outbits(16,RSF16_ENCODE(freq),2,port);
++ outbits(9, 0x2, 3, dev->io);
++ outbits(16, RSF16_ENCODE(freq), 2, dev->io);
+
+- fmr2_unmute(port);
++ fmr2_unmute(dev->io);
+
+ /* wait 0.11 sec */
+ msleep(110);
+
+ /* NOTE if mute this stop radio
+ you must set freq on unmute */
+- dev->stereo = fmr2_stereo_mode(port);
++ dev->stereo = fmr2_stereo_mode(dev->io);
+ return 0;
+ }
+
+ /* !!! not tested, in my card this does't work !!! */
+-static int fmr2_setvolume(struct fmr2_device *dev)
++static int fmr2_setvolume(struct fmr2 *dev)
+ {
+ int vol[16] = { 0x021, 0x084, 0x090, 0x104,
+ 0x110, 0x204, 0x210, 0x402,
+ 0x404, 0x408, 0x410, 0x801,
+ 0x802, 0x804, 0x808, 0x810 };
+- int i, a, port = dev->port;
++ int i, a;
+ int n = vol[dev->curvol & 0x0f];
+
+ if (dev->card_type != 11)
+ return 1;
+
+ for (i = 12; --i >= 0; ) {
+- a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */
+- outb(a | 4, port);
+- wait(4, port);
+- outb(a | 0x24, port);
+- wait(4, port);
+- outb(a | 4, port);
+- wait(4, port);
++ a = ((n >> i) & 1) << 6; /* if (a==0) a = 0; else a = 0x40; */
++ outb(a | 4, dev->io);
++ wait(4, dev->io);
++ outb(a | 0x24, dev->io);
++ wait(4, dev->io);
++ outb(a | 4, dev->io);
++ wait(4, dev->io);
+ }
+ for (i = 6; --i >= 0; ) {
+ a = ((0x18 >> i) & 1) << 6;
+- outb(a | 4, port);
+- wait(4,port);
+- outb(a | 0x24, port);
+- wait(4,port);
+- outb(a|4, port);
+- wait(4,port);
++ outb(a | 4, dev->io);
++ wait(4, dev->io);
++ outb(a | 0x24, dev->io);
++ wait(4, dev->io);
++ outb(a | 4, dev->io);
++ wait(4, dev->io);
+ }
+- wait(4, port);
+- outb(0x14, port);
+-
++ wait(4, dev->io);
++ outb(0x14, dev->io);
+ return 0;
+ }
+
+@@ -220,9 +212,9 @@ static int vidioc_querycap(struct file *file, void *priv,
+ {
+ strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver));
+ strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+@@ -230,54 +222,52 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+ int mult;
+- struct fmr2_device *fmr2 = video_drvdata(file);
++ struct fmr2 *fmr2 = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+
+ mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
+- v->rangelow = RSF16_MINFREQ/mult;
+- v->rangehigh = RSF16_MAXFREQ/mult;
++ v->rangelow = RSF16_MINFREQ / mult;
++ v->rangehigh = RSF16_MAXFREQ / mult;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
+ v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW;
+ v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
+ V4L2_TUNER_MODE_MONO;
+- mutex_lock(&lock);
++ mutex_lock(&fmr2->lock);
+ v->signal = fmr2_getsigstr(fmr2);
+- mutex_unlock(&lock);
++ mutex_unlock(&fmr2->lock);
+ return 0;
+ }
+
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct fmr2_device *fmr2 = video_drvdata(file);
++ struct fmr2 *fmr2 = video_drvdata(file);
+
+ if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
+ f->frequency *= 1000;
+ if (f->frequency < RSF16_MINFREQ ||
+- f->frequency > RSF16_MAXFREQ )
++ f->frequency > RSF16_MAXFREQ)
+ return -EINVAL;
+- /*rounding in steps of 200 to match th freq
+- that will be used */
+- fmr2->curfreq = (f->frequency/200)*200;
++ /* rounding in steps of 200 to match the freq
++ that will be used */
++ fmr2->curfreq = (f->frequency / 200) * 200;
+
+ /* set card freq (if not muted) */
+ if (fmr2->curvol && !fmr2->mute) {
+- mutex_lock(&lock);
++ mutex_lock(&fmr2->lock);
+ fmr2_setfreq(fmr2);
+- mutex_unlock(&lock);
++ mutex_unlock(&fmr2->lock);
+ }
+ return 0;
+ }
+@@ -285,7 +275,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct fmr2_device *fmr2 = video_drvdata(file);
++ struct fmr2 *fmr2 = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = fmr2->curfreq;
+@@ -297,13 +287,16 @@ static int vidioc_g_frequency(struct file *file, void *priv,
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
++ struct fmr2 *fmr2 = video_drvdata(file);
+
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &radio_qctrl[i], sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
++ case V4L2_CID_AUDIO_VOLUME:
++ /* Only card_type == 11 implements volume */
++ if (fmr2->card_type == 11)
++ return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0);
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ }
+ return -EINVAL;
+ }
+@@ -311,7 +304,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct fmr2_device *fmr2 = video_drvdata(file);
++ struct fmr2 *fmr2 = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -327,18 +320,14 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct fmr2_device *fmr2 = video_drvdata(file);
++ struct fmr2 *fmr2 = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ fmr2->mute = ctrl->value;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+- if (ctrl->value > radio_qctrl[AUD_VOL_INDEX].maximum)
+- fmr2->curvol = radio_qctrl[AUD_VOL_INDEX].maximum;
+- else
+- fmr2->curvol = ctrl->value;
+-
++ fmr2->curvol = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
+@@ -351,25 +340,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ printk(KERN_DEBUG "mute\n");
+ #endif
+
+- mutex_lock(&lock);
++ mutex_lock(&fmr2->lock);
+ if (fmr2->curvol && !fmr2->mute) {
+ fmr2_setvolume(fmr2);
+ /* Set frequency and unmute card */
+ fmr2_setfreq(fmr2);
+ } else
+- fmr2_mute(fmr2->port);
+- mutex_unlock(&lock);
+- return 0;
+-}
+-
+-static int vidioc_g_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
++ fmr2_mute(fmr2->io);
++ mutex_unlock(&fmr2->lock);
+ return 0;
+ }
+
+@@ -381,36 +359,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
+- return 0;
++ return i ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_audio(struct file *file, void *priv,
++static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+-static struct fmr2_device fmr2_unit;
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ return a->index ? -EINVAL : 0;
++}
+
+-static int fmr2_exclusive_open(struct file *file)
++static int fmr2_open(struct file *file)
+ {
+- return test_and_set_bit(0, &fmr2_unit.in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int fmr2_exclusive_release(struct file *file)
++static int fmr2_release(struct file *file)
+ {
+- clear_bit(0, &fmr2_unit.in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations fmr2_fops = {
+ .owner = THIS_MODULE,
+- .open = fmr2_exclusive_open,
+- .release = fmr2_exclusive_release,
++ .open = fmr2_open,
++ .release = fmr2_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -429,67 +409,64 @@ static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ };
+
+-static struct video_device fmr2_radio = {
+- .name = "SF16FMR2 radio",
+- .fops = &fmr2_fops,
+- .ioctl_ops = &fmr2_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ static int __init fmr2_init(void)
+ {
+- fmr2_unit.port = io;
+- fmr2_unit.curvol = 0;
+- fmr2_unit.mute = 0;
+- fmr2_unit.curfreq = 0;
+- fmr2_unit.stereo = 1;
+- fmr2_unit.flags = V4L2_TUNER_CAP_LOW;
+- fmr2_unit.card_type = 0;
+- video_set_drvdata(&fmr2_radio, &fmr2_unit);
+-
+- mutex_init(&lock);
+-
+- if (!request_region(io, 2, "sf16fmr2")) {
+- printk(KERN_ERR "radio-sf16fmr2: request_region failed!\n");
++ struct fmr2 *fmr2 = &fmr2_card;
++ struct v4l2_device *v4l2_dev = &fmr2->v4l2_dev;
++ int res;
++
++ strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name));
++ fmr2->io = io;
++ fmr2->stereo = 1;
++ fmr2->flags = V4L2_TUNER_CAP_LOW;
++ mutex_init(&fmr2->lock);
++
++ if (!request_region(fmr2->io, 2, "sf16fmr2")) {
++ v4l2_err(v4l2_dev, "request_region failed!\n");
+ return -EBUSY;
+ }
+
+- if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io, 2);
+- return -EINVAL;
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(fmr2->io, 2);
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ return res;
+ }
+
+- printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
+- /* mute card - prevents noisy bootups */
+- mutex_lock(&lock);
+- fmr2_mute(io);
+- fmr2_product_info(&fmr2_unit);
+- mutex_unlock(&lock);
+- debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
++ strlcpy(fmr2->vdev.name, v4l2_dev->name, sizeof(fmr2->vdev.name));
++ fmr2->vdev.v4l2_dev = v4l2_dev;
++ fmr2->vdev.fops = &fmr2_fops;
++ fmr2->vdev.ioctl_ops = &fmr2_ioctl_ops;
++ fmr2->vdev.release = video_device_release_empty;
++ video_set_drvdata(&fmr2->vdev, fmr2);
+
+- /* Only card_type == 11 implements volume */
+- if (fmr2_unit.card_type != 11)
+- radio_qctrl[AUD_VOL_INDEX].maximum = 1;
++ if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(v4l2_dev);
++ release_region(fmr2->io, 2);
++ return -EINVAL;
++ }
+
++ v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io);
++ /* mute card - prevents noisy bootups */
++ mutex_lock(&fmr2->lock);
++ fmr2_mute(fmr2->io);
++ fmr2_product_info(fmr2);
++ mutex_unlock(&fmr2->lock);
++ debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type));
+ return 0;
+ }
+
+-MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
+-MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
+-MODULE_LICENSE("GPL");
+-
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
+-module_param(radio_nr, int, 0);
+-
+-static void __exit fmr2_cleanup_module(void)
++static void __exit fmr2_exit(void)
+ {
+- video_unregister_device(&fmr2_radio);
+- release_region(io,2);
++ struct fmr2 *fmr2 = &fmr2_card;
++
++ video_unregister_device(&fmr2->vdev);
++ v4l2_device_unregister(&fmr2->v4l2_dev);
++ release_region(fmr2->io, 2);
+ }
+
+ module_init(fmr2_init);
+-module_exit(fmr2_cleanup_module);
++module_exit(fmr2_exit);
+
+ #ifndef MODULE
+
+diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
+index 4dfed6a..713e242 100644
+--- a/drivers/media/radio/radio-si470x.c
++++ b/drivers/media/radio/radio-si470x.c
+@@ -5,8 +5,9 @@
+ * - Silicon Labs USB FM Radio Reference Design
+ * - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
+ * - KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
++ * - Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear)
+ *
+- * Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net>
++ * Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.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
+@@ -29,7 +30,7 @@
+ * 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net>
+ * Version 1.0.0
+ * - First working version
+- * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net>
++ * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net>
+ * Version 1.0.1
+ * - Improved error handling, every function now returns errno
+ * - Improved multi user access (start/mute/stop)
+@@ -104,6 +105,7 @@
+ * 2009-01-31 Rick Bronson <rick@efn.org>
+ * Tobias Lorenz <tobias.lorenz@gmx.net>
+ * - add LED status output
++ * - get HW/SW version from scratchpad
+ *
+ * ToDo:
+ * - add firmware download/update support
+@@ -114,10 +116,10 @@
+ /* driver definitions */
+ #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
+ #define DRIVER_NAME "radio-si470x"
+-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 8)
++#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 9)
+ #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
+ #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
+-#define DRIVER_VERSION "1.0.8"
++#define DRIVER_VERSION "1.0.9"
+
+
+ /* kernel includes */
+@@ -145,7 +147,7 @@ static struct usb_device_id si470x_usb_driver_id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
+ /* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) },
+- /* DealExtreme USB Radio */
++ /* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) },
+ /* Terminating entry */
+ { }
+@@ -345,7 +347,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
+
+ /* Report 19: stream */
+ #define STREAM_REPORT_SIZE 3
+-#define STREAM_REPORT 19
++#define STREAM_REPORT 19
+
+ /* Report 20: scratch */
+ #define SCRATCH_PAGE_SIZE 63
+@@ -353,9 +355,13 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
+ #define SCRATCH_REPORT 20
+
+ /* Reports 19-22: flash upgrade of the C8051F321 */
++#define WRITE_REPORT_SIZE 4
+ #define WRITE_REPORT 19
++#define FLASH_REPORT_SIZE 64
+ #define FLASH_REPORT 20
++#define CRC_REPORT_SIZE 3
+ #define CRC_REPORT 21
++#define RESPONSE_REPORT_SIZE 2
+ #define RESPONSE_REPORT 22
+
+ /* Report 23: currently unused, but can accept 60 byte reports on the HID */
+@@ -414,7 +420,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
+
+ /* bootloader commands */
+ #define GET_SW_VERSION_COMMAND 0x00
+-#define SET_PAGE_COMMAND 0x01
++#define SET_PAGE_COMMAND 0x01
+ #define ERASE_PAGE_COMMAND 0x02
+ #define WRITE_PAGE_COMMAND 0x03
+ #define CRC_ON_PAGE_COMMAND 0x04
+@@ -428,12 +434,6 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
+ #define COMMAND_FAILED 0x02
+ #define COMMAND_PENDING 0x03
+
+-/* buffer sizes */
+-#define COMMAND_BUFFER_SIZE 4
+-#define RESPONSE_BUFFER_SIZE 2
+-#define FLASH_BUFFER_SIZE 64
+-#define CRC_BUFFER_SIZE 3
+-
+
+
+ /**************************************************************************
+@@ -465,6 +465,10 @@ struct si470x_device {
+ unsigned int buf_size;
+ unsigned int rd_index;
+ unsigned int wr_index;
++
++ /* scratch page */
++ unsigned char software_version;
++ unsigned char hardware_version;
+ };
+
+
+@@ -480,7 +484,7 @@ struct si470x_device {
+
+
+ /**************************************************************************
+- * General Driver Functions
++ * General Driver Functions - REGISTER_REPORTs
+ **************************************************************************/
+
+ /*
+@@ -566,60 +570,6 @@ static int si470x_set_register(struct si470x_device *radio, int regnr)
+
+
+ /*
+- * si470x_get_all_registers - read entire registers
+- */
+-static int si470x_get_all_registers(struct si470x_device *radio)
+-{
+- unsigned char buf[ENTIRE_REPORT_SIZE];
+- int retval;
+- unsigned char regnr;
+-
+- buf[0] = ENTIRE_REPORT;
+-
+- retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
+-
+- if (retval >= 0)
+- for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
+- radio->registers[regnr] = get_unaligned_be16(
+- &buf[regnr * RADIO_REGISTER_SIZE + 1]);
+-
+- return (retval < 0) ? -EINVAL : 0;
+-}
+-
+-
+-/*
+- * si470x_get_rds_registers - read rds registers
+- */
+-static int si470x_get_rds_registers(struct si470x_device *radio)
+-{
+- unsigned char buf[RDS_REPORT_SIZE];
+- int retval;
+- int size;
+- unsigned char regnr;
+-
+- buf[0] = RDS_REPORT;
+-
+- retval = usb_interrupt_msg(radio->usbdev,
+- usb_rcvintpipe(radio->usbdev, 1),
+- (void *) &buf, sizeof(buf), &size, usb_timeout);
+- if (size != sizeof(buf))
+- printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
+- "return size differs: %d != %zu\n", size, sizeof(buf));
+- if (retval < 0)
+- printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
+- "usb_interrupt_msg returned %d\n", retval);
+-
+- if (retval >= 0)
+- for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
+- radio->registers[STATUSRSSI + regnr] =
+- get_unaligned_be16(
+- &buf[regnr * RADIO_REGISTER_SIZE + 1]);
+-
+- return (retval < 0) ? -EINVAL : 0;
+-}
+-
+-
+-/*
+ * si470x_set_chan - set the channel
+ */
+ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
+@@ -887,6 +837,70 @@ static int si470x_rds_on(struct si470x_device *radio)
+
+
+ /**************************************************************************
++ * General Driver Functions - ENTIRE_REPORT
++ **************************************************************************/
++
++/*
++ * si470x_get_all_registers - read entire registers
++ */
++static int si470x_get_all_registers(struct si470x_device *radio)
++{
++ unsigned char buf[ENTIRE_REPORT_SIZE];
++ int retval;
++ unsigned char regnr;
++
++ buf[0] = ENTIRE_REPORT;
++
++ retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
++
++ if (retval >= 0)
++ for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
++ radio->registers[regnr] = get_unaligned_be16(
++ &buf[regnr * RADIO_REGISTER_SIZE + 1]);
++
++ return (retval < 0) ? -EINVAL : 0;
++}
++
++
++
++/**************************************************************************
++ * General Driver Functions - RDS_REPORT
++ **************************************************************************/
++
++/*
++ * si470x_get_rds_registers - read rds registers
++ */
++static int si470x_get_rds_registers(struct si470x_device *radio)
++{
++ unsigned char buf[RDS_REPORT_SIZE];
++ int retval;
++ int size;
++ unsigned char regnr;
++
++ buf[0] = RDS_REPORT;
++
++ retval = usb_interrupt_msg(radio->usbdev,
++ usb_rcvintpipe(radio->usbdev, 1),
++ (void *) &buf, sizeof(buf), &size, usb_timeout);
++ if (size != sizeof(buf))
++ printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
++ "return size differs: %d != %zu\n", size, sizeof(buf));
++ if (retval < 0)
++ printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
++ "usb_interrupt_msg returned %d\n", retval);
++
++ if (retval >= 0)
++ for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
++ radio->registers[STATUSRSSI + regnr] =
++ get_unaligned_be16(
++ &buf[regnr * RADIO_REGISTER_SIZE + 1]);
++
++ return (retval < 0) ? -EINVAL : 0;
++}
++
++
++
++/**************************************************************************
+ * General Driver Functions - LED_REPORT
+ **************************************************************************/
+
+@@ -911,6 +925,35 @@ static int si470x_set_led_state(struct si470x_device *radio,
+
+
+ /**************************************************************************
++ * General Driver Functions - SCRATCH_REPORT
++ **************************************************************************/
++
++/*
++ * si470x_get_scratch_versions - gets the scratch page and version infos
++ */
++static int si470x_get_scratch_page_versions(struct si470x_device *radio)
++{
++ unsigned char buf[SCRATCH_REPORT_SIZE];
++ int retval;
++
++ buf[0] = SCRATCH_REPORT;
++
++ retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
++
++ if (retval < 0)
++ printk(KERN_WARNING DRIVER_NAME ": si470x_get_scratch: "
++ "si470x_get_report returned %d\n", retval);
++ else {
++ radio->software_version = buf[1];
++ radio->hardware_version = buf[2];
++ }
++
++ return (retval < 0) ? -EINVAL : 0;
++}
++
++
++
++/**************************************************************************
+ * RDS Driver Functions
+ **************************************************************************/
+
+@@ -1124,6 +1167,7 @@ static int si470x_fops_open(struct file *file)
+ }
+
+ if (radio->users == 1) {
++ /* start radio */
+ retval = si470x_start(radio);
+ if (retval < 0)
+ usb_autopm_put_interface(radio->intf);
+@@ -1165,6 +1209,7 @@ static int si470x_fops_release(struct file *file)
+ /* cancel read processes */
+ wake_up_interruptible(&radio->read_queue);
+
++ /* stop radio */
+ retval = si470x_stop(radio);
+ usb_autopm_put_interface(radio->intf);
+ }
+@@ -1226,9 +1271,11 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
+ static int si470x_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *capability)
+ {
++ struct si470x_device *radio = video_drvdata(file);
++
+ strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+ strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+- sprintf(capability->bus_info, "USB");
++ usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info));
+ capability->version = DRIVER_KERNEL_VERSION;
+ capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+ V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+@@ -1636,7 +1683,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
+ sizeof(si470x_viddev_template));
+ video_set_drvdata(radio->videodev, radio);
+
+- /* show some infos about the specific device */
++ /* show some infos about the specific si470x device */
+ if (si470x_get_all_registers(radio) < 0) {
+ retval = -EIO;
+ goto err_all;
+@@ -1644,7 +1691,16 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
+ printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
+ radio->registers[DEVICEID], radio->registers[CHIPID]);
+
+- /* check if firmware is current */
++ /* get software and hardware versions */
++ if (si470x_get_scratch_page_versions(radio) < 0) {
++ retval = -EIO;
++ goto err_all;
++ }
++ printk(KERN_INFO DRIVER_NAME
++ ": software version %d, hardware version %d\n",
++ radio->software_version, radio->hardware_version);
++
++ /* check if device and firmware is current */
+ if ((radio->registers[CHIPID] & CHIPID_FIRMWARE)
+ < RADIO_SW_VERSION_CURRENT) {
+ printk(KERN_WARNING DRIVER_NAME
+@@ -1657,7 +1713,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
+ ": If you have some trouble using this driver,\n");
+ printk(KERN_WARNING DRIVER_NAME
+ ": please report to V4L ML at "
+- "video4linux-list@redhat.com\n");
++ "linux-media@vger.kernel.org\n");
+ }
+
+ /* set initial frequency */
+diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
+index 4d35308..3936238 100644
+--- a/drivers/media/radio/radio-tea5764.c
++++ b/drivers/media/radio/radio-tea5764.c
+@@ -298,7 +298,8 @@ static int vidioc_querycap(struct file *file, void *priv,
+
+ strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
+ strlcpy(v->card, dev->name, sizeof(v->card));
+- snprintf(v->bus_info, sizeof(v->bus_info), "I2C:%s", dev->dev.bus_id);
++ snprintf(v->bus_info, sizeof(v->bus_info),
++ "I2C:%s", dev_name(&dev->dev));
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
+index 0798d71..5b007f5 100644
+--- a/drivers/media/radio/radio-terratec.c
++++ b/drivers/media/radio/radio-terratec.c
+@@ -27,16 +27,29 @@
+ #include <linux/module.h> /* Modules */
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+-#include <linux/delay.h> /* udelay */
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/videodev2.h> /* kernel radio structs */
+-#include <media/v4l2-common.h>
++#include <linux/mutex.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#include <linux/io.h> /* outb, outb_p */
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+-#include <linux/spinlock.h>
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
++MODULE_AUTHOR("R.OFFERMANNS & others");
++MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
++MODULE_LICENSE("GPL");
++
++#ifndef CONFIG_RADIO_TERRATEC_PORT
++#define CONFIG_RADIO_TERRATEC_PORT 0x590
++#endif
++
++static int io = CONFIG_RADIO_TERRATEC_PORT;
++static int radio_nr = -1;
++
++module_param(io, int, 0);
++MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
++module_param(radio_nr, int, 0);
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
+
+ static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+@@ -57,13 +70,6 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+ }
+ };
+
+-#ifndef CONFIG_RADIO_TERRATEC_PORT
+-#define CONFIG_RADIO_TERRATEC_PORT 0x590
+-#endif
+-
+-/**************** this ones are for the terratec *******************/
+-#define BASEPORT 0x590
+-#define VOLPORT 0x591
+ #define WRT_DIS 0x00
+ #define CLK_OFF 0x00
+ #define IIC_DATA 0x01
+@@ -71,138 +77,124 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+ #define DATA 0x04
+ #define CLK_ON 0x08
+ #define WRT_EN 0x10
+-/*******************************************************************/
+
+-static int io = CONFIG_RADIO_TERRATEC_PORT;
+-static int radio_nr = -1;
+-static spinlock_t lock;
+-
+-struct tt_device
++struct terratec
+ {
+- unsigned long in_use;
+- int port;
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ int io;
+ int curvol;
+ unsigned long curfreq;
+ int muted;
++ struct mutex lock;
+ };
+
++static struct terratec terratec_card;
+
+ /* local things */
+
+-static void cardWriteVol(int volume)
++static void tt_write_vol(struct terratec *tt, int volume)
+ {
+ int i;
+- volume = volume+(volume * 32); // change both channels
+- spin_lock(&lock);
+- for (i=0;i<8;i++)
+- {
+- if (volume & (0x80>>i))
+- outb(0x80, VOLPORT);
+- else outb(0x00, VOLPORT);
++
++ volume = volume + (volume * 32); /* change both channels */
++ mutex_lock(&tt->lock);
++ for (i = 0; i < 8; i++) {
++ if (volume & (0x80 >> i))
++ outb(0x80, tt->io + 1);
++ else
++ outb(0x00, tt->io + 1);
+ }
+- spin_unlock(&lock);
++ mutex_unlock(&tt->lock);
+ }
+
+
+
+-static void tt_mute(struct tt_device *dev)
++static void tt_mute(struct terratec *tt)
+ {
+- dev->muted = 1;
+- cardWriteVol(0);
++ tt->muted = 1;
++ tt_write_vol(tt, 0);
+ }
+
+-static int tt_setvol(struct tt_device *dev, int vol)
++static int tt_setvol(struct terratec *tt, int vol)
+ {
+-
+-// printk(KERN_ERR "setvol called, vol = %d\n", vol);
+-
+- if(vol == dev->curvol) { /* requested volume = current */
+- if (dev->muted) { /* user is unmuting the card */
+- dev->muted = 0;
+- cardWriteVol(vol); /* enable card */
++ if (vol == tt->curvol) { /* requested volume = current */
++ if (tt->muted) { /* user is unmuting the card */
++ tt->muted = 0;
++ tt_write_vol(tt, vol); /* enable card */
+ }
+-
+ return 0;
+ }
+
+- if(vol == 0) { /* volume = 0 means mute the card */
+- cardWriteVol(0); /* "turn off card" by setting vol to 0 */
+- dev->curvol = vol; /* track the volume state! */
++ if (vol == 0) { /* volume = 0 means mute the card */
++ tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */
++ tt->curvol = vol; /* track the volume state! */
+ return 0;
+ }
+
+- dev->muted = 0;
+-
+- cardWriteVol(vol);
+-
+- dev->curvol = vol;
+-
++ tt->muted = 0;
++ tt_write_vol(tt, vol);
++ tt->curvol = vol;
+ return 0;
+-
+ }
+
+
+ /* this is the worst part in this driver */
+ /* many more or less strange things are going on here, but hey, it works :) */
+
+-static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
++static int tt_setfreq(struct terratec *tt, unsigned long freq1)
+ {
+ int freq;
+ int i;
+ int p;
+ int temp;
+ long rest;
+-
+ unsigned char buffer[25]; /* we have to bit shift 25 registers */
+- freq = freq1/160; /* convert the freq. to a nice to handle value */
+- for(i=24;i>-1;i--)
+- buffer[i]=0;
+
+- rest = freq*10+10700; /* i once had understood what is going on here */
++ mutex_lock(&tt->lock);
++
++ tt->curfreq = freq1;
++
++ freq = freq1 / 160; /* convert the freq. to a nice to handle value */
++ memset(buffer, 0, sizeof(buffer));
++
++ rest = freq * 10 + 10700; /* I once had understood what is going on here */
+ /* maybe some wise guy (friedhelm?) can comment this stuff */
+- i=13;
+- p=10;
+- temp=102400;
+- while (rest!=0)
+- {
+- if (rest%temp == rest)
++ i = 13;
++ p = 10;
++ temp = 102400;
++ while (rest != 0) {
++ if (rest % temp == rest)
+ buffer[i] = 0;
+- else
+- {
++ else {
+ buffer[i] = 1;
+- rest = rest-temp;
++ rest = rest - temp;
+ }
+ i--;
+ p--;
+- temp = temp/2;
++ temp = temp / 2;
+ }
+
+- spin_lock(&lock);
+-
+- for (i=24;i>-1;i--) /* bit shift the values to the radiocard */
+- {
+- if (buffer[i]==1)
+- {
+- outb(WRT_EN|DATA, BASEPORT);
+- outb(WRT_EN|DATA|CLK_ON , BASEPORT);
+- outb(WRT_EN|DATA, BASEPORT);
+- }
+- else
+- {
+- outb(WRT_EN|0x00, BASEPORT);
+- outb(WRT_EN|0x00|CLK_ON , BASEPORT);
++ for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */
++ if (buffer[i] == 1) {
++ outb(WRT_EN | DATA, tt->io);
++ outb(WRT_EN | DATA | CLK_ON, tt->io);
++ outb(WRT_EN | DATA, tt->io);
++ } else {
++ outb(WRT_EN | 0x00, tt->io);
++ outb(WRT_EN | 0x00 | CLK_ON, tt->io);
+ }
+ }
+- outb(0x00, BASEPORT);
++ outb(0x00, tt->io);
+
+- spin_unlock(&lock);
++ mutex_unlock(&tt->lock);
+
+ return 0;
+ }
+
+-static int tt_getsigstr(struct tt_device *dev) /* TODO */
++static int tt_getsigstr(struct terratec *tt)
+ {
+- if (inb(io) & 2) /* bit set = no signal present */
++ if (inb(tt->io) & 2) /* bit set = no signal present */
+ return 0;
+ return 1; /* signal present */
+ }
+@@ -212,53 +204,50 @@ static int vidioc_querycap(struct file *file, void *priv,
+ {
+ strlcpy(v->driver, "radio-terratec", sizeof(v->driver));
+ strlcpy(v->card, "ActiveRadio", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- struct tt_device *tt = video_drvdata(file);
++ struct terratec *tt = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+- v->rangelow = (87*16000);
+- v->rangehigh = (108*16000);
++ v->rangelow = 87 * 16000;
++ v->rangehigh = 108 * 16000;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v->capability = V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
+- v->signal = 0xFFFF*tt_getsigstr(tt);
++ v->signal = 0xFFFF * tt_getsigstr(tt);
+ return 0;
+ }
+
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct tt_device *tt = video_drvdata(file);
++ struct terratec *tt = video_drvdata(file);
+
+- tt->curfreq = f->frequency;
+- tt_setfreq(tt, tt->curfreq);
++ tt_setfreq(tt, f->frequency);
+ return 0;
+ }
+
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct tt_device *tt = video_drvdata(file);
++ struct terratec *tt = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = tt->curfreq;
+@@ -272,8 +261,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
++ memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
+ return 0;
+ }
+ }
+@@ -283,7 +271,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct tt_device *tt = video_drvdata(file);
++ struct terratec *tt = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -302,7 +290,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct tt_device *tt = video_drvdata(file);
++ struct terratec *tt = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -318,17 +306,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ return -EINVAL;
+ }
+
+-static int vidioc_g_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -337,36 +314,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
+- return 0;
++ return i ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_audio(struct file *file, void *priv,
++static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+-static struct tt_device terratec_unit;
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ return a->index ? -EINVAL : 0;
++}
+
+-static int terratec_exclusive_open(struct file *file)
++static int terratec_open(struct file *file)
+ {
+- return test_and_set_bit(0, &terratec_unit.in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int terratec_exclusive_release(struct file *file)
++static int terratec_release(struct file *file)
+ {
+- clear_bit(0, &terratec_unit.in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations terratec_fops = {
+ .owner = THIS_MODULE,
+- .open = terratec_exclusive_open,
+- .release = terratec_exclusive_release,
++ .open = terratec_open,
++ .release = terratec_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -385,60 +364,63 @@ static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
+ .vidioc_s_input = vidioc_s_input,
+ };
+
+-static struct video_device terratec_radio = {
+- .name = "TerraTec ActiveRadio",
+- .fops = &terratec_fops,
+- .ioctl_ops = &terratec_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ static int __init terratec_init(void)
+ {
+- if(io==-1)
+- {
+- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
++ struct terratec *tt = &terratec_card;
++ struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
++ int res;
++
++ strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name));
++ tt->io = io;
++ if (tt->io == -1) {
++ v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n");
+ return -EINVAL;
+ }
+- if (!request_region(io, 2, "terratec"))
+- {
+- printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
++ if (!request_region(tt->io, 2, "terratec")) {
++ v4l2_err(v4l2_dev, "port 0x%x already in use\n", io);
+ return -EBUSY;
+ }
+
+- video_set_drvdata(&terratec_radio, &terratec_unit);
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(tt->io, 2);
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ return res;
++ }
++
++ strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name));
++ tt->vdev.v4l2_dev = v4l2_dev;
++ tt->vdev.fops = &terratec_fops;
++ tt->vdev.ioctl_ops = &terratec_ioctl_ops;
++ tt->vdev.release = video_device_release_empty;
++ video_set_drvdata(&tt->vdev, tt);
+
+- spin_lock_init(&lock);
++ mutex_init(&tt->lock);
+
+- if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io,2);
++ if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(&tt->v4l2_dev);
++ release_region(tt->io, 2);
+ return -EINVAL;
+ }
+
+- printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
++ v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
+
+ /* mute card - prevents noisy bootups */
+-
+- /* this ensures that the volume is all the way down */
+- cardWriteVol(0);
+- terratec_unit.curvol = 0;
+-
++ tt_write_vol(tt, 0);
+ return 0;
+ }
+
+-MODULE_AUTHOR("R.OFFERMANNS & others");
+-MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
+-MODULE_LICENSE("GPL");
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
+-module_param(radio_nr, int, 0);
+-
+-static void __exit terratec_cleanup_module(void)
++static void __exit terratec_exit(void)
+ {
+- video_unregister_device(&terratec_radio);
+- release_region(io,2);
+- printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
++ struct terratec *tt = &terratec_card;
++ struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
++
++ video_unregister_device(&tt->vdev);
++ v4l2_device_unregister(&tt->v4l2_dev);
++ release_region(tt->io, 2);
++ v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n");
+ }
+
+ module_init(terratec_init);
+-module_exit(terratec_cleanup_module);
++module_exit(terratec_exit);
+
+diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
+index bdf9cb6..d1be649 100644
+--- a/drivers/media/radio/radio-trust.c
++++ b/drivers/media/radio/radio-trust.c
+@@ -19,49 +19,15 @@
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/ioport.h>
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+ #include <linux/videodev2.h>
+-#include <media/v4l2-common.h>
++#include <linux/io.h>
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+-
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- },{
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 65535,
+- .step = 2048,
+- .default_value = 65535,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- },{
+- .id = V4L2_CID_AUDIO_BASS,
+- .name = "Bass",
+- .minimum = 0,
+- .maximum = 65535,
+- .step = 4370,
+- .default_value = 32768,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- },{
+- .id = V4L2_CID_AUDIO_TREBLE,
+- .name = "Treble",
+- .minimum = 0,
+- .maximum = 65535,
+- .step = 4370,
+- .default_value = 32768,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- },
+-};
++MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
++MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
++MODULE_LICENSE("GPL");
+
+ /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
+
+@@ -71,26 +37,41 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+
+ static int io = CONFIG_RADIO_TRUST_PORT;
+ static int radio_nr = -1;
+-static int ioval = 0xf;
+-static __u16 curvol;
+-static __u16 curbass;
+-static __u16 curtreble;
+-static unsigned long curfreq;
+-static int curstereo;
+-static int curmute;
+-static unsigned long in_use;
++
++module_param(io, int, 0);
++MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
++module_param(radio_nr, int, 0);
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
++
++struct trust {
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ int io;
++ int ioval;
++ __u16 curvol;
++ __u16 curbass;
++ __u16 curtreble;
++ int muted;
++ unsigned long curfreq;
++ int curstereo;
++ int curmute;
++ struct mutex lock;
++};
++
++static struct trust trust_card;
+
+ /* i2c addresses */
+ #define TDA7318_ADDR 0x88
+ #define TSA6060T_ADDR 0xc4
+
+-#define TR_DELAY do { inb(io); inb(io); inb(io); } while(0)
+-#define TR_SET_SCL outb(ioval |= 2, io)
+-#define TR_CLR_SCL outb(ioval &= 0xfd, io)
+-#define TR_SET_SDA outb(ioval |= 1, io)
+-#define TR_CLR_SDA outb(ioval &= 0xfe, io)
++#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0)
++#define TR_SET_SCL outb(tr->ioval |= 2, tr->io)
++#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io)
++#define TR_SET_SDA outb(tr->ioval |= 1, tr->io)
++#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io)
+
+-static void write_i2c(int n, ...)
++static void write_i2c(struct trust *tr, int n, ...)
+ {
+ unsigned char val, mask;
+ va_list args;
+@@ -136,62 +117,77 @@ static void write_i2c(int n, ...)
+ va_end(args);
+ }
+
+-static void tr_setvol(__u16 vol)
++static void tr_setvol(struct trust *tr, __u16 vol)
+ {
+- curvol = vol / 2048;
+- write_i2c(2, TDA7318_ADDR, curvol ^ 0x1f);
++ mutex_lock(&tr->lock);
++ tr->curvol = vol / 2048;
++ write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f);
++ mutex_unlock(&tr->lock);
+ }
+
+ static int basstreble2chip[15] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
+ };
+
+-static void tr_setbass(__u16 bass)
++static void tr_setbass(struct trust *tr, __u16 bass)
+ {
+- curbass = bass / 4370;
+- write_i2c(2, TDA7318_ADDR, 0x60 | basstreble2chip[curbass]);
++ mutex_lock(&tr->lock);
++ tr->curbass = bass / 4370;
++ write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]);
++ mutex_unlock(&tr->lock);
+ }
+
+-static void tr_settreble(__u16 treble)
++static void tr_settreble(struct trust *tr, __u16 treble)
+ {
+- curtreble = treble / 4370;
+- write_i2c(2, TDA7318_ADDR, 0x70 | basstreble2chip[curtreble]);
++ mutex_lock(&tr->lock);
++ tr->curtreble = treble / 4370;
++ write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]);
++ mutex_unlock(&tr->lock);
+ }
+
+-static void tr_setstereo(int stereo)
++static void tr_setstereo(struct trust *tr, int stereo)
+ {
+- curstereo = !!stereo;
+- ioval = (ioval & 0xfb) | (!curstereo << 2);
+- outb(ioval, io);
++ mutex_lock(&tr->lock);
++ tr->curstereo = !!stereo;
++ tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2);
++ outb(tr->ioval, tr->io);
++ mutex_unlock(&tr->lock);
+ }
+
+-static void tr_setmute(int mute)
++static void tr_setmute(struct trust *tr, int mute)
+ {
+- curmute = !!mute;
+- ioval = (ioval & 0xf7) | (curmute << 3);
+- outb(ioval, io);
++ mutex_lock(&tr->lock);
++ tr->curmute = !!mute;
++ tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3);
++ outb(tr->ioval, tr->io);
++ mutex_unlock(&tr->lock);
+ }
+
+-static int tr_getsigstr(void)
++static int tr_getsigstr(struct trust *tr)
+ {
+ int i, v;
+
+- for(i = 0, v = 0; i < 100; i++) v |= inb(io);
+- return (v & 1)? 0 : 0xffff;
++ mutex_lock(&tr->lock);
++ for (i = 0, v = 0; i < 100; i++)
++ v |= inb(tr->io);
++ mutex_unlock(&tr->lock);
++ return (v & 1) ? 0 : 0xffff;
+ }
+
+-static int tr_getstereo(void)
++static int tr_getstereo(struct trust *tr)
+ {
+ /* don't know how to determine it, just return the setting */
+- return curstereo;
++ return tr->curstereo;
+ }
+
+-static void tr_setfreq(unsigned long f)
++static void tr_setfreq(struct trust *tr, unsigned long f)
+ {
++ mutex_lock(&tr->lock);
++ tr->curfreq = f;
+ f /= 160; /* Convert to 10 kHz units */
+- f += 1070; /* Add 10.7 MHz IF */
+-
+- write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
++ f += 1070; /* Add 10.7 MHz IF */
++ write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
++ mutex_unlock(&tr->lock);
+ }
+
+ static int vidioc_querycap(struct file *file, void *priv,
+@@ -199,68 +195,75 @@ static int vidioc_querycap(struct file *file, void *priv,
+ {
+ strlcpy(v->driver, "radio-trust", sizeof(v->driver));
+ strlcpy(v->card, "Trust FM Radio", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
++ struct trust *tr = video_drvdata(file);
++
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+- v->rangelow = (87.5*16000);
+- v->rangehigh = (108*16000);
+- v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->rangelow = 87.5 * 16000;
++ v->rangehigh = 108 * 16000;
++ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ v->capability = V4L2_TUNER_CAP_LOW;
+- if (tr_getstereo())
++ if (tr_getstereo(tr))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+- v->signal = tr_getsigstr();
++ v->signal = tr_getsigstr(tr);
+ return 0;
+ }
+
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
++ struct trust *tr = video_drvdata(file);
+
++ if (v->index)
++ return -EINVAL;
++ tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO);
+ return 0;
+ }
+
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- curfreq = f->frequency;
+- tr_setfreq(curfreq);
++ struct trust *tr = video_drvdata(file);
++
++ tr_setfreq(tr, f->frequency);
+ return 0;
+ }
+
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
++ struct trust *tr = video_drvdata(file);
++
+ f->type = V4L2_TUNER_RADIO;
+- f->frequency = curfreq;
++ f->frequency = tr->curfreq;
+ return 0;
+ }
+
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535);
++ case V4L2_CID_AUDIO_BASS:
++ case V4L2_CID_AUDIO_TREBLE:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768);
+ }
+ return -EINVAL;
+ }
+@@ -268,18 +271,20 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
++ struct trust *tr = video_drvdata(file);
++
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+- ctrl->value = curmute;
++ ctrl->value = tr->curmute;
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+- ctrl->value = curvol * 2048;
++ ctrl->value = tr->curvol * 2048;
+ return 0;
+ case V4L2_CID_AUDIO_BASS:
+- ctrl->value = curbass * 4370;
++ ctrl->value = tr->curbass * 4370;
+ return 0;
+ case V4L2_CID_AUDIO_TREBLE:
+- ctrl->value = curtreble * 4370;
++ ctrl->value = tr->curtreble * 4370;
+ return 0;
+ }
+ return -EINVAL;
+@@ -288,34 +293,25 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
++ struct trust *tr = video_drvdata(file);
++
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+- tr_setmute(ctrl->value);
++ tr_setmute(tr, ctrl->value);
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+- tr_setvol(ctrl->value);
++ tr_setvol(tr, ctrl->value);
+ return 0;
+ case V4L2_CID_AUDIO_BASS:
+- tr_setbass(ctrl->value);
++ tr_setbass(tr, ctrl->value);
+ return 0;
+ case V4L2_CID_AUDIO_TREBLE:
+- tr_settreble(ctrl->value);
++ tr_settreble(tr, ctrl->value);
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+-static int vidioc_g_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -324,34 +320,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
++ return i ? -EINVAL : 0;
++}
++
++static int vidioc_g_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+ static int vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
+- return 0;
++ return a->index ? -EINVAL : 0;
+ }
+
+-static int trust_exclusive_open(struct file *file)
++static int trust_open(struct file *file)
+ {
+- return test_and_set_bit(0, &in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int trust_exclusive_release(struct file *file)
++static int trust_release(struct file *file)
+ {
+- clear_bit(0, &in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations trust_fops = {
+ .owner = THIS_MODULE,
+- .open = trust_exclusive_open,
+- .release = trust_exclusive_release,
++ .open = trust_open,
++ .release = trust_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -370,59 +370,72 @@ static const struct v4l2_ioctl_ops trust_ioctl_ops = {
+ .vidioc_s_input = vidioc_s_input,
+ };
+
+-static struct video_device trust_radio = {
+- .name = "Trust FM Radio",
+- .fops = &trust_fops,
+- .ioctl_ops = &trust_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ static int __init trust_init(void)
+ {
+- if(io == -1) {
+- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
++ struct trust *tr = &trust_card;
++ struct v4l2_device *v4l2_dev = &tr->v4l2_dev;
++ int res;
++
++ strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name));
++ tr->io = io;
++ tr->ioval = 0xf;
++ mutex_init(&tr->lock);
++
++ if (tr->io == -1) {
++ v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n");
+ return -EINVAL;
+ }
+- if(!request_region(io, 2, "Trust FM Radio")) {
+- printk(KERN_ERR "trust: port 0x%x already in use\n", io);
++ if (!request_region(tr->io, 2, "Trust FM Radio")) {
++ v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io);
+ return -EBUSY;
+ }
+- if (video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io, 2);
++
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(tr->io, 2);
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ return res;
++ }
++
++ strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name));
++ tr->vdev.v4l2_dev = v4l2_dev;
++ tr->vdev.fops = &trust_fops;
++ tr->vdev.ioctl_ops = &trust_ioctl_ops;
++ tr->vdev.release = video_device_release_empty;
++ video_set_drvdata(&tr->vdev, tr);
++
++ if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(v4l2_dev);
++ release_region(tr->io, 2);
+ return -EINVAL;
+ }
+
+- printk(KERN_INFO "Trust FM Radio card driver v1.0.\n");
++ v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
+
+- write_i2c(2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
+- write_i2c(2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
+- write_i2c(2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
+- write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */
+- write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */
++ write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
++ write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
++ write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
++ write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */
++ write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */
+
+- tr_setvol(0x8000);
+- tr_setbass(0x8000);
+- tr_settreble(0x8000);
+- tr_setstereo(1);
++ tr_setvol(tr, 0xffff);
++ tr_setbass(tr, 0x8000);
++ tr_settreble(tr, 0x8000);
++ tr_setstereo(tr, 1);
+
+ /* mute card - prevents noisy bootups */
+- tr_setmute(1);
++ tr_setmute(tr, 1);
+
+ return 0;
+ }
+
+-MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
+-MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
+-MODULE_LICENSE("GPL");
+-
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
+-module_param(radio_nr, int, 0);
+-
+ static void __exit cleanup_trust_module(void)
+ {
+- video_unregister_device(&trust_radio);
+- release_region(io, 2);
++ struct trust *tr = &trust_card;
++
++ video_unregister_device(&tr->vdev);
++ v4l2_device_unregister(&tr->v4l2_dev);
++ release_region(tr->io, 2);
+ }
+
+ module_init(trust_init);
+diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
+index 5c3b319..92d923c 100644
+--- a/drivers/media/radio/radio-typhoon.c
++++ b/drivers/media/radio/radio-typhoon.c
+@@ -34,37 +34,15 @@
+ #include <linux/module.h> /* Modules */
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+-#include <linux/proc_fs.h> /* radio card status report */
+-#include <linux/seq_file.h>
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+ #include <linux/videodev2.h> /* kernel radio structs */
+-#include <media/v4l2-common.h>
++#include <linux/io.h> /* outb, outb_p */
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,1,1)
+-#define BANNER "Typhoon Radio Card driver v0.1.1\n"
+-
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- },{
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 65535,
+- .step = 1<<14,
+- .default_value = 0xff,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- }
+-};
+-
++MODULE_AUTHOR("Dr. Henrik Seidel");
++MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
++MODULE_LICENSE("GPL");
+
+ #ifndef CONFIG_RADIO_TYPHOON_PORT
+ #define CONFIG_RADIO_TYPHOON_PORT -1
+@@ -74,13 +52,26 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+ #define CONFIG_RADIO_TYPHOON_MUTEFREQ 0
+ #endif
+
+-#ifndef CONFIG_PROC_FS
+-#undef CONFIG_RADIO_TYPHOON_PROC_FS
+-#endif
++static int io = CONFIG_RADIO_TYPHOON_PORT;
++static int radio_nr = -1;
+
+-struct typhoon_device {
+- unsigned long in_use;
+- int iobase;
++module_param(io, int, 0);
++MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)");
++
++module_param(radio_nr, int, 0);
++
++static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ;
++module_param(mutefreq, ulong, 0);
++MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
++
++#define RADIO_VERSION KERNEL_VERSION(0, 1, 1)
++
++#define BANNER "Typhoon Radio Card driver v0.1.1\n"
++
++struct typhoon {
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ int io;
+ int curvol;
+ int muted;
+ unsigned long curfreq;
+@@ -88,25 +79,19 @@ struct typhoon_device {
+ struct mutex lock;
+ };
+
+-static void typhoon_setvol_generic(struct typhoon_device *dev, int vol);
+-static int typhoon_setfreq_generic(struct typhoon_device *dev,
+- unsigned long frequency);
+-static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency);
+-static void typhoon_mute(struct typhoon_device *dev);
+-static void typhoon_unmute(struct typhoon_device *dev);
+-static int typhoon_setvol(struct typhoon_device *dev, int vol);
++static struct typhoon typhoon_card;
+
+-static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
++static void typhoon_setvol_generic(struct typhoon *dev, int vol)
+ {
+ mutex_lock(&dev->lock);
+ vol >>= 14; /* Map 16 bit to 2 bit */
+ vol &= 3;
+- outb_p(vol / 2, dev->iobase); /* Set the volume, high bit. */
+- outb_p(vol % 2, dev->iobase + 2); /* Set the volume, low bit. */
++ outb_p(vol / 2, dev->io); /* Set the volume, high bit. */
++ outb_p(vol % 2, dev->io + 2); /* Set the volume, low bit. */
+ mutex_unlock(&dev->lock);
+ }
+
+-static int typhoon_setfreq_generic(struct typhoon_device *dev,
++static int typhoon_setfreq_generic(struct typhoon *dev,
+ unsigned long frequency)
+ {
+ unsigned long outval;
+@@ -130,22 +115,22 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev,
+ outval -= (10 * x * x + 10433) / 20866;
+ outval += 4 * x - 11505;
+
+- outb_p((outval >> 8) & 0x01, dev->iobase + 4);
+- outb_p(outval >> 9, dev->iobase + 6);
+- outb_p(outval & 0xff, dev->iobase + 8);
++ outb_p((outval >> 8) & 0x01, dev->io + 4);
++ outb_p(outval >> 9, dev->io + 6);
++ outb_p(outval & 0xff, dev->io + 8);
+ mutex_unlock(&dev->lock);
+
+ return 0;
+ }
+
+-static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency)
++static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency)
+ {
+ typhoon_setfreq_generic(dev, frequency);
+ dev->curfreq = frequency;
+ return 0;
+ }
+
+-static void typhoon_mute(struct typhoon_device *dev)
++static void typhoon_mute(struct typhoon *dev)
+ {
+ if (dev->muted == 1)
+ return;
+@@ -154,7 +139,7 @@ static void typhoon_mute(struct typhoon_device *dev)
+ dev->muted = 1;
+ }
+
+-static void typhoon_unmute(struct typhoon_device *dev)
++static void typhoon_unmute(struct typhoon *dev)
+ {
+ if (dev->muted == 0)
+ return;
+@@ -163,7 +148,7 @@ static void typhoon_unmute(struct typhoon_device *dev)
+ dev->muted = 0;
+ }
+
+-static int typhoon_setvol(struct typhoon_device *dev, int vol)
++static int typhoon_setvol(struct typhoon *dev, int vol)
+ {
+ if (dev->muted && vol != 0) { /* user is unmuting the card */
+ dev->curvol = vol;
+@@ -188,9 +173,9 @@ static int vidioc_querycap(struct file *file, void *priv,
+ {
+ strlcpy(v->driver, "radio-typhoon", sizeof(v->driver));
+ strlcpy(v->card, "Typhoon Radio", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+@@ -200,10 +185,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+- v->rangelow = (87.5*16000);
+- v->rangehigh = (108*16000);
++ v->rangelow = 87.5 * 16000;
++ v->rangehigh = 108 * 16000;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v->capability = V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
+@@ -214,44 +199,37 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+-
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_frequency(struct file *file, void *priv,
++static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct typhoon_device *typhoon = video_drvdata(file);
++ struct typhoon *dev = video_drvdata(file);
+
+- typhoon->curfreq = f->frequency;
+- typhoon_setfreq(typhoon, typhoon->curfreq);
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = dev->curfreq;
+ return 0;
+ }
+
+-static int vidioc_g_frequency(struct file *file, void *priv,
++static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct typhoon_device *typhoon = video_drvdata(file);
+-
+- f->type = V4L2_TUNER_RADIO;
+- f->frequency = typhoon->curfreq;
++ struct typhoon *dev = video_drvdata(file);
+
++ dev->curfreq = f->frequency;
++ typhoon_setfreq(dev, dev->curfreq);
+ return 0;
+ }
+
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535);
+ }
+ return -EINVAL;
+ }
+@@ -259,14 +237,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct typhoon_device *typhoon = video_drvdata(file);
++ struct typhoon *dev = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+- ctrl->value = typhoon->muted;
++ ctrl->value = dev->muted;
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+- ctrl->value = typhoon->curvol;
++ ctrl->value = dev->curvol;
+ return 0;
+ }
+ return -EINVAL;
+@@ -275,33 +253,22 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct typhoon_device *typhoon = video_drvdata(file);
++ struct typhoon *dev = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value)
+- typhoon_mute(typhoon);
++ typhoon_mute(dev);
+ else
+- typhoon_unmute(typhoon);
++ typhoon_unmute(dev);
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+- typhoon_setvol(typhoon, ctrl->value);
++ typhoon_setvol(dev, ctrl->value);
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+-static int vidioc_g_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -310,45 +277,62 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
++ return i ? -EINVAL : 0;
++}
++
++static int vidioc_g_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+ static int vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
+- return 0;
++ return a->index ? -EINVAL : 0;
+ }
+
+-static struct typhoon_device typhoon_unit =
++static int vidioc_log_status(struct file *file, void *priv)
+ {
+- .iobase = CONFIG_RADIO_TYPHOON_PORT,
+- .curfreq = CONFIG_RADIO_TYPHOON_MUTEFREQ,
+- .mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ,
+-};
++ struct typhoon *dev = video_drvdata(file);
++ struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
++
++ v4l2_info(v4l2_dev, BANNER);
++#ifdef MODULE
++ v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n");
++#else
++ v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n");
++#endif
++ v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4);
++ v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol);
++ v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ? "on" : "off");
++ v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io);
++ v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4);
++ return 0;
++}
+
+-static int typhoon_exclusive_open(struct file *file)
++static int typhoon_open(struct file *file)
+ {
+- return test_and_set_bit(0, &typhoon_unit.in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int typhoon_exclusive_release(struct file *file)
++static int typhoon_release(struct file *file)
+ {
+- clear_bit(0, &typhoon_unit.in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations typhoon_fops = {
+ .owner = THIS_MODULE,
+- .open = typhoon_exclusive_open,
+- .release = typhoon_exclusive_release,
++ .open = typhoon_open,
++ .release = typhoon_release,
+ .ioctl = video_ioctl2,
+ };
+
+ static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
++ .vidioc_log_status = vidioc_log_status,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+@@ -363,125 +347,72 @@ static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ };
+
+-static struct video_device typhoon_radio = {
+- .name = "Typhoon Radio",
+- .fops = &typhoon_fops,
+- .ioctl_ops = &typhoon_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+-#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
+-
+-static int typhoon_proc_show(struct seq_file *m, void *v)
+-{
+- #ifdef MODULE
+- #define MODULEPROCSTRING "Driver loaded as a module"
+- #else
+- #define MODULEPROCSTRING "Driver compiled into kernel"
+- #endif
+-
+- seq_puts(m, BANNER);
+- seq_puts(m, "Load type: " MODULEPROCSTRING "\n\n");
+- seq_printf(m, "frequency = %lu kHz\n",
+- typhoon_unit.curfreq >> 4);
+- seq_printf(m, "volume = %d\n", typhoon_unit.curvol);
+- seq_printf(m, "mute = %s\n", typhoon_unit.muted ?
+- "on" : "off");
+- seq_printf(m, "iobase = 0x%x\n", typhoon_unit.iobase);
+- seq_printf(m, "mute frequency = %lu kHz\n",
+- typhoon_unit.mutefreq >> 4);
+- return 0;
+-}
+-
+-static int typhoon_proc_open(struct inode *inode, struct file *file)
++static int __init typhoon_init(void)
+ {
+- return single_open(file, typhoon_proc_show, NULL);
+-}
+-
+-static const struct file_operations typhoon_proc_fops = {
+- .owner = THIS_MODULE,
+- .open = typhoon_proc_open,
+- .read = seq_read,
+- .llseek = seq_lseek,
+- .release = single_release,
+-};
+-#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */
+-
+-MODULE_AUTHOR("Dr. Henrik Seidel");
+-MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
+-MODULE_LICENSE("GPL");
+-
+-static int io = -1;
+-static int radio_nr = -1;
+-
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)");
+-module_param(radio_nr, int, 0);
++ struct typhoon *dev = &typhoon_card;
++ struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
++ int res;
+
+-#ifdef MODULE
+-static unsigned long mutefreq;
+-module_param(mutefreq, ulong, 0);
+-MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
+-#endif
++ strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
++ dev->io = io;
++ dev->curfreq = dev->mutefreq = mutefreq;
+
+-static int __init typhoon_init(void)
+-{
+-#ifdef MODULE
+- if (io == -1) {
+- printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n");
++ if (dev->io == -1) {
++ v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
+ return -EINVAL;
+ }
+- typhoon_unit.iobase = io;
+
+- if (mutefreq < 87000 || mutefreq > 108500) {
+- printk(KERN_ERR "radio-typhoon: You must set a frequency (in kHz) used when muting the card,\n");
+- printk(KERN_ERR "radio-typhoon: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
++ if (dev->mutefreq < 87000 || dev->mutefreq > 108500) {
++ v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n");
++ v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
+ return -EINVAL;
+ }
+- typhoon_unit.mutefreq = mutefreq;
+-#endif /* MODULE */
+-
+- printk(KERN_INFO BANNER);
+- mutex_init(&typhoon_unit.lock);
+- io = typhoon_unit.iobase;
+- if (!request_region(io, 8, "typhoon")) {
+- printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n",
+- typhoon_unit.iobase);
++
++ mutex_init(&dev->lock);
++ if (!request_region(dev->io, 8, "typhoon")) {
++ v4l2_err(v4l2_dev, "port 0x%x already in use\n",
++ dev->io);
+ return -EBUSY;
+ }
+
+- video_set_drvdata(&typhoon_radio, &typhoon_unit);
+- if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io, 8);
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(dev->io, 8);
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ return res;
++ }
++ v4l2_info(v4l2_dev, BANNER);
++
++ strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
++ dev->vdev.v4l2_dev = v4l2_dev;
++ dev->vdev.fops = &typhoon_fops;
++ dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
++ dev->vdev.release = video_device_release_empty;
++ video_set_drvdata(&dev->vdev, dev);
++ if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(&dev->v4l2_dev);
++ release_region(dev->io, 8);
+ return -EINVAL;
+ }
+- printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase);
+- printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n",
+- typhoon_unit.mutefreq);
+- typhoon_unit.mutefreq <<= 4;
++ v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
++ v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq);
++ dev->mutefreq <<= 4;
+
+ /* mute card - prevents noisy bootups */
+- typhoon_mute(&typhoon_unit);
+-
+-#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
+- if (!proc_create("driver/radio-typhoon", 0, NULL, &typhoon_proc_fops))
+- printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
+-#endif
++ typhoon_mute(dev);
+
+ return 0;
+ }
+
+-static void __exit typhoon_cleanup_module(void)
++static void __exit typhoon_exit(void)
+ {
++ struct typhoon *dev = &typhoon_card;
+
+-#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
+- remove_proc_entry("driver/radio-typhoon", NULL);
+-#endif
+-
+- video_unregister_device(&typhoon_radio);
+- release_region(io, 8);
++ video_unregister_device(&dev->vdev);
++ v4l2_device_unregister(&dev->v4l2_dev);
++ release_region(dev->io, 8);
+ }
+
+ module_init(typhoon_init);
+-module_exit(typhoon_cleanup_module);
++module_exit(typhoon_exit);
+
+diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
+index d2ac17e..1f85f20 100644
+--- a/drivers/media/radio/radio-zoltrix.c
++++ b/drivers/media/radio/radio-zoltrix.c
+@@ -33,33 +33,16 @@
+ #include <linux/init.h> /* Initdata */
+ #include <linux/ioport.h> /* request_region */
+ #include <linux/delay.h> /* udelay, msleep */
+-#include <asm/io.h> /* outb, outb_p */
+-#include <asm/uaccess.h> /* copy to/from user */
+ #include <linux/videodev2.h> /* kernel radio structs */
+-#include <media/v4l2-common.h>
++#include <linux/mutex.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++#include <linux/io.h> /* outb, outb_p */
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+
+-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+-
+-static struct v4l2_queryctrl radio_qctrl[] = {
+- {
+- .id = V4L2_CID_AUDIO_MUTE,
+- .name = "Mute",
+- .minimum = 0,
+- .maximum = 1,
+- .default_value = 1,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- },{
+- .id = V4L2_CID_AUDIO_VOLUME,
+- .name = "Volume",
+- .minimum = 0,
+- .maximum = 65535,
+- .step = 4096,
+- .default_value = 0xff,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- }
+-};
++MODULE_AUTHOR("C.van Schaik");
++MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
++MODULE_LICENSE("GPL");
+
+ #ifndef CONFIG_RADIO_ZOLTRIX_PORT
+ #define CONFIG_RADIO_ZOLTRIX_PORT -1
+@@ -68,9 +51,16 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+ static int io = CONFIG_RADIO_ZOLTRIX_PORT;
+ static int radio_nr = -1;
+
+-struct zol_device {
+- unsigned long in_use;
+- int port;
++module_param(io, int, 0);
++MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
++module_param(radio_nr, int, 0);
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
++
++struct zoltrix {
++ struct v4l2_device v4l2_dev;
++ struct video_device vdev;
++ int io;
+ int curvol;
+ unsigned long curfreq;
+ int muted;
+@@ -78,161 +68,158 @@ struct zol_device {
+ struct mutex lock;
+ };
+
+-static int zol_setvol(struct zol_device *dev, int vol)
++static struct zoltrix zoltrix_card;
++
++static int zol_setvol(struct zoltrix *zol, int vol)
+ {
+- dev->curvol = vol;
+- if (dev->muted)
++ zol->curvol = vol;
++ if (zol->muted)
+ return 0;
+
+- mutex_lock(&dev->lock);
++ mutex_lock(&zol->lock);
+ if (vol == 0) {
+- outb(0, io);
+- outb(0, io);
+- inb(io + 3); /* Zoltrix needs to be read to confirm */
+- mutex_unlock(&dev->lock);
++ outb(0, zol->io);
++ outb(0, zol->io);
++ inb(zol->io + 3); /* Zoltrix needs to be read to confirm */
++ mutex_unlock(&zol->lock);
+ return 0;
+ }
+
+- outb(dev->curvol-1, io);
++ outb(zol->curvol-1, zol->io);
+ msleep(10);
+- inb(io + 2);
+- mutex_unlock(&dev->lock);
++ inb(zol->io + 2);
++ mutex_unlock(&zol->lock);
+ return 0;
+ }
+
+-static void zol_mute(struct zol_device *dev)
++static void zol_mute(struct zoltrix *zol)
+ {
+- dev->muted = 1;
+- mutex_lock(&dev->lock);
+- outb(0, io);
+- outb(0, io);
+- inb(io + 3); /* Zoltrix needs to be read to confirm */
+- mutex_unlock(&dev->lock);
++ zol->muted = 1;
++ mutex_lock(&zol->lock);
++ outb(0, zol->io);
++ outb(0, zol->io);
++ inb(zol->io + 3); /* Zoltrix needs to be read to confirm */
++ mutex_unlock(&zol->lock);
+ }
+
+-static void zol_unmute(struct zol_device *dev)
++static void zol_unmute(struct zoltrix *zol)
+ {
+- dev->muted = 0;
+- zol_setvol(dev, dev->curvol);
++ zol->muted = 0;
++ zol_setvol(zol, zol->curvol);
+ }
+
+-static int zol_setfreq(struct zol_device *dev, unsigned long freq)
++static int zol_setfreq(struct zoltrix *zol, unsigned long freq)
+ {
+ /* tunes the radio to the desired frequency */
++ struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
+ unsigned long long bitmask, f, m;
+- unsigned int stereo = dev->stereo;
++ unsigned int stereo = zol->stereo;
+ int i;
+
+ if (freq == 0) {
+- printk(KERN_WARNING "zoltrix: received zero freq. Failed to set.\n");
++ v4l2_warn(v4l2_dev, "cannot set a frequency of 0.\n");
+ return -EINVAL;
+ }
+
+ m = (freq / 160 - 8800) * 2;
+- f = (unsigned long long) m + 0x4d1c;
++ f = (unsigned long long)m + 0x4d1c;
+
+ bitmask = 0xc480402c10080000ull;
+ i = 45;
+
+- mutex_lock(&dev->lock);
++ mutex_lock(&zol->lock);
+
+- outb(0, io);
+- outb(0, io);
+- inb(io + 3); /* Zoltrix needs to be read to confirm */
++ zol->curfreq = freq;
+
+- outb(0x40, io);
+- outb(0xc0, io);
++ outb(0, zol->io);
++ outb(0, zol->io);
++ inb(zol->io + 3); /* Zoltrix needs to be read to confirm */
+
+- bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( stereo << 31));
++ outb(0x40, zol->io);
++ outb(0xc0, zol->io);
++
++ bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31));
+ while (i--) {
+ if ((bitmask & 0x8000000000000000ull) != 0) {
+- outb(0x80, io);
++ outb(0x80, zol->io);
+ udelay(50);
+- outb(0x00, io);
++ outb(0x00, zol->io);
+ udelay(50);
+- outb(0x80, io);
++ outb(0x80, zol->io);
+ udelay(50);
+ } else {
+- outb(0xc0, io);
++ outb(0xc0, zol->io);
+ udelay(50);
+- outb(0x40, io);
++ outb(0x40, zol->io);
+ udelay(50);
+- outb(0xc0, io);
++ outb(0xc0, zol->io);
+ udelay(50);
+ }
+ bitmask *= 2;
+ }
+ /* termination sequence */
+- outb(0x80, io);
+- outb(0xc0, io);
+- outb(0x40, io);
++ outb(0x80, zol->io);
++ outb(0xc0, zol->io);
++ outb(0x40, zol->io);
+ udelay(1000);
+- inb(io+2);
++ inb(zol->io + 2);
+
+ udelay(1000);
+
+- if (dev->muted)
+- {
+- outb(0, io);
+- outb(0, io);
+- inb(io + 3);
++ if (zol->muted) {
++ outb(0, zol->io);
++ outb(0, zol->io);
++ inb(zol->io + 3);
+ udelay(1000);
+ }
+
+- mutex_unlock(&dev->lock);
++ mutex_unlock(&zol->lock);
+
+- if(!dev->muted)
+- {
+- zol_setvol(dev, dev->curvol);
+- }
++ if (!zol->muted)
++ zol_setvol(zol, zol->curvol);
+ return 0;
+ }
+
+ /* Get signal strength */
+-
+-static int zol_getsigstr(struct zol_device *dev)
++static int zol_getsigstr(struct zoltrix *zol)
+ {
+ int a, b;
+
+- mutex_lock(&dev->lock);
+- outb(0x00, io); /* This stuff I found to do nothing */
+- outb(dev->curvol, io);
++ mutex_lock(&zol->lock);
++ outb(0x00, zol->io); /* This stuff I found to do nothing */
++ outb(zol->curvol, zol->io);
+ msleep(20);
+
+- a = inb(io);
++ a = inb(zol->io);
+ msleep(10);
+- b = inb(io);
++ b = inb(zol->io);
+
+- mutex_unlock(&dev->lock);
++ mutex_unlock(&zol->lock);
+
+ if (a != b)
+- return (0);
++ return 0;
+
+- if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */
+- || (a == 0xef)) /* with a binary scanner on the card io */
+- return (1);
+- return (0);
++ /* I found this out by playing with a binary scanner on the card io */
++ return a == 0xcf || a == 0xdf || a == 0xef;
+ }
+
+-static int zol_is_stereo (struct zol_device *dev)
++static int zol_is_stereo(struct zoltrix *zol)
+ {
+ int x1, x2;
+
+- mutex_lock(&dev->lock);
++ mutex_lock(&zol->lock);
+
+- outb(0x00, io);
+- outb(dev->curvol, io);
++ outb(0x00, zol->io);
++ outb(zol->curvol, zol->io);
+ msleep(20);
+
+- x1 = inb(io);
++ x1 = inb(zol->io);
+ msleep(10);
+- x2 = inb(io);
++ x2 = inb(zol->io);
+
+- mutex_unlock(&dev->lock);
++ mutex_unlock(&zol->lock);
+
+- if ((x1 == x2) && (x1 == 0xcf))
+- return 1;
+- return 0;
++ return x1 == x2 && x1 == 0xcf;
+ }
+
+ static int vidioc_querycap(struct file *file, void *priv,
+@@ -240,59 +227,54 @@ static int vidioc_querycap(struct file *file, void *priv,
+ {
+ strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver));
+ strlcpy(v->card, "Zoltrix Radio", sizeof(v->card));
+- sprintf(v->bus_info, "ISA");
++ strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
+ v->version = RADIO_VERSION;
+- v->capabilities = V4L2_CAP_TUNER;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+ }
+
+ static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- struct zol_device *zol = video_drvdata(file);
++ struct zoltrix *zol = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+- strcpy(v->name, "FM");
++ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+- v->rangelow = (88*16000);
+- v->rangehigh = (108*16000);
+- v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->rangelow = 88 * 16000;
++ v->rangehigh = 108 * 16000;
++ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ v->capability = V4L2_TUNER_CAP_LOW;
+ if (zol_is_stereo(zol))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+- v->signal = 0xFFFF*zol_getsigstr(zol);
++ v->signal = 0xFFFF * zol_getsigstr(zol);
+ return 0;
+ }
+
+ static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+ {
+- if (v->index > 0)
+- return -EINVAL;
+- return 0;
++ return v->index ? -EINVAL : 0;
+ }
+
+ static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct zol_device *zol = video_drvdata(file);
++ struct zoltrix *zol = video_drvdata(file);
+
+- zol->curfreq = f->frequency;
+- if (zol_setfreq(zol, zol->curfreq) != 0) {
+- printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
++ if (zol_setfreq(zol, f->frequency) != 0)
+ return -EINVAL;
+- }
+ return 0;
+ }
+
+ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+ {
+- struct zol_device *zol = video_drvdata(file);
++ struct zoltrix *zol = video_drvdata(file);
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = zol->curfreq;
+@@ -302,14 +284,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
+ static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+- if (qc->id && qc->id == radio_qctrl[i].id) {
+- memcpy(qc, &(radio_qctrl[i]),
+- sizeof(*qc));
+- return 0;
+- }
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535);
+ }
+ return -EINVAL;
+ }
+@@ -317,7 +296,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct zol_device *zol = video_drvdata(file);
++ struct zoltrix *zol = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -333,7 +312,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct zol_device *zol = video_drvdata(file);
++ struct zoltrix *zol = video_drvdata(file);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+@@ -341,43 +320,30 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ zol_mute(zol);
+ else {
+ zol_unmute(zol);
+- zol_setvol(zol,zol->curvol);
++ zol_setvol(zol, zol->curvol);
+ }
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+- zol_setvol(zol,ctrl->value/4096);
++ zol_setvol(zol, ctrl->value / 4096);
+ return 0;
+ }
+ zol->stereo = 1;
+- if (zol_setfreq(zol, zol->curfreq) != 0) {
+- printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
++ if (zol_setfreq(zol, zol->curfreq) != 0)
+ return -EINVAL;
+- }
+ #if 0
+ /* FIXME: Implement stereo/mono switch on V4L2 */
+- if (v->mode & VIDEO_SOUND_STEREO) {
+- zol->stereo = 1;
+- zol_setfreq(zol, zol->curfreq);
+- }
+- if (v->mode & VIDEO_SOUND_MONO) {
+- zol->stereo = 0;
+- zol_setfreq(zol, zol->curfreq);
+- }
++ if (v->mode & VIDEO_SOUND_STEREO) {
++ zol->stereo = 1;
++ zol_setfreq(zol, zol->curfreq);
++ }
++ if (v->mode & VIDEO_SOUND_MONO) {
++ zol->stereo = 0;
++ zol_setfreq(zol, zol->curfreq);
++ }
+ #endif
+ return -EINVAL;
+ }
+
+-static int vidioc_g_audio(struct file *file, void *priv,
+- struct v4l2_audio *a)
+-{
+- if (a->index > 1)
+- return -EINVAL;
+-
+- strcpy(a->name, "Radio");
+- a->capability = V4L2_AUDCAP_STEREO;
+- return 0;
+-}
+-
+ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+ *i = 0;
+@@ -386,37 +352,39 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+
+ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
+- if (i != 0)
+- return -EINVAL;
+- return 0;
++ return i ? -EINVAL : 0;
+ }
+
+-static int vidioc_s_audio(struct file *file, void *priv,
++static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+ {
+- if (a->index != 0)
+- return -EINVAL;
++ a->index = 0;
++ strlcpy(a->name, "Radio", sizeof(a->name));
++ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+
+-static struct zol_device zoltrix_unit;
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ return a->index ? -EINVAL : 0;
++}
+
+-static int zoltrix_exclusive_open(struct file *file)
++static int zoltrix_open(struct file *file)
+ {
+- return test_and_set_bit(0, &zoltrix_unit.in_use) ? -EBUSY : 0;
++ return 0;
+ }
+
+-static int zoltrix_exclusive_release(struct file *file)
++static int zoltrix_release(struct file *file)
+ {
+- clear_bit(0, &zoltrix_unit.in_use);
+ return 0;
+ }
+
+ static const struct v4l2_file_operations zoltrix_fops =
+ {
+ .owner = THIS_MODULE,
+- .open = zoltrix_exclusive_open,
+- .release = zoltrix_exclusive_release,
++ .open = zoltrix_open,
++ .release = zoltrix_release,
+ .ioctl = video_ioctl2,
+ };
+
+@@ -435,67 +403,75 @@ static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ };
+
+-static struct video_device zoltrix_radio = {
+- .name = "Zoltrix Radio Plus",
+- .fops = &zoltrix_fops,
+- .ioctl_ops = &zoltrix_ioctl_ops,
+- .release = video_device_release_empty,
+-};
+-
+ static int __init zoltrix_init(void)
+ {
+- if (io == -1) {
+- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
++ struct zoltrix *zol = &zoltrix_card;
++ struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
++ int res;
++
++ strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name));
++ zol->io = io;
++ if (zol->io == -1) {
++ v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n");
+ return -EINVAL;
+ }
+- if ((io != 0x20c) && (io != 0x30c)) {
+- printk(KERN_ERR "zoltrix: invalid port, try 0x20c or 0x30c\n");
++ if (zol->io != 0x20c && zol->io != 0x30c) {
++ v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n");
+ return -ENXIO;
+ }
+
+- video_set_drvdata(&zoltrix_radio, &zoltrix_unit);
+- if (!request_region(io, 2, "zoltrix")) {
+- printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
++ if (!request_region(zol->io, 2, "zoltrix")) {
++ v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io);
+ return -EBUSY;
+ }
+
+- if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+- release_region(io, 2);
++ res = v4l2_device_register(NULL, v4l2_dev);
++ if (res < 0) {
++ release_region(zol->io, 2);
++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
++ return res;
++ }
++
++ strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
++ zol->vdev.v4l2_dev = v4l2_dev;
++ zol->vdev.fops = &zoltrix_fops;
++ zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
++ zol->vdev.release = video_device_release_empty;
++ video_set_drvdata(&zol->vdev, zol);
++
++ if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
++ v4l2_device_unregister(v4l2_dev);
++ release_region(zol->io, 2);
+ return -EINVAL;
+ }
+- printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
++ v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
+
+- mutex_init(&zoltrix_unit.lock);
++ mutex_init(&zol->lock);
+
+ /* mute card - prevents noisy bootups */
+
+ /* this ensures that the volume is all the way down */
+
+- outb(0, io);
+- outb(0, io);
++ outb(0, zol->io);
++ outb(0, zol->io);
+ msleep(20);
+- inb(io + 3);
++ inb(zol->io + 3);
+
+- zoltrix_unit.curvol = 0;
+- zoltrix_unit.stereo = 1;
++ zol->curvol = 0;
++ zol->stereo = 1;
+
+ return 0;
+ }
+
+-MODULE_AUTHOR("C.van Schaik");
+-MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
+-MODULE_LICENSE("GPL");
+-
+-module_param(io, int, 0);
+-MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
+-module_param(radio_nr, int, 0);
+-
+-static void __exit zoltrix_cleanup_module(void)
++static void __exit zoltrix_exit(void)
+ {
+- video_unregister_device(&zoltrix_radio);
+- release_region(io, 2);
++ struct zoltrix *zol = &zoltrix_card;
++
++ video_unregister_device(&zol->vdev);
++ v4l2_device_unregister(&zol->v4l2_dev);
++ release_region(zol->io, 2);
+ }
+
+ module_init(zoltrix_init);
+-module_exit(zoltrix_cleanup_module);
++module_exit(zoltrix_exit);
+
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index 19cf3b8..76bad58 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -249,11 +249,25 @@ config VIDEO_VP27SMPX
+ To compile this driver as a module, choose M here: the
+ module will be called vp27smpx.
+
++comment "RDS decoders"
++
++config VIDEO_SAA6588
++ tristate "SAA6588 Radio Chip RDS decoder support"
++ depends on VIDEO_V4L2 && I2C
++
++ help
++ Support for this Radio Data System (RDS) decoder. This allows
++ seeing radio station identification transmitted using this
++ standard.
++
++ To compile this driver as a module, choose M here: the
++ module will be called saa6588.
++
+ comment "Video decoders"
+
+ config VIDEO_BT819
+ tristate "BT819A VideoStream decoder"
+- depends on VIDEO_V4L1 && I2C
++ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for BT819A video decoder.
+
+@@ -262,7 +276,7 @@ config VIDEO_BT819
+
+ config VIDEO_BT856
+ tristate "BT856 VideoStream decoder"
+- depends on VIDEO_V4L1 && I2C
++ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for BT856 video decoder.
+
+@@ -271,7 +285,7 @@ config VIDEO_BT856
+
+ config VIDEO_BT866
+ tristate "BT866 VideoStream decoder"
+- depends on VIDEO_V4L1 && I2C
++ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for BT866 video decoder.
+
+@@ -280,7 +294,7 @@ config VIDEO_BT866
+
+ config VIDEO_KS0127
+ tristate "KS0127 video decoder"
+- depends on VIDEO_V4L1 && I2C
++ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for KS0127 video decoder.
+
+@@ -307,38 +321,18 @@ config VIDEO_TCM825X
+
+ config VIDEO_SAA7110
+ tristate "Philips SAA7110 video decoder"
+- depends on VIDEO_V4L1 && I2C
++ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7110 video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7110.
+
+-config VIDEO_SAA7111
+- tristate "Philips SAA7111 video decoder"
+- depends on VIDEO_V4L1 && I2C
+- ---help---
+- Support for the Philips SAA711 video decoder.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called saa7111.
+-
+-config VIDEO_SAA7114
+- tristate "Philips SAA7114 video decoder"
+- depends on VIDEO_V4L1 && I2C
+- ---help---
+- Support for the Philips SAA7114 video decoder. This driver
+- is used only on Zoran driver and should be moved soon to
+- SAA711x module.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called saa7114.
+-
+ config VIDEO_SAA711X
+- tristate "Philips SAA7113/4/5 video decoders"
++ tristate "Philips SAA7111/3/4/5 video decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+- Support for the Philips SAA7113/4/5 video decoders.
++ Support for the Philips SAA7111/3/4/5 video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7115.
+@@ -383,7 +377,7 @@ config VIDEO_TVP5150
+
+ config VIDEO_VPX3220
+ tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
+- depends on VIDEO_V4L1 && I2C
++ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for VPX322x video decoders.
+
+@@ -421,7 +415,7 @@ config VIDEO_SAA7127
+
+ config VIDEO_SAA7185
+ tristate "Philips SAA7185 video encoder"
+- depends on VIDEO_V4L1 && I2C
++ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7185 video encoder.
+
+@@ -430,7 +424,7 @@ config VIDEO_SAA7185
+
+ config VIDEO_ADV7170
+ tristate "Analog Devices ADV7170 video encoder"
+- depends on VIDEO_V4L1 && I2C
++ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Analog Devices ADV7170 video encoder driver
+
+@@ -439,7 +433,7 @@ config VIDEO_ADV7170
+
+ config VIDEO_ADV7175
+ tristate "Analog Devices ADV7175 video encoder"
+- depends on VIDEO_V4L1 && I2C
++ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Analog Devices ADV7175 video encoder driver
+
+@@ -487,18 +481,6 @@ config VIDEO_VIVI
+
+ source "drivers/media/video/bt8xx/Kconfig"
+
+-config VIDEO_SAA6588
+- tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards"
+- depends on I2C && VIDEO_BT848
+-
+- help
+- Support for Radio Data System (RDS) decoder. This allows seeing
+- radio station identification transmitted using this standard.
+- Currently, it works only with bt8x8 chips.
+-
+- To compile this driver as a module, choose M here: the
+- module will be called saa6588.
+-
+ config VIDEO_PMS
+ tristate "Mediavision Pro Movie Studio Video For Linux"
+ depends on ISA && VIDEO_V4L1
+@@ -602,7 +584,6 @@ config VIDEO_SAA5249
+ config VIDEO_VINO
+ tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
+ depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
+- select I2C_ALGO_SGI
+ select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
+ help
+ Say Y here to build in support for the Vino video input system found
+@@ -639,7 +620,7 @@ config VIDEO_MXB
+ depends on PCI && VIDEO_V4L1 && I2C
+ select VIDEO_SAA7146_VV
+ select VIDEO_TUNER
+- select VIDEO_SAA7115 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
+@@ -728,13 +709,6 @@ config SOC_CAMERA_MT9M001
+ This driver supports MT9M001 cameras from Micron, monochrome
+ and colour models.
+
+-config MT9M001_PCA9536_SWITCH
+- bool "pca9536 datawidth switch for mt9m001"
+- depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO
+- help
+- Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
+- extender to switch between 8 and 10 bit datawidth modes
+-
+ config SOC_CAMERA_MT9M111
+ tristate "mt9m111 and mt9m112 support"
+ depends on SOC_CAMERA && I2C
+@@ -754,13 +728,6 @@ config SOC_CAMERA_MT9V022
+ help
+ This driver supports MT9V022 cameras from Micron
+
+-config MT9V022_PCA9536_SWITCH
+- bool "pca9536 datawidth switch for mt9v022"
+- depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO
+- help
+- Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
+- extender to switch between 8 and 10 bit datawidth modes
+-
+ config SOC_CAMERA_TW9910
+ tristate "tw9910 support"
+ depends on SOC_CAMERA && I2C
+@@ -779,6 +746,13 @@ config SOC_CAMERA_OV772X
+ help
+ This is a ov772x camera driver
+
++config VIDEO_MX3
++ tristate "i.MX3x Camera Sensor Interface driver"
++ depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
++ select VIDEOBUF_DMA_CONTIG
++ ---help---
++ This is a v4l2 driver for the i.MX3x Camera Sensor Interface
++
+ config VIDEO_PXA27x
+ tristate "PXA27x Quick Capture Interface driver"
+ depends on VIDEO_DEV && PXA27x && SOC_CAMERA
+@@ -817,6 +791,8 @@ source "drivers/media/video/gspca/Kconfig"
+
+ source "drivers/media/video/pvrusb2/Kconfig"
+
++source "drivers/media/video/hdpvr/Kconfig"
++
+ source "drivers/media/video/em28xx/Kconfig"
+
+ source "drivers/media/video/usbvision/Kconfig"
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index 72f6d03..b904674 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -30,7 +30,6 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
+ obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
+ obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
+ obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
+-obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
+
+ obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
+ obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
+@@ -43,8 +42,6 @@ obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
+ obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
+ obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
+ obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
+-obj-$(CONFIG_VIDEO_SAA7111) += saa7111.o
+-obj-$(CONFIG_VIDEO_SAA7114) += saa7114.o
+ obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+ obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
+ obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
+@@ -122,6 +119,8 @@ obj-$(CONFIG_USB_PWC) += pwc/
+ obj-$(CONFIG_USB_ZC0301) += zc0301/
+ obj-$(CONFIG_USB_GSPCA) += gspca/
+
++obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
++
+ obj-$(CONFIG_USB_IBMCAM) += usbvideo/
+ obj-$(CONFIG_USB_KONICAWC) += usbvideo/
+ obj-$(CONFIG_USB_VICAM) += usbvideo/
+@@ -134,10 +133,11 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/
+ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+ obj-$(CONFIG_VIDEO_CX23885) += cx23885/
+
+-obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
++obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
++obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
+ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
+ obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
+-obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
++obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
+ obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
+ obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
+ obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
+diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
+index e0eb4f3..873c30a 100644
+--- a/drivers/media/video/adv7170.c
++++ b/drivers/media/video/adv7170.c
+@@ -34,15 +34,16 @@
+ #include <asm/uaccess.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-id.h>
+-#include <linux/videodev.h>
+-#include <linux/video_encoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
+ MODULE_AUTHOR("Maxim Yevtyushkin");
+ MODULE_LICENSE("GPL");
+
++
+ static int debug;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+@@ -50,38 +51,43 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ /* ----------------------------------------------------------------------- */
+
+ struct adv7170 {
++ struct v4l2_subdev sd;
+ unsigned char reg[128];
+
+- int norm;
++ v4l2_std_id norm;
+ int input;
+- int enable;
+- int bright;
+- int contrast;
+- int hue;
+- int sat;
+ };
+
++static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct adv7170, sd);
++}
++
+ 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)
++static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+ {
+- struct adv7170 *encoder = i2c_get_clientdata(client);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct adv7170 *encoder = to_adv7170(sd);
+
+ encoder->reg[reg] = value;
+ return i2c_smbus_write_byte_data(client, reg, value);
+ }
+
+-static inline int adv7170_read(struct i2c_client *client, u8 reg)
++static inline int adv7170_read(struct v4l2_subdev *sd, u8 reg)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
+ return i2c_smbus_read_byte_data(client, reg);
+ }
+
+-static int adv7170_write_block(struct i2c_client *client,
++static int adv7170_write_block(struct v4l2_subdev *sd,
+ const u8 *data, unsigned int len)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct adv7170 *encoder = to_adv7170(sd);
+ int ret = -1;
+ u8 reg;
+
+@@ -89,7 +95,6 @@ static int adv7170_write_block(struct i2c_client *client,
+ * 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);
+ u8 block_data[32];
+ int block_len;
+
+@@ -110,7 +115,7 @@ static int adv7170_write_block(struct i2c_client *client,
+ /* do some slow I2C emulation kind of thing */
+ while (len >= 2) {
+ reg = *data++;
+- ret = adv7170_write(client, reg, *data++);
++ ret = adv7170_write(sd, reg, *data++);
+ if (ret < 0)
+ break;
+ len -= 2;
+@@ -128,203 +133,161 @@ static int adv7170_write_block(struct i2c_client *client,
+ #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
++ 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
++ 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 cmd, void *arg)
++static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+ {
+- 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;
++ struct adv7170 *encoder = to_adv7170(sd);
++
++ v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
++
++ if (std & V4L2_STD_NTSC) {
++ adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
++ if (encoder->input == 0)
++ adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
++ adv7170_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7170_write(sd, 0x07, TR0MODE);
++ } else if (std & V4L2_STD_PAL) {
++ adv7170_write_block(sd, init_PAL, sizeof(init_PAL));
++ if (encoder->input == 0)
++ adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
++ adv7170_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7170_write(sd, 0x07, TR0MODE);
++ } else {
++ v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
++ (unsigned long long)std);
++ return -EINVAL;
+ }
++ v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
++ encoder->norm = std;
++ return 0;
++}
+
+- case ENCODER_SET_NORM:
+- {
+- int iarg = *(int *) arg;
+-
+- v4l_dbg(1, debug, client, "set norm %d\n", 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:
+- v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
+- return -EINVAL;
+- }
+- v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
+- encoder->norm = iarg;
+- break;
+- }
++static int adv7170_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
++{
++ struct adv7170 *encoder = to_adv7170(sd);
+
+- 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 */
+-
+- v4l_dbg(1, debug, client, "set input from %s\n",
+- 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:
+- v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
+- return -EINVAL;
+- }
+- v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
+- encoder->input = iarg;
+- break;
+- }
++ /* RJ: route->input = 0: input is from decoder
++ route->input = 1: input is from ZR36060
++ route->input = 2: color bar */
+
+- case ENCODER_SET_OUTPUT:
+- {
+- int *iarg = arg;
++ v4l2_dbg(1, debug, sd, "set input from %s\n",
++ route->input == 0 ? "decoder" : "ZR36060");
+
+- /* not much choice of outputs */
+- if (*iarg != 0) {
+- return -EINVAL;
+- }
++ switch (route->input) {
++ case 0:
++ adv7170_write(sd, 0x01, 0x20);
++ adv7170_write(sd, 0x08, TR1CAPT); /* TR1 */
++ adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
++ adv7170_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7170_write(sd, 0x07, TR0MODE);
++ /* udelay(10); */
+ break;
+- }
+-
+- case ENCODER_ENABLE_OUTPUT:
+- {
+- int *iarg = arg;
+
+- encoder->enable = !!*iarg;
++ case 1:
++ adv7170_write(sd, 0x01, 0x00);
++ adv7170_write(sd, 0x08, TR1PLAY); /* TR1 */
++ adv7170_write(sd, 0x02, 0x08);
++ adv7170_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7170_write(sd, 0x07, TR0MODE);
++ /* udelay(10); */
+ break;
+- }
+
+ default:
++ v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
+ return -EINVAL;
+ }
+-
++ v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
++ encoder->input = route->input;
+ return 0;
+ }
+
++static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7170, 0);
++}
++
+ /* ----------------------------------------------------------------------- */
+
+-static unsigned short normal_i2c[] = {
+- 0xd4 >> 1, 0xd6 >> 1, /* adv7170 IDs */
+- 0x54 >> 1, 0x56 >> 1, /* adv7171 IDs */
+- I2C_CLIENT_END
++static const struct v4l2_subdev_core_ops adv7170_core_ops = {
++ .g_chip_ident = adv7170_g_chip_ident,
+ };
+
+-I2C_CLIENT_INSMOD;
++static const struct v4l2_subdev_video_ops adv7170_video_ops = {
++ .s_std_output = adv7170_s_std_output,
++ .s_routing = adv7170_s_routing,
++};
++
++static const struct v4l2_subdev_ops adv7170_ops = {
++ .core = &adv7170_core_ops,
++ .video = &adv7170_video_ops,
++};
++
++/* ----------------------------------------------------------------------- */
+
+ static int adv7170_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ struct adv7170 *encoder;
++ struct v4l2_subdev *sd;
+ int i;
+
+ /* Check if the adapter supports the needed features */
+@@ -337,26 +300,29 @@ static int adv7170_probe(struct i2c_client *client,
+ encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
+ if (encoder == NULL)
+ return -ENOMEM;
+- encoder->norm = VIDEO_MODE_NTSC;
++ sd = &encoder->sd;
++ v4l2_i2c_subdev_init(sd, client, &adv7170_ops);
++ encoder->norm = V4L2_STD_NTSC;
+ encoder->input = 0;
+- encoder->enable = 1;
+- i2c_set_clientdata(client, encoder);
+
+- i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC));
++ i = adv7170_write_block(sd, 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);
+- v4l_dbg(1, debug, client, "revision %d\n", i & 1);
++ i = adv7170_write(sd, 0x07, TR0MODE | TR0RST);
++ i = adv7170_write(sd, 0x07, TR0MODE);
++ i = adv7170_read(sd, 0x12);
++ v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
+ }
+ if (i < 0)
+- v4l_dbg(1, debug, client, "init error 0x%x\n", i);
++ v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
+ return 0;
+ }
+
+ static int adv7170_remove(struct i2c_client *client)
+ {
+- kfree(i2c_get_clientdata(client));
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_adv7170(sd));
+ return 0;
+ }
+
+@@ -371,8 +337,6 @@ MODULE_DEVICE_TABLE(i2c, adv7170_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "adv7170",
+- .driverid = I2C_DRIVERID_ADV7170,
+- .command = adv7170_command,
+ .probe = adv7170_probe,
+ .remove = adv7170_remove,
+ .id_table = adv7170_id,
+diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
+index 6008e84..ff12103 100644
+--- a/drivers/media/video/adv7175.c
++++ b/drivers/media/video/adv7175.c
+@@ -30,15 +30,19 @@
+ #include <asm/uaccess.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-id.h>
+-#include <linux/videodev.h>
+-#include <linux/video_encoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
+ MODULE_AUTHOR("Dave Perks");
+ MODULE_LICENSE("GPL");
+
++#define I2C_ADV7175 0xd4
++#define I2C_ADV7176 0x54
++
++
+ static int debug;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+@@ -46,36 +50,38 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ /* ----------------------------------------------------------------------- */
+
+ struct adv7175 {
+- int norm;
++ struct v4l2_subdev sd;
++ v4l2_std_id norm;
+ int input;
+- int enable;
+- int bright;
+- int contrast;
+- int hue;
+- int sat;
+ };
+
+-#define I2C_ADV7175 0xd4
+-#define I2C_ADV7176 0x54
++static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct adv7175, sd);
++}
+
+ static char *inputs[] = { "pass_through", "play_back", "color_bar" };
+-static char *norms[] = { "PAL", "NTSC", "SECAM->PAL (may not work!)" };
+
+ /* ----------------------------------------------------------------------- */
+
+-static inline int adv7175_write(struct i2c_client *client, u8 reg, u8 value)
++static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
+ return i2c_smbus_write_byte_data(client, reg, value);
+ }
+
+-static inline int adv7175_read(struct i2c_client *client, u8 reg)
++static inline int adv7175_read(struct v4l2_subdev *sd, u8 reg)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
+ return i2c_smbus_read_byte_data(client, reg);
+ }
+
+-static int adv7175_write_block(struct i2c_client *client,
++static int adv7175_write_block(struct v4l2_subdev *sd,
+ const u8 *data, unsigned int len)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = -1;
+ u8 reg;
+
+@@ -103,7 +109,7 @@ static int adv7175_write_block(struct i2c_client *client,
+ /* do some slow I2C emulation kind of thing */
+ while (len >= 2) {
+ reg = *data++;
+- ret = adv7175_write(client, reg, *data++);
++ ret = adv7175_write(sd, reg, *data++);
+ if (ret < 0)
+ break;
+ len -= 2;
+@@ -113,18 +119,18 @@ static int adv7175_write_block(struct i2c_client *client,
+ return ret;
+ }
+
+-static void set_subcarrier_freq(struct i2c_client *client, int pass_through)
++static void set_subcarrier_freq(struct v4l2_subdev *sd, int pass_through)
+ {
+ /* for some reason pass_through NTSC needs
+ * a different sub-carrier freq to remain stable. */
+ if (pass_through)
+- adv7175_write(client, 0x02, 0x00);
++ adv7175_write(sd, 0x02, 0x00);
+ else
+- adv7175_write(client, 0x02, 0x55);
++ adv7175_write(sd, 0x02, 0x55);
+
+- adv7175_write(client, 0x03, 0x55);
+- adv7175_write(client, 0x04, 0x55);
+- adv7175_write(client, 0x05, 0x25);
++ adv7175_write(sd, 0x03, 0x55);
++ adv7175_write(sd, 0x04, 0x55);
++ adv7175_write(sd, 0x05, 0x25);
+ }
+
+ /* ----------------------------------------------------------------------- */
+@@ -184,180 +190,144 @@ static const unsigned char init_ntsc[] = {
+ 0x06, 0x1a, /* subc. phase */
+ };
+
+-static int adv7175_command(struct i2c_client *client, unsigned cmd, void *arg)
++static int adv7175_init(struct v4l2_subdev *sd, u32 val)
+ {
+- struct adv7175 *encoder = i2c_get_clientdata(client);
++ /* This is just for testing!!! */
++ adv7175_write_block(sd, init_common, sizeof(init_common));
++ adv7175_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7175_write(sd, 0x07, TR0MODE);
++ return 0;
++}
+
+- switch (cmd) {
+- 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;
++static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
++{
++ struct adv7175 *encoder = to_adv7175(sd);
++
++ if (std & V4L2_STD_NTSC) {
++ adv7175_write_block(sd, init_ntsc, sizeof(init_ntsc));
++ if (encoder->input == 0)
++ adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */
++ adv7175_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7175_write(sd, 0x07, TR0MODE);
++ } else if (std & V4L2_STD_PAL) {
++ adv7175_write_block(sd, init_pal, sizeof(init_pal));
++ if (encoder->input == 0)
++ adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */
++ adv7175_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7175_write(sd, 0x07, TR0MODE);
++ } else if (std & V4L2_STD_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(sd, init_pal, sizeof(init_pal));
++ if (encoder->input == 0)
++ adv7175_write(sd, 0x0d, 0x49); /* Disable genlock */
++ adv7175_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7175_write(sd, 0x07, TR0MODE);
++ } else {
++ v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
++ (unsigned long long)std);
++ return -EINVAL;
++ }
++ v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
++ encoder->norm = std;
++ return 0;
++}
+
+- case ENCODER_GET_CAPABILITIES:
+- {
+- struct video_encoder_capability *cap = arg;
++static int adv7175_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
++{
++ struct adv7175 *encoder = to_adv7175(sd);
+
+- cap->flags = VIDEO_ENCODER_PAL |
+- VIDEO_ENCODER_NTSC |
+- VIDEO_ENCODER_SECAM; /* well, hacky */
+- cap->inputs = 2;
+- cap->outputs = 1;
+- break;
+- }
++ /* RJ: route->input = 0: input is from decoder
++ route->input = 1: input is from ZR36060
++ route->input = 2: color bar */
+
+- 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:
+- v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
+- return -EINVAL;
+- }
+- v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
+- encoder->norm = iarg;
++ switch (route->input) {
++ case 0:
++ adv7175_write(sd, 0x01, 0x00);
++
++ if (encoder->norm & V4L2_STD_NTSC)
++ set_subcarrier_freq(sd, 1);
++
++ adv7175_write(sd, 0x0c, TR1CAPT); /* TR1 */
++ if (encoder->norm & V4L2_STD_SECAM)
++ adv7175_write(sd, 0x0d, 0x49); /* Disable genlock */
++ else
++ adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */
++ adv7175_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7175_write(sd, 0x07, TR0MODE);
++ /*udelay(10);*/
+ 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);
+-
+- if (encoder->norm == VIDEO_MODE_NTSC)
+- set_subcarrier_freq(client, 1);
+-
+- 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;
+-
+- case 1:
+- adv7175_write(client, 0x01, 0x00);
+-
+- if (encoder->norm == VIDEO_MODE_NTSC)
+- set_subcarrier_freq(client, 0);
+-
+- 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);
+-
+- if (encoder->norm == VIDEO_MODE_NTSC)
+- set_subcarrier_freq(client, 0);
+-
+- adv7175_write(client, 0x0d, 0x49);
+- adv7175_write(client, 0x07, TR0MODE | TR0RST);
+- adv7175_write(client, 0x07, TR0MODE);
+- /* udelay(10); */
+- break;
+-
+- default:
+- v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
+- return -EINVAL;
+- }
+- v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
+- encoder->input = iarg;
+- break;
+- }
++ case 1:
++ adv7175_write(sd, 0x01, 0x00);
+
+- case ENCODER_SET_OUTPUT:
+- {
+- int *iarg = arg;
++ if (encoder->norm & V4L2_STD_NTSC)
++ set_subcarrier_freq(sd, 0);
+
+- /* not much choice of outputs */
+- if (*iarg != 0)
+- return -EINVAL;
++ adv7175_write(sd, 0x0c, TR1PLAY); /* TR1 */
++ adv7175_write(sd, 0x0d, 0x49);
++ adv7175_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7175_write(sd, 0x07, TR0MODE);
++ /* udelay(10); */
+ break;
+- }
+
+- case ENCODER_ENABLE_OUTPUT:
+- {
+- int *iarg = arg;
++ case 2:
++ adv7175_write(sd, 0x01, 0x80);
++
++ if (encoder->norm & V4L2_STD_NTSC)
++ set_subcarrier_freq(sd, 0);
+
+- encoder->enable = !!*iarg;
++ adv7175_write(sd, 0x0d, 0x49);
++ adv7175_write(sd, 0x07, TR0MODE | TR0RST);
++ adv7175_write(sd, 0x07, TR0MODE);
++ /* udelay(10); */
+ break;
+- }
+
+ default:
++ v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
+ return -EINVAL;
+ }
+-
++ v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
++ encoder->input = route->input;
+ return 0;
+ }
+
++static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0);
++}
++
+ /* ----------------------------------------------------------------------- */
+
+-/*
+- * 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 const struct v4l2_subdev_core_ops adv7175_core_ops = {
++ .g_chip_ident = adv7175_g_chip_ident,
++ .init = adv7175_init,
+ };
+
+-I2C_CLIENT_INSMOD;
++static const struct v4l2_subdev_video_ops adv7175_video_ops = {
++ .s_std_output = adv7175_s_std_output,
++ .s_routing = adv7175_s_routing,
++};
++
++static const struct v4l2_subdev_ops adv7175_ops = {
++ .core = &adv7175_core_ops,
++ .video = &adv7175_video_ops,
++};
++
++/* ----------------------------------------------------------------------- */
+
+ static int adv7175_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ int i;
+ struct adv7175 *encoder;
++ struct v4l2_subdev *sd;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+@@ -369,26 +339,29 @@ static int adv7175_probe(struct i2c_client *client,
+ encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
+ if (encoder == NULL)
+ return -ENOMEM;
+- encoder->norm = VIDEO_MODE_PAL;
++ sd = &encoder->sd;
++ v4l2_i2c_subdev_init(sd, client, &adv7175_ops);
++ encoder->norm = V4L2_STD_NTSC;
+ encoder->input = 0;
+- encoder->enable = 1;
+- i2c_set_clientdata(client, encoder);
+
+- i = adv7175_write_block(client, init_common, sizeof(init_common));
++ i = adv7175_write_block(sd, 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);
+- v4l_dbg(1, debug, client, "revision %d\n", i & 1);
++ i = adv7175_write(sd, 0x07, TR0MODE | TR0RST);
++ i = adv7175_write(sd, 0x07, TR0MODE);
++ i = adv7175_read(sd, 0x12);
++ v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
+ }
+ if (i < 0)
+- v4l_dbg(1, debug, client, "init error 0x%x\n", i);
++ v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
+ return 0;
+ }
+
+ static int adv7175_remove(struct i2c_client *client)
+ {
+- kfree(i2c_get_clientdata(client));
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_adv7175(sd));
+ return 0;
+ }
+
+@@ -403,8 +376,6 @@ MODULE_DEVICE_TABLE(i2c, adv7175_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "adv7175",
+- .driverid = I2C_DRIVERID_ADV7175,
+- .command = adv7175_command,
+ .probe = adv7175_probe,
+ .remove = adv7175_remove,
+ .id_table = adv7175_id,
+diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
+index 018f72b..05cdf49 100644
+--- a/drivers/media/video/au0828/Kconfig
++++ b/drivers/media/video/au0828/Kconfig
+@@ -1,13 +1,13 @@
+
+ config VIDEO_AU0828
+ tristate "Auvitek AU0828 support"
+- depends on I2C && INPUT && DVB_CORE && USB
++ depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
+ select I2C_ALGOBIT
+ select VIDEO_TVEEPROM
+- select DVB_AU8522 if !DVB_FE_CUSTOMIZE
+- select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+- select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE
+- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
++ select DVB_AU8522 if !DVB_FE_CUSTOMISE
++ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+ ---help---
+ This is a video4linux driver for Auvitek's USB device.
+
+diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile
+index cd2c582..4d26231 100644
+--- a/drivers/media/video/au0828/Makefile
++++ b/drivers/media/video/au0828/Makefile
+@@ -1,4 +1,4 @@
+-au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
++au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o
+
+ obj-$(CONFIG_VIDEO_AU0828) += au0828.o
+
+diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
+index d60123b..1aabaa7 100644
+--- a/drivers/media/video/au0828/au0828-cards.c
++++ b/drivers/media/video/au0828/au0828-cards.c
+@@ -21,25 +21,89 @@
+
+ #include "au0828.h"
+ #include "au0828-cards.h"
++#include "au8522.h"
++#include "media/tuner.h"
++#include "media/v4l2-common.h"
++
++void hvr950q_cs5340_audio(void *priv, int enable)
++{
++ /* Because the HVR-950q shares an i2s bus between the cs5340 and the
++ au8522, we need to hold cs5340 in reset when using the au8522 */
++ struct au0828_dev *dev = priv;
++ if (enable == 1)
++ au0828_set(dev, REG_000, 0x10);
++ else
++ au0828_clear(dev, REG_000, 0x10);
++}
+
+ struct au0828_board au0828_boards[] = {
+ [AU0828_BOARD_UNKNOWN] = {
+ .name = "Unknown board",
++ .tuner_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR850] = {
+ .name = "Hauppauge HVR850",
++ .tuner_type = TUNER_XC5000,
++ .tuner_addr = 0x61,
++ .input = {
++ {
++ .type = AU0828_VMUX_TELEVISION,
++ .vmux = AU8522_COMPOSITE_CH4_SIF,
++ .amux = AU8522_AUDIO_SIF,
++ },
++ {
++ .type = AU0828_VMUX_COMPOSITE,
++ .vmux = AU8522_COMPOSITE_CH1,
++ .amux = AU8522_AUDIO_NONE,
++ .audio_setup = hvr950q_cs5340_audio,
++ },
++ {
++ .type = AU0828_VMUX_SVIDEO,
++ .vmux = AU8522_SVIDEO_CH13,
++ .amux = AU8522_AUDIO_NONE,
++ .audio_setup = hvr950q_cs5340_audio,
++ },
++ },
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
+ .name = "Hauppauge HVR950Q",
++ .tuner_type = TUNER_XC5000,
++ .tuner_addr = 0x61,
++ .input = {
++ {
++ .type = AU0828_VMUX_TELEVISION,
++ .vmux = AU8522_COMPOSITE_CH4_SIF,
++ .amux = AU8522_AUDIO_SIF,
++ },
++ {
++ .type = AU0828_VMUX_COMPOSITE,
++ .vmux = AU8522_COMPOSITE_CH1,
++ .amux = AU8522_AUDIO_NONE,
++ .audio_setup = hvr950q_cs5340_audio,
++ },
++ {
++ .type = AU0828_VMUX_SVIDEO,
++ .vmux = AU8522_SVIDEO_CH13,
++ .amux = AU8522_AUDIO_NONE,
++ .audio_setup = hvr950q_cs5340_audio,
++ },
++ },
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
+ .name = "Hauppauge HVR950Q rev xxF8",
++ .tuner_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
+ },
+ [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
+ .name = "DViCO FusionHDTV USB",
++ .tuner_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
+ },
+ [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
+ .name = "Hauppauge Woodbury",
++ .tuner_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
+ },
+ };
+
+@@ -52,7 +116,7 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
+
+ dprintk(1, "%s()\n", __func__);
+
+- switch (dev->board) {
++ switch (dev->boardnr) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+@@ -81,17 +145,18 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
+ struct tveeprom tv;
+
+ tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
++ dev->board.tuner_type = tv.tuner_type;
+
+ /* Make sure we support the board model */
+ switch (tv.model) {
+ case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
+- case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
+- case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+- case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+- case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+- case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */
+- case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
+- case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
++ case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
++ case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
++ case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
++ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
++ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
++ case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
++ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
+ case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
+ break;
+ default:
+@@ -107,15 +172,21 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
+ void au0828_card_setup(struct au0828_dev *dev)
+ {
+ static u8 eeprom[256];
++ struct tuner_setup tun_setup;
++ struct v4l2_subdev *sd;
++ unsigned int mode_mask = T_ANALOG_TV |
++ T_DIGITAL_TV;
+
+ dprintk(1, "%s()\n", __func__);
+
++ memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
++
+ if (dev->i2c_rc == 0) {
+ dev->i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
+ }
+
+- switch (dev->board) {
++ switch (dev->boardnr) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+@@ -124,6 +195,32 @@ void au0828_card_setup(struct au0828_dev *dev)
+ hauppauge_eeprom(dev, eeprom+0xa0);
+ break;
+ }
++
++ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
++ /* Load the analog demodulator driver (note this would need to
++ be abstracted out if we ever need to support a different
++ demod) */
++ sd = v4l2_i2c_new_subdev(&dev->i2c_adap, "au8522", "au8522",
++ 0x8e >> 1);
++ if (sd == NULL)
++ printk(KERN_ERR "analog subdev registration failed\n");
++ }
++
++ /* Setup tuners */
++ if (dev->board.tuner_type != TUNER_ABSENT) {
++ /* Load the tuner module, which does the attach */
++ sd = v4l2_i2c_new_subdev(&dev->i2c_adap, "tuner", "tuner",
++ dev->board.tuner_addr);
++ if (sd == NULL)
++ printk(KERN_ERR "tuner subdev registration fail\n");
++
++ tun_setup.mode_mask = mode_mask;
++ tun_setup.type = dev->board.tuner_type;
++ tun_setup.addr = dev->board.tuner_addr;
++ tun_setup.tuner_callback = au0828_tuner_callback;
++ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
++ &tun_setup);
++ }
+ }
+
+ /*
+@@ -135,7 +232,7 @@ void au0828_gpio_setup(struct au0828_dev *dev)
+ {
+ dprintk(1, "%s()\n", __func__);
+
+- switch (dev->board) {
++ switch (dev->boardnr) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+@@ -144,21 +241,23 @@ void au0828_gpio_setup(struct au0828_dev *dev)
+ * 4 - CS5340
+ * 5 - AU8522 Demodulator
+ * 6 - eeprom W/P
++ * 7 - power supply
+ * 9 - XC5000 Tuner
+ */
+
+ /* Into reset */
+ au0828_write(dev, REG_003, 0x02);
+- au0828_write(dev, REG_002, 0x88 | 0x20);
++ au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+ au0828_write(dev, REG_001, 0x0);
+ au0828_write(dev, REG_000, 0x0);
+ msleep(100);
+
+- /* Out of reset */
++ /* Out of reset (leave the cs5340 in reset until needed) */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_001, 0x02);
+- au0828_write(dev, REG_002, 0x88 | 0x20);
+- au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40);
++ au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
++ au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
++
+ msleep(250);
+ break;
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
+index 5765e86..8c761d1 100644
+--- a/drivers/media/video/au0828/au0828-core.c
++++ b/drivers/media/video/au0828/au0828-core.c
+@@ -36,6 +36,8 @@ int au0828_debug;
+ module_param_named(debug, au0828_debug, int, 0644);
+ MODULE_PARM_DESC(debug, "enable debug messages");
+
++static atomic_t au0828_instance = ATOMIC_INIT(0);
++
+ #define _AU0828_BULKPIPE 0x03
+ #define _BULKPIPESIZE 0xffff
+
+@@ -51,13 +53,13 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
+ {
+ recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
+- dprintk(8, "%s(0x%x) = 0x%x\n", __func__, reg, dev->ctrlmsg[0]);
++ dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, dev->ctrlmsg[0]);
+ return dev->ctrlmsg[0];
+ }
+
+ u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
+ {
+- dprintk(8, "%s(0x%x, 0x%x)\n", __func__, reg, val);
++ dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
+ return send_control_msg(dev, CMD_REQUEST_OUT, val, reg,
+ dev->ctrlmsg, 0);
+ }
+@@ -146,9 +148,14 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
+ /* Digital TV */
+ au0828_dvb_unregister(dev);
+
++ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
++ au0828_analog_unregister(dev);
++
+ /* I2C */
+ au0828_i2c_unregister(dev);
+
++ v4l2_device_unregister(&dev->v4l2_dev);
++
+ usb_set_intfdata(interface, NULL);
+
+ mutex_lock(&dev->mutex);
+@@ -162,7 +169,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
+ static int au0828_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+ {
+- int ifnum;
++ int ifnum, retval, i;
+ struct au0828_dev *dev;
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+
+@@ -185,10 +192,22 @@ static int au0828_usb_probe(struct usb_interface *interface,
+ mutex_init(&dev->mutex);
+ mutex_init(&dev->dvb.lock);
+ dev->usbdev = usbdev;
+- dev->board = id->driver_info;
++ dev->boardnr = id->driver_info;
+
+ usb_set_intfdata(interface, dev);
+
++ /* Create the v4l2_device */
++ i = atomic_inc_return(&au0828_instance) - 1;
++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s-%03d",
++ "au0828", i);
++ retval = v4l2_device_register(&dev->usbdev->dev, &dev->v4l2_dev);
++ if (retval) {
++ printk(KERN_ERR "%s() v4l2_device_register failed\n",
++ __func__);
++ kfree(dev);
++ return -EIO;
++ }
++
+ /* Power Up the bridge */
+ au0828_write(dev, REG_600, 1 << 4);
+
+@@ -201,12 +220,15 @@ static int au0828_usb_probe(struct usb_interface *interface,
+ /* Setup */
+ au0828_card_setup(dev);
+
++ /* Analog TV */
++ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
++ au0828_analog_register(dev, interface);
++
+ /* Digital TV */
+ au0828_dvb_register(dev);
+
+ printk(KERN_INFO "Registered device AU0828 [%s]\n",
+- au0828_boards[dev->board].name == NULL ? "Unset" :
+- au0828_boards[dev->board].name);
++ dev->board.name == NULL ? "Unset" : dev->board.name);
+
+ return 0;
+ }
+diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
+index a882cf5..14baffc 100644
+--- a/drivers/media/video/au0828/au0828-dvb.c
++++ b/drivers/media/video/au0828/au0828-dvb.c
+@@ -378,7 +378,7 @@ int au0828_dvb_register(struct au0828_dev *dev)
+ dprintk(1, "%s()\n", __func__);
+
+ /* init frontend */
+- switch (dev->board) {
++ switch (dev->boardnr) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ dvb->frontend = dvb_attach(au8522_attach,
+diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
+index d618fba..f9a958d 100644
+--- a/drivers/media/video/au0828/au0828-i2c.c
++++ b/drivers/media/video/au0828/au0828-i2c.c
+@@ -140,13 +140,39 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+ dprintk(4, "%s()\n", __func__);
+
+ au0828_write(dev, REG_2FF, 0x01);
+- au0828_write(dev, REG_202, 0x07);
++
++ /* FIXME: There is a problem with i2c communications with xc5000 that
++ requires us to slow down the i2c clock until we have a better
++ strategy (such as using the secondary i2c bus to do firmware
++ loading */
++ if ((msg->addr << 1) == 0xc2)
++ au0828_write(dev, REG_202, 0x40);
++ else
++ au0828_write(dev, REG_202, 0x07);
+
+ /* Hardware needs 8 bit addresses */
+ au0828_write(dev, REG_203, msg->addr << 1);
+
+ dprintk(4, "SEND: %02x\n", msg->addr);
+
++ /* Deal with i2c_scan */
++ if (msg->len == 0) {
++ /* The analog tuner detection code makes use of the SMBUS_QUICK
++ message (which involves a zero length i2c write). To avoid
++ checking the status register when we didn't strobe out any
++ actual bytes to the bus, just do a read check. This is
++ consistent with how I saw i2c device checking done in the
++ USB trace of the Windows driver */
++ au0828_write(dev, REG_200, 0x20);
++ if (!i2c_wait_done(i2c_adap))
++ return -EIO;
++
++ if (i2c_wait_read_ack(i2c_adap))
++ return -EIO;
++
++ return 0;
++ }
++
+ for (i = 0; i < msg->len;) {
+
+ dprintk(4, " %02x\n", msg->buf[i]);
+@@ -191,7 +217,15 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+ dprintk(4, "%s()\n", __func__);
+
+ au0828_write(dev, REG_2FF, 0x01);
+- au0828_write(dev, REG_202, 0x07);
++
++ /* FIXME: There is a problem with i2c communications with xc5000 that
++ requires us to slow down the i2c clock until we have a better
++ strategy (such as using the secondary i2c bus to do firmware
++ loading */
++ if ((msg->addr << 1) == 0xc2)
++ au0828_write(dev, REG_202, 0x40);
++ else
++ au0828_write(dev, REG_202, 0x07);
+
+ /* Hardware needs 8 bit addresses */
+ au0828_write(dev, REG_203, msg->addr << 1);
+@@ -265,33 +299,6 @@ err:
+ return retval;
+ }
+
+-static int attach_inform(struct i2c_client *client)
+-{
+- dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+- client->driver->driver.name, client->addr, client->name);
+-
+- if (!client->driver->command)
+- return 0;
+-
+- return 0;
+-}
+-
+-static int detach_inform(struct i2c_client *client)
+-{
+- dprintk(1, "i2c detach [client=%s]\n", client->name);
+-
+- return 0;
+-}
+-
+-void au0828_call_i2c_clients(struct au0828_dev *dev,
+- unsigned int cmd, void *arg)
+-{
+- if (dev->i2c_rc != 0)
+- return;
+-
+- i2c_clients_command(&dev->i2c_adap, cmd, arg);
+-}
+-
+ static u32 au0828_functionality(struct i2c_adapter *adap)
+ {
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+@@ -309,9 +316,6 @@ static struct i2c_adapter au0828_i2c_adap_template = {
+ .owner = THIS_MODULE,
+ .id = I2C_HW_B_AU0828,
+ .algo = &au0828_i2c_algo_template,
+- .class = I2C_CLASS_TV_ANALOG,
+- .client_register = attach_inform,
+- .client_unregister = detach_inform,
+ };
+
+ static struct i2c_client au0828_i2c_client_template = {
+@@ -356,9 +360,9 @@ int au0828_i2c_register(struct au0828_dev *dev)
+ strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+ sizeof(dev->i2c_adap.name));
+
+- dev->i2c_algo.data = dev;
++ dev->i2c_adap.algo = &dev->i2c_algo;
+ dev->i2c_adap.algo_data = dev;
+- i2c_set_adapdata(&dev->i2c_adap, dev);
++ i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+ i2c_add_adapter(&dev->i2c_adap);
+
+ dev->i2c_client.adapter = &dev->i2c_adap;
+diff --git a/drivers/media/video/au0828/au0828-reg.h b/drivers/media/video/au0828/au0828-reg.h
+index 1e87fa0..b15e4a3 100644
+--- a/drivers/media/video/au0828/au0828-reg.h
++++ b/drivers/media/video/au0828/au0828-reg.h
+@@ -27,6 +27,9 @@
+ #define REG_002 0x002
+ #define REG_003 0x003
+
++#define AU0828_SENSORCTRL_100 0x100
++#define AU0828_SENSORCTRL_VBI_103 0x103
++
+ #define REG_200 0x200
+ #define REG_201 0x201
+ #define REG_202 0x202
+@@ -35,4 +38,7 @@
+ #define REG_209 0x209
+ #define REG_2FF 0x2ff
+
++/* Audio registers */
++#define AU0828_AUDIOCTRL_50C 0x50C
++
+ #define REG_600 0x600
+diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
+new file mode 100644
+index 0000000..f7ad495
+--- /dev/null
++++ b/drivers/media/video/au0828/au0828-video.c
+@@ -0,0 +1,1712 @@
++/*
++ * Auvitek AU0828 USB Bridge (Analog video support)
++ *
++ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
++ * Copyright (C) 2005-2008 Auvitek International, Ltd.
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA.
++ */
++
++/* Developer Notes:
++ *
++ * VBI support is not yet working
++ * The hardware scaler supported is unimplemented
++ * AC97 audio support is unimplemented (only i2s audio mode)
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/suspend.h>
++#include <linux/version.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/tuner.h>
++#include "au0828.h"
++#include "au0828-reg.h"
++
++static LIST_HEAD(au0828_devlist);
++static DEFINE_MUTEX(au0828_sysfs_lock);
++
++#define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1)
++
++/* ------------------------------------------------------------------
++ Videobuf operations
++ ------------------------------------------------------------------*/
++
++static unsigned int isoc_debug;
++module_param(isoc_debug, int, 0644);
++MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
++
++#define au0828_isocdbg(fmt, arg...) \
++do {\
++ if (isoc_debug) { \
++ printk(KERN_INFO "au0828 %s :"fmt, \
++ __func__ , ##arg); \
++ } \
++ } while (0)
++
++static inline void print_err_status(struct au0828_dev *dev,
++ int packet, int status)
++{
++ char *errmsg = "Unknown";
++
++ switch (status) {
++ case -ENOENT:
++ errmsg = "unlinked synchronuously";
++ break;
++ case -ECONNRESET:
++ errmsg = "unlinked asynchronuously";
++ break;
++ case -ENOSR:
++ errmsg = "Buffer error (overrun)";
++ break;
++ case -EPIPE:
++ errmsg = "Stalled (device not responding)";
++ break;
++ case -EOVERFLOW:
++ errmsg = "Babble (bad cable?)";
++ break;
++ case -EPROTO:
++ errmsg = "Bit-stuff error (bad cable?)";
++ break;
++ case -EILSEQ:
++ errmsg = "CRC/Timeout (could be anything)";
++ break;
++ case -ETIME:
++ errmsg = "Device does not respond";
++ break;
++ }
++ if (packet < 0) {
++ au0828_isocdbg("URB status %d [%s].\n", status, errmsg);
++ } else {
++ au0828_isocdbg("URB packet %d, status %d [%s].\n",
++ packet, status, errmsg);
++ }
++}
++
++static int check_dev(struct au0828_dev *dev)
++{
++ if (dev->dev_state & DEV_DISCONNECTED) {
++ printk(KERN_INFO "v4l2 ioctl: device not present\n");
++ return -ENODEV;
++ }
++
++ if (dev->dev_state & DEV_MISCONFIGURED) {
++ printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
++ "close and open it again\n");
++ return -EIO;
++ }
++ return 0;
++}
++
++/*
++ * IRQ callback, called by URB callback
++ */
++static void au0828_irq_callback(struct urb *urb)
++{
++ struct au0828_dmaqueue *dma_q = urb->context;
++ struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
++ int rc, i;
++
++ switch (urb->status) {
++ case 0: /* success */
++ case -ETIMEDOUT: /* NAK */
++ break;
++ case -ECONNRESET: /* kill */
++ case -ENOENT:
++ case -ESHUTDOWN:
++ au0828_isocdbg("au0828_irq_callback called: status kill\n");
++ return;
++ default: /* unknown error */
++ au0828_isocdbg("urb completition error %d.\n", urb->status);
++ break;
++ }
++
++ /* Copy data from URB */
++ spin_lock(&dev->slock);
++ rc = dev->isoc_ctl.isoc_copy(dev, urb);
++ spin_unlock(&dev->slock);
++
++ /* Reset urb buffers */
++ for (i = 0; i < urb->number_of_packets; i++) {
++ urb->iso_frame_desc[i].status = 0;
++ urb->iso_frame_desc[i].actual_length = 0;
++ }
++ urb->status = 0;
++
++ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
++ if (urb->status) {
++ au0828_isocdbg("urb resubmit failed (error=%i)\n",
++ urb->status);
++ }
++}
++
++/*
++ * Stop and Deallocate URBs
++ */
++void au0828_uninit_isoc(struct au0828_dev *dev)
++{
++ struct urb *urb;
++ int i;
++
++ au0828_isocdbg("au0828: called au0828_uninit_isoc\n");
++
++ dev->isoc_ctl.nfields = -1;
++ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
++ urb = dev->isoc_ctl.urb[i];
++ if (urb) {
++ if (!irqs_disabled())
++ usb_kill_urb(urb);
++ else
++ usb_unlink_urb(urb);
++
++ if (dev->isoc_ctl.transfer_buffer[i]) {
++ usb_buffer_free(dev->usbdev,
++ urb->transfer_buffer_length,
++ dev->isoc_ctl.transfer_buffer[i],
++ urb->transfer_dma);
++ }
++ usb_free_urb(urb);
++ dev->isoc_ctl.urb[i] = NULL;
++ }
++ dev->isoc_ctl.transfer_buffer[i] = NULL;
++ }
++
++ kfree(dev->isoc_ctl.urb);
++ kfree(dev->isoc_ctl.transfer_buffer);
++
++ dev->isoc_ctl.urb = NULL;
++ dev->isoc_ctl.transfer_buffer = NULL;
++ dev->isoc_ctl.num_bufs = 0;
++}
++
++/*
++ * Allocate URBs and start IRQ
++ */
++int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
++ int num_bufs, int max_pkt_size,
++ int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb))
++{
++ struct au0828_dmaqueue *dma_q = &dev->vidq;
++ int i;
++ int sb_size, pipe;
++ struct urb *urb;
++ int j, k;
++ int rc;
++
++ au0828_isocdbg("au0828: called au0828_prepare_isoc\n");
++
++ /* De-allocates all pending stuff */
++ au0828_uninit_isoc(dev);
++
++ dev->isoc_ctl.isoc_copy = isoc_copy;
++ dev->isoc_ctl.num_bufs = num_bufs;
++
++ dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
++ if (!dev->isoc_ctl.urb) {
++ au0828_isocdbg("cannot alloc memory for usb buffers\n");
++ return -ENOMEM;
++ }
++
++ dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
++ GFP_KERNEL);
++ if (!dev->isoc_ctl.transfer_buffer) {
++ au0828_isocdbg("cannot allocate memory for usb transfer\n");
++ kfree(dev->isoc_ctl.urb);
++ return -ENOMEM;
++ }
++
++ dev->isoc_ctl.max_pkt_size = max_pkt_size;
++ dev->isoc_ctl.buf = NULL;
++
++ sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
++
++ /* allocate urbs and transfer buffers */
++ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
++ urb = usb_alloc_urb(max_packets, GFP_KERNEL);
++ if (!urb) {
++ au0828_isocdbg("cannot alloc isoc_ctl.urb %i\n", i);
++ au0828_uninit_isoc(dev);
++ return -ENOMEM;
++ }
++ dev->isoc_ctl.urb[i] = urb;
++
++ dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->usbdev,
++ sb_size, GFP_KERNEL, &urb->transfer_dma);
++ if (!dev->isoc_ctl.transfer_buffer[i]) {
++ printk("unable to allocate %i bytes for transfer"
++ " buffer %i%s\n",
++ sb_size, i,
++ in_interrupt() ? " while in int" : "");
++ au0828_uninit_isoc(dev);
++ return -ENOMEM;
++ }
++ memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
++
++ pipe = usb_rcvisocpipe(dev->usbdev,
++ dev->isoc_in_endpointaddr),
++
++ usb_fill_int_urb(urb, dev->usbdev, pipe,
++ dev->isoc_ctl.transfer_buffer[i], sb_size,
++ au0828_irq_callback, dma_q, 1);
++
++ urb->number_of_packets = max_packets;
++ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
++
++ k = 0;
++ for (j = 0; j < max_packets; j++) {
++ urb->iso_frame_desc[j].offset = k;
++ urb->iso_frame_desc[j].length =
++ dev->isoc_ctl.max_pkt_size;
++ k += dev->isoc_ctl.max_pkt_size;
++ }
++ }
++
++ init_waitqueue_head(&dma_q->wq);
++
++ /* submit urbs and enables IRQ */
++ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
++ rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
++ if (rc) {
++ au0828_isocdbg("submit of urb %i failed (error=%i)\n",
++ i, rc);
++ au0828_uninit_isoc(dev);
++ return rc;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * Announces that a buffer were filled and request the next
++ */
++static inline void buffer_filled(struct au0828_dev *dev,
++ struct au0828_dmaqueue *dma_q,
++ struct au0828_buffer *buf)
++{
++ /* Advice that buffer was filled */
++ au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
++
++ buf->vb.state = VIDEOBUF_DONE;
++ buf->vb.field_count++;
++ do_gettimeofday(&buf->vb.ts);
++
++ dev->isoc_ctl.buf = NULL;
++
++ list_del(&buf->vb.queue);
++ wake_up(&buf->vb.done);
++}
++
++/*
++ * Identify the buffer header type and properly handles
++ */
++static void au0828_copy_video(struct au0828_dev *dev,
++ struct au0828_dmaqueue *dma_q,
++ struct au0828_buffer *buf,
++ unsigned char *p,
++ unsigned char *outp, unsigned long len)
++{
++ void *fieldstart, *startwrite, *startread;
++ int linesdone, currlinedone, offset, lencopy, remain;
++ int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
++
++ if (dma_q->pos + len > buf->vb.size)
++ len = buf->vb.size - dma_q->pos;
++
++ startread = p;
++ remain = len;
++
++ /* Interlaces frame */
++ if (buf->top_field)
++ fieldstart = outp;
++ else
++ fieldstart = outp + bytesperline;
++
++ linesdone = dma_q->pos / bytesperline;
++ currlinedone = dma_q->pos % bytesperline;
++ offset = linesdone * bytesperline * 2 + currlinedone;
++ startwrite = fieldstart + offset;
++ lencopy = bytesperline - currlinedone;
++ lencopy = lencopy > remain ? remain : lencopy;
++
++ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
++ au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
++ ((char *)startwrite + lencopy) -
++ ((char *)outp + buf->vb.size));
++ remain = (char *)outp + buf->vb.size - (char *)startwrite;
++ lencopy = remain;
++ }
++ if (lencopy <= 0)
++ return;
++ memcpy(startwrite, startread, lencopy);
++
++ remain -= lencopy;
++
++ while (remain > 0) {
++ startwrite += lencopy + bytesperline;
++ startread += lencopy;
++ if (bytesperline > remain)
++ lencopy = remain;
++ else
++ lencopy = bytesperline;
++
++ if ((char *)startwrite + lencopy > (char *)outp +
++ buf->vb.size) {
++ au0828_isocdbg("Overflow %zi bytes past buf end (2)\n",
++ ((char *)startwrite + lencopy) -
++ ((char *)outp + buf->vb.size));
++ lencopy = remain = (char *)outp + buf->vb.size -
++ (char *)startwrite;
++ }
++ if (lencopy <= 0)
++ break;
++
++ memcpy(startwrite, startread, lencopy);
++
++ remain -= lencopy;
++ }
++
++ if (offset > 1440) {
++ /* We have enough data to check for greenscreen */
++ if (outp[0] < 0x60 && outp[1440] < 0x60)
++ dev->greenscreen_detected = 1;
++ }
++
++ dma_q->pos += len;
++}
++
++/*
++ * video-buf generic routine to get the next available buffer
++ */
++static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
++ struct au0828_buffer **buf)
++{
++ struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
++
++ if (list_empty(&dma_q->active)) {
++ au0828_isocdbg("No active queue to serve\n");
++ dev->isoc_ctl.buf = NULL;
++ *buf = NULL;
++ return;
++ }
++
++ /* Get the next buffer */
++ *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
++ dev->isoc_ctl.buf = *buf;
++
++ return;
++}
++
++/*
++ * Controls the isoc copy of each urb packet
++ */
++static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
++{
++ struct au0828_buffer *buf;
++ struct au0828_dmaqueue *dma_q = urb->context;
++ unsigned char *outp = NULL;
++ int i, len = 0, rc = 1;
++ unsigned char *p;
++ unsigned char fbyte;
++
++ if (!dev)
++ return 0;
++
++ if ((dev->dev_state & DEV_DISCONNECTED) ||
++ (dev->dev_state & DEV_MISCONFIGURED))
++ return 0;
++
++ if (urb->status < 0) {
++ print_err_status(dev, -1, urb->status);
++ if (urb->status == -ENOENT)
++ return 0;
++ }
++
++ buf = dev->isoc_ctl.buf;
++ if (buf != NULL)
++ outp = videobuf_to_vmalloc(&buf->vb);
++
++ for (i = 0; i < urb->number_of_packets; i++) {
++ int status = urb->iso_frame_desc[i].status;
++
++ if (status < 0) {
++ print_err_status(dev, i, status);
++ if (urb->iso_frame_desc[i].status != -EPROTO)
++ continue;
++ }
++
++ if (urb->iso_frame_desc[i].actual_length <= 0)
++ continue;
++
++ if (urb->iso_frame_desc[i].actual_length >
++ dev->max_pkt_size) {
++ au0828_isocdbg("packet bigger than packet size");
++ continue;
++ }
++
++ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
++ fbyte = p[0];
++ len = urb->iso_frame_desc[i].actual_length - 4;
++ p += 4;
++
++ if (fbyte & 0x80) {
++ len -= 4;
++ p += 4;
++ au0828_isocdbg("Video frame %s\n",
++ (fbyte & 0x40) ? "odd" : "even");
++ if (!(fbyte & 0x40)) {
++ if (buf != NULL)
++ buffer_filled(dev, dma_q, buf);
++ get_next_buf(dma_q, &buf);
++ if (buf == NULL)
++ outp = NULL;
++ else
++ outp = videobuf_to_vmalloc(&buf->vb);
++ }
++
++ if (buf != NULL) {
++ if (fbyte & 0x40)
++ buf->top_field = 1;
++ else
++ buf->top_field = 0;
++ }
++
++ dma_q->pos = 0;
++ }
++ if (buf != NULL)
++ au0828_copy_video(dev, dma_q, buf, p, outp, len);
++ }
++ return rc;
++}
++
++static int
++buffer_setup(struct videobuf_queue *vq, unsigned int *count,
++ unsigned int *size)
++{
++ struct au0828_fh *fh = vq->priv_data;
++ *size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
++
++ if (0 == *count)
++ *count = AU0828_DEF_BUF;
++
++ if (*count < AU0828_MIN_BUF)
++ *count = AU0828_MIN_BUF;
++ return 0;
++}
++
++/* This is called *without* dev->slock held; please keep it that way */
++static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
++{
++ struct au0828_fh *fh = vq->priv_data;
++ struct au0828_dev *dev = fh->dev;
++ unsigned long flags = 0;
++ if (in_interrupt())
++ BUG();
++
++ /* We used to wait for the buffer to finish here, but this didn't work
++ because, as we were keeping the state as VIDEOBUF_QUEUED,
++ videobuf_queue_cancel marked it as finished for us.
++ (Also, it could wedge forever if the hardware was misconfigured.)
++
++ This should be safe; by the time we get here, the buffer isn't
++ queued anymore. If we ever start marking the buffers as
++ VIDEOBUF_ACTIVE, it won't be, though.
++ */
++ spin_lock_irqsave(&dev->slock, flags);
++ if (dev->isoc_ctl.buf == buf)
++ dev->isoc_ctl.buf = NULL;
++ spin_unlock_irqrestore(&dev->slock, flags);
++
++ videobuf_vmalloc_free(&buf->vb);
++ buf->vb.state = VIDEOBUF_NEEDS_INIT;
++}
++
++static int
++buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
++ enum v4l2_field field)
++{
++ struct au0828_fh *fh = vq->priv_data;
++ struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
++ struct au0828_dev *dev = fh->dev;
++ int rc = 0, urb_init = 0;
++
++ buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
++
++ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
++ return -EINVAL;
++
++ buf->vb.width = dev->width;
++ buf->vb.height = dev->height;
++ buf->vb.field = field;
++
++ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
++ rc = videobuf_iolock(vq, &buf->vb, NULL);
++ if (rc < 0) {
++ printk(KERN_INFO "videobuf_iolock failed\n");
++ goto fail;
++ }
++ }
++
++ if (!dev->isoc_ctl.num_bufs)
++ urb_init = 1;
++
++ if (urb_init) {
++ rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB,
++ AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
++ au0828_isoc_copy);
++ if (rc < 0) {
++ printk(KERN_INFO "au0828_init_isoc failed\n");
++ goto fail;
++ }
++ }
++
++ buf->vb.state = VIDEOBUF_PREPARED;
++ return 0;
++
++fail:
++ free_buffer(vq, buf);
++ return rc;
++}
++
++static void
++buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
++{
++ struct au0828_buffer *buf = container_of(vb,
++ struct au0828_buffer,
++ vb);
++ struct au0828_fh *fh = vq->priv_data;
++ struct au0828_dev *dev = fh->dev;
++ struct au0828_dmaqueue *vidq = &dev->vidq;
++
++ buf->vb.state = VIDEOBUF_QUEUED;
++ list_add_tail(&buf->vb.queue, &vidq->active);
++}
++
++static void buffer_release(struct videobuf_queue *vq,
++ struct videobuf_buffer *vb)
++{
++ struct au0828_buffer *buf = container_of(vb,
++ struct au0828_buffer,
++ vb);
++
++ free_buffer(vq, buf);
++}
++
++static struct videobuf_queue_ops au0828_video_qops = {
++ .buf_setup = buffer_setup,
++ .buf_prepare = buffer_prepare,
++ .buf_queue = buffer_queue,
++ .buf_release = buffer_release,
++};
++
++/* ------------------------------------------------------------------
++ V4L2 interface
++ ------------------------------------------------------------------*/
++
++static int au0828_i2s_init(struct au0828_dev *dev)
++{
++ /* Enable i2s mode */
++ au0828_writereg(dev, AU0828_AUDIOCTRL_50C, 0x01);
++ return 0;
++}
++
++/*
++ * Auvitek au0828 analog stream enable
++ * Please set interface0 to AS5 before enable the stream
++ */
++int au0828_analog_stream_enable(struct au0828_dev *d)
++{
++ dprintk(1, "au0828_analog_stream_enable called\n");
++ au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00);
++ au0828_writereg(d, 0x106, 0x00);
++ /* set x position */
++ au0828_writereg(d, 0x110, 0x00);
++ au0828_writereg(d, 0x111, 0x00);
++ au0828_writereg(d, 0x114, 0xa0);
++ au0828_writereg(d, 0x115, 0x05);
++ /* set y position */
++ au0828_writereg(d, 0x112, 0x02);
++ au0828_writereg(d, 0x113, 0x00);
++ au0828_writereg(d, 0x116, 0xf2);
++ au0828_writereg(d, 0x117, 0x00);
++ au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3);
++
++ return 0;
++}
++
++int au0828_analog_stream_disable(struct au0828_dev *d)
++{
++ dprintk(1, "au0828_analog_stream_disable called\n");
++ au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0);
++ return 0;
++}
++
++void au0828_analog_stream_reset(struct au0828_dev *dev)
++{
++ dprintk(1, "au0828_analog_stream_reset called\n");
++ au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0);
++ mdelay(30);
++ au0828_writereg(dev, AU0828_SENSORCTRL_100, 0xb3);
++}
++
++/*
++ * Some operations needs to stop current streaming
++ */
++static int au0828_stream_interrupt(struct au0828_dev *dev)
++{
++ int ret = 0;
++
++ dev->stream_state = STREAM_INTERRUPT;
++ if (dev->dev_state == DEV_DISCONNECTED)
++ return -ENODEV;
++ else if (ret) {
++ dev->dev_state = DEV_MISCONFIGURED;
++ dprintk(1, "%s device is misconfigured!\n", __func__);
++ return ret;
++ }
++ return 0;
++}
++
++/*
++ * au0828_release_resources
++ * unregister v4l2 devices
++ */
++void au0828_analog_unregister(struct au0828_dev *dev)
++{
++ dprintk(1, "au0828_release_resources called\n");
++ mutex_lock(&au0828_sysfs_lock);
++
++ if (dev->vdev) {
++ list_del(&dev->au0828list);
++ video_unregister_device(dev->vdev);
++ }
++ if (dev->vbi_dev)
++ video_unregister_device(dev->vbi_dev);
++
++ mutex_unlock(&au0828_sysfs_lock);
++}
++
++
++/* Usage lock check functions */
++static int res_get(struct au0828_fh *fh)
++{
++ struct au0828_dev *dev = fh->dev;
++ int rc = 0;
++
++ /* This instance already has stream_on */
++ if (fh->stream_on)
++ return rc;
++
++ if (dev->stream_on)
++ return -EBUSY;
++
++ dev->stream_on = 1;
++ fh->stream_on = 1;
++ return rc;
++}
++
++static int res_check(struct au0828_fh *fh)
++{
++ return fh->stream_on;
++}
++
++static void res_free(struct au0828_fh *fh)
++{
++ struct au0828_dev *dev = fh->dev;
++
++ fh->stream_on = 0;
++ dev->stream_on = 0;
++}
++
++static int au0828_v4l2_open(struct file *filp)
++{
++ int minor = video_devdata(filp)->minor;
++ int ret = 0;
++ struct au0828_dev *h, *dev = NULL;
++ struct au0828_fh *fh;
++ int type = 0;
++ struct list_head *list;
++
++ list_for_each(list, &au0828_devlist) {
++ h = list_entry(list, struct au0828_dev, au0828list);
++ if (h->vdev->minor == minor) {
++ dev = h;
++ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ }
++#ifdef VBI_IS_WORKING
++ if (h->vbi_dev->minor == minor) {
++ dev = h;
++ type = V4L2_BUF_TYPE_VBI_CAPTURE;
++ }
++#endif
++ }
++
++ if (NULL == dev)
++ return -ENODEV;
++
++ fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
++ if (NULL == fh) {
++ dprintk(1, "Failed allocate au0828_fh struct!\n");
++ return -ENOMEM;
++ }
++
++ fh->type = type;
++ fh->dev = dev;
++ filp->private_data = fh;
++
++ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
++ /* set au0828 interface0 to AS5 here again */
++ ret = usb_set_interface(dev->usbdev, 0, 5);
++ if (ret < 0) {
++ printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
++ return -EBUSY;
++ }
++ dev->width = NTSC_STD_W;
++ dev->height = NTSC_STD_H;
++ dev->frame_size = dev->width * dev->height * 2;
++ dev->field_size = dev->width * dev->height;
++ dev->bytesperline = dev->width * 2;
++
++ au0828_analog_stream_enable(dev);
++ au0828_analog_stream_reset(dev);
++
++ /* If we were doing ac97 instead of i2s, it would go here...*/
++ au0828_i2s_init(dev);
++
++ dev->stream_state = STREAM_OFF;
++ dev->dev_state |= DEV_INITIALIZED;
++ }
++
++ dev->users++;
++
++ videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
++ NULL, &dev->slock, fh->type,
++ V4L2_FIELD_INTERLACED,
++ sizeof(struct au0828_buffer), fh);
++
++ return ret;
++}
++
++static int au0828_v4l2_close(struct file *filp)
++{
++ int ret;
++ struct au0828_fh *fh = filp->private_data;
++ struct au0828_dev *dev = fh->dev;
++
++ mutex_lock(&dev->lock);
++ if (res_check(fh))
++ res_free(fh);
++
++ if (dev->users == 1) {
++ videobuf_stop(&fh->vb_vidq);
++ videobuf_mmap_free(&fh->vb_vidq);
++
++ if (dev->dev_state & DEV_DISCONNECTED) {
++ au0828_analog_unregister(dev);
++ mutex_unlock(&dev->lock);
++ kfree(dev);
++ return 0;
++ }
++
++ au0828_analog_stream_disable(dev);
++
++ au0828_uninit_isoc(dev);
++
++ /* When close the device, set the usb intf0 into alt0 to free
++ USB bandwidth */
++ ret = usb_set_interface(dev->usbdev, 0, 0);
++ if (ret < 0)
++ printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
++ }
++
++ kfree(fh);
++ dev->users--;
++ wake_up_interruptible_nr(&dev->open, 1);
++ mutex_unlock(&dev->lock);
++ return 0;
++}
++
++static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
++ size_t count, loff_t *pos)
++{
++ struct au0828_fh *fh = filp->private_data;
++ struct au0828_dev *dev = fh->dev;
++ int rc;
++
++ rc = check_dev(dev);
++ if (rc < 0)
++ return rc;
++
++ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++ mutex_lock(&dev->lock);
++ rc = res_get(fh);
++ mutex_unlock(&dev->lock);
++
++ if (unlikely(rc < 0))
++ return rc;
++
++ return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
++ filp->f_flags & O_NONBLOCK);
++ }
++ return 0;
++}
++
++static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
++{
++ struct au0828_fh *fh = filp->private_data;
++ struct au0828_dev *dev = fh->dev;
++ int rc;
++
++ rc = check_dev(dev);
++ if (rc < 0)
++ return rc;
++
++ mutex_lock(&dev->lock);
++ rc = res_get(fh);
++ mutex_unlock(&dev->lock);
++
++ if (unlikely(rc < 0))
++ return POLLERR;
++
++ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
++ return POLLERR;
++
++ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
++}
++
++static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ struct au0828_fh *fh = filp->private_data;
++ struct au0828_dev *dev = fh->dev;
++ int rc;
++
++ rc = check_dev(dev);
++ if (rc < 0)
++ return rc;
++
++ mutex_lock(&dev->lock);
++ rc = res_get(fh);
++ mutex_unlock(&dev->lock);
++
++ if (unlikely(rc < 0))
++ return rc;
++
++ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
++
++ dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n",
++ (unsigned long)vma->vm_start,
++ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
++ rc);
++
++ return rc;
++}
++
++static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
++ struct v4l2_format *format)
++{
++ int ret;
++ int width = format->fmt.pix.width;
++ int height = format->fmt.pix.height;
++ unsigned int maxwidth, maxheight;
++
++ maxwidth = 720;
++ maxheight = 480;
++
++#ifdef VBI_IS_WORKING
++ if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
++ dprintk(1, "VBI format set: to be supported!\n");
++ return 0;
++ }
++ if (format->type == V4L2_BUF_TYPE_VBI_CAPTURE)
++ return 0;
++#endif
++ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ /* If they are demanding a format other than the one we support,
++ bail out (tvtime asks for UYVY and then retries with YUYV) */
++ if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
++ return -EINVAL;
++
++ /* format->fmt.pix.width only support 720 and height 480 */
++ if (width != 720)
++ width = 720;
++ if (height != 480)
++ height = 480;
++
++ format->fmt.pix.width = width;
++ format->fmt.pix.height = height;
++ format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
++ format->fmt.pix.bytesperline = width * 2;
++ format->fmt.pix.sizeimage = width * height * 2;
++ format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
++ format->fmt.pix.field = V4L2_FIELD_INTERLACED;
++
++ if (cmd == VIDIOC_TRY_FMT)
++ return 0;
++
++ /* maybe set new image format, driver current only support 720*480 */
++ dev->width = width;
++ dev->height = height;
++ dev->frame_size = width * height * 2;
++ dev->field_size = width * height;
++ dev->bytesperline = width * 2;
++
++ if (dev->stream_state == STREAM_ON) {
++ dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n");
++ ret = au0828_stream_interrupt(dev);
++ if (ret != 0) {
++ dprintk(1, "error interrupting video stream!\n");
++ return ret;
++ }
++ }
++
++ /* set au0828 interface0 to AS5 here again */
++ ret = usb_set_interface(dev->usbdev, 0, 5);
++ if (ret < 0) {
++ printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
++ return -EBUSY;
++ }
++
++ au0828_analog_stream_enable(dev);
++
++ return 0;
++}
++
++
++static int vidioc_queryctrl(struct file *file, void *priv,
++ struct v4l2_queryctrl *qc)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
++ if (qc->type)
++ return 0;
++ else
++ return -EINVAL;
++}
++
++static int vidioc_querycap(struct file *file, void *priv,
++ struct v4l2_capability *cap)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ strlcpy(cap->driver, "au0828", sizeof(cap->driver));
++ strlcpy(cap->card, dev->board.name, sizeof(cap->card));
++ strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
++
++ cap->version = AU0828_VERSION_CODE;
++
++ /*set the device capabilities */
++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
++#ifdef VBI_IS_WORKING
++ V4L2_CAP_VBI_CAPTURE |
++#endif
++ V4L2_CAP_AUDIO |
++ V4L2_CAP_READWRITE |
++ V4L2_CAP_STREAMING |
++ V4L2_CAP_TUNER;
++ return 0;
++}
++
++static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_fmtdesc *f)
++{
++ if (f->index)
++ return -EINVAL;
++
++ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ strcpy(f->description, "Packed YUV2");
++
++ f->flags = 0;
++ f->pixelformat = V4L2_PIX_FMT_UYVY;
++
++ return 0;
++}
++
++static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ f->fmt.pix.width = dev->width;
++ f->fmt.pix.height = dev->height;
++ f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
++ f->fmt.pix.bytesperline = dev->bytesperline;
++ f->fmt.pix.sizeimage = dev->frame_size;
++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
++ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
++ return 0;
++}
++
++static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
++}
++
++static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ int rc;
++
++ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
++ printk(KERN_INFO "%s queue busy\n", __func__);
++ rc = -EBUSY;
++ goto out;
++ }
++
++ if (dev->stream_on && !fh->stream_on) {
++ printk(KERN_INFO "%s device in use by another fh\n", __func__);
++ rc = -EBUSY;
++ goto out;
++ }
++
++ return au0828_set_format(dev, VIDIOC_S_FMT, f);
++out:
++ return rc;
++}
++
++static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ /* FIXME: when we support something other than NTSC, we are going to
++ have to make the au0828 bridge adjust the size of its capture
++ buffer, which is currently hardcoded at 720x480 */
++
++ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_std, *norm);
++ return 0;
++}
++
++static int vidioc_enum_input(struct file *file, void *priv,
++ struct v4l2_input *input)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ unsigned int tmp;
++
++ static const char *inames[] = {
++ [AU0828_VMUX_UNDEFINED] = "Undefined",
++ [AU0828_VMUX_COMPOSITE] = "Composite",
++ [AU0828_VMUX_SVIDEO] = "S-Video",
++ [AU0828_VMUX_CABLE] = "Cable TV",
++ [AU0828_VMUX_TELEVISION] = "Television",
++ [AU0828_VMUX_DVB] = "DVB",
++ [AU0828_VMUX_DEBUG] = "tv debug"
++ };
++
++ tmp = input->index;
++
++ if (tmp > AU0828_MAX_INPUT)
++ return -EINVAL;
++ if (AUVI_INPUT(tmp).type == 0)
++ return -EINVAL;
++
++ input->index = tmp;
++ strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
++ if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
++ (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
++ input->type |= V4L2_INPUT_TYPE_TUNER;
++ else
++ input->type |= V4L2_INPUT_TYPE_CAMERA;
++
++ input->std = dev->vdev->tvnorms;
++
++ return 0;
++}
++
++static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ *i = dev->ctrl_input;
++ return 0;
++}
++
++static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ int i;
++ struct v4l2_routing route;
++
++ dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
++ index);
++ if (index >= AU0828_MAX_INPUT)
++ return -EINVAL;
++ if (AUVI_INPUT(index).type == 0)
++ return -EINVAL;
++ dev->ctrl_input = index;
++
++ switch (AUVI_INPUT(index).type) {
++ case AU0828_VMUX_SVIDEO:
++ dev->input_type = AU0828_VMUX_SVIDEO;
++ break;
++ case AU0828_VMUX_COMPOSITE:
++ dev->input_type = AU0828_VMUX_COMPOSITE;
++ break;
++ case AU0828_VMUX_TELEVISION:
++ dev->input_type = AU0828_VMUX_TELEVISION;
++ break;
++ default:
++ dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
++ AUVI_INPUT(index).type);
++ break;
++ }
++
++ route.input = AUVI_INPUT(index).vmux;
++ route.output = 0;
++ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, &route);
++
++ for (i = 0; i < AU0828_MAX_INPUT; i++) {
++ int enable = 0;
++ if (AUVI_INPUT(i).audio_setup == NULL)
++ continue;
++
++ if (i == index)
++ enable = 1;
++ else
++ enable = 0;
++ if (enable) {
++ (AUVI_INPUT(i).audio_setup)(dev, enable);
++ } else {
++ /* Make sure we leave it turned on if some
++ other input is routed to this callback */
++ if ((AUVI_INPUT(i).audio_setup) !=
++ ((AUVI_INPUT(index).audio_setup))) {
++ (AUVI_INPUT(i).audio_setup)(dev, enable);
++ }
++ }
++ }
++
++ route.input = AUVI_INPUT(index).amux;
++ v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, &route);
++ return 0;
++}
++
++static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ unsigned int index = a->index;
++
++ if (a->index > 1)
++ return -EINVAL;
++
++ index = dev->ctrl_ainput;
++ if (index == 0)
++ strcpy(a->name, "Television");
++ else
++ strcpy(a->name, "Line in");
++
++ a->capability = V4L2_AUDCAP_STEREO;
++ a->index = index;
++ return 0;
++}
++
++static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ if (a->index != dev->ctrl_ainput)
++ return -EINVAL;
++ return 0;
++}
++
++static int vidioc_g_ctrl(struct file *file, void *priv,
++ struct v4l2_control *ctrl)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
++ return 0;
++
++}
++
++static int vidioc_s_ctrl(struct file *file, void *priv,
++ struct v4l2_control *ctrl)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
++ return 0;
++}
++
++static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ if (t->index != 0)
++ return -EINVAL;
++
++ strcpy(t->name, "Auvitek tuner");
++ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
++ return 0;
++}
++
++static int vidioc_s_tuner(struct file *file, void *priv,
++ struct v4l2_tuner *t)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ if (t->index != 0)
++ return -EINVAL;
++
++ t->type = V4L2_TUNER_ANALOG_TV;
++ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
++ dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
++ t->afc);
++ return 0;
++
++}
++
++static int vidioc_g_frequency(struct file *file, void *priv,
++ struct v4l2_frequency *freq)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ freq->type = V4L2_TUNER_ANALOG_TV;
++ freq->frequency = dev->ctrl_freq;
++ return 0;
++}
++
++static int vidioc_s_frequency(struct file *file, void *priv,
++ struct v4l2_frequency *freq)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ if (freq->tuner != 0)
++ return -EINVAL;
++ if (freq->type != V4L2_TUNER_ANALOG_TV)
++ return -EINVAL;
++
++ dev->ctrl_freq = freq->frequency;
++
++ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
++
++ au0828_analog_stream_reset(dev);
++
++ return 0;
++}
++
++static int vidioc_g_chip_ident(struct file *file, void *priv,
++ struct v4l2_dbg_chip_ident *chip)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ chip->ident = V4L2_IDENT_NONE;
++ chip->revision = 0;
++
++ if (v4l2_chip_match_host(&chip->match)) {
++ chip->ident = V4L2_IDENT_AU0828;
++ return 0;
++ }
++
++ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
++ if (chip->ident == V4L2_IDENT_NONE)
++ return -EINVAL;
++
++ return 0;
++}
++
++static int vidioc_cropcap(struct file *file, void *priv,
++ struct v4l2_cropcap *cc)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ cc->bounds.left = 0;
++ cc->bounds.top = 0;
++ cc->bounds.width = dev->width;
++ cc->bounds.height = dev->height;
++
++ cc->defrect = cc->bounds;
++
++ cc->pixelaspect.numerator = 54;
++ cc->pixelaspect.denominator = 59;
++
++ return 0;
++}
++
++static int vidioc_streamon(struct file *file, void *priv,
++ enum v4l2_buf_type type)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ int rc;
++
++ rc = check_dev(dev);
++ if (rc < 0)
++ return rc;
++
++ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++ au0828_analog_stream_enable(dev);
++ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
++ }
++
++ mutex_lock(&dev->lock);
++ rc = res_get(fh);
++
++ if (likely(rc >= 0))
++ rc = videobuf_streamon(&fh->vb_vidq);
++ mutex_unlock(&dev->lock);
++
++ return rc;
++}
++
++static int vidioc_streamoff(struct file *file, void *priv,
++ enum v4l2_buf_type type)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ int i;
++ int ret;
++ int rc;
++
++ rc = check_dev(dev);
++ if (rc < 0)
++ return rc;
++
++ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (type != fh->type)
++ return -EINVAL;
++
++ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
++ ret = au0828_stream_interrupt(dev);
++ if (ret != 0)
++ return ret;
++ }
++
++ for (i = 0; i < AU0828_MAX_INPUT; i++) {
++ if (AUVI_INPUT(i).audio_setup == NULL)
++ continue;
++ (AUVI_INPUT(i).audio_setup)(dev, 0);
++ }
++
++ mutex_lock(&dev->lock);
++ videobuf_streamoff(&fh->vb_vidq);
++ res_free(fh);
++ mutex_unlock(&dev->lock);
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int vidioc_g_register(struct file *file, void *priv,
++ struct v4l2_dbg_register *reg)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ switch (reg->match.type) {
++ case V4L2_CHIP_MATCH_I2C_DRIVER:
++ v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int vidioc_s_register(struct file *file, void *priv,
++ struct v4l2_dbg_register *reg)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++
++ switch (reg->match.type) {
++ case V4L2_CHIP_MATCH_I2C_DRIVER:
++ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
++ return 0;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++#endif
++
++static int vidioc_reqbufs(struct file *file, void *priv,
++ struct v4l2_requestbuffers *rb)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ int rc;
++
++ rc = check_dev(dev);
++ if (rc < 0)
++ return rc;
++
++ return videobuf_reqbufs(&fh->vb_vidq, rb);
++}
++
++static int vidioc_querybuf(struct file *file, void *priv,
++ struct v4l2_buffer *b)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ int rc;
++
++ rc = check_dev(dev);
++ if (rc < 0)
++ return rc;
++
++ return videobuf_querybuf(&fh->vb_vidq, b);
++}
++
++static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ int rc;
++
++ rc = check_dev(dev);
++ if (rc < 0)
++ return rc;
++
++ return videobuf_qbuf(&fh->vb_vidq, b);
++}
++
++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++ struct au0828_fh *fh = priv;
++ struct au0828_dev *dev = fh->dev;
++ int rc;
++
++ rc = check_dev(dev);
++ if (rc < 0)
++ return rc;
++
++ /* Workaround for a bug in the au0828 hardware design that sometimes
++ results in the colorspace being inverted */
++ if (dev->greenscreen_detected == 1) {
++ dprintk(1, "Detected green frame. Resetting stream...\n");
++ au0828_analog_stream_reset(dev);
++ dev->greenscreen_detected = 0;
++ }
++
++ return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
++}
++
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
++{
++ struct au0828_fh *fh = priv;
++
++ return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
++}
++#endif
++
++static struct v4l2_file_operations au0828_v4l_fops = {
++ .owner = THIS_MODULE,
++ .open = au0828_v4l2_open,
++ .release = au0828_v4l2_close,
++ .read = au0828_v4l2_read,
++ .poll = au0828_v4l2_poll,
++ .mmap = au0828_v4l2_mmap,
++ .ioctl = video_ioctl2,
++};
++
++static const struct v4l2_ioctl_ops video_ioctl_ops = {
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
++#ifdef VBI_IS_WORKING
++ .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
++ .vidioc_try_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
++ .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
++#endif
++ .vidioc_g_audio = vidioc_g_audio,
++ .vidioc_s_audio = vidioc_s_audio,
++ .vidioc_cropcap = vidioc_cropcap,
++#ifdef VBI_IS_WORKING
++ .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
++ .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
++ .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
++#endif
++ .vidioc_reqbufs = vidioc_reqbufs,
++ .vidioc_querybuf = vidioc_querybuf,
++ .vidioc_qbuf = vidioc_qbuf,
++ .vidioc_dqbuf = vidioc_dqbuf,
++ .vidioc_s_std = vidioc_s_std,
++ .vidioc_enum_input = vidioc_enum_input,
++ .vidioc_g_input = vidioc_g_input,
++ .vidioc_s_input = vidioc_s_input,
++ .vidioc_queryctrl = vidioc_queryctrl,
++ .vidioc_g_ctrl = vidioc_g_ctrl,
++ .vidioc_s_ctrl = vidioc_s_ctrl,
++ .vidioc_streamon = vidioc_streamon,
++ .vidioc_streamoff = vidioc_streamoff,
++ .vidioc_g_tuner = vidioc_g_tuner,
++ .vidioc_s_tuner = vidioc_s_tuner,
++ .vidioc_g_frequency = vidioc_g_frequency,
++ .vidioc_s_frequency = vidioc_s_frequency,
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .vidioc_g_register = vidioc_g_register,
++ .vidioc_s_register = vidioc_s_register,
++#endif
++ .vidioc_g_chip_ident = vidioc_g_chip_ident,
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++ .vidiocgmbuf = vidiocgmbuf,
++#endif
++};
++
++static const struct video_device au0828_video_template = {
++ .fops = &au0828_v4l_fops,
++ .release = video_device_release,
++ .ioctl_ops = &video_ioctl_ops,
++ .minor = -1,
++ .tvnorms = V4L2_STD_NTSC_M,
++ .current_norm = V4L2_STD_NTSC_M,
++};
++
++/**************************************************************************/
++
++int au0828_analog_register(struct au0828_dev *dev,
++ struct usb_interface *interface)
++{
++ int retval = -ENOMEM;
++ struct usb_host_interface *iface_desc;
++ struct usb_endpoint_descriptor *endpoint;
++ int i;
++
++ dprintk(1, "au0828_analog_register called!\n");
++
++ /* set au0828 usb interface0 to as5 */
++ retval = usb_set_interface(dev->usbdev,
++ interface->cur_altsetting->desc.bInterfaceNumber, 5);
++ if (retval != 0) {
++ printk(KERN_INFO "Failure setting usb interface0 to as5\n");
++ return retval;
++ }
++
++ /* Figure out which endpoint has the isoc interface */
++ iface_desc = interface->cur_altsetting;
++ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
++ endpoint = &iface_desc->endpoint[i].desc;
++ if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
++ == USB_DIR_IN) &&
++ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
++ == USB_ENDPOINT_XFER_ISOC)) {
++
++ /* we find our isoc in endpoint */
++ u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
++ dev->max_pkt_size = (tmp & 0x07ff) *
++ (((tmp & 0x1800) >> 11) + 1);
++ dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
++ }
++ }
++ if (!(dev->isoc_in_endpointaddr)) {
++ printk(KERN_INFO "Could not locate isoc endpoint\n");
++ kfree(dev);
++ return -ENODEV;
++ }
++
++ init_waitqueue_head(&dev->open);
++ spin_lock_init(&dev->slock);
++ mutex_init(&dev->lock);
++
++ INIT_LIST_HEAD(&dev->vidq.active);
++ INIT_LIST_HEAD(&dev->vidq.queued);
++
++ dev->width = NTSC_STD_W;
++ dev->height = NTSC_STD_H;
++ dev->field_size = dev->width * dev->height;
++ dev->frame_size = dev->field_size << 1;
++ dev->bytesperline = dev->width << 1;
++ dev->ctrl_ainput = 0;
++
++ /* allocate and fill v4l2 video struct */
++ dev->vdev = video_device_alloc();
++ if (NULL == dev->vdev) {
++ dprintk(1, "Can't allocate video_device.\n");
++ return -ENOMEM;
++ }
++
++#ifdef VBI_IS_WORKING
++ dev->vbi_dev = video_device_alloc();
++ if (NULL == dev->vbi_dev) {
++ dprintk(1, "Can't allocate vbi_device.\n");
++ kfree(dev->vdev);
++ return -ENOMEM;
++ }
++#endif
++
++ /* Fill the video capture device struct */
++ *dev->vdev = au0828_video_template;
++ dev->vdev->parent = &dev->usbdev->dev;
++ strcpy(dev->vdev->name, "au0828a video");
++
++#ifdef VBI_IS_WORKING
++ /* Setup the VBI device */
++ *dev->vbi_dev = au0828_video_template;
++ dev->vbi_dev->parent = &dev->usbdev->dev;
++ strcpy(dev->vbi_dev->name, "au0828a vbi");
++#endif
++
++ list_add_tail(&dev->au0828list, &au0828_devlist);
++
++ /* Register the v4l2 device */
++ retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
++ if (retval != 0) {
++ dprintk(1, "unable to register video device (error = %d).\n",
++ retval);
++ list_del(&dev->au0828list);
++ video_device_release(dev->vdev);
++ return -ENODEV;
++ }
++
++#ifdef VBI_IS_WORKING
++ /* Register the vbi device */
++ retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
++ if (retval != 0) {
++ dprintk(1, "unable to register vbi device (error = %d).\n",
++ retval);
++ list_del(&dev->au0828list);
++ video_device_release(dev->vbi_dev);
++ video_device_release(dev->vdev);
++ return -ENODEV;
++ }
++#endif
++
++ dprintk(1, "%s completed!\n", __func__);
++
++ return 0;
++}
++
+diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
+index 9d6a116..6ed1a61 100644
+--- a/drivers/media/video/au0828/au0828.h
++++ b/drivers/media/video/au0828/au0828.h
+@@ -24,6 +24,11 @@
+ #include <linux/i2c-algo-bit.h>
+ #include <media/tveeprom.h>
+
++/* Analog */
++#include <linux/videodev2.h>
++#include <media/videobuf-vmalloc.h>
++#include <media/v4l2-device.h>
++
+ /* DVB */
+ #include "demux.h"
+ #include "dmxdev.h"
+@@ -39,8 +44,45 @@
+ #define URB_COUNT 16
+ #define URB_BUFSIZE (0xe522)
+
++/* Analog constants */
++#define NTSC_STD_W 720
++#define NTSC_STD_H 480
++
++#define AU0828_INTERLACED_DEFAULT 1
++#define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0)
++
++/* Defination for AU0828 USB transfer */
++#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */
++#define AU0828_ISO_PACKETS_PER_URB 10
++
++#define AU0828_MIN_BUF 4
++#define AU0828_DEF_BUF 8
++
++#define AU0828_MAX_INPUT 4
++
++enum au0828_itype {
++ AU0828_VMUX_UNDEFINED = 0,
++ AU0828_VMUX_COMPOSITE,
++ AU0828_VMUX_SVIDEO,
++ AU0828_VMUX_CABLE,
++ AU0828_VMUX_TELEVISION,
++ AU0828_VMUX_DVB,
++ AU0828_VMUX_DEBUG
++};
++
++struct au0828_input {
++ enum au0828_itype type;
++ unsigned int vmux;
++ unsigned int amux;
++ void (*audio_setup) (void *priv, int enable);
++};
++
+ struct au0828_board {
+ char *name;
++ unsigned int tuner_type;
++ unsigned char tuner_addr;
++ struct au0828_input input[AU0828_MAX_INPUT];
++
+ };
+
+ struct au0828_dvb {
+@@ -55,31 +97,143 @@ struct au0828_dvb {
+ int feeding;
+ };
+
++enum au0828_stream_state {
++ STREAM_OFF,
++ STREAM_INTERRUPT,
++ STREAM_ON
++};
++
++#define AUVI_INPUT(nr) (dev->board.input[nr])
++
++/* device state */
++enum au0828_dev_state {
++ DEV_INITIALIZED = 0x01,
++ DEV_DISCONNECTED = 0x02,
++ DEV_MISCONFIGURED = 0x04
++};
++
++struct au0828_fh {
++ struct au0828_dev *dev;
++ unsigned int stream_on:1; /* Locks streams */
++ struct videobuf_queue vb_vidq;
++ enum v4l2_buf_type type;
++};
++
++struct au0828_usb_isoc_ctl {
++ /* max packet size of isoc transaction */
++ int max_pkt_size;
++
++ /* number of allocated urbs */
++ int num_bufs;
++
++ /* urb for isoc transfers */
++ struct urb **urb;
++
++ /* transfer buffers for isoc transfer */
++ char **transfer_buffer;
++
++ /* Last buffer command and region */
++ u8 cmd;
++ int pos, size, pktsize;
++
++ /* Last field: ODD or EVEN? */
++ int field;
++
++ /* Stores incomplete commands */
++ u32 tmp_buf;
++ int tmp_buf_len;
++
++ /* Stores already requested buffers */
++ struct au0828_buffer *buf;
++
++ /* Stores the number of received fields */
++ int nfields;
++
++ /* isoc urb callback */
++ int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb);
++
++};
++
++/* buffer for one video frame */
++struct au0828_buffer {
++ /* common v4l buffer stuff -- must be first */
++ struct videobuf_buffer vb;
++
++ struct list_head frame;
++ int top_field;
++ int receiving;
++};
++
++struct au0828_dmaqueue {
++ struct list_head active;
++ struct list_head queued;
++
++ wait_queue_head_t wq;
++
++ /* Counters to control buffer fill */
++ int pos;
++};
++
+ struct au0828_dev {
+ struct mutex mutex;
+ struct usb_device *usbdev;
+- int board;
++ int boardnr;
++ struct au0828_board board;
+ u8 ctrlmsg[64];
+
+ /* I2C */
+ struct i2c_adapter i2c_adap;
+- struct i2c_algo_bit_data i2c_algo;
++ struct i2c_algorithm i2c_algo;
+ struct i2c_client i2c_client;
+ u32 i2c_rc;
+
+ /* Digital */
+ struct au0828_dvb dvb;
+
++ /* Analog */
++ struct list_head au0828list;
++ struct v4l2_device v4l2_dev;
++ int users;
++ unsigned int stream_on:1; /* Locks streams */
++ struct video_device *vdev;
++ struct video_device *vbi_dev;
++ int width;
++ int height;
++ u32 field_size;
++ u32 frame_size;
++ u32 bytesperline;
++ int type;
++ u8 ctrl_ainput;
++ __u8 isoc_in_endpointaddr;
++ u8 isoc_init_ok;
++ int greenscreen_detected;
++ unsigned int frame_count;
++ int ctrl_freq;
++ int input_type;
++ unsigned int ctrl_input;
++ enum au0828_dev_state dev_state;
++ enum au0828_stream_state stream_state;
++ wait_queue_head_t open;
++
++ struct mutex lock;
++
++ /* Isoc control struct */
++ struct au0828_dmaqueue vidq;
++ struct au0828_usb_isoc_ctl isoc_ctl;
++ spinlock_t slock;
++
++ /* usb transfer */
++ int alt; /* alternate */
++ int max_pkt_size; /* max packet size of isoc transaction */
++ int num_alt; /* Number of alternative settings */
++ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
++ struct urb *urb[AU0828_MAX_ISO_BUFS]; /* urb for isoc transfers */
++ char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
++ transfer */
++
+ /* USB / URB Related */
+ int urb_streaming;
+ struct urb *urbs[URB_COUNT];
+-
+-};
+-
+-struct au0828_buff {
+- struct au0828_dev *dev;
+- struct urb *purb;
+- struct list_head buff_list;
+ };
+
+ /* ----------------------------------------------------------- */
+@@ -111,8 +265,13 @@ extern void au0828_card_setup(struct au0828_dev *dev);
+ /* au0828-i2c.c */
+ extern int au0828_i2c_register(struct au0828_dev *dev);
+ extern int au0828_i2c_unregister(struct au0828_dev *dev);
+-extern void au0828_call_i2c_clients(struct au0828_dev *dev,
+- unsigned int cmd, void *arg);
++
++/* ----------------------------------------------------------- */
++/* au0828-video.c */
++int au0828_analog_register(struct au0828_dev *dev,
++ struct usb_interface *interface);
++int au0828_analog_stream_disable(struct au0828_dev *d);
++void au0828_analog_unregister(struct au0828_dev *dev);
+
+ /* ----------------------------------------------------------- */
+ /* au0828-dvb.c */
+diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
+index a07b7b8..df4516d 100644
+--- a/drivers/media/video/bt819.c
++++ b/drivers/media/video/bt819.c
+@@ -29,16 +29,16 @@
+ */
+
+ #include <linux/module.h>
+-#include <linux/delay.h>
+ #include <linux/types.h>
+ #include <linux/ioctl.h>
+-#include <asm/uaccess.h>
++#include <linux/delay.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-id.h>
+-#include <linux/videodev.h>
+-#include <linux/video_decoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
++#include <media/bt819.h>
+
+ MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
+ MODULE_AUTHOR("Mike Bernson & Dave Perks");
+@@ -48,13 +48,15 @@ static int debug;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
++
+ /* ----------------------------------------------------------------------- */
+
+ struct bt819 {
++ struct v4l2_subdev sd;
+ unsigned char reg[32];
+
+- int initialized;
+- int norm;
++ v4l2_std_id norm;
++ int ident;
+ int input;
+ int enable;
+ int bright;
+@@ -63,6 +65,11 @@ struct bt819 {
+ int sat;
+ };
+
++static inline struct bt819 *to_bt819(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct bt819, sd);
++}
++
+ struct timing {
+ int hactive;
+ int hdelay;
+@@ -80,24 +87,23 @@ static struct timing timing_data[] = {
+
+ /* ----------------------------------------------------------------------- */
+
+-static inline int bt819_write(struct i2c_client *client, u8 reg, u8 value)
++static inline int bt819_write(struct bt819 *decoder, u8 reg, u8 value)
+ {
+- struct bt819 *decoder = i2c_get_clientdata(client);
++ struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
+
+ decoder->reg[reg] = value;
+ return i2c_smbus_write_byte_data(client, reg, value);
+ }
+
+-static inline int bt819_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
++static inline int bt819_setbit(struct bt819 *decoder, u8 reg, u8 bit, u8 value)
+ {
+- struct bt819 *decoder = i2c_get_clientdata(client);
+-
+- return bt819_write(client, reg,
++ return bt819_write(decoder, reg,
+ (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0));
+ }
+
+-static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
++static int bt819_write_block(struct bt819 *decoder, const u8 *data, unsigned int len)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
+ int ret = -1;
+ u8 reg;
+
+@@ -105,7 +111,6 @@ static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned
+ * 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);
+ u8 block_data[32];
+ int block_len;
+
+@@ -126,7 +131,8 @@ static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned
+ /* do some slow I2C emulation kind of thing */
+ while (len >= 2) {
+ reg = *data++;
+- if ((ret = bt819_write(client, reg, *data++)) < 0)
++ ret = bt819_write(decoder, reg, *data++);
++ if (ret < 0)
+ break;
+ len -= 2;
+ }
+@@ -135,15 +141,15 @@ static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned
+ return ret;
+ }
+
+-static inline int bt819_read(struct i2c_client *client, u8 reg)
++static inline int bt819_read(struct bt819 *decoder, u8 reg)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
++
+ return i2c_smbus_read_byte_data(client, reg);
+ }
+
+-static int bt819_init(struct i2c_client *client)
++static int bt819_init(struct v4l2_subdev *sd)
+ {
+- struct bt819 *decoder = i2c_get_clientdata(client);
+-
+ static unsigned char init[] = {
+ /*0x1f, 0x00,*/ /* Reset */
+ 0x01, 0x59, /* 0x01 input format */
+@@ -178,7 +184,8 @@ static int bt819_init(struct i2c_client *client)
+ 0x1a, 0x80, /* 0x1a ADC Interface */
+ };
+
+- struct timing *timing = &timing_data[decoder->norm];
++ struct bt819 *decoder = to_bt819(sd);
++ struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0];
+
+ init[0x03 * 2 - 1] =
+ (((timing->vdelay >> 8) & 0x03) << 6) |
+@@ -192,266 +199,306 @@ static int bt819_init(struct i2c_client *client)
+ init[0x08 * 2 - 1] = timing->hscale >> 8;
+ init[0x09 * 2 - 1] = timing->hscale & 0xff;
+ /* 0x15 in array is address 0x19 */
+- init[0x15 * 2 - 1] = (decoder->norm == 0) ? 115 : 93; /* Chroma burst delay */
++ init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93; /* Chroma burst delay */
+ /* reset */
+- bt819_write(client, 0x1f, 0x00);
++ bt819_write(decoder, 0x1f, 0x00);
+ mdelay(1);
+
+ /* init */
+- return bt819_write_block(client, init, sizeof(init));
++ return bt819_write_block(decoder, init, sizeof(init));
+ }
+
+ /* ----------------------------------------------------------------------- */
+
+-static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg)
++static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
+ {
+- int temp;
++ struct bt819 *decoder = to_bt819(sd);
++ int status = bt819_read(decoder, 0x00);
++ int res = V4L2_IN_ST_NO_SIGNAL;
++ v4l2_std_id std;
+
+- struct bt819 *decoder = i2c_get_clientdata(client);
++ if ((status & 0x80))
++ res = 0;
+
+- if (!decoder->initialized) { /* First call to bt819_init could be */
+- bt819_init(client); /* without #FRST = 0 */
+- decoder->initialized = 1;
+- }
++ if ((status & 0x10))
++ std = V4L2_STD_PAL;
++ else
++ std = V4L2_STD_NTSC;
++ if (pstd)
++ *pstd = std;
++ if (pstatus)
++ *pstatus = status;
+
+- switch (cmd) {
+- case 0:
+- /* This is just for testing!!! */
+- bt819_init(client);
+- break;
++ v4l2_dbg(1, debug, sd, "get status %x\n", status);
++ return 0;
++}
+
+- case DECODER_GET_CAPABILITIES:
+- {
+- struct video_decoder_capability *cap = arg;
++static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
++{
++ return bt819_status(sd, NULL, std);
++}
+
+- cap->flags = VIDEO_DECODER_PAL |
+- VIDEO_DECODER_NTSC |
+- VIDEO_DECODER_AUTO |
+- VIDEO_DECODER_CCIR;
+- cap->inputs = 8;
+- cap->outputs = 1;
+- break;
++static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status)
++{
++ return bt819_status(sd, status, NULL);
++}
++
++static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
++{
++ struct bt819 *decoder = to_bt819(sd);
++ struct timing *timing = NULL;
++
++ v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
++
++ if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
++ v4l2_err(sd, "no notify found!\n");
++
++ if (std & V4L2_STD_NTSC) {
++ v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
++ bt819_setbit(decoder, 0x01, 0, 1);
++ bt819_setbit(decoder, 0x01, 1, 0);
++ bt819_setbit(decoder, 0x01, 5, 0);
++ bt819_write(decoder, 0x18, 0x68);
++ bt819_write(decoder, 0x19, 0x5d);
++ /* bt819_setbit(decoder, 0x1a, 5, 1); */
++ timing = &timing_data[1];
++ } else if (std & V4L2_STD_PAL) {
++ v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
++ bt819_setbit(decoder, 0x01, 0, 1);
++ bt819_setbit(decoder, 0x01, 1, 1);
++ bt819_setbit(decoder, 0x01, 5, 1);
++ bt819_write(decoder, 0x18, 0x7f);
++ bt819_write(decoder, 0x19, 0x72);
++ /* bt819_setbit(decoder, 0x1a, 5, 0); */
++ timing = &timing_data[0];
++ } else {
++ v4l2_dbg(1, debug, sd, "unsupported norm %llx\n",
++ (unsigned long long)std);
++ return -EINVAL;
+ }
++ bt819_write(decoder, 0x03,
++ (((timing->vdelay >> 8) & 0x03) << 6) |
++ (((timing->vactive >> 8) & 0x03) << 4) |
++ (((timing->hdelay >> 8) & 0x03) << 2) |
++ ((timing->hactive >> 8) & 0x03));
++ bt819_write(decoder, 0x04, timing->vdelay & 0xff);
++ bt819_write(decoder, 0x05, timing->vactive & 0xff);
++ bt819_write(decoder, 0x06, timing->hdelay & 0xff);
++ bt819_write(decoder, 0x07, timing->hactive & 0xff);
++ bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff);
++ bt819_write(decoder, 0x09, timing->hscale & 0xff);
++ decoder->norm = std;
++ v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0);
++ return 0;
++}
+
+- case DECODER_GET_STATUS:
+- {
+- int *iarg = arg;
+- int status;
+- int res;
++static int bt819_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
++{
++ struct bt819 *decoder = to_bt819(sd);
+
+- status = bt819_read(client, 0x00);
+- res = 0;
+- if ((status & 0x80))
+- res |= DECODER_STATUS_GOOD;
++ v4l2_dbg(1, debug, sd, "set input %x\n", route->input);
+
+- 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;
+- else
+- res |= DECODER_STATUS_NTSC;
+- break;
+- }
+- res |= DECODER_STATUS_COLOR;
+- *iarg = res;
++ if (route->input < 0 || route->input > 7)
++ return -EINVAL;
+
+- v4l_dbg(1, debug, client, "get status %x\n", *iarg);
+- break;
++ if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
++ v4l2_err(sd, "no notify found!\n");
++
++ if (decoder->input != route->input) {
++ v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
++ decoder->input = route->input;
++ /* 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);
++ }
++ v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0);
+ }
++ return 0;
++}
+
+- case DECODER_SET_NORM:
+- {
+- int *iarg = arg;
+- struct timing *timing = NULL;
+-
+- v4l_dbg(1, debug, client, "set norm %x\n", *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:
+- v4l_dbg(1, debug, client, "unsupported norm %x\n", *iarg);
+- return -EINVAL;
+- }
++static int bt819_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct bt819 *decoder = to_bt819(sd);
+
+- 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) );
+- 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);
+- }
++ v4l2_dbg(1, debug, sd, "enable output %x\n", enable);
+
+- decoder->norm = *iarg;
+- break;
++ if (decoder->enable != enable) {
++ decoder->enable = enable;
++ bt819_setbit(decoder, 0x16, 7, !enable);
+ }
++ return 0;
++}
+
+- case DECODER_SET_INPUT:
+- {
+- int *iarg = arg;
+-
+- v4l_dbg(1, debug, client, "set input %x\n", *iarg);
+-
+- if (*iarg < 0 || *iarg > 7)
+- return -EINVAL;
+-
+- 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);
+- }
+- }
++static int bt819_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
++{
++ switch (qc->id) {
++ case V4L2_CID_BRIGHTNESS:
++ v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+ break;
+- }
+
+- case DECODER_SET_OUTPUT:
+- {
+- int *iarg = arg;
++ case V4L2_CID_CONTRAST:
++ v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
++ break;
+
+- v4l_dbg(1, debug, client, "set output %x\n", *iarg);
++ case V4L2_CID_SATURATION:
++ v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
++ break;
+
+- /* not much choice of outputs */
+- if (*iarg != 0)
+- return -EINVAL;
++ case V4L2_CID_HUE:
++ v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+ break;
+- }
+
+- case DECODER_ENABLE_OUTPUT:
+- {
+- int *iarg = arg;
+- int enable = (*iarg != 0);
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
+
+- v4l_dbg(1, debug, client, "enable output %x\n", *iarg);
++static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct bt819 *decoder = to_bt819(sd);
++ int temp;
+
+- if (decoder->enable != enable) {
+- decoder->enable = enable;
+- bt819_setbit(client, 0x16, 7, !enable);
+- }
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ if (decoder->bright == ctrl->value)
++ break;
++ decoder->bright = ctrl->value;
++ bt819_write(decoder, 0x0a, decoder->bright);
+ break;
+- }
+
+- case DECODER_SET_PICTURE:
+- {
+- struct video_picture *pic = arg;
+-
+- v4l_dbg(1, debug, client,
+- "set picture brightness %d contrast %d colour %d\n",
+- pic->brightness, pic->contrast, pic->colour);
++ case V4L2_CID_CONTRAST:
++ if (decoder->contrast == ctrl->value)
++ break;
++ decoder->contrast = ctrl->value;
++ bt819_write(decoder, 0x0c, decoder->contrast & 0xff);
++ bt819_setbit(decoder, 0x0b, 2, ((decoder->contrast >> 8) & 0x01));
++ break;
+
++ case V4L2_CID_SATURATION:
++ if (decoder->sat == ctrl->value)
++ break;
++ decoder->sat = ctrl->value;
++ bt819_write(decoder, 0x0d, (decoder->sat >> 7) & 0xff);
++ bt819_setbit(decoder, 0x0b, 1, ((decoder->sat >> 15) & 0x01));
++
++ /* Ratio between U gain and V gain must stay the same as
++ the ratio between the default U and V gain values. */
++ temp = (decoder->sat * 180) / 254;
++ bt819_write(decoder, 0x0e, (temp >> 7) & 0xff);
++ bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01);
++ break;
+
+- 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);
+- }
++ case V4L2_CID_HUE:
++ if (decoder->hue == ctrl->value)
++ break;
++ decoder->hue = ctrl->value;
++ bt819_write(decoder, 0x0f, decoder->hue);
++ break;
+
+- 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));
+- }
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
+
+- 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);
+- }
++static int bt819_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct bt819 *decoder = to_bt819(sd);
+
+- 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));
+- }
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ ctrl->value = decoder->bright;
++ break;
++ case V4L2_CID_CONTRAST:
++ ctrl->value = decoder->contrast;
++ break;
++ case V4L2_CID_SATURATION:
++ ctrl->value = decoder->sat;
++ break;
++ case V4L2_CID_HUE:
++ ctrl->value = decoder->hue;
+ break;
+- }
+-
+ default:
+ return -EINVAL;
+ }
+-
+ return 0;
+ }
+
++static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct bt819 *decoder = to_bt819(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
++}
++
+ /* ----------------------------------------------------------------------- */
+
+-static unsigned short normal_i2c[] = { 0x8a >> 1, I2C_CLIENT_END };
++static const struct v4l2_subdev_core_ops bt819_core_ops = {
++ .g_chip_ident = bt819_g_chip_ident,
++ .g_ctrl = bt819_g_ctrl,
++ .s_ctrl = bt819_s_ctrl,
++ .queryctrl = bt819_queryctrl,
++};
++
++static const struct v4l2_subdev_tuner_ops bt819_tuner_ops = {
++ .s_std = bt819_s_std,
++};
++
++static const struct v4l2_subdev_video_ops bt819_video_ops = {
++ .s_routing = bt819_s_routing,
++ .s_stream = bt819_s_stream,
++ .querystd = bt819_querystd,
++ .g_input_status = bt819_g_input_status,
++};
++
++static const struct v4l2_subdev_ops bt819_ops = {
++ .core = &bt819_core_ops,
++ .tuner = &bt819_tuner_ops,
++ .video = &bt819_video_ops,
++};
+
+-I2C_CLIENT_INSMOD;
++/* ----------------------------------------------------------------------- */
+
+ static int bt819_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ int i, ver;
+ struct bt819 *decoder;
++ struct v4l2_subdev *sd;
+ const char *name;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+- ver = bt819_read(client, 0x17);
++ decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
++ if (decoder == NULL)
++ return -ENOMEM;
++ sd = &decoder->sd;
++ v4l2_i2c_subdev_init(sd, client, &bt819_ops);
++
++ ver = bt819_read(decoder, 0x17);
+ switch (ver & 0xf0) {
+ case 0x70:
+ name = "bt819a";
++ decoder->ident = V4L2_IDENT_BT819A;
+ break;
+ case 0x60:
+ name = "bt817a";
++ decoder->ident = V4L2_IDENT_BT817A;
+ break;
+ case 0x20:
+ name = "bt815a";
++ decoder->ident = V4L2_IDENT_BT815A;
+ break;
+ default:
+- v4l_dbg(1, debug, client,
++ v4l2_dbg(1, debug, sd,
+ "unknown chip version 0x%02x\n", ver);
+ return -ENODEV;
+ }
+@@ -459,28 +506,26 @@ static int bt819_probe(struct i2c_client *client,
+ v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+ client->addr << 1, client->adapter->name);
+
+- decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
+- if (decoder == NULL)
+- return -ENOMEM;
+- decoder->norm = VIDEO_MODE_NTSC;
++ decoder->norm = V4L2_STD_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);
+-
+- i = bt819_init(client);
++ decoder->bright = 0;
++ decoder->contrast = 0xd8; /* 100% of original signal */
++ decoder->hue = 0;
++ decoder->sat = 0xfe; /* 100% of original signal */
++
++ i = bt819_init(sd);
+ if (i < 0)
+- v4l_dbg(1, debug, client, "init status %d\n", i);
++ v4l2_dbg(1, debug, sd, "init status %d\n", i);
+ return 0;
+ }
+
+ static int bt819_remove(struct i2c_client *client)
+ {
+- kfree(i2c_get_clientdata(client));
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_bt819(sd));
+ return 0;
+ }
+
+@@ -496,8 +541,6 @@ MODULE_DEVICE_TABLE(i2c, bt819_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "bt819",
+- .driverid = I2C_DRIVERID_BT819,
+- .command = bt819_command,
+ .probe = bt819_probe,
+ .remove = bt819_remove,
+ .id_table = bt819_id,
+diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
+index 4213867..78db395 100644
+--- a/drivers/media/video/bt856.c
++++ b/drivers/media/video/bt856.c
+@@ -34,10 +34,10 @@
+ #include <asm/uaccess.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-id.h>
+-#include <linux/videodev.h>
+-#include <linux/video_encoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
+ MODULE_AUTHOR("Mike Bernson & Dave Perks");
+@@ -47,43 +47,46 @@ static int debug;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
++
+ /* ----------------------------------------------------------------------- */
+
+ #define BT856_REG_OFFSET 0xDA
+ #define BT856_NR_REG 6
+
+ struct bt856 {
++ struct v4l2_subdev sd;
+ unsigned char reg[BT856_NR_REG];
+
+- int norm;
+- int enable;
++ v4l2_std_id norm;
+ };
+
++static inline struct bt856 *to_bt856(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct bt856, sd);
++}
++
+ /* ----------------------------------------------------------------------- */
+
+-static inline int bt856_write(struct i2c_client *client, u8 reg, u8 value)
++static inline int bt856_write(struct bt856 *encoder, u8 reg, u8 value)
+ {
+- struct bt856 *encoder = i2c_get_clientdata(client);
++ struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
+
+ encoder->reg[reg - BT856_REG_OFFSET] = value;
+ return i2c_smbus_write_byte_data(client, reg, value);
+ }
+
+-static inline int bt856_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
++static inline int bt856_setbit(struct bt856 *encoder, u8 reg, u8 bit, u8 value)
+ {
+- struct bt856 *encoder = i2c_get_clientdata(client);
+-
+- return bt856_write(client, reg,
++ return bt856_write(encoder, reg,
+ (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
+ (value ? (1 << bit) : 0));
+ }
+
+-static void bt856_dump(struct i2c_client *client)
++static void bt856_dump(struct bt856 *encoder)
+ {
+ int i;
+- struct bt856 *encoder = i2c_get_clientdata(client);
+
+- v4l_info(client, "register dump:\n");
++ v4l2_info(&encoder->sd, "register dump:\n");
+ for (i = 0; i < BT856_NR_REG; i += 2)
+ printk(KERN_CONT " %02x", encoder->reg[i]);
+ printk(KERN_CONT "\n");
+@@ -91,153 +94,120 @@ static void bt856_dump(struct i2c_client *client)
+
+ /* ----------------------------------------------------------------------- */
+
+-static int bt856_command(struct i2c_client *client, unsigned cmd, void *arg)
++static int bt856_init(struct v4l2_subdev *sd, u32 arg)
+ {
+- struct bt856 *encoder = i2c_get_clientdata(client);
+-
+- switch (cmd) {
+- case 0:
+- /* This is just for testing!!! */
+- v4l_dbg(1, debug, client, "init\n");
+- 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);
+- break;
+-
+- case ENCODER_GET_CAPABILITIES:
+- {
+- struct video_encoder_capability *cap = arg;
+-
+- v4l_dbg(1, debug, client, "get capabilities\n");
++ struct bt856 *encoder = to_bt856(sd);
++
++ /* This is just for testing!!! */
++ v4l2_dbg(1, debug, sd, "init\n");
++ bt856_write(encoder, 0xdc, 0x18);
++ bt856_write(encoder, 0xda, 0);
++ bt856_write(encoder, 0xde, 0);
++
++ bt856_setbit(encoder, 0xdc, 3, 1);
++ /*bt856_setbit(encoder, 0xdc, 6, 0);*/
++ bt856_setbit(encoder, 0xdc, 4, 1);
++
++ if (encoder->norm & V4L2_STD_NTSC)
++ bt856_setbit(encoder, 0xdc, 2, 0);
++ else
++ bt856_setbit(encoder, 0xdc, 2, 1);
++
++ bt856_setbit(encoder, 0xdc, 1, 1);
++ bt856_setbit(encoder, 0xde, 4, 0);
++ bt856_setbit(encoder, 0xde, 3, 1);
++ if (debug != 0)
++ bt856_dump(encoder);
++ return 0;
++}
+
+- cap->flags = VIDEO_ENCODER_PAL |
+- VIDEO_ENCODER_NTSC |
+- VIDEO_ENCODER_CCIR;
+- cap->inputs = 2;
+- cap->outputs = 1;
+- break;
+- }
++static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
++{
++ struct bt856 *encoder = to_bt856(sd);
+
+- case ENCODER_SET_NORM:
+- {
+- int *iarg = arg;
+-
+- v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
+-
+- switch (*iarg) {
+- case VIDEO_MODE_NTSC:
+- bt856_setbit(client, 0xdc, 2, 0);
+- 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;
+- }
+- encoder->norm = *iarg;
+- if (debug != 0)
+- bt856_dump(client);
+- break;
+- }
++ v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
+
+- case ENCODER_SET_INPUT:
+- {
+- int *iarg = arg;
+-
+- v4l_dbg(1, debug, client, "set input %d\n", *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;
++ if (std & V4L2_STD_NTSC) {
++ bt856_setbit(encoder, 0xdc, 2, 0);
++ } else if (std & V4L2_STD_PAL) {
++ bt856_setbit(encoder, 0xdc, 2, 1);
++ bt856_setbit(encoder, 0xda, 0, 0);
++ /*bt856_setbit(encoder, 0xda, 0, 1);*/
++ } else {
++ return -EINVAL;
+ }
++ encoder->norm = std;
++ if (debug != 0)
++ bt856_dump(encoder);
++ return 0;
++}
+
+- case ENCODER_SET_OUTPUT:
+- {
+- int *iarg = arg;
++static int bt856_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
++{
++ struct bt856 *encoder = to_bt856(sd);
+
+- v4l_dbg(1, debug, client, "set output %d\n", *iarg);
++ v4l2_dbg(1, debug, sd, "set input %d\n", route->input);
+
+- /* not much choice of outputs */
+- if (*iarg != 0)
+- return -EINVAL;
++ /* We only have video bus.
++ * route->input= 0: input is from bt819
++ * route->input= 1: input is from ZR36060 */
++ switch (route->input) {
++ 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 ENCODER_ENABLE_OUTPUT:
+- {
+- int *iarg = arg;
+-
+- encoder->enable = !!*iarg;
+-
+- v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
++ 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;
+ }
+
++ if (debug != 0)
++ bt856_dump(encoder);
+ return 0;
+ }
+
++static int bt856_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT856, 0);
++}
++
+ /* ----------------------------------------------------------------------- */
+
+-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
++static const struct v4l2_subdev_core_ops bt856_core_ops = {
++ .g_chip_ident = bt856_g_chip_ident,
++ .init = bt856_init,
++};
++
++static const struct v4l2_subdev_video_ops bt856_video_ops = {
++ .s_std_output = bt856_s_std_output,
++ .s_routing = bt856_s_routing,
++};
+
+-I2C_CLIENT_INSMOD;
++static const struct v4l2_subdev_ops bt856_ops = {
++ .core = &bt856_core_ops,
++ .video = &bt856_video_ops,
++};
++
++/* ----------------------------------------------------------------------- */
+
+ static int bt856_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ struct bt856 *encoder;
++ struct v4l2_subdev *sd;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+@@ -249,41 +219,38 @@ static int bt856_probe(struct i2c_client *client,
+ encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
+ if (encoder == NULL)
+ return -ENOMEM;
+- encoder->norm = VIDEO_MODE_NTSC;
+- encoder->enable = 1;
+- i2c_set_clientdata(client, encoder);
++ sd = &encoder->sd;
++ v4l2_i2c_subdev_init(sd, client, &bt856_ops);
++ encoder->norm = V4L2_STD_NTSC;
+
+- bt856_write(client, 0xdc, 0x18);
+- bt856_write(client, 0xda, 0);
+- bt856_write(client, 0xde, 0);
++ bt856_write(encoder, 0xdc, 0x18);
++ bt856_write(encoder, 0xda, 0);
++ bt856_write(encoder, 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) {
++ if (encoder->norm & V4L2_STD_NTSC)
++ bt856_setbit(encoder, 0xdc, 2, 0);
++ else
++ bt856_setbit(encoder, 0xdc, 2, 1);
+
+- 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);
++ bt856_setbit(encoder, 0xdc, 1, 1);
++ bt856_setbit(encoder, 0xde, 4, 0);
++ bt856_setbit(encoder, 0xde, 3, 1);
+
+ if (debug != 0)
+- bt856_dump(client);
++ bt856_dump(encoder);
+ return 0;
+ }
+
+ static int bt856_remove(struct i2c_client *client)
+ {
+- kfree(i2c_get_clientdata(client));
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_bt856(sd));
+ return 0;
+ }
+
+@@ -295,8 +262,6 @@ MODULE_DEVICE_TABLE(i2c, bt856_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "bt856",
+- .driverid = I2C_DRIVERID_BT856,
+- .command = bt856_command,
+ .probe = bt856_probe,
+ .remove = bt856_remove,
+ .id_table = bt856_id,
+diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
+index 596f9e2..350cae4 100644
+--- a/drivers/media/video/bt866.c
++++ b/drivers/media/video/bt866.c
+@@ -34,10 +34,10 @@
+ #include <asm/uaccess.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-id.h>
+-#include <linux/videodev.h>
+-#include <linux/video_encoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
+ MODULE_AUTHOR("Mike Bernson & Dave Perks");
+@@ -47,22 +47,22 @@ static int debug;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
++
+ /* ----------------------------------------------------------------------- */
+
+ struct bt866 {
++ struct v4l2_subdev sd;
+ u8 reg[256];
+-
+- int norm;
+- int enable;
+- int bright;
+- int contrast;
+- int hue;
+- int sat;
+ };
+
+-static int bt866_write(struct i2c_client *client, u8 subaddr, u8 data)
++static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
+ {
+- struct bt866 *encoder = i2c_get_clientdata(client);
++ return container_of(sd, struct bt866, sd);
++}
++
++static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
+ u8 buffer[2];
+ int err;
+
+@@ -89,163 +89,120 @@ static int bt866_write(struct i2c_client *client, u8 subaddr, u8 data)
+ return 0;
+ }
+
+-static int bt866_command(struct i2c_client *client, unsigned cmd, void *arg)
++static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+ {
+- struct bt866 *encoder = i2c_get_clientdata(client);
+-
+- switch (cmd) {
+- case ENCODER_GET_CAPABILITIES:
+- {
+- struct video_encoder_capability *cap = arg;
+-
+- v4l_dbg(1, debug, client, "get capabilities\n");
+-
+- 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;
+-
+- v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
+-
+- switch (*iarg) {
+- case VIDEO_MODE_NTSC:
+- break;
+-
+- case VIDEO_MODE_PAL:
+- break;
+-
+- default:
+- return -EINVAL;
+- }
+- encoder->norm = *iarg;
+- break;
+- }
+-
+- case ENCODER_SET_INPUT:
+- {
+- int *iarg = arg;
+- static const __u8 init[] = {
+- 0xc8, 0xcc, /* CRSCALE */
+- 0xca, 0x91, /* CBSCALE */
+- 0xcc, 0x24, /* YC16 | OSDNUM */
+- 0xda, 0x00, /* */
+- 0xdc, 0x24, /* SETMODE | PAL */
+- 0xde, 0x02, /* EACTIVE */
+-
+- /* overlay colors */
+- 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
+- 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
+- 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
+- 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
+- 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
+- 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
+- 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
+- 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
+-
+- 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
+- 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
+- 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
+- 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
+- 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
+- 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
+- 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
+- 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
+- };
+- int i;
+- u8 val;
+-
+- for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
+- bt866_write(client, init[i], init[i+1]);
+-
+- val = encoder->reg[0xdc];
+-
+- if (*iarg == 0)
+- val |= 0x40; /* CBSWAP */
+- else
+- val &= ~0x40; /* !CBSWAP */
+-
+- bt866_write(client, 0xdc, val);
+-
+- val = encoder->reg[0xcc];
+- if (*iarg == 2)
+- val |= 0x01; /* OSDBAR */
+- else
+- val &= ~0x01; /* !OSDBAR */
+- bt866_write(client, 0xcc, val);
+-
+- v4l_dbg(1, debug, client, "set input %d\n", *iarg);
+-
+- switch (*iarg) {
+- case 0:
+- break;
+- case 1:
+- break;
+- default:
+- return -EINVAL;
+- }
+- break;
+- }
+-
+- case ENCODER_SET_OUTPUT:
+- {
+- int *iarg = arg;
+-
+- v4l_dbg(1, debug, client, "set output %d\n", *iarg);
+-
+- /* not much choice of outputs */
+- if (*iarg != 0)
+- return -EINVAL;
+- break;
+- }
+-
+- case ENCODER_ENABLE_OUTPUT:
+- {
+- int *iarg = arg;
+- encoder->enable = !!*iarg;
++ v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
+
+- v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
+- break;
+- }
+-
+- case 4711:
+- {
+- int *iarg = arg;
+- __u8 val;
+-
+- v4l_dbg(1, debug, client, "square %d\n", *iarg);
++ /* Only PAL supported by this driver at the moment! */
++ if (!(std & V4L2_STD_NTSC))
++ return -EINVAL;
++ return 0;
++}
+
+- val = encoder->reg[0xdc];
+- if (*iarg)
+- val |= 1; /* SQUARE */
+- else
+- val &= ~1; /* !SQUARE */
+- bt866_write(client, 0xdc, val);
++static int bt866_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
++{
++ static const __u8 init[] = {
++ 0xc8, 0xcc, /* CRSCALE */
++ 0xca, 0x91, /* CBSCALE */
++ 0xcc, 0x24, /* YC16 | OSDNUM */
++ 0xda, 0x00, /* */
++ 0xdc, 0x24, /* SETMODE | PAL */
++ 0xde, 0x02, /* EACTIVE */
++
++ /* overlay colors */
++ 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
++ 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
++ 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
++ 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
++ 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
++ 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
++ 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
++ 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
++
++ 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
++ 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
++ 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
++ 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
++ 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
++ 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
++ 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
++ 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
++ };
++ struct bt866 *encoder = to_bt866(sd);
++ u8 val;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
++ bt866_write(encoder, init[i], init[i+1]);
++
++ val = encoder->reg[0xdc];
++
++ if (route->input == 0)
++ val |= 0x40; /* CBSWAP */
++ else
++ val &= ~0x40; /* !CBSWAP */
++
++ bt866_write(encoder, 0xdc, val);
++
++ val = encoder->reg[0xcc];
++ if (route->input == 2)
++ val |= 0x01; /* OSDBAR */
++ else
++ val &= ~0x01; /* !OSDBAR */
++ bt866_write(encoder, 0xcc, val);
++
++ v4l2_dbg(1, debug, sd, "set input %d\n", route->input);
++
++ switch (route->input) {
++ case 0:
++ case 1:
++ case 2:
+ break;
+- }
+-
+ default:
+ return -EINVAL;
+ }
+-
+ return 0;
+ }
+
+-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
++#if 0
++/* Code to setup square pixels, might be of some use in the future,
++ but is currently unused. */
++ val = encoder->reg[0xdc];
++ if (*iarg)
++ val |= 1; /* SQUARE */
++ else
++ val &= ~1; /* !SQUARE */
++ bt866_write(client, 0xdc, val);
++#endif
++
++static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0);
++}
++
++/* ----------------------------------------------------------------------- */
++
++static const struct v4l2_subdev_core_ops bt866_core_ops = {
++ .g_chip_ident = bt866_g_chip_ident,
++};
++
++static const struct v4l2_subdev_video_ops bt866_video_ops = {
++ .s_std_output = bt866_s_std_output,
++ .s_routing = bt866_s_routing,
++};
+
+-I2C_CLIENT_INSMOD;
++static const struct v4l2_subdev_ops bt866_ops = {
++ .core = &bt866_core_ops,
++ .video = &bt866_video_ops,
++};
+
+ static int bt866_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ struct bt866 *encoder;
++ struct v4l2_subdev *sd;
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
+@@ -253,20 +210,18 @@ static int bt866_probe(struct i2c_client *client,
+ encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
+ if (encoder == NULL)
+ return -ENOMEM;
+-
+- i2c_set_clientdata(client, encoder);
++ sd = &encoder->sd;
++ v4l2_i2c_subdev_init(sd, client, &bt866_ops);
+ return 0;
+ }
+
+ static int bt866_remove(struct i2c_client *client)
+ {
+- kfree(i2c_get_clientdata(client));
+- return 0;
+-}
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+-static int bt866_legacy_probe(struct i2c_adapter *adapter)
+-{
+- return adapter->id == I2C_HW_B_ZR36067;
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_bt866(sd));
++ return 0;
+ }
+
+ static const struct i2c_device_id bt866_id[] = {
+@@ -277,10 +232,7 @@ MODULE_DEVICE_TABLE(i2c, bt866_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "bt866",
+- .driverid = I2C_DRIVERID_BT866,
+- .command = bt866_command,
+ .probe = bt866_probe,
+ .remove = bt866_remove,
+- .legacy_probe = bt866_legacy_probe,
+ .id_table = bt866_id,
+ };
+diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
+index ce71e8e..3077c45 100644
+--- a/drivers/media/video/bt8xx/Kconfig
++++ b/drivers/media/video/bt8xx/Kconfig
+@@ -10,7 +10,7 @@ config VIDEO_BT848
+ select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO
+- select VIDEO_TDA9875 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO
+ ---help---
+ Support for BT848 based frame grabber/overlay boards. This includes
+ the Miro, Hauppauge and STB boards. Please read the material in
+diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
+index d24dcc0..b9c3ba5 100644
+--- a/drivers/media/video/bt8xx/bttv-cards.c
++++ b/drivers/media/video/bt8xx/bttv-cards.c
+@@ -73,6 +73,11 @@ static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input);
+
+ static void geovision_muxsel(struct bttv *btv, unsigned int input);
+
++static void phytec_muxsel(struct bttv *btv, unsigned int input);
++
++static void gv800s_muxsel(struct bttv *btv, unsigned int input);
++static void gv800s_init(struct bttv *btv);
++
+ static int terratec_active_radio_upgrade(struct bttv *btv);
+ static int tea5757_read(struct bttv *btv);
+ static int tea5757_write(struct bttv *btv, int value);
+@@ -91,12 +96,10 @@ static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+ static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+ static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+ static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
++static unsigned int audiodev[BTTV_MAX];
++static unsigned int saa6588[BTTV_MAX];
+ static struct bttv *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL };
+-#ifdef MODULE
+-static unsigned int autoload = 1;
+-#else
+-static unsigned int autoload;
+-#endif
++static unsigned int autoload = UNSET;
+ static unsigned int gpiomask = UNSET;
+ static unsigned int audioall = UNSET;
+ static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
+@@ -115,6 +118,7 @@ module_param_array(pll, int, NULL, 0444);
+ module_param_array(tuner, int, NULL, 0444);
+ module_param_array(svhs, int, NULL, 0444);
+ module_param_array(remote, int, NULL, 0444);
++module_param_array(audiodev, int, NULL, 0444);
+ module_param_array(audiomux, int, NULL, 0444);
+
+ MODULE_PARM_DESC(triton1,"set ETBF pci config bit "
+@@ -125,7 +129,14 @@ MODULE_PARM_DESC(latency,"pci latency timer");
+ MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
+ MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
+ MODULE_PARM_DESC(tuner,"specify installed tuner type");
+-MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
++MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore");
++MODULE_PARM_DESC(audiodev, "specify audio device:\n"
++ "\t\t-1 = no audio\n"
++ "\t\t 0 = autodetect (default)\n"
++ "\t\t 1 = msp3400\n"
++ "\t\t 2 = tda7432\n"
++ "\t\t 3 = tvaudio");
++MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition.");
+ MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+ " [some VIA/SIS chipsets are known to have problem with overlay]");
+
+@@ -246,6 +257,10 @@ static struct CARD {
+ { 0xa182ff0d, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0e, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0f, BTTV_BOARD_IVC120, "IVC-120G" },
++ { 0xf0500000, BTTV_BOARD_IVCE8784, "IVCE-8784" },
++ { 0xf0500001, BTTV_BOARD_IVCE8784, "IVCE-8784" },
++ { 0xf0500002, BTTV_BOARD_IVCE8784, "IVCE-8784" },
++ { 0xf0500003, BTTV_BOARD_IVCE8784, "IVCE-8784" },
+
+ { 0x41424344, BTTV_BOARD_GRANDTEC, "GrandTec Multi Capture" },
+ { 0x01020304, BTTV_BOARD_XGUARD, "Grandtec Grand X-Guard" },
+@@ -289,6 +304,8 @@ static struct CARD {
+ /* Duplicate PCI ID, reconfigure for this board during the eeprom read.
+ * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */
+
++ { 0x109e036e, BTTV_BOARD_CONCEPTRONIC_CTVFMI2, "Conceptronic CTVFMi v2"},
++
+ /* DVB cards (using pci function .1 for mpeg data xfer) */
+ { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" },
+ { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+@@ -305,6 +322,20 @@ static struct CARD {
+ { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" },
+ { 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" },
+ { 0x18011000, BTTV_BOARD_ENLTV_FM_2, "Encore ENL TV-FM-2" },
++ { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" },
++ { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" },
++ { 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" },
++ { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" },
++
++ { 0x15401830, BTTV_BOARD_PV183, "Provideo PV183-1" },
++ { 0x15401831, BTTV_BOARD_PV183, "Provideo PV183-2" },
++ { 0x15401832, BTTV_BOARD_PV183, "Provideo PV183-3" },
++ { 0x15401833, BTTV_BOARD_PV183, "Provideo PV183-4" },
++ { 0x15401834, BTTV_BOARD_PV183, "Provideo PV183-5" },
++ { 0x15401835, BTTV_BOARD_PV183, "Provideo PV183-6" },
++ { 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" },
++ { 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" },
++
+ { 0, -1, NULL }
+ };
+
+@@ -316,59 +347,50 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_UNKNOWN] = {
+ .name = " *** UNKNOWN/GENERIC *** ",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
+ .svhs = 2,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MIRO] = {
+ .name = "MIRO PCTV",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 15,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 2, 0, 0, 0 },
+ .gpiomute = 10,
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_HAUPPAUGE] = {
+ .name = "Hauppauge (bt848)",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 7,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 1, 2, 3 },
+ .gpiomute = 4,
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_STB] = {
+ .name = "STB, Gateway P/N 6000699 (bt848)",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 7,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 4, 0, 2, 3 },
+ .gpiomute = 1,
+ .no_msp34xx = 1,
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+@@ -377,202 +399,177 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_INTEL] = {
+ .name = "Intel Create and Share PCI/ Smart Video Recorder III",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 2,
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_DIAMOND] = {
+ .name = "Diamond DTV2000",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 3,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = { 0, 1, 0, 1 },
+ .gpiomute = 3,
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_AVERMEDIA] = {
+ .name = "AVerMedia TVPhone",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 3,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomask = 0x0f,
+ .gpiomux = { 0x0c, 0x04, 0x08, 0x04 },
+ /* 0x04 for some cards ?? */
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= avermedia_tvphone_audio,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_MATRIX_VISION] = {
+ .name = "MATRIX-Vision MV-Delta",
+ .video_inputs = 5,
+- .audio_inputs = 1,
+- .tuner = UNSET,
++ /* .audio_inputs= 1, */
+ .svhs = 3,
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 0, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0, 0),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 1,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x08 ---------------------------------- */
+ [BTTV_BOARD_FLYVIDEO] = {
+ .name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xc00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0xc00, 0x800, 0x400 },
+ .gpiomute = 0xc00,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TURBOTV] = {
+ .name = "IMS/IXmicro TurboTV",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 3,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 1, 1, 2, 3 },
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_HAUPPAUGE878] = {
+ .name = "Hauppauge (bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x0f, /* old: 7 */
+- .muxsel = { 2, 0, 1, 1 },
++ .muxsel = MUXSEL(2, 0, 1, 1),
+ .gpiomux = { 0, 1, 2, 3 },
+ .gpiomute = 4,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MIROPRO] = {
+ .name = "MIRO PCTV pro",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x3014f,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x20001,0x10001, 0, 0 },
+ .gpiomute = 10,
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x0c ---------------------------------- */
+ [BTTV_BOARD_ADSTECH_TV] = {
+ .name = "ADS Technologies Channel Surfer TV (bt848)",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 15,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 13, 14, 11, 7 },
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_AVERMEDIA98] = {
+ .name = "AVerMedia TVCapture 98",
+ .video_inputs = 3,
+- .audio_inputs = 4,
+- .tuner = 0,
++ /* .audio_inputs= 4, */
+ .svhs = 2,
+ .gpiomask = 15,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 13, 14, 11, 7 },
+ .needs_tvaudio = 1,
+ .msp34xx_alt = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= avermedia_tv_stereo_audio,
+ .no_gpioirq = 1,
+ },
+ [BTTV_BOARD_VHX] = {
+ .name = "Aimslab Video Highway Xtreme (VHX)",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 7,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 2, 1, 3 }, /* old: {0, 1, 2, 3, 4} */
+ .gpiomute = 4,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ZOLTRIX] = {
+ .name = "Zoltrix TV-Max",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 15,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0, 1, 0 },
+ .gpiomute = 10,
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x10 ---------------------------------- */
+ [BTTV_BOARD_PIXVIEWPLAYTV] = {
+ .name = "Prolink Pixelview PlayTV (bt878)",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x01fe00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
+ .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 },
+ .gpiomute = 0x002000,
+@@ -580,194 +577,170 @@ struct tvcard bttv_tvcards[] = {
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_WINVIEW_601] = {
+ .name = "Leadtek WinView 601",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x8300f8,
+- .muxsel = { 2, 3, 1, 1,0 },
++ .muxsel = MUXSEL(2, 3, 1, 1, 0),
+ .gpiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
+ .gpiomute = 0xcfa007,
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .volume_gpio = winview_volume,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_AVEC_INTERCAP] = {
+ .name = "AVEC Intercapture",
+ .video_inputs = 3,
+- .audio_inputs = 2,
+- .tuner = 0,
++ /* .audio_inputs= 2, */
+ .svhs = 2,
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 1, 0, 0, 0 },
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_LIFE_FLYKIT] = {
+ .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = UNSET,
+- .svhs = UNSET,
++ /* .audio_inputs= 1, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0x8dff00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0 },
+ .no_msp34xx = 1,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x14 ---------------------------------- */
+ [BTTV_BOARD_CEI_RAFFLES] = {
+ .name = "CEI Raffles Card",
+ .video_inputs = 3,
+- .audio_inputs = 3,
+- .tuner = 0,
++ /* .audio_inputs= 3, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_CONFERENCETV] = {
+ .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+ .video_inputs = 4,
+- .audio_inputs = 2, /* tuner, line in */
+- .tuner = 0,
++ /* .audio_inputs= 2, tuner, line in */
+ .svhs = 2,
+ .gpiomask = 0x1800,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0x800, 0x1000, 0x1000 },
+ .gpiomute = 0x1800,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_PHOEBE_TVMAS] = {
+ .name = "Askey CPH050/ Phoebe Tv Master + FM",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xc00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 1, 0x800, 0x400 },
+ .gpiomute = 0xc00,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MODTEC_205] = {
+ .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
+- .svhs = UNSET,
++ /* .audio_inputs= 1, */
++ .svhs = NO_SVHS,
++ .has_dig_in = 1,
+ .gpiomask = 7,
+- .muxsel = { 2, 3, -1 },
+- .digital_mode = DIGITAL_MODE_CAMERA,
++ .muxsel = MUXSEL(2, 3, 0), /* input 2 is digital */
++ /* .digital_mode= DIGITAL_MODE_CAMERA, */
+ .gpiomux = { 0, 0, 0, 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_ALPS_TSBB5_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x18 ---------------------------------- */
+ [BTTV_BOARD_MAGICTVIEW061] = {
+ .name = "Askey CPH05X/06X (bt878) [many vendors]",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xe00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = {0x400, 0x400, 0x400, 0x400 },
+ .gpiomute = 0xc00,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_VOBIS_BOOSTAR] = {
+ .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x1f0fff,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x20000, 0x30000, 0x10000, 0 },
+ .gpiomute = 0x40000,
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= terratv_audio,
+ },
+ [BTTV_BOARD_HAUPPAUG_WCAM] = {
+ .name = "Hauppauge WinCam newer (bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 3,
+ .gpiomask = 7,
+- .muxsel = { 2, 0, 1, 1 },
++ .muxsel = MUXSEL(2, 0, 1, 1),
+ .gpiomux = { 0, 1, 2, 3 },
+ .gpiomute = 4,
+ .needs_tvaudio = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MAXI] = {
+ .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+ .video_inputs = 4,
+- .audio_inputs = 2,
+- .tuner = 0,
++ /* .audio_inputs= 2, */
+ .svhs = 2,
+ .gpiomask = 0x1800,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0x800, 0x1000, 0x1000 },
+ .gpiomute = 0x1800,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x1c ---------------------------------- */
+ [BTTV_BOARD_TERRATV] = {
+ .name = "Terratec TerraTV+ Version 1.1 (bt878)",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x1f0fff,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x20000, 0x30000, 0x10000, 0x00000 },
+ .gpiomute = 0x40000,
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= terratv_audio,
+ /* GPIO wiring:
+ External 20 pin connector (for Active Radio Upgrade board)
+@@ -805,87 +778,77 @@ struct tvcard bttv_tvcards[] = {
+ /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
+ .name = "Imagenation PXC200",
+ .video_inputs = 5,
+- .audio_inputs = 1,
+- .tuner = UNSET,
++ /* .audio_inputs= 1, */
+ .svhs = 1, /* was: 4 */
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 0, 0},
++ .muxsel = MUXSEL(2, 3, 1, 0, 0),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 1,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .muxsel_hook = PXC200_muxsel,
+
+ },
+ [BTTV_BOARD_FLYVIDEO_98] = {
+ .name = "Lifeview FlyVideo 98 LR50",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x1800, /* 0x8dfe00 */
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0x0800, 0x1000, 0x1000 },
+ .gpiomute = 0x1800,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_IPROTV] = {
+ .name = "Formac iProTV, Formac ProTV I (bt848)",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 3,
+ .gpiomask = 1,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 1, 0, 0, 0 },
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x20 ---------------------------------- */
+ [BTTV_BOARD_INTEL_C_S_PCI] = {
+ .name = "Intel Create and Share PCI/ Smart Video Recorder III",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 2,
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TERRATVALUE] = {
+ .name = "Terratec TerraTValue Version Bt878",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xffff00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x500, 0, 0x300, 0x900 },
+ .gpiomute = 0x900,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_WINFAST2000] = {
+ .name = "Leadtek WinFast 2000/ WinFast 2000 XP",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1, 1, 0 }, /* TV, CVid, SVid, CVid over SVid connector */
++ /* TV, CVid, SVid, CVid over SVid connector */
++ .muxsel = MUXSEL(2, 3, 1, 1, 0),
+ /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
+ .gpiomask = 0xb33000,
+ .gpiomux = { 0x122000,0x1000,0x0000,0x620000 },
+@@ -906,217 +869,191 @@ struct tvcard bttv_tvcards[] = {
+ .has_radio = 1,
+ .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= winfast2000_audio,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_CHRONOS_VS2] = {
+ .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+ .video_inputs = 4,
+- .audio_inputs = 3,
+- .tuner = 0,
++ /* .audio_inputs= 3, */
+ .svhs = 2,
+ .gpiomask = 0x1800,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0x800, 0x1000, 0x1000 },
+ .gpiomute = 0x1800,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x24 ---------------------------------- */
+ [BTTV_BOARD_TYPHOON_TVIEW] = {
+ .name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+ .video_inputs = 4,
+- .audio_inputs = 3,
+- .tuner = 0,
++ /* .audio_inputs= 3, */
+ .svhs = 2,
+ .gpiomask = 0x1800,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0x800, 0x1000, 0x1000 },
+ .gpiomute = 0x1800,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_PXELVWPLTVPRO] = {
+ .name = "Prolink PixelView PlayTV pro",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xff,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x21, 0x20, 0x24, 0x2c },
+ .gpiomute = 0x29,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MAGICTVIEW063] = {
+ .name = "Askey CPH06X TView99",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x551e00,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = { 0x551400, 0x551200, 0, 0 },
+ .gpiomute = 0x551c00,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_PINNACLE] = {
+ .name = "Pinnacle PCTV Studio/Rave",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x03000F,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 2, 0xd0001, 0, 0 },
+ .gpiomute = 1,
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x28 ---------------------------------- */
+ [BTTV_BOARD_STB2] = {
+ .name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 7,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 4, 0, 2, 3 },
+ .gpiomute = 1,
+ .no_msp34xx = 1,
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_AVPHONE98] = {
+ .name = "AVerMedia TVPhone 98",
+ .video_inputs = 3,
+- .audio_inputs = 4,
+- .tuner = 0,
++ /* .audio_inputs= 4, */
+ .svhs = 2,
+ .gpiomask = 15,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 13, 4, 11, 7 },
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ .audio_mode_gpio= avermedia_tvphone_audio,
+ },
+ [BTTV_BOARD_PV951] = {
+ .name = "ProVideo PV951", /* pic16c54 */
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 1},
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0, 0, 0},
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ONAIR_TV] = {
+ .name = "Little OnAir TV",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xe00b,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
+ .gpiomute = 0xff3ffc,
+ .no_msp34xx = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x2c ---------------------------------- */
+ [BTTV_BOARD_SIGMA_TVII_FM] = {
+ .name = "Sigma TVII-FM",
+ .video_inputs = 2,
+- .audio_inputs = 1,
+- .tuner = 0,
+- .svhs = UNSET,
++ /* .audio_inputs= 1, */
++ .svhs = NO_SVHS,
+ .gpiomask = 3,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 1, 1, 0, 2 },
+ .gpiomute = 3,
+ .no_msp34xx = 1,
+ .pll = PLL_NONE,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MATRIX_VISION2] = {
+ .name = "MATRIX-Vision MV-Delta 2",
+ .video_inputs = 5,
+- .audio_inputs = 1,
+- .tuner = UNSET,
++ /* .audio_inputs= 1, */
+ .svhs = 3,
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 0, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0, 0),
+ .gpiomux = { 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ZOLTRIX_GENIE] = {
+ .name = "Zoltrix Genie TV/FM",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xbcf03f,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0 },
+ .gpiomute = 0xbcb03f,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4039FR5_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TERRATVRADIO] = {
+ .name = "Terratec TV/Radio+",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x70000,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x20000, 0x30000, 0x10000, 0 },
+ .gpiomute = 0x40000,
+ .needs_tvaudio = 1,
+@@ -1124,7 +1061,6 @@ struct tvcard bttv_tvcards[] = {
+ .pll = PLL_35,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+
+@@ -1132,51 +1068,46 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_DYNALINK] = {
+ .name = "Askey CPH03x/ Dynalink Magic TView",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 15,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = {2,0,0,0 },
+ .gpiomute = 1,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_GVBCTV3PCI] = {
+ .name = "IODATA GV-BCTV3/PCI",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x010f00,
+- .muxsel = {2, 3, 0, 0 },
++ .muxsel = MUXSEL(2, 3, 0, 0),
+ .gpiomux = {0x10000, 0, 0x10000, 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_ALPS_TSHC6_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= gvbctv3pci_audio,
+ },
+ [BTTV_BOARD_PXELVWPLTVPAK] = {
+ .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
+ .video_inputs = 5,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 3,
++ .has_dig_in = 1,
+ .gpiomask = 0xAA0000,
+- .muxsel = { 2,3,1,1,-1 },
+- .digital_mode = DIGITAL_MODE_CAMERA,
++ .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */
++ /* .digital_mode= DIGITAL_MODE_CAMERA, */
+ .gpiomux = { 0x20000, 0, 0x80000, 0x80000 },
+ .gpiomute = 0xa8000,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ /* GPIO wiring: (different from Rev.4C !)
+ GPIO17: U4.A0 (first hef4052bt)
+@@ -1191,17 +1122,15 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_EAGLE] = {
+ .name = "Eagle Wireless Capricorn2 (bt878A)",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 7,
+- .muxsel = { 2, 0, 1, 1 },
++ .muxsel = MUXSEL(2, 0, 1, 1),
+ .gpiomux = { 0, 1, 2, 3 },
+ .gpiomute = 4,
+ .pll = PLL_28,
+ .tuner_type = UNSET /* TUNER_ALPS_TMDH2_NTSC */,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x34 ---------------------------------- */
+@@ -1209,11 +1138,10 @@ struct tvcard bttv_tvcards[] = {
+ /* David Härdeman <david@2gen.com> */
+ .name = "Pinnacle PCTV Studio Pro",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 3,
+ .gpiomask = 0x03000F,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 1, 0xd0001, 0, 0 },
+ .gpiomute = 10,
+ /* sound path (5 sources):
+@@ -1229,25 +1157,22 @@ struct tvcard bttv_tvcards[] = {
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TVIEW_RDS_FM] = {
+ /* Claas Langbehn <claas@bigfoot.com>,
+ Sven Grothklags <sven@upb.de> */
+ .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
+ .video_inputs = 4,
+- .audio_inputs = 3,
+- .tuner = 0,
++ /* .audio_inputs= 3, */
+ .svhs = 2,
+ .gpiomask = 0x1c,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0, 0x10, 8 },
+ .gpiomute = 4,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_LIFETEC_9415] = {
+@@ -1258,11 +1183,10 @@ struct tvcard bttv_tvcards[] = {
+ options tuner type=5 */
+ .name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x18e0,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x0000,0x0800,0x1000,0x1000 },
+ .gpiomute = 0x18e0,
+ /* For cards with tda9820/tda9821:
+@@ -1272,25 +1196,22 @@ struct tvcard bttv_tvcards[] = {
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_BESTBUY_EASYTV] = {
+ /* Miguel Angel Alvarez <maacruz@navegalia.com>
+ old Easy TV BT848 version (model CPH031) */
+ .name = "Askey CPH031/ BESTBUY Easy TV",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xF,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = { 2, 0, 0, 0 },
+ .gpiomute = 10,
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x38 ---------------------------------- */
+@@ -1298,17 +1219,15 @@ struct tvcard bttv_tvcards[] = {
+ /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
+ .name = "Lifeview FlyVideo 98FM LR50",
+ .video_inputs = 4,
+- .audio_inputs = 3,
+- .tuner = 0,
++ /* .audio_inputs= 3, */
+ .svhs = 2,
+ .gpiomask = 0x1800,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0x800, 0x1000, 0x1000 },
+ .gpiomute = 0x1800,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ /* This is the ultimate cheapo capture card
+ * just a BT848A on a small PCB!
+@@ -1316,51 +1235,45 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_GRANDTEC] = {
+ .name = "GrandTec 'Grand Video Capture' (Bt848)",
+ .video_inputs = 2,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 1,
+ .gpiomask = 0,
+- .muxsel = { 3, 1 },
++ .muxsel = MUXSEL(3, 1),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_35,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ASKEY_CPH060] = {
+ /* Daniel Herrington <daniel.herrington@home.com> */
+ .name = "Askey CPH060/ Phoebe TV Master Only (No FM)",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xe00,
+- .muxsel = { 2, 3, 1, 1},
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x400, 0x400, 0x400, 0x400 },
+ .gpiomute = 0x800,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4036FY5_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ASKEY_CPH03X] = {
+ /* Matti Mottus <mottus@physic.ut.ee> */
+ .name = "Askey CPH03x TV Capturer",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x03000F,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = { 2, 0, 0, 0 },
+ .gpiomute = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x3c ---------------------------------- */
+@@ -1368,34 +1281,30 @@ struct tvcard bttv_tvcards[] = {
+ /* Philip Blundell <philb@gnu.org> */
+ .name = "Modular Technology MM100PCTV",
+ .video_inputs = 2,
+- .audio_inputs = 2,
+- .tuner = 0,
+- .svhs = UNSET,
++ /* .audio_inputs= 2, */
++ .svhs = NO_SVHS,
+ .gpiomask = 11,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 2, 0, 0, 1 },
+ .gpiomute = 8,
+ .pll = PLL_35,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_GMV1] = {
+ /* Adrian Cox <adrian@humboldt.co.uk */
+ .name = "AG Electronics GMV1",
+ .video_inputs = 2,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 1,
+ .gpiomask = 0xF,
+- .muxsel = { 2, 2 },
++ .muxsel = MUXSEL(2, 2),
+ .gpiomux = { },
+ .no_msp34xx = 1,
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_BESTBUY_EASYTV2] = {
+ /* Miguel Angel Alvarez <maacruz@navegalia.com>
+@@ -1403,34 +1312,30 @@ struct tvcard bttv_tvcards[] = {
+ special thanks to Informatica Mieres for providing the card */
+ .name = "Askey CPH061/ BESTBUY Easy TV (bt878)",
+ .video_inputs = 3,
+- .audio_inputs = 2,
+- .tuner = 0,
++ /* .audio_inputs= 2, */
+ .svhs = 2,
+ .gpiomask = 0xFF,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = { 1, 0, 4, 4 },
+ .gpiomute = 9,
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ATI_TVWONDER] = {
+ /* Lukas Gebauer <geby@volny.cz> */
+ .name = "ATI TV-Wonder",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xf03f,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = { 0xbffe, 0, 0xbfff, 0 },
+ .gpiomute = 0xbffe,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x40 ---------------------------------- */
+@@ -1438,27 +1343,24 @@ struct tvcard bttv_tvcards[] = {
+ /* Lukas Gebauer <geby@volny.cz> */
+ .name = "ATI TV-Wonder VE",
+ .video_inputs = 2,
+- .audio_inputs = 1,
+- .tuner = 0,
+- .svhs = UNSET,
++ /* .audio_inputs= 1, */
++ .svhs = NO_SVHS,
+ .gpiomask = 1,
+- .muxsel = { 2, 3, 0, 1 },
++ .muxsel = MUXSEL(2, 3, 0, 1),
+ .gpiomux = { 0, 0, 1, 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_FLYVIDEO2000] = {
+ /* DeeJay <deejay@westel900.net (2000S) */
+ .name = "Lifeview FlyVideo 2000S LR90",
+ .video_inputs = 3,
+- .audio_inputs = 3,
+- .tuner = 0,
++ /* .audio_inputs= 3, */
+ .svhs = 2,
+ .gpiomask = 0x18e0,
+- .muxsel = { 2, 3, 0, 1 },
++ .muxsel = MUXSEL(2, 3, 0, 1),
+ /* Radio changed from 1e80 to 0x800 to make
+ FlyVideo2000S in .hu happy (gm)*/
+ /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
+@@ -1471,40 +1373,35 @@ struct tvcard bttv_tvcards[] = {
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TERRATVALUER] = {
+ .name = "Terratec TValueRadio",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0xffff00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x500, 0x500, 0x300, 0x900 },
+ .gpiomute = 0x900,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_GVBCTV4PCI] = {
+ /* TANAKA Kei <peg00625@nifty.com> */
+ .name = "IODATA GV-BCTV4/PCI",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x010f00,
+- .muxsel = {2, 3, 0, 0 },
++ .muxsel = MUXSEL(2, 3, 0, 0),
+ .gpiomux = {0x10000, 0, 0x10000, 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_SHARP_2U5JF5540_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= gvbctv3pci_audio,
+ },
+
+@@ -1514,9 +1411,8 @@ struct tvcard bttv_tvcards[] = {
+ /* try "insmod msp3400 simple=0" if you have
+ * sound problems with this card. */
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
+- .svhs = UNSET,
++ /* .audio_inputs= 1, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0x4f8a00,
+ /* 0x100000: 1=MSP enabled (0=disable again)
+ * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+@@ -1524,10 +1420,9 @@ struct tvcard bttv_tvcards[] = {
+ .gpiomute = 0x947fff,
+ /* tvtuner, radio, external,internal, mute, stereo
+ * tuner, Composit, SVid, Composit-on-Svid-adapter */
+- .muxsel = { 2, 3 ,0 ,1 },
++ .muxsel = MUXSEL(2, 3, 0, 1),
+ .tuner_type = TUNER_MT2032,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+@@ -1536,9 +1431,8 @@ struct tvcard bttv_tvcards[] = {
+ /* try "insmod msp3400 simple=0" if you have
+ * sound problems with this card. */
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
+- .svhs = UNSET,
++ /* .audio_inputs= 1, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0x4f8a00,
+ /* 0x100000: 1=MSP enabled (0=disable again)
+ * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+@@ -1546,10 +1440,9 @@ struct tvcard bttv_tvcards[] = {
+ .gpiomute = 0x947fff,
+ /* tvtuner, radio, external,internal, mute, stereo
+ * tuner, Composit, SVid, Composit-on-Svid-adapter */
+- .muxsel = { 2, 3 ,0 ,1 },
++ .muxsel = MUXSEL(2, 3, 0, 1),
+ .tuner_type = TUNER_MT2032,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+@@ -1557,31 +1450,27 @@ struct tvcard bttv_tvcards[] = {
+ /* Philip Blundell <pb@nexus.co.uk> */
+ .name = "Active Imaging AIMMS",
+ .video_inputs = 1,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .tuner_type = UNSET,
++ /* .audio_inputs= 0, */
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+- .muxsel = { 2 },
++ .muxsel = MUXSEL(2),
+ .gpiomask = 0
+ },
+ [BTTV_BOARD_PV_BT878P_PLUS] = {
+ /* Tomasz Pyra <hellfire@sedez.iq.pl> */
+ .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
+ .video_inputs = 3,
+- .audio_inputs = 4,
+- .tuner = 0,
++ /* .audio_inputs= 4, */
+ .svhs = 2,
+ .gpiomask = 15,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0, 11, 7 }, /* TV and Radio with same GPIO ! */
+ .gpiomute = 13,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_LG_PAL_I_FM,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ /* GPIO wiring:
+ GPIO0: U4.A0 (hef4052bt)
+@@ -1594,15 +1483,14 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_FLYVIDEO98EZ] = {
+ .name = "Lifeview FlyVideo 98EZ (capture only) LR51",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
++ /* AV1, AV2, SVHS, CVid adapter on SVHS */
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x48 ---------------------------------- */
+@@ -1610,11 +1498,10 @@ struct tvcard bttv_tvcards[] = {
+ /* Dariusz Kowalewski <darekk@automex.pl> */
+ .name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x3f,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x01, 0x00, 0x03, 0x03 },
+ .gpiomute = 0x09,
+ .needs_tvaudio = 1,
+@@ -1623,7 +1510,6 @@ struct tvcard bttv_tvcards[] = {
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */
+ .has_radio = 1, /* Note: not all cards have radio */
+ .has_remote = 1,
+@@ -1640,49 +1526,42 @@ struct tvcard bttv_tvcards[] = {
+ /* you must jumper JP5 for the card to work */
+ .name = "Sensoray 311",
+ .video_inputs = 5,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 4,
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 0, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0, 0),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 0,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_RV605] = {
+ /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
+ .name = "RemoteVision MX (RV605)",
+ .video_inputs = 16,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0x00,
+ .gpiomask2 = 0x07ff,
+- .muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
+- 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
++ .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .muxsel_hook = rv605_muxsel,
+ },
+ [BTTV_BOARD_POWERCLR_MTV878] = {
+ .name = "Powercolor MTV878/ MTV878R/ MTV878F",
+ .video_inputs = 3,
+- .audio_inputs = 2,
+- .tuner = 0,
++ /* .audio_inputs= 2, */
+ .svhs = 2,
+ .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
+- .muxsel = { 2, 1, 1, },
++ .muxsel = MUXSEL(2, 1, 1),
+ .gpiomux = { 0, 1, 2, 2 },
+ .gpiomute = 4,
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+@@ -1692,42 +1571,38 @@ struct tvcard bttv_tvcards[] = {
+ /* Masaki Suzuki <masaki@btree.org> */
+ .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x140007,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 1, 2, 3 },
+ .gpiomute = 4,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= windvr_audio,
+ },
+ [BTTV_BOARD_GRANDTEC_MULTI] = {
+ .name = "GrandTec Multi Capture Card (Bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_KWORLD] = {
+ .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+ .video_inputs = 4,
+- .audio_inputs = 3,
+- .tuner = 0,
++ /* .audio_inputs= 3, */
+ .svhs = 2,
+ .gpiomask = 7,
+- .muxsel = { 2, 3, 1, 1 }, /* Tuner, SVid, SVHS, SVid to SVHS connector */
++ /* Tuner, SVid, SVHS, SVid to SVHS connector */
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0, 4, 4 },/* Yes, this tuner uses the same audio output for TV and FM radio!
+ * This card lacks external Audio In, so we mute it on Ext. & Int.
+ * The PCB can take a sbx1637/sbx1673, wiring unknown.
+@@ -1741,7 +1616,6 @@ struct tvcard bttv_tvcards[] = {
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+ radio signal strength indicators work fine. */
+ .has_radio = 1,
+@@ -1759,27 +1633,24 @@ struct tvcard bttv_tvcards[] = {
+ /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+ .name = "DSP Design TCVIDEO",
+ .video_inputs = 4,
+- .svhs = UNSET,
+- .muxsel = { 2, 3, 1, 0 },
++ .svhs = NO_SVHS,
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x50 ---------------------------------- */
+ [BTTV_BOARD_HAUPPAUGEPVR] = {
+ .name = "Hauppauge WinTV PVR",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+- .muxsel = { 2, 0, 1, 1 },
++ .muxsel = MUXSEL(2, 0, 1, 1),
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 7,
+ .gpiomux = {7},
+@@ -1787,32 +1658,28 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_GVBCTV5PCI] = {
+ .name = "IODATA GV-BCTV5/PCI",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x0f0f80,
+- .muxsel = {2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = {0x030000, 0x010000, 0, 0 },
+ .gpiomute = 0x020000,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= gvbctv5pci_audio,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_OSPREY1x0] = {
+ .name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
+ .video_inputs = 4, /* id-inputs-clock */
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 3,
+- .muxsel = { 3, 2, 0, 1 },
++ .muxsel = MUXSEL(3, 2, 0, 1),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1820,14 +1687,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY1x0_848] = {
+ .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
+ .video_inputs = 3,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1 },
++ .muxsel = MUXSEL(2, 3, 1),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1837,14 +1702,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY101_848] = {
+ .name = "Osprey 101 (848)", /* 0x05-40C0-C1 */
+ .video_inputs = 2,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 1,
+- .muxsel = { 3, 1 },
++ .muxsel = MUXSEL(3, 1),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1852,14 +1715,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY1x1] = {
+ .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */
+ .video_inputs = 1,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .muxsel = { 0 },
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
++ .muxsel = MUXSEL(0),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1867,14 +1728,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY1x1_SVID] = {
+ .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */
+ .video_inputs = 2,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 1,
+- .muxsel = { 0, 1 },
++ .muxsel = MUXSEL(0, 1),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1882,14 +1741,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY2xx] = {
+ .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */
+ .video_inputs = 1,
+- .audio_inputs = 1,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .muxsel = { 0 },
++ /* .audio_inputs= 1, */
++ .svhs = NO_SVHS,
++ .muxsel = MUXSEL(0),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1899,14 +1756,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY2x0_SVID] = {
+ .name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */
+ .video_inputs = 2,
+- .audio_inputs = 1,
+- .tuner = UNSET,
++ /* .audio_inputs= 1, */
+ .svhs = 1,
+- .muxsel = { 0, 1 },
++ .muxsel = MUXSEL(0, 1),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1914,14 +1769,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY2x0] = {
+ .name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */
+ .video_inputs = 2,
+- .audio_inputs = 1,
+- .tuner = UNSET,
++ /* .audio_inputs= 1, */
+ .svhs = 1,
+- .muxsel = { 2, 3 },
++ .muxsel = MUXSEL(2, 3),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1929,14 +1782,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY500] = {
+ .name = "Osprey 500", /* 500 */
+ .video_inputs = 2,
+- .audio_inputs = 1,
+- .tuner = UNSET,
++ /* .audio_inputs= 1, */
+ .svhs = 1,
+- .muxsel = { 2, 3 },
++ .muxsel = MUXSEL(2, 3),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1944,12 +1795,10 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY540] = {
+ .name = "Osprey 540", /* 540 */
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = UNSET,
++ /* .audio_inputs= 1, */
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -1959,14 +1808,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY2000] = {
+ .name = "Osprey 2000", /* 2000 */
+ .video_inputs = 2,
+- .audio_inputs = 1,
+- .tuner = UNSET,
++ /* .audio_inputs= 1, */
+ .svhs = 1,
+- .muxsel = { 2, 3 },
++ .muxsel = MUXSEL(2, 3),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */
+@@ -1975,14 +1822,12 @@ struct tvcard bttv_tvcards[] = {
+ /* M G Berberich <berberic@forwiss.uni-passau.de> */
+ .name = "IDS Eagle",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .tuner_type = UNSET,
++ /* .audio_inputs= 0, */
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+- .svhs = UNSET,
++ .svhs = NO_SVHS,
+ .gpiomask = 0,
+- .muxsel = { 0, 1, 2, 3 },
++ .muxsel = MUXSEL(2, 2, 2, 2),
+ .muxsel_hook = eagle_muxsel,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+@@ -1991,16 +1836,14 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_PINNACLESAT] = {
+ .name = "Pinnacle PCTV Sat",
+ .video_inputs = 2,
+- .audio_inputs = 0,
++ /* .audio_inputs= 0, */
+ .svhs = 1,
+- .tuner = UNSET,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+- .muxsel = { 3, 1 },
++ .muxsel = MUXSEL(3, 1),
+ .pll = PLL_28,
+ .no_gpioirq = 1,
+ .has_dvb = 1,
+@@ -2008,18 +1851,16 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_FORMAC_PROTV] = {
+ .name = "Formac ProTV II (bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 3,
+ .gpiomask = 2,
+ /* TV, Comp1, Composite over SVID con, SVID */
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 2, 2, 0, 0 },
+ .pll = PLL_28,
+ .has_radio = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ /* sound routing:
+ GPIO=0x00,0x01,0x03: mute (?)
+ 0x02: both TV and radio (tuner: FM1216/I)
+@@ -2033,62 +1874,55 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_MACHTV] = {
+ .name = "MachTV",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
+- .svhs = UNSET,
++ /* .audio_inputs= 1, */
++ .svhs = NO_SVHS,
+ .gpiomask = 7,
+- .muxsel = { 2, 3, 1, 1},
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 1, 2, 3},
+ .gpiomute = 4,
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_EURESYS_PICOLO] = {
+ .name = "Euresys Picolo",
+ .video_inputs = 3,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 2,
+ .gpiomask = 0,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+- .muxsel = { 2, 0, 1},
++ .muxsel = MUXSEL(2, 0, 1),
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_PV150] = {
+ /* Luc Van Hoeylandt <luc@e-magic.be> */
+ .name = "ProVideo PV150", /* 0x4f */
+ .video_inputs = 2,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0,
+- .muxsel = { 2, 3 },
++ .muxsel = MUXSEL(2, 3),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_AD_TVK503] = {
+ /* Hiroshi Takekawa <sian@big.or.jp> */
+ /* This card lacks subsystem ID */
+ .name = "AD-TVK503", /* 0x63 */
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x001e8007,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ /* Tuner, Radio, external, internal, off, on */
+ .gpiomux = { 0x08, 0x0f, 0x0a, 0x08 },
+ .gpiomute = 0x0f,
+@@ -2097,7 +1931,6 @@ struct tvcard bttv_tvcards[] = {
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .audio_mode_gpio= adtvk503_audio,
+ },
+
+@@ -2105,17 +1938,15 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_HERCULES_SM_TV] = {
+ .name = "Hercules Smart TV Stereo",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ /* Notes:
+ - card lacks subsystem ID
+ - stereo variant w/ daughter board with tda9874a @0xb0
+@@ -2129,16 +1960,15 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_PACETV] = {
+ .name = "Pace TV & Radio Card",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1, 1 }, /* Tuner, CVid, SVid, CVid over SVid connector */
++ /* Tuner, CVid, SVid, CVid over SVid connector */
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomask = 0,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ .pll = PLL_28,
+ /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
+@@ -2152,27 +1982,34 @@ struct tvcard bttv_tvcards[] = {
+ /* Chris Willing <chris@vislab.usyd.edu.au> */
+ .name = "IVC-200",
+ .video_inputs = 1,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .tuner_type = UNSET,
++ /* .audio_inputs= 0, */
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+- .svhs = UNSET,
++ .svhs = NO_SVHS,
++ .gpiomask = 0xdf,
++ .muxsel = MUXSEL(2),
++ .pll = PLL_28,
++ },
++ [BTTV_BOARD_IVCE8784] = {
++ .name = "IVCE-8784",
++ .video_inputs = 1,
++ /* .audio_inputs= 0, */
++ .tuner_type = TUNER_ABSENT,
++ .tuner_addr = ADDR_UNSET,
++ .svhs = NO_SVHS,
+ .gpiomask = 0xdf,
+- .muxsel = { 2 },
++ .muxsel = MUXSEL(2),
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_XGUARD] = {
+ .name = "Grand X-Guard / Trust 814PCI",
+ .video_inputs = 16,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .gpiomask2 = 0xff,
+- .muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
++ .muxsel = MUXSEL(2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0),
+ .muxsel_hook = xguard_muxsel,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+@@ -2184,16 +2021,14 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_NEBULA_DIGITV] = {
+ .name = "Nebula Electronics DigiTV",
+ .video_inputs = 1,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .muxsel = { 2, 3, 1, 0 },
++ .svhs = NO_SVHS,
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_dvb = 1,
+ .has_remote = 1,
+ .gpiomask = 0x1b,
+@@ -2203,118 +2038,101 @@ struct tvcard bttv_tvcards[] = {
+ /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
+ .name = "ProVideo PV143",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD009X1_VD011_MINIDIN] = {
+ /* M.Klahr@phytec.de */
+ .name = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET, /* card has no tuner */
++ /* .audio_inputs= 0, */
+ .svhs = 3,
+ .gpiomask = 0x00,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD009X1_VD011_COMBI] = {
+ .name = "PHYTEC VD-009-X1 VD-011 Combi (bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET, /* card has no tuner */
++ /* .audio_inputs= 0, */
+ .svhs = 3,
+ .gpiomask = 0x00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x6c ---------------------------------- */
+ [BTTV_BOARD_VD009_MINIDIN] = {
+ .name = "PHYTEC VD-009 MiniDIN (bt878)",
+ .video_inputs = 10,
+- .audio_inputs = 0,
+- .tuner = UNSET, /* card has no tuner */
++ /* .audio_inputs= 0, */
+ .svhs = 9,
+ .gpiomask = 0x00,
+- .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
+- via the upper nibble of muxsel. here: used for
+- xternal video-mux */
+- .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
++ .gpiomask2 = 0x03, /* used for external vodeo mux */
++ .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 0),
++ .muxsel_hook = phytec_muxsel,
+ .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD009_COMBI] = {
+ .name = "PHYTEC VD-009 Combi (bt878)",
+ .video_inputs = 10,
+- .audio_inputs = 0,
+- .tuner = UNSET, /* card has no tuner */
++ /* .audio_inputs= 0, */
+ .svhs = 9,
+ .gpiomask = 0x00,
+- .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
+- via the upper nibble of muxsel. here: used for
+- xternal video-mux */
+- .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
++ .gpiomask2 = 0x03, /* used for external vodeo mux */
++ .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 1),
++ .muxsel_hook = phytec_muxsel,
+ .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_IVC100] = {
+ .name = "IVC-100",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .tuner_type = UNSET,
++ /* .audio_inputs= 0, */
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+- .svhs = UNSET,
++ .svhs = NO_SVHS,
+ .gpiomask = 0xdf,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_IVC120] = {
+ /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
+ .name = "IVC-120G",
+ .video_inputs = 16,
+- .audio_inputs = 0, /* card has no audio */
+- .tuner = UNSET, /* card has no tuner */
+- .tuner_type = UNSET,
++ /* .audio_inputs= 0, */
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+- .svhs = UNSET, /* card has no svhs */
++ .svhs = NO_SVHS, /* card has no svhs */
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .gpiomask = 0x00,
+- .muxsel = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+- 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
++ .muxsel = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ .muxsel_hook = ivc120_muxsel,
+ .pll = PLL_28,
+ },
+@@ -2323,13 +2141,11 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_PC_HDTV] = {
+ .name = "pcHDTV HD-2000 TV",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .tuner_type = TUNER_PHILIPS_FCV1236D,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_dvb = 1,
+ },
+ [BTTV_BOARD_TWINHAN_DST] = {
+@@ -2339,38 +2155,34 @@ struct tvcard bttv_tvcards[] = {
+ .no_tda7432 = 1,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_video = 1,
+ .has_dvb = 1,
+ },
+ [BTTV_BOARD_WINFASTVC100] = {
+ .name = "Winfast VC100",
+ .video_inputs = 3,
+- .audio_inputs = 0,
++ /* .audio_inputs= 0, */
+ .svhs = 1,
+- .tuner = UNSET,
+- .muxsel = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
++ /* Vid In, SVid In, Vid over SVid in connector */
++ .muxsel = MUXSEL(3, 1, 1, 3),
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_TEV560] = {
+ .name = "Teppro TEV-560/InterVision IV-560",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 3,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 1, 1, 1, 1 },
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_35,
+ },
+
+@@ -2378,14 +2190,12 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_SIMUS_GVC1100] = {
+ .name = "SIMUS GVC1100",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .tuner_type = UNSET,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+- .muxsel = { 2, 2, 2, 2 },
++ .muxsel = MUXSEL(2, 2, 2, 2),
+ .gpiomask = 0x3F,
+ .muxsel_hook = gvc1100_muxsel,
+ },
+@@ -2393,47 +2203,41 @@ struct tvcard bttv_tvcards[] = {
+ /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
+ .name = "NGS NGSTV+",
+ .video_inputs = 3,
+- .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x008007,
+- .muxsel = { 2, 3, 0, 0 },
++ .muxsel = MUXSEL(2, 3, 0, 0),
+ .gpiomux = { 0, 0, 0, 0 },
+ .gpiomute = 0x000003,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_LMLBT4] = {
+ /* http://linuxmedialabs.com */
+ .name = "LMLBT4",
+ .video_inputs = 4, /* IN1,IN2,IN3,IN4 */
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .muxsel = { 2, 3, 1, 0 },
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .needs_tvaudio = 0,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TEKRAM_M205] = {
+ /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
+ .name = "Tekram M205 PRO",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .svhs = 2,
+ .needs_tvaudio = 0,
+ .gpiomask = 0x68,
+- .muxsel = { 2, 3, 1 },
++ .muxsel = MUXSEL(2, 3, 1),
+ .gpiomux = { 0x68, 0x68, 0x61, 0x61 },
+ .pll = PLL_28,
+ },
+@@ -2444,18 +2248,16 @@ struct tvcard bttv_tvcards[] = {
+ /* bt878 TV + FM without subsystem ID */
+ .name = "Conceptronic CONTVFMi",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x008007,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 1, 2, 2 },
+ .gpiomute = 3,
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
+@@ -2466,37 +2268,34 @@ struct tvcard bttv_tvcards[] = {
+ /*0x79 in bttv.h*/
+ .name = "Euresys Picolo Tetra",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0,
+ .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+- .muxsel = {2,2,2,2},/*878A input is always MUX0, see above.*/
++ /*878A input is always MUX0, see above.*/
++ .muxsel = MUXSEL(2, 2, 2, 2),
+ .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
+ .pll = PLL_28,
+ .needs_tvaudio = 0,
+ .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_SPIRIT_TV] = {
+ /* Spirit TV Tuner from http://spiritmodems.com.au */
+ /* Stafford Goodsell <surge@goliath.homeunix.org> */
+ .name = "Spirit TV Tuner",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x0000000f,
+- .muxsel = { 2, 1, 1 },
++ .muxsel = MUXSEL(2, 1, 1),
+ .gpiomux = { 0x02, 0x00, 0x00, 0x00 },
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ },
+@@ -2505,11 +2304,9 @@ struct tvcard bttv_tvcards[] = {
+ .name = "AVerMedia AVerTV DVB-T 771",
+ .video_inputs = 2,
+ .svhs = 1,
+- .tuner = UNSET,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+- .muxsel = { 3 , 3 },
++ .muxsel = MUXSEL(3, 3),
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -2524,54 +2321,47 @@ struct tvcard bttv_tvcards[] = {
+ /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
+ .name = "AverMedia AverTV DVB-T 761",
+ .video_inputs = 2,
+- .tuner = UNSET,
+ .svhs = 1,
+- .muxsel = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
++ .muxsel = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_dvb = 1,
+ .no_gpioirq = 1,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_MATRIX_VISIONSQ] = {
+ /* andre.schwarz@matrix-vision.de */
+- .name = "MATRIX Vision Sigma-SQ",
+- .video_inputs = 16,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .gpiomask = 0x0,
+- .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
+- 3, 3, 3, 3, 3, 3, 3, 3 },
+- .muxsel_hook = sigmaSQ_muxsel,
+- .gpiomux = { 0 },
+- .no_msp34xx = 1,
+- .pll = PLL_28,
+- .tuner_type = UNSET,
+- .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
++ .name = "MATRIX Vision Sigma-SQ",
++ .video_inputs = 16,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
++ .gpiomask = 0x0,
++ .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3),
++ .muxsel_hook = sigmaSQ_muxsel,
++ .gpiomux = { 0 },
++ .no_msp34xx = 1,
++ .pll = PLL_28,
++ .tuner_type = TUNER_ABSENT,
++ .tuner_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MATRIX_VISIONSLC] = {
+ /* andre.schwarz@matrix-vision.de */
+- .name = "MATRIX Vision Sigma-SLC",
+- .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .gpiomask = 0x0,
+- .muxsel = { 2, 2, 2, 2 },
+- .muxsel_hook = sigmaSLC_muxsel,
+- .gpiomux = { 0 },
+- .no_msp34xx = 1,
+- .pll = PLL_28,
+- .tuner_type = UNSET,
+- .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
++ .name = "MATRIX Vision Sigma-SLC",
++ .video_inputs = 4,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
++ .gpiomask = 0x0,
++ .muxsel = MUXSEL(2, 2, 2, 2),
++ .muxsel_hook = sigmaSLC_muxsel,
++ .gpiomux = { 0 },
++ .no_msp34xx = 1,
++ .pll = PLL_28,
++ .tuner_type = TUNER_ABSENT,
++ .tuner_addr = ADDR_UNSET,
+ },
+ /* BTTV_BOARD_APAC_VIEWCOMP */
+ [BTTV_BOARD_APAC_VIEWCOMP] = {
+@@ -2579,18 +2369,16 @@ struct tvcard bttv_tvcards[] = {
+ /* bt878 TV + FM 0x00000000 subsystem ID */
+ .name = "APAC Viewcomp 878(AMAX)",
+ .video_inputs = 2,
+- .audio_inputs = 1,
+- .tuner = 0,
+- .svhs = UNSET,
++ /* .audio_inputs= 1, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0xFF,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 2, 0, 0, 0 },
+ .gpiomute = 10,
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */
+ .has_radio = 1, /* not every card has radio */
+ },
+@@ -2599,46 +2387,40 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_DVICO_DVBT_LITE] = {
+ /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
+ .name = "DViCO FusionHDTV DVB-T Lite",
+- .tuner = UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .no_video = 1,
+ .has_dvb = 1,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VGEAR_MYVCD] = {
+ /* Steven <photon38@pchome.com.tw> */
+ .name = "V-Gear MyVCD",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x3f,
+- .muxsel = {2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .gpiomux = {0x31, 0x31, 0x31, 0x31 },
+ .gpiomute = 0x31,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_radio = 0,
+ },
+ [BTTV_BOARD_SUPER_TV] = {
+ /* Rick C <cryptdragoon@gmail.com> */
+ .name = "Super TV Tuner",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x008007,
+ .gpiomux = { 0, 0x000001,0,0 },
+ .needs_tvaudio = 1,
+@@ -2648,17 +2430,15 @@ struct tvcard bttv_tvcards[] = {
+ /* Chris Fanning <video4linux@haydon.net> */
+ .name = "Tibet Systems 'Progress DVR' CS16",
+ .video_inputs = 16,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
++ .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .muxsel_hook = tibetCS16_muxsel,
+ },
+ [BTTV_BOARD_KODICOM_4400R] = {
+@@ -2675,12 +2455,10 @@ struct tvcard bttv_tvcards[] = {
+ */
+ .name = "Kodicom 4400R (master)",
+ .video_inputs = 16,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .tuner_type = UNSET,
++ /* .audio_inputs= 0, */
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+- .svhs = UNSET,
++ .svhs = NO_SVHS,
+ /* GPIO bits 0-9 used for analog switch:
+ * 00 - 03: camera selector
+ * 04 - 06: channel (controller) selector
+@@ -2691,7 +2469,7 @@ struct tvcard bttv_tvcards[] = {
+ */
+ .gpiomask = 0x0003ff,
+ .no_gpioirq = 1,
+- .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
++ .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+@@ -2707,15 +2485,13 @@ struct tvcard bttv_tvcards[] = {
+ */
+ .name = "Kodicom 4400R (slave)",
+ .video_inputs = 16,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .tuner_type = UNSET,
++ /* .audio_inputs= 0, */
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+- .svhs = UNSET,
++ .svhs = NO_SVHS,
+ .gpiomask = 0x010000,
+ .no_gpioirq = 1,
+- .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
++ .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+@@ -2728,27 +2504,23 @@ struct tvcard bttv_tvcards[] = {
+ /* Adlink RTV24 with special unlock codes */
+ .name = "Adlink RTV24",
+ .video_inputs = 4,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1, 0 },
++ .muxsel = MUXSEL(2, 3, 1, 0),
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ /* ---- card 0x87---------------------------------- */
+ [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = {
+ /* Michael Krufky <mkrufky@m1k.net> */
+ .name = "DViCO FusionHDTV 5 Lite",
+- .tuner = 0,
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .video_inputs = 3,
+- .audio_inputs = 1,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1 },
++ .muxsel = MUXSEL(2, 3, 1),
+ .gpiomask = 0x00e00007,
+ .gpiomux = { 0x00400005, 0, 0x00000001, 0 },
+ .gpiomute = 0x00c00007,
+@@ -2762,75 +2534,68 @@ struct tvcard bttv_tvcards[] = {
+ /* Mauro Carvalho Chehab <mchehab@infradead.org> */
+ .name = "Acorp Y878F",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x01fe00,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 },
+ .gpiomute = 0x002000,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_YMEC_TVF66T5_B_DFF,
+ .tuner_addr = 0xc1 >>1,
+- .radio_addr = 0xc1 >>1,
+ .has_radio = 1,
+ },
+ /* ---- card 0x89 ---------------------------------- */
+ [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = {
+ .name = "Conceptronic CTVFMi v2",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x001c0007,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 1, 2, 2 },
+ .gpiomute = 3,
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TENA_9533_DI,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
+ /* ---- card 0x8a ---------------------------------- */
+ [BTTV_BOARD_PV_BT878P_2E] = {
+- .name = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
+- .video_inputs = 5,
+- .audio_inputs = 1,
+- .tuner = 0,
+- .svhs = 3,
+- .gpiomask = 0x01fe00,
+- .muxsel = { 2,3,1,1,-1 },
+- .digital_mode = DIGITAL_MODE_CAMERA,
+- .gpiomux = { 0x00400, 0x10400, 0x04400, 0x80000 },
+- .gpiomute = 0x12400,
+- .no_msp34xx = 1,
+- .pll = PLL_28,
+- .tuner_type = TUNER_LG_PAL_FM,
+- .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+- .has_remote = 1,
++ .name = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
++ .video_inputs = 5,
++ /* .audio_inputs= 1, */
++ .svhs = 3,
++ .has_dig_in = 1,
++ .gpiomask = 0x01fe00,
++ .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */
++ /* .digital_mode= DIGITAL_MODE_CAMERA, */
++ .gpiomux = { 0x00400, 0x10400, 0x04400, 0x80000 },
++ .gpiomute = 0x12400,
++ .no_msp34xx = 1,
++ .pll = PLL_28,
++ .tuner_type = TUNER_LG_PAL_FM,
++ .tuner_addr = ADDR_UNSET,
++ .has_remote = 1,
+ },
+ /* ---- card 0x8b ---------------------------------- */
+ [BTTV_BOARD_PV_M4900] = {
+ /* Sérgio Fortier <sergiofortier@yahoo.com.br> */
+ .name = "Prolink PixelView PlayTV MPEG2 PV-M4900",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x3f,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x21, 0x20, 0x24, 0x2c },
+ .gpiomute = 0x29,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_YMEC_TVF_5533MF,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ .has_remote = 1,
+ },
+@@ -2850,17 +2615,15 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_OSPREY440] = {
+ .name = "Osprey 440",
+ .video_inputs = 4,
+- .audio_inputs = 2, /* this is meaningless */
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .muxsel = { 2, 3, 0, 1 }, /* 3,0,1 are guesses */
++ /* .audio_inputs= 2, */
++ .svhs = NO_SVHS,
++ .muxsel = MUXSEL(2, 3, 0, 1), /* 3,0,1 are guesses */
+ .gpiomask = 0x303,
+ .gpiomute = 0x000, /* int + 32kHz */
+ .gpiomux = { 0, 0, 0x000, 0x100},
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+@@ -2869,28 +2632,25 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_ASOUND_SKYEYE] = {
+ .name = "Asound Skyeye PCTV",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 15,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 2, 0, 0, 0 },
+ .gpiomute = 1,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ /* ---- card 0x8e ---------------------------------- */
+ [BTTV_BOARD_SABRENT_TVFM] = {
+ .name = "Sabrent TV-FM (bttv version)",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x108007,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 100000, 100002, 100002, 100000 },
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+@@ -2904,17 +2664,15 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = {
+ .name = "Hauppauge ImpactVCB (bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0x0f, /* old: 7 */
+- .muxsel = { 0, 1, 3, 2 }, /* Composite 0-3 */
++ .muxsel = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MACHTV_MAGICTV] = {
+ /* Julian Calaby <julian.calaby@gmail.com>
+@@ -2926,16 +2684,14 @@ struct tvcard bttv_tvcards[] = {
+
+ .name = "MagicTV", /* rebranded MachTV */
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 7,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 1, 2, 3 },
+ .gpiomute = 4,
+ .tuner_type = TUNER_TEMIC_4009FR5_PAL,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ .has_remote = 1,
+@@ -2943,36 +2699,30 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_SSAI_SECURITY] = {
+ .name = "SSAI Security Video Interface",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .muxsel = { 0, 1, 2, 3 },
+- .tuner_type = UNSET,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
++ .muxsel = MUXSEL(0, 1, 2, 3),
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_SSAI_ULTRASOUND] = {
+ .name = "SSAI Ultrasound Video Interface",
+ .video_inputs = 2,
+- .audio_inputs = 0,
+- .tuner = UNSET,
++ /* .audio_inputs= 0, */
+ .svhs = 1,
+- .muxsel = { 2, 0, 1, 3 },
+- .tuner_type = UNSET,
++ .muxsel = MUXSEL(2, 0, 1, 3),
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ /* ---- card 0x94---------------------------------- */
+ [BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
+ .name = "DViCO FusionHDTV 2",
+- .tuner = 0,
+ .tuner_type = TUNER_PHILIPS_FCV1236D,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .video_inputs = 3,
+- .audio_inputs = 1,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+- .muxsel = { 2, 3, 1 },
++ .muxsel = MUXSEL(2, 3, 1),
+ .gpiomask = 0x00e00007,
+ .gpiomux = { 0x00400005, 0, 0x00000001, 0 },
+ .gpiomute = 0x00c00007,
+@@ -2984,36 +2734,31 @@ struct tvcard bttv_tvcards[] = {
+ [BTTV_BOARD_TYPHOON_TVTUNERPCI] = {
+ .name = "Typhoon TV-Tuner PCI (50684)",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x3014f,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0x20001,0x10001, 0, 0 },
+ .gpiomute = 10,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_GEOVISION_GV600] = {
+ /* emhn@usb.ve */
+- .name = "Geovision GV-600",
+- .video_inputs = 16,
+- .audio_inputs = 0,
+- .tuner = UNSET,
+- .svhs = UNSET,
+- .gpiomask = 0x0,
+- .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 2, 2, 2, 2, 2 },
+- .muxsel_hook = geovision_muxsel,
+- .gpiomux = { 0 },
+- .no_msp34xx = 1,
+- .pll = PLL_28,
+- .tuner_type = UNSET,
+- .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
++ .name = "Geovision GV-600",
++ .video_inputs = 16,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
++ .gpiomask = 0x0,
++ .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
++ .muxsel_hook = geovision_muxsel,
++ .gpiomux = { 0 },
++ .no_msp34xx = 1,
++ .pll = PLL_28,
++ .tuner_type = TUNER_ABSENT,
++ .tuner_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_KOZUMI_KTV_01C] = {
+ /* Mauro Lacy <mauro@lacy.com.ar>
+@@ -3021,17 +2766,15 @@ struct tvcard bttv_tvcards[] = {
+
+ .name = "Kozumi KTV-01C",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ .gpiomask = 0x008007,
+- .muxsel = { 2, 3, 1, 1 },
++ .muxsel = MUXSEL(2, 3, 1, 1),
+ .gpiomux = { 0, 1, 2, 2 }, /* CONTVFMi */
+ .gpiomute = 3, /* CONTVFMi */
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ .has_remote = 1,
+@@ -3041,8 +2784,7 @@ struct tvcard bttv_tvcards[] = {
+ Mauro Carvalho Chehab <mchehab@infradead.org */
+ .name = "Encore ENL TV-FM-2",
+ .video_inputs = 3,
+- .audio_inputs = 1,
+- .tuner = 0,
++ /* .audio_inputs= 1, */
+ .svhs = 2,
+ /* bit 6 -> IR disabled
+ bit 18/17 = 00 -> mute
+@@ -3051,12 +2793,11 @@ struct tvcard bttv_tvcards[] = {
+ 11 -> internal audio input
+ */
+ .gpiomask = 0x060040,
+- .muxsel = { 2, 3, 3 },
++ .muxsel = MUXSEL(2, 3, 3),
+ .gpiomux = { 0x60000, 0x60000, 0x20000, 0x20000 },
+ .gpiomute = 0,
+ .tuner_type = TUNER_TCL_MF02GIP_5N,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ .has_remote = 1,
+@@ -3065,50 +2806,111 @@ struct tvcard bttv_tvcards[] = {
+ /* D.Heer@Phytec.de */
+ .name = "PHYTEC VD-012 (bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET, /* card has no tuner */
+- .svhs = UNSET, /* card has no s-video */
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
+ .gpiomask = 0x00,
+- .muxsel = { 0, 2, 3, 1 },
++ .muxsel = MUXSEL(0, 2, 3, 1),
+ .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD012_X1] = {
+ /* D.Heer@Phytec.de */
+ .name = "PHYTEC VD-012-X1 (bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET, /* card has no tuner */
++ /* .audio_inputs= 0, */
+ .svhs = 3,
+ .gpiomask = 0x00,
+- .muxsel = { 2, 3, 1 },
++ .muxsel = MUXSEL(2, 3, 1),
+ .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD012_X2] = {
+ /* D.Heer@Phytec.de */
+ .name = "PHYTEC VD-012-X2 (bt878)",
+ .video_inputs = 4,
+- .audio_inputs = 0,
+- .tuner = UNSET, /* card has no tuner */
++ /* .audio_inputs= 0, */
+ .svhs = 3,
+ .gpiomask = 0x00,
+- .muxsel = { 3, 2, 1 },
++ .muxsel = MUXSEL(3, 2, 1),
+ .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+- .tuner_type = UNSET,
++ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
+- }
++ },
++ [BTTV_BOARD_GEOVISION_GV800S] = {
++ /* Bruno Christo <bchristo@inf.ufsm.br>
++ *
++ * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
++ * 1 audio input per BT878A = 4 audio inputs
++ * 4 video inputs per BT878A = 16 video inputs
++ * This is the first BT878A chip of the GV-800(S). It's the
++ * "master" chip and it controls the video inputs through an
++ * analog multiplexer (a CD22M3494) via some GPIO pins. The
++ * slaves should use card type 0x9e (following this one).
++ * There is a EEPROM on the card which is currently not handled.
++ * The audio input is not working yet.
++ */
++ .name = "Geovision GV-800(S) (master)",
++ .video_inputs = 4,
++ /* .audio_inputs= 1, */
++ .tuner_type = TUNER_ABSENT,
++ .tuner_addr = ADDR_UNSET,
++ .svhs = NO_SVHS,
++ .gpiomask = 0xf107f,
++ .no_gpioirq = 1,
++ .muxsel = MUXSEL(2, 2, 2, 2),
++ .pll = PLL_28,
++ .no_msp34xx = 1,
++ .no_tda7432 = 1,
++ .no_tda9875 = 1,
++ .muxsel_hook = gv800s_muxsel,
++ },
++ [BTTV_BOARD_GEOVISION_GV800S_SL] = {
++ /* Bruno Christo <bchristo@inf.ufsm.br>
++ *
++ * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
++ * 1 audio input per BT878A = 4 audio inputs
++ * 4 video inputs per BT878A = 16 video inputs
++ * The 3 other BT878A chips are "slave" chips of the GV-800(S)
++ * and should use this card type.
++ * The audio input is not working yet.
++ */
++ .name = "Geovision GV-800(S) (slave)",
++ .video_inputs = 4,
++ /* .audio_inputs= 1, */
++ .tuner_type = TUNER_ABSENT,
++ .tuner_addr = ADDR_UNSET,
++ .svhs = NO_SVHS,
++ .gpiomask = 0x00,
++ .no_gpioirq = 1,
++ .muxsel = MUXSEL(2, 2, 2, 2),
++ .pll = PLL_28,
++ .no_msp34xx = 1,
++ .no_tda7432 = 1,
++ .no_tda9875 = 1,
++ .muxsel_hook = gv800s_muxsel,
++ },
++ [BTTV_BOARD_PV183] = {
++ .name = "ProVideo PV183", /* 0x9f */
++ .video_inputs = 2,
++ /* .audio_inputs= 0, */
++ .svhs = NO_SVHS,
++ .gpiomask = 0,
++ .muxsel = MUXSEL(2, 3),
++ .gpiomux = { 0 },
++ .needs_tvaudio = 0,
++ .no_msp34xx = 1,
++ .pll = PLL_28,
++ .tuner_type = TUNER_ABSENT,
++ .tuner_addr = ADDR_UNSET,
++ },
+ };
+
+ static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
+@@ -3152,7 +2954,7 @@ void __devinit bttv_idcard(struct bttv *btv)
+ btv->c.nr, btv->cardid & 0xffff,
+ (btv->cardid >> 16) & 0xffff);
+ printk(KERN_DEBUG "please mail id, board name and "
+- "the correct card= insmod option to video4linux-list@redhat.com\n");
++ "the correct card= insmod option to linux-media@vger.kernel.org\n");
+ }
+ }
+
+@@ -3403,8 +3205,7 @@ static void init_ids_eagle(struct bttv *btv)
+ * has its own multiplexer */
+ static void eagle_muxsel(struct bttv *btv, unsigned int input)
+ {
+- btaor((2)<<5, ~(3<<5), BT848_IFORM);
+- gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]);
++ gpio_bits(3, input & 3);
+
+ /* composite */
+ /* set chroma ADC to sleep */
+@@ -3523,6 +3324,17 @@ void __devinit bttv_init_card1(struct bttv *btv)
+ /* initialization part two -- after registering i2c bus */
+ void __devinit bttv_init_card2(struct bttv *btv)
+ {
++ static const unsigned short tvaudio_addrs[] = {
++ I2C_ADDR_TDA8425 >> 1,
++ I2C_ADDR_TEA6300 >> 1,
++ I2C_ADDR_TEA6420 >> 1,
++ I2C_ADDR_TDA9840 >> 1,
++ I2C_ADDR_TDA985x_L >> 1,
++ I2C_ADDR_TDA985x_H >> 1,
++ I2C_ADDR_TDA9874 >> 1,
++ I2C_ADDR_PIC16C54 >> 1,
++ I2C_CLIENT_END
++ };
+ int addr=ADDR_UNSET;
+
+ btv->tuner_type = UNSET;
+@@ -3629,6 +3441,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
+ case BTTV_BOARD_KODICOM_4400R:
+ kodicom4400r_init(btv);
+ break;
++ case BTTV_BOARD_GEOVISION_GV800S:
++ gv800s_init(btv);
++ break;
+ }
+
+ /* pll configuration */
+@@ -3670,13 +3485,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
+ addr = bttv_tvcards[btv->c.type].tuner_addr;
+
+ if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
+- if(UNSET == btv->tuner_type)
++ if (UNSET == btv->tuner_type)
+ btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
+ if (UNSET != tuner[btv->c.nr])
+ btv->tuner_type = tuner[btv->c.nr];
+
+- if (btv->tuner_type == TUNER_ABSENT ||
+- bttv_tvcards[btv->c.type].tuner == UNSET)
++ if (btv->tuner_type == TUNER_ABSENT)
+ printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr);
+ else if(btv->tuner_type == UNSET)
+ printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr);
+@@ -3684,14 +3498,35 @@ void __devinit bttv_init_card2(struct bttv *btv)
+ printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
+ btv->tuner_type);
+
+- if (btv->tuner_type != UNSET) {
++ if (autoload != UNSET) {
++ printk(KERN_WARNING "bttv%d: the autoload option is obsolete.\n", btv->c.nr);
++ printk(KERN_WARNING "bttv%d: use option msp3400, tda7432 or tvaudio to\n", btv->c.nr);
++ printk(KERN_WARNING "bttv%d: override which audio module should be used.\n", btv->c.nr);
++ }
++
++ if (UNSET == btv->tuner_type)
++ btv->tuner_type = TUNER_ABSENT;
++
++ if (btv->tuner_type != TUNER_ABSENT) {
+ struct tuner_setup tun_setup;
+
++ /* Load tuner module before issuing tuner config call! */
++ if (bttv_tvcards[btv->c.type].has_radio)
++ v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
++ "tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_RADIO));
++ v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
++ "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
++ v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap, "tuner",
++ "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
++
+ tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.type = btv->tuner_type;
+ tun_setup.addr = addr;
+
+- bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
++ if (bttv_tvcards[btv->c.type].has_radio)
++ tun_setup.mode_mask |= T_RADIO;
++
++ bttv_call_all(btv, tuner, s_type_addr, &tun_setup);
+ }
+
+ if (btv->tda9887_conf) {
+@@ -3700,10 +3535,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &btv->tda9887_conf;
+
+- bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg);
++ bttv_call_all(btv, tuner, s_config, &tda9887_cfg);
+ }
+
+- btv->svhs = bttv_tvcards[btv->c.type].svhs;
++ btv->dig = bttv_tvcards[btv->c.type].has_dig_in ?
++ bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET;
++ btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ?
++ UNSET : bttv_tvcards[btv->c.type].svhs;
+ if (svhs[btv->c.nr] != UNSET)
+ btv->svhs = svhs[btv->c.nr];
+ if (remote[btv->c.nr] != UNSET)
+@@ -3720,34 +3558,127 @@ void __devinit bttv_init_card2(struct bttv *btv)
+ if (bttv_tvcards[btv->c.type].audio_mode_gpio)
+ btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
+
+- if (!autoload)
+- return;
+-
+- if (bttv_tvcards[btv->c.type].tuner == UNSET)
++ if (btv->tuner_type == TUNER_ABSENT)
+ return; /* no tuner or related drivers to load */
+
++ if (btv->has_saa6588 || saa6588[btv->c.nr]) {
++ /* Probe for RDS receiver chip */
++ static const unsigned short addrs[] = {
++ 0x20 >> 1,
++ 0x22 >> 1,
++ I2C_CLIENT_END
++ };
++ struct v4l2_subdev *sd;
++
++ sd = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
++ "saa6588", "saa6588", addrs);
++ btv->has_saa6588 = (sd != NULL);
++ }
++
+ /* try to detect audio/fader chips */
+- if (!bttv_tvcards[btv->c.type].no_msp34xx &&
+- bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
+- request_module("msp3400");
+
+- if (bttv_tvcards[btv->c.type].msp34xx_alt &&
+- bttv_I2CRead(btv, I2C_ADDR_MSP3400_ALT, "MSP34xx (alternate address)") >=0)
+- request_module("msp3400");
++ /* First check if the user specified the audio chip via a module
++ option. */
++
++ switch (audiodev[btv->c.nr]) {
++ case -1:
++ return; /* do not load any audio module */
++
++ case 0: /* autodetect */
++ break;
++
++ case 1: {
++ /* The user specified that we should probe for msp3400 */
++ static const unsigned short addrs[] = {
++ I2C_ADDR_MSP3400 >> 1,
++ I2C_ADDR_MSP3400_ALT >> 1,
++ I2C_CLIENT_END
++ };
++
++ btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
++ "msp3400", "msp3400", addrs);
++ if (btv->sd_msp34xx)
++ return;
++ goto no_audio;
++ }
++
++ case 2: {
++ /* The user specified that we should probe for tda7432 */
++ static const unsigned short addrs[] = {
++ I2C_ADDR_TDA7432 >> 1,
++ I2C_CLIENT_END
++ };
++
++ if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
++ "tda7432", "tda7432", addrs))
++ return;
++ goto no_audio;
++ }
++
++ case 3: {
++ /* The user specified that we should probe for tvaudio */
++ btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
++ "tvaudio", "tvaudio", tvaudio_addrs);
++ if (btv->sd_tvaudio)
++ return;
++ goto no_audio;
++ }
++
++ default:
++ printk(KERN_WARNING "bttv%d: unknown audiodev value!\n",
++ btv->c.nr);
++ return;
++ }
+
+- if (!bttv_tvcards[btv->c.type].no_tda9875 &&
+- bttv_I2CRead(btv, I2C_ADDR_TDA9875, "TDA9875") >=0)
+- request_module("tda9875");
++ /* There were no overrides, so now we try to discover this through the
++ card definition */
++
++ /* probe for msp3400 first: this driver can detect whether or not
++ it really is a msp3400, so it will return NULL when the device
++ found is really something else (e.g. a tea6300). */
++ if (!bttv_tvcards[btv->c.type].no_msp34xx) {
++ static const unsigned short addrs[] = {
++ I2C_ADDR_MSP3400 >> 1,
++ I2C_CLIENT_END
++ };
++
++ btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
++ "msp3400", "msp3400", addrs);
++ } else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
++ static const unsigned short addrs[] = {
++ I2C_ADDR_MSP3400_ALT >> 1,
++ I2C_CLIENT_END
++ };
++
++ btv->sd_msp34xx = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
++ "msp3400", "msp3400", addrs);
++ }
+
+- if (!bttv_tvcards[btv->c.type].no_tda7432 &&
+- bttv_I2CRead(btv, I2C_ADDR_TDA7432, "TDA7432") >=0)
+- request_module("tda7432");
++ /* If we found a msp34xx, then we're done. */
++ if (btv->sd_msp34xx)
++ return;
+
+- if (bttv_tvcards[btv->c.type].needs_tvaudio)
+- request_module("tvaudio");
++ /* it might also be a tda7432. */
++ if (!bttv_tvcards[btv->c.type].no_tda7432) {
++ static const unsigned short addrs[] = {
++ I2C_ADDR_TDA7432 >> 1,
++ I2C_CLIENT_END
++ };
+
+- if (btv->tuner_type != UNSET && btv->tuner_type != TUNER_ABSENT)
+- request_module("tuner");
++ if (v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
++ "tda7432", "tda7432", addrs))
++ return;
++ }
++
++ /* Now see if we can find one of the tvaudio devices. */
++ btv->sd_tvaudio = v4l2_i2c_new_probed_subdev(&btv->c.i2c_adap,
++ "tvaudio", "tvaudio", tvaudio_addrs);
++ if (btv->sd_tvaudio)
++ return;
++
++no_audio:
++ printk(KERN_WARNING "bttv%d: audio absent, no audio device found!\n",
++ btv->c.nr);
+ }
+
+
+@@ -3819,6 +3750,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv)
+ printk("bttv%d: Terratec Active Radio Upgrade found.\n",
+ btv->c.nr);
+ btv->has_radio = 1;
++ btv->has_saa6588 = 1;
+ btv->has_matchbox = 1;
+ } else {
+ btv->has_radio = 0;
+@@ -4067,27 +3999,26 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
+ btv->has_remote ? "yes" : "no");
+ }
+
+-/* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */
+-void bttv_tda9880_setnorm(struct bttv *btv, int norm)
++/*
++ * For Voodoo TV/FM and Voodoo 200. These cards' tuners use a TDA9880
++ * analog demod, which is not I2C controlled like the newer and more common
++ * TDA9887 series. Instead is has two tri-state input pins, S0 and S1,
++ * that control the IF for the video and audio. Apparently, bttv GPIO
++ * 0x10000 is connected to S0. S0 low selects a 38.9 MHz VIF for B/G/D/K/I
++ * (i.e., PAL) while high selects 45.75 MHz for M/N (i.e., NTSC).
++ */
++u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits)
+ {
+- /* fix up our card entry */
+- if(norm==V4L2_STD_NTSC) {
+- bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+- bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
+- bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+- bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x957fff;
+- dprintk("bttv_tda9880_setnorm to NTSC\n");
+- }
+- else {
+- bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
+- bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff;
+- bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
+- bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x947fff;
+- dprintk("bttv_tda9880_setnorm to PAL\n");
++
++ if (btv->audio == TVAUDIO_INPUT_TUNER) {
++ if (bttv_tvnorms[btv->tvnorm].v4l2_id & V4L2_STD_MN)
++ gpiobits |= 0x10000;
++ else
++ gpiobits &= ~0x10000;
+ }
+- /* set GPIO according */
+- gpio_bits(bttv_tvcards[btv->c.type].gpiomask,
+- bttv_tvcards[btv->c.type].gpiomux[btv->audio]);
++
++ gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpiobits);
++ return gpiobits;
+ }
+
+
+@@ -4463,6 +4394,11 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
+ */
+ static void rv605_muxsel(struct bttv *btv, unsigned int input)
+ {
++ static const u8 muxgpio[] = { 0x3, 0x1, 0x2, 0x4, 0xf, 0x7, 0xe, 0x0,
++ 0xd, 0xb, 0xc, 0x6, 0x9, 0x5, 0x8, 0xa };
++
++ gpio_bits(0x07f, muxgpio[input]);
++
+ /* reset all conections */
+ gpio_bits(0x200,0x200);
+ mdelay(1);
+@@ -4470,7 +4406,6 @@ static void rv605_muxsel(struct bttv *btv, unsigned int input)
+ mdelay(1);
+
+ /* create a new connection */
+- gpio_bits(0x480,0x080);
+ gpio_bits(0x480,0x480);
+ mdelay(1);
+ gpio_bits(0x480,0x080);
+@@ -4729,8 +4664,7 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input)
+ bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02,
+ ((matrix == 2) ? 0x03 : 0x00), 1); /* 9-12 */
+
+- /* Selects MUX0 for input on the 878 */
+- btaor((0)<<5, ~(3<<5), BT848_IFORM);
++ /* 878's MUX0 is already selected for input via muxsel values */
+ }
+
+
+@@ -4814,6 +4748,132 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
+ printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux);
+ }
+
++static void phytec_muxsel(struct bttv *btv, unsigned int input)
++{
++ unsigned int mux = input % 4;
++
++ if (input == btv->svhs)
++ mux = 0;
++
++ gpio_bits(0x3, mux);
++}
++
++/*
++ * GeoVision GV-800(S) functions
++ * Bruno Christo <bchristo@inf.ufsm.br>
++*/
++
++/* This is a function to control the analog switch, which determines which
++ * camera is routed to which controller. The switch comprises an X-address
++ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
++ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
++ * A data value (gpio bit 18) of '1' enables the switch, and '0' disables
++ * the switch. A STROBE bit (gpio bit 17) latches the data value into the
++ * specified address. There is also a chip select (gpio bit 16).
++ * The idea is to set the address and chip select together, bring
++ * STROBE high, write the data, and finally bring STROBE back to low.
++ */
++static void gv800s_write(struct bttv *btv,
++ unsigned char xaddr,
++ unsigned char yaddr,
++ unsigned char data) {
++ /* On the "master" 878A:
++ * GPIO bits 0-9 are used for the analog switch:
++ * 00 - 03: camera selector
++ * 04 - 06: 878A (controller) selector
++ * 16: cselect
++ * 17: strobe
++ * 18: data (1->on, 0->off)
++ * 19: reset
++ */
++ const u32 ADDRESS = ((xaddr&0xf) | (yaddr&3)<<4);
++ const u32 CSELECT = 1<<16;
++ const u32 STROBE = 1<<17;
++ const u32 DATA = data<<18;
++
++ gpio_bits(0x1007f, ADDRESS | CSELECT); /* write ADDRESS and CSELECT */
++ gpio_bits(0x20000, STROBE); /* STROBE high */
++ gpio_bits(0x40000, DATA); /* write DATA */
++ gpio_bits(0x20000, ~STROBE); /* STROBE low */
++}
++
++/*
++ * GeoVision GV-800(S) muxsel
++ *
++ * Each of the 4 cards (controllers) use this function.
++ * The controller using this function selects the input through the GPIO pins
++ * of the "master" card. A pointer to this card is stored in master[btv->c.nr].
++ *
++ * The parameter 'input' is the requested camera number (0-4) on the controller.
++ * The map array has the address of each input. Note that the addresses in the
++ * array are in the sequence the original GeoVision driver uses, that is, set
++ * every controller to input 0, then to input 1, 2, 3, repeat. This means that
++ * the physical "camera 1" connector corresponds to controller 0 input 0,
++ * "camera 2" corresponds to controller 1 input 0, and so on.
++ *
++ * After getting the input address, the function then writes the appropriate
++ * data to the analog switch, and housekeeps the local copy of the switch
++ * information.
++ */
++static void gv800s_muxsel(struct bttv *btv, unsigned int input)
++{
++ struct bttv *mctlr;
++ char *sw_status;
++ int xaddr, yaddr;
++ static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 },
++ { 0x1, 0x5, 0xb, 0x7 },
++ { 0x2, 0x8, 0xc, 0xe },
++ { 0x3, 0x9, 0xd, 0xf } };
++ input = input%4;
++ mctlr = master[btv->c.nr];
++ if (mctlr == NULL) {
++ /* do nothing until the "master" is detected */
++ return;
++ }
++ yaddr = (btv->c.nr - mctlr->c.nr) & 3;
++ sw_status = (char *)(&mctlr->mbox_we);
++ xaddr = map[yaddr][input] & 0xf;
++
++ /* Check if the controller/camera pair has changed, ignore otherwise */
++ if (sw_status[yaddr] != xaddr) {
++ /* disable the old switch, enable the new one and save status */
++ gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
++ sw_status[yaddr] = xaddr;
++ gv800s_write(mctlr, xaddr, yaddr, 1);
++ }
++}
++
++/* GeoVision GV-800(S) "master" chip init */
++static void gv800s_init(struct bttv *btv)
++{
++ char *sw_status = (char *)(&btv->mbox_we);
++ int ix;
++
++ gpio_inout(0xf107f, 0xf107f);
++ gpio_write(1<<19); /* reset the analog MUX */
++ gpio_write(0);
++
++ /* Preset camera 0 to the 4 controllers */
++ for (ix = 0; ix < 4; ix++) {
++ sw_status[ix] = ix;
++ gv800s_write(btv, ix, ix, 1);
++ }
++
++ /* Inputs on the "master" controller need this brightness fix */
++ bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1);
++
++ if (btv->c.nr > BTTV_MAX-4)
++ return;
++ /*
++ * Store the "master" controller pointer in the master
++ * array for later use in the muxsel function.
++ */
++ master[btv->c.nr] = btv;
++ master[btv->c.nr+1] = btv;
++ master[btv->c.nr+2] = btv;
++ master[btv->c.nr+3] = btv;
++}
++
+ /* ----------------------------------------------------------------------- */
+ /* motherboard chipset specific stuff */
+
+diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
+index c71f394..7a8ca0d 100644
+--- a/drivers/media/video/bt8xx/bttv-driver.c
++++ b/drivers/media/video/bt8xx/bttv-driver.c
+@@ -58,7 +58,7 @@
+
+
+ unsigned int bttv_num; /* number of Bt848s in use */
+-struct bttv bttvs[BTTV_MAX];
++struct bttv *bttvs[BTTV_MAX];
+
+ unsigned int bttv_debug;
+ unsigned int bttv_verbose = 1;
+@@ -167,7 +167,7 @@ static ssize_t show_card(struct device *cd,
+ struct device_attribute *attr, char *buf)
+ {
+ struct video_device *vfd = container_of(cd, struct video_device, dev);
+- struct bttv *btv = dev_get_drvdata(vfd->parent);
++ struct bttv *btv = video_get_drvdata(vfd);
+ return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
+ }
+ static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
+@@ -1040,7 +1040,7 @@ static void bt848A_set_timing(struct bttv *btv)
+ int table_idx = bttv_tvnorms[btv->tvnorm].sram;
+ int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
+
+- if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
++ if (btv->input == btv->dig) {
+ dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
+ btv->c.nr,table_idx);
+
+@@ -1142,7 +1142,7 @@ video_mux(struct bttv *btv, unsigned int input)
+ btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+ btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+ }
+- mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
++ mux = bttv_muxsel(btv, input);
+ btaor(mux<<5, ~(3<<5), BT848_IFORM);
+ dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
+ btv->c.nr,input,mux);
+@@ -1163,7 +1163,6 @@ audio_mux(struct bttv *btv, int input, int mute)
+ {
+ int gpio_val, signal;
+ struct v4l2_control ctrl;
+- struct i2c_client *c;
+
+ gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
+ bttv_tvcards[btv->c.type].gpiomask);
+@@ -1180,7 +1179,16 @@ audio_mux(struct bttv *btv, int input, int mute)
+ else
+ gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
+
+- gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
++ switch (btv->c.type) {
++ case BTTV_BOARD_VOODOOTV_FM:
++ case BTTV_BOARD_VOODOOTV_200:
++ gpio_val = bttv_tda9880_setnorm(btv, gpio_val);
++ break;
++
++ default:
++ gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
++ }
++
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
+ if (in_interrupt())
+@@ -1188,9 +1196,8 @@ audio_mux(struct bttv *btv, int input, int mute)
+
+ ctrl.id = V4L2_CID_AUDIO_MUTE;
+ ctrl.value = btv->mute;
+- bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
+- c = btv->i2c_msp34xx_client;
+- if (c) {
++ bttv_call_all(btv, core, s_ctrl, &ctrl);
++ if (btv->sd_msp34xx) {
+ struct v4l2_routing route;
+
+ /* Note: the inputs tuner/radio/extern/intern are translated
+@@ -1229,15 +1236,14 @@ audio_mux(struct bttv *btv, int input, int mute)
+ break;
+ }
+ route.output = MSP_OUTPUT_DEFAULT;
+- c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
++ v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing, &route);
+ }
+- c = btv->i2c_tvaudio_client;
+- if (c) {
++ if (btv->sd_tvaudio) {
+ struct v4l2_routing route;
+
+ route.input = input;
+ route.output = 0;
+- c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
++ v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, &route);
+ }
+ return 0;
+ }
+@@ -1277,7 +1283,7 @@ bttv_crop_calc_limits(struct bttv_crop *c)
+ }
+
+ static void
+-bttv_crop_reset(struct bttv_crop *c, int norm)
++bttv_crop_reset(struct bttv_crop *c, unsigned int norm)
+ {
+ c->rect = bttv_tvnorms[norm].cropcap.defrect;
+ bttv_crop_calc_limits(c);
+@@ -1290,16 +1296,13 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
+ const struct bttv_tvnorm *tvnorm;
+ v4l2_std_id id;
+
+- if (norm < 0 || norm >= BTTV_TVNORMS)
+- return -EINVAL;
++ BUG_ON(norm >= BTTV_TVNORMS);
++ BUG_ON(btv->tvnorm >= BTTV_TVNORMS);
+
+ tvnorm = &bttv_tvnorms[norm];
+
+- if (btv->tvnorm < 0 ||
+- btv->tvnorm >= BTTV_TVNORMS ||
+- 0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
+- &tvnorm->cropcap,
+- sizeof (tvnorm->cropcap))) {
++ if (!memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap,
++ sizeof (tvnorm->cropcap))) {
+ bttv_crop_reset(&btv->crop[0], norm);
+ btv->crop[1] = btv->crop[0]; /* current = default */
+
+@@ -1322,11 +1325,11 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
+ switch (btv->c.type) {
+ case BTTV_BOARD_VOODOOTV_FM:
+ case BTTV_BOARD_VOODOOTV_200:
+- bttv_tda9880_setnorm(btv,norm);
++ bttv_tda9880_setnorm(btv, gpio_read());
+ break;
+ }
+ id = tvnorm->v4l2_id;
+- bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
++ bttv_call_all(btv, tuner, s_std, id);
+
+ return 0;
+ }
+@@ -1350,8 +1353,8 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm)
+ } else {
+ video_mux(btv,input);
+ }
+- audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
+- TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
++ audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ?
++ TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN);
+ set_tvnorm(btv, norm);
+ }
+
+@@ -1470,7 +1473,7 @@ static int bttv_g_ctrl(struct file *file, void *priv,
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+- bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c);
++ bttv_call_all(btv, core, g_ctrl, c);
+ break;
+
+ case V4L2_CID_PRIVATE_CHROMA_AGC:
+@@ -1544,12 +1547,12 @@ static int bttv_s_ctrl(struct file *file, void *f,
+ if (btv->volume_gpio)
+ btv->volume_gpio(btv, c->value);
+
+- bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
++ bttv_call_all(btv, core, s_ctrl, c);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+- bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
++ bttv_call_all(btv, core, s_ctrl, c);
+ break;
+
+ case V4L2_CID_PRIVATE_CHROMA_AGC:
+@@ -1888,20 +1891,15 @@ static int bttv_enum_input(struct file *file, void *priv,
+ {
+ struct bttv_fh *fh = priv;
+ struct bttv *btv = fh->btv;
+- unsigned int n;
+-
+- n = i->index;
++ int n;
+
+- if (n >= bttv_tvcards[btv->c.type].video_inputs)
++ if (i->index >= bttv_tvcards[btv->c.type].video_inputs)
+ return -EINVAL;
+
+- memset(i, 0, sizeof(*i));
+-
+- i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ i->audioset = 1;
+
+- if (i->index == bttv_tvcards[btv->c.type].tuner) {
++ if (btv->tuner_type != TUNER_ABSENT && i->index == 0) {
+ sprintf(i->name, "Television");
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ i->tuner = 0;
+@@ -1965,14 +1963,14 @@ static int bttv_s_tuner(struct file *file, void *priv,
+ if (0 != err)
+ return err;
+
+- if (UNSET == bttv_tvcards[btv->c.type].tuner)
++ if (btv->tuner_type == TUNER_ABSENT)
+ return -EINVAL;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ mutex_lock(&btv->lock);
+- bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
++ bttv_call_all(btv, tuner, s_tuner, t);
+
+ if (btv->audio_mode_gpio)
+ btv->audio_mode_gpio(btv, t, 1);
+@@ -2017,7 +2015,7 @@ static int bttv_s_frequency(struct file *file, void *priv,
+ return -EINVAL;
+ mutex_lock(&btv->lock);
+ btv->freq = f->frequency;
+- bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f);
++ bttv_call_all(btv, tuner, s_frequency, f);
+ if (btv->has_matchbox && btv->radio_user)
+ tea5757_set_freq(btv, btv->freq);
+ mutex_unlock(&btv->lock);
+@@ -2031,7 +2029,7 @@ static int bttv_log_status(struct file *file, void *f)
+
+ printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n",
+ btv->c.nr, btv->c.nr);
+- bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
++ bttv_call_all(btv, core, log_status);
+ printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n",
+ btv->c.nr, btv->c.nr);
+ return 0;
+@@ -2659,8 +2657,7 @@ static int bttv_querycap(struct file *file, void *priv,
+ if (no_overlay <= 0)
+ cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+
+- if (bttv_tvcards[btv->c.type].tuner != UNSET &&
+- bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
++ if (btv->tuner_type != TUNER_ABSENT)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+ }
+@@ -2927,13 +2924,9 @@ static int bttv_g_parm(struct file *file, void *f,
+ {
+ struct bttv_fh *fh = f;
+ struct bttv *btv = fh->btv;
+- struct v4l2_standard s;
+
+- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+- v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
+- bttv_tvnorms[btv->tvnorm].name);
+- parm->parm.capture.timeperframe = s.frameperiod;
++ v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
++ &parm->parm.capture.timeperframe);
+ return 0;
+ }
+
+@@ -2943,15 +2936,14 @@ static int bttv_g_tuner(struct file *file, void *priv,
+ struct bttv_fh *fh = priv;
+ struct bttv *btv = fh->btv;
+
+- if (UNSET == bttv_tvcards[btv->c.type].tuner)
++ if (btv->tuner_type == TUNER_ABSENT)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+
+ mutex_lock(&btv->lock);
+- memset(t, 0, sizeof(*t));
+ t->rxsubchans = V4L2_TUNER_SUB_MONO;
+- bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
++ bttv_call_all(btv, tuner, g_tuner, t);
+ strcpy(t->name, "Television");
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->type = V4L2_TUNER_ANALOG_TV;
+@@ -3212,29 +3204,19 @@ err:
+ static int bttv_open(struct file *file)
+ {
+ int minor = video_devdata(file)->minor;
+- struct bttv *btv = NULL;
++ struct bttv *btv = video_drvdata(file);
+ struct bttv_fh *fh;
+ enum v4l2_buf_type type = 0;
+- unsigned int i;
+
+ dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
+
+ lock_kernel();
+- for (i = 0; i < bttv_num; i++) {
+- if (bttvs[i].video_dev &&
+- bttvs[i].video_dev->minor == minor) {
+- btv = &bttvs[i];
+- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- break;
+- }
+- if (bttvs[i].vbi_dev &&
+- bttvs[i].vbi_dev->minor == minor) {
+- btv = &bttvs[i];
+- type = V4L2_BUF_TYPE_VBI_CAPTURE;
+- break;
+- }
+- }
+- if (NULL == btv) {
++ if (btv->video_dev->minor == minor) {
++ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ } else if (btv->vbi_dev->minor == minor) {
++ type = V4L2_BUF_TYPE_VBI_CAPTURE;
++ } else {
++ WARN_ON(1);
+ unlock_kernel();
+ return -ENODEV;
+ }
+@@ -3424,20 +3406,14 @@ static struct video_device bttv_video_template = {
+ static int radio_open(struct file *file)
+ {
+ int minor = video_devdata(file)->minor;
+- struct bttv *btv = NULL;
++ struct bttv *btv = video_drvdata(file);
+ struct bttv_fh *fh;
+- unsigned int i;
+
+ dprintk("bttv: open minor=%d\n",minor);
+
+ lock_kernel();
+- for (i = 0; i < bttv_num; i++) {
+- if (bttvs[i].radio_dev && bttvs[i].radio_dev->minor == minor) {
+- btv = &bttvs[i];
+- break;
+- }
+- }
+- if (NULL == btv) {
++ WARN_ON(btv->radio_dev && btv->radio_dev->minor != minor);
++ if (!btv->radio_dev || btv->radio_dev->minor != minor) {
+ unlock_kernel();
+ return -ENODEV;
+ }
+@@ -3458,7 +3434,7 @@ static int radio_open(struct file *file)
+
+ btv->radio_user++;
+
+- bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
++ bttv_call_all(btv, tuner, s_radio);
+ audio_input(btv,TVAUDIO_INPUT_RADIO);
+
+ mutex_unlock(&btv->lock);
+@@ -3478,7 +3454,7 @@ static int radio_release(struct file *file)
+
+ btv->radio_user--;
+
+- bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
++ bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd);
+
+ return 0;
+ }
+@@ -3503,16 +3479,15 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+ struct bttv_fh *fh = priv;
+ struct bttv *btv = fh->btv;
+
+- if (UNSET == bttv_tvcards[btv->c.type].tuner)
++ if (btv->tuner_type == TUNER_ABSENT)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+ mutex_lock(&btv->lock);
+- memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
+
+- bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
++ bttv_call_all(btv, tuner, g_tuner, t);
+
+ if (btv->audio_mode_gpio)
+ btv->audio_mode_gpio(btv, t, 0);
+@@ -3554,7 +3529,7 @@ static int radio_s_tuner(struct file *file, void *priv,
+ if (0 != t->index)
+ return -EINVAL;
+
+- bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
++ bttv_call_all(btv, tuner, g_tuner, t);
+ return 0;
+ }
+
+@@ -3615,7 +3590,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
+ cmd.instance = file;
+ cmd.result = -ENODEV;
+
+- bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
++ bttv_call_all(btv, core, ioctl, RDS_CMD_READ, &cmd);
+
+ return cmd.result;
+ }
+@@ -3628,7 +3603,7 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
+ cmd.instance = file;
+ cmd.event_list = wait;
+ cmd.result = -ENODEV;
+- bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
++ bttv_call_all(btv, core, ioctl, RDS_CMD_POLL, &cmd);
+
+ return cmd.result;
+ }
+@@ -3712,14 +3687,14 @@ static void bttv_risc_disasm(struct bttv *btv,
+ unsigned int i,j,n;
+
+ printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+- btv->c.name, risc->cpu, (unsigned long)risc->dma);
++ btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma);
+ for (i = 0; i < (risc->size >> 2); i += n) {
+- printk("%s: 0x%lx: ", btv->c.name,
++ printk("%s: 0x%lx: ", btv->c.v4l2_dev.name,
+ (unsigned long)(risc->dma + (i<<2)));
+ n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));
+ for (j = 1; j < n; j++)
+ printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
+- btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
++ btv->c.v4l2_dev.name, (unsigned long)(risc->dma + ((i+j)<<2)),
+ risc->cpu[i+j], j);
+ if (0 == risc->cpu[i])
+ break;
+@@ -4195,9 +4170,10 @@ static struct video_device *vdev_init(struct bttv *btv,
+ return NULL;
+ *vfd = *template;
+ vfd->minor = -1;
+- vfd->parent = &btv->c.pci->dev;
++ vfd->v4l2_dev = &btv->c.v4l2_dev;
+ vfd->release = video_device_release;
+ vfd->debug = bttv_debug;
++ video_set_drvdata(vfd, btv);
+ snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
+ btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
+ type_name, bttv_tvcards[btv->c.type].name);
+@@ -4307,10 +4283,14 @@ static int __devinit bttv_probe(struct pci_dev *dev,
+ if (bttv_num == BTTV_MAX)
+ return -ENOMEM;
+ printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
+- btv=&bttvs[bttv_num];
+- memset(btv,0,sizeof(*btv));
++ bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL);
++ if (btv == NULL) {
++ printk(KERN_ERR "bttv: out of memory.\n");
++ return -ENOMEM;
++ }
+ btv->c.nr = bttv_num;
+- sprintf(btv->c.name,"bttv%d",btv->c.nr);
++ snprintf(btv->c.v4l2_dev.name, sizeof(btv->c.v4l2_dev.name),
++ "bttv%d", btv->c.nr);
+
+ /* initialize structs / fill in defaults */
+ mutex_init(&btv->lock);
+@@ -4347,7 +4327,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
+ }
+ if (!request_mem_region(pci_resource_start(dev,0),
+ pci_resource_len(dev,0),
+- btv->c.name)) {
++ btv->c.v4l2_dev.name)) {
+ printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
+ btv->c.nr,
+ (unsigned long long)pci_resource_start(dev,0));
+@@ -4355,7 +4335,12 @@ static int __devinit bttv_probe(struct pci_dev *dev,
+ }
+ pci_set_master(dev);
+ pci_set_command(dev);
+- pci_set_drvdata(dev,btv);
++
++ result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev);
++ if (result < 0) {
++ printk(KERN_WARNING "bttv%d: v4l2_device_register() failed\n", btv->c.nr);
++ goto fail0;
++ }
+
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+@@ -4379,7 +4364,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
+ /* disable irqs, register irq handler */
+ btwrite(0, BT848_INT_MASK);
+ result = request_irq(btv->c.pci->irq, bttv_irq,
+- IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
++ IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv);
+ if (result < 0) {
+ printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
+ bttv_num,btv->c.pci->irq);
+@@ -4463,21 +4448,24 @@ static int __devinit bttv_probe(struct pci_dev *dev,
+ bttv_num++;
+ return 0;
+
+- fail2:
++fail2:
+ free_irq(btv->c.pci->irq,btv);
+
+- fail1:
++fail1:
++ v4l2_device_unregister(&btv->c.v4l2_dev);
++
++fail0:
+ if (btv->bt848_mmio)
+ iounmap(btv->bt848_mmio);
+ release_mem_region(pci_resource_start(btv->c.pci,0),
+ pci_resource_len(btv->c.pci,0));
+- pci_set_drvdata(dev,NULL);
+ return result;
+ }
+
+ static void __devexit bttv_remove(struct pci_dev *pci_dev)
+ {
+- struct bttv *btv = pci_get_drvdata(pci_dev);
++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
++ struct bttv *btv = to_bttv(v4l2_dev);
+
+ if (bttv_verbose)
+ printk("bttv%d: unloading\n",btv->c.nr);
+@@ -4511,14 +4499,18 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
+ release_mem_region(pci_resource_start(btv->c.pci,0),
+ pci_resource_len(btv->c.pci,0));
+
+- pci_set_drvdata(pci_dev, NULL);
++ v4l2_device_unregister(&btv->c.v4l2_dev);
++ bttvs[btv->c.nr] = NULL;
++ kfree(btv);
++
+ return;
+ }
+
+ #ifdef CONFIG_PM
+ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
+ {
+- struct bttv *btv = pci_get_drvdata(pci_dev);
++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
++ struct bttv *btv = to_bttv(v4l2_dev);
+ struct bttv_buffer_set idle;
+ unsigned long flags;
+
+@@ -4553,7 +4545,8 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
+
+ static int bttv_resume(struct pci_dev *pci_dev)
+ {
+- struct bttv *btv = pci_get_drvdata(pci_dev);
++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
++ struct bttv *btv = to_bttv(v4l2_dev);
+ unsigned long flags;
+ int err;
+
+diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
+index bcd2cd2..a99d92f 100644
+--- a/drivers/media/video/bt8xx/bttv-i2c.c
++++ b/drivers/media/video/bt8xx/bttv-i2c.c
+@@ -36,8 +36,6 @@
+ #include <linux/jiffies.h>
+ #include <asm/io.h>
+
+-static int attach_inform(struct i2c_client *client);
+-
+ static int i2c_debug;
+ static int i2c_hw;
+ static int i2c_scan;
+@@ -231,7 +229,8 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
+
+ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+ {
+- struct bttv *btv = i2c_get_adapdata(i2c_adap);
++ struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap);
++ struct bttv *btv = to_bttv(v4l2_dev);
+ int retval = 0;
+ int i;
+
+@@ -265,52 +264,6 @@ static const struct i2c_algorithm bttv_algo = {
+ /* ----------------------------------------------------------------------- */
+ /* I2C functions - common stuff */
+
+-static int attach_inform(struct i2c_client *client)
+-{
+- struct bttv *btv = i2c_get_adapdata(client->adapter);
+- int addr=ADDR_UNSET;
+-
+-
+- if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+- addr = bttv_tvcards[btv->c.type].tuner_addr;
+-
+-
+- if (bttv_debug)
+- printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
+- btv->c.nr, client->driver->driver.name, client->addr,
+- client->name);
+- if (!client->driver->command)
+- return 0;
+-
+- if (client->driver->id == I2C_DRIVERID_MSP3400)
+- btv->i2c_msp34xx_client = client;
+- if (client->driver->id == I2C_DRIVERID_TVAUDIO)
+- btv->i2c_tvaudio_client = client;
+- if (btv->tuner_type != UNSET) {
+- struct tuner_setup tun_setup;
+-
+- if ((addr==ADDR_UNSET) ||
+- (addr==client->addr)) {
+-
+- tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV | T_RADIO;
+- tun_setup.type = btv->tuner_type;
+- tun_setup.addr = addr;
+- bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+- }
+-
+- }
+-
+- return 0;
+-}
+-
+-void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
+-{
+- if (0 != btv->i2c_rc)
+- return;
+- i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
+-}
+-
+-
+ /* read I2C */
+ int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
+ {
+@@ -417,21 +370,15 @@ int __devinit init_bttv_i2c(struct bttv *btv)
+ btv->c.i2c_adap.algo_data = &btv->i2c_algo;
+ }
+ btv->c.i2c_adap.owner = THIS_MODULE;
+- btv->c.i2c_adap.class = I2C_CLASS_TV_ANALOG;
+- btv->c.i2c_adap.client_register = attach_inform;
+
+ btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
+ snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
+ "bt%d #%d [%s]", btv->id, btv->c.nr,
+ btv->use_i2c_hw ? "hw" : "sw");
+
+- i2c_set_adapdata(&btv->c.i2c_adap, btv);
++ i2c_set_adapdata(&btv->c.i2c_adap, &btv->c.v4l2_dev);
+ btv->i2c_client.adapter = &btv->c.i2c_adap;
+
+- if (bttv_tvcards[btv->c.type].no_video)
+- btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
+- if (bttv_tvcards[btv->c.type].has_dvb)
+- btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
+
+ if (btv->use_i2c_hw) {
+ btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
+@@ -441,7 +388,7 @@ int __devinit init_bttv_i2c(struct bttv *btv)
+ btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap);
+ }
+ if (0 == btv->i2c_rc && i2c_scan)
+- do_i2c_scan(btv->c.name,&btv->i2c_client);
++ do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
+ return btv->i2c_rc;
+ }
+
+diff --git a/drivers/media/video/bt8xx/bttv-if.c b/drivers/media/video/bt8xx/bttv-if.c
+index ecf0798..a6a540d 100644
+--- a/drivers/media/video/bt8xx/bttv-if.c
++++ b/drivers/media/video/bt8xx/bttv-if.c
+@@ -47,7 +47,10 @@ struct pci_dev* bttv_get_pcidev(unsigned int card)
+ {
+ if (card >= bttv_num)
+ return NULL;
+- return bttvs[card].c.pci;
++ if (!bttvs[card])
++ return NULL;
++
++ return bttvs[card]->c.pci;
+ }
+
+
+@@ -59,7 +62,10 @@ int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
+ return -EINVAL;
+ }
+
+- btv = &bttvs[card];
++ btv = bttvs[card];
++ if (!btv)
++ return -ENODEV;
++
+ gpio_inout(mask,data);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"extern enable");
+@@ -74,7 +80,9 @@ int bttv_read_gpio(unsigned int card, unsigned long *data)
+ return -EINVAL;
+ }
+
+- btv = &bttvs[card];
++ btv = bttvs[card];
++ if (!btv)
++ return -ENODEV;
+
+ if(btv->shutdown) {
+ return -ENODEV;
+@@ -94,7 +102,9 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
+ return -EINVAL;
+ }
+
+- btv = &bttvs[card];
++ btv = bttvs[card];
++ if (!btv)
++ return -ENODEV;
+
+ /* prior setting BT848_GPIO_REG_INP is (probably) not needed
+ because direct input is set on init */
+diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
+index 5b1b8e4..d16af28 100644
+--- a/drivers/media/video/bt8xx/bttv-risc.c
++++ b/drivers/media/video/bt8xx/bttv-risc.c
+@@ -341,7 +341,7 @@ bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
+ int totalwidth = tvnorm->totalwidth;
+ int scaledtwidth = tvnorm->scaledtwidth;
+
+- if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
++ if (btv->input == btv->dig) {
+ swidth = 720;
+ totalwidth = 858;
+ scaledtwidth = 858;
+@@ -391,7 +391,7 @@ bttv_calc_geo (struct bttv * btv,
+ && crop->width == tvnorm->cropcap.defrect.width
+ && crop->height == tvnorm->cropcap.defrect.height
+ && width <= tvnorm->swidth /* see PAL-Nc et al */)
+- || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
++ || btv->input == btv->dig) {
+ bttv_calc_geo_old(btv, geo, width, height,
+ both_fields, tvnorm);
+ return;
+diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
+index 6819e21..e79a402 100644
+--- a/drivers/media/video/bt8xx/bttv-vbi.c
++++ b/drivers/media/video/bt8xx/bttv-vbi.c
+@@ -411,7 +411,7 @@ int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
+ return 0;
+ }
+
+-void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm)
++void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm)
+ {
+ const struct bttv_tvnorm *tvnorm;
+ unsigned int real_samples_per_line;
+diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
+index 529bf6c..3d36daf 100644
+--- a/drivers/media/video/bt8xx/bttv.h
++++ b/drivers/media/video/bt8xx/bttv.h
+@@ -14,8 +14,9 @@
+ #ifndef _BTTV_H_
+ #define _BTTV_H_
+
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <linux/i2c.h>
++#include <media/v4l2-device.h>
+ #include <media/ir-common.h>
+ #include <media/ir-kbd-i2c.h>
+ #include <media/i2c-addr.h>
+@@ -180,6 +181,10 @@
+ #define BTTV_BOARD_VD012 0x99
+ #define BTTV_BOARD_VD012_X1 0x9a
+ #define BTTV_BOARD_VD012_X2 0x9b
++#define BTTV_BOARD_IVCE8784 0x9c
++#define BTTV_BOARD_GEOVISION_GV800S 0x9d
++#define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e
++#define BTTV_BOARD_PV183 0x9f
+
+
+ /* more card-specific defines */
+@@ -191,12 +196,9 @@
+ #define WINVIEW_PT2254_DATA 0x20
+ #define WINVIEW_PT2254_STROBE 0x80
+
+-/* digital_mode */
+-#define DIGITAL_MODE_VIDEO 1
+-#define DIGITAL_MODE_CAMERA 2
+-
+ struct bttv_core {
+ /* device structs */
++ struct v4l2_device v4l2_dev;
+ struct pci_dev *pci;
+ struct i2c_adapter i2c_adap;
+ struct list_head subs; /* struct bttv_sub_device */
+@@ -204,59 +206,79 @@ struct bttv_core {
+ /* device config */
+ unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
+ unsigned int type; /* card type (pointer into tvcards[]) */
+- char name[8]; /* dev name */
+ };
+
+ struct bttv;
+
+-
+-struct tvcard
+-{
++struct tvcard {
+ char *name;
+- unsigned int video_inputs;
+- unsigned int audio_inputs;
+- unsigned int tuner;
+- unsigned int svhs;
+- unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
++ void (*volume_gpio)(struct bttv *btv, __u16 volume);
++ void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++ void (*muxsel_hook)(struct bttv *btv, unsigned int input);
++
++ /* MUX bits for each input, two bits per input starting with the LSB */
++ u32 muxsel; /* Use MUXSEL() to set */
++
+ u32 gpiomask;
+- u32 muxsel[16];
+ u32 gpiomux[4]; /* Tuner, Radio, external, internal */
+ u32 gpiomute; /* GPIO mute setting */
+ u32 gpiomask2; /* GPIO MUX mask */
+
++ unsigned int tuner_type;
++ u8 tuner_addr;
++ u8 video_inputs; /* Number of inputs */
++ unsigned int svhs:4; /* Which input is s-video */
++#define NO_SVHS 15
++ unsigned int pll:2;
++#define PLL_NONE 0
++#define PLL_28 1
++#define PLL_35 2
++
+ /* i2c audio flags */
+ unsigned int no_msp34xx:1;
+ unsigned int no_tda9875:1;
+ unsigned int no_tda7432:1;
+ unsigned int needs_tvaudio:1;
+ unsigned int msp34xx_alt:1;
++ /* Note: currently no card definition needs to mark the presence
++ of a RDS saa6588 chip. If this is ever needed, then add a new
++ 'has_saa6588' bit here. */
+
+- /* flag: video pci function is unused */
+- unsigned int no_video:1;
++ unsigned int no_video:1; /* video pci function is unused */
+ unsigned int has_dvb:1;
+ unsigned int has_remote:1;
++ unsigned int has_radio:1;
++ unsigned int has_dig_in:1; /* Has digital input (always last input) */
+ unsigned int no_gpioirq:1;
+-
+- /* other settings */
+- unsigned int pll;
+-#define PLL_NONE 0
+-#define PLL_28 1
+-#define PLL_35 2
+-
+- unsigned int tuner_type;
+- unsigned int tuner_addr;
+- unsigned int radio_addr;
+-
+- unsigned int has_radio;
+-
+- void (*volume_gpio)(struct bttv *btv, __u16 volume);
+- void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+-
+- void (*muxsel_hook)(struct bttv *btv, unsigned int input);
+ };
+
+ extern struct tvcard bttv_tvcards[];
+
++/*
++ * This bit of cpp voodoo is used to create a macro with a variable number of
++ * arguments (1 to 16). It will pack each argument into a word two bits at a
++ * time. It can't be a function because it needs to be compile time constant to
++ * initialize structures. Since each argument must fit in two bits, it's ok
++ * that they are changed to octal. One should not use hex number, macros, or
++ * anything else with this macro. Just use plain integers from 0 to 3.
++ */
++#define _MUXSELf(a) 0##a << 30
++#define _MUXSELe(a, b...) 0##a << 28 | _MUXSELf(b)
++#define _MUXSELd(a, b...) 0##a << 26 | _MUXSELe(b)
++#define _MUXSELc(a, b...) 0##a << 24 | _MUXSELd(b)
++#define _MUXSELb(a, b...) 0##a << 22 | _MUXSELc(b)
++#define _MUXSELa(a, b...) 0##a << 20 | _MUXSELb(b)
++#define _MUXSEL9(a, b...) 0##a << 18 | _MUXSELa(b)
++#define _MUXSEL8(a, b...) 0##a << 16 | _MUXSEL9(b)
++#define _MUXSEL7(a, b...) 0##a << 14 | _MUXSEL8(b)
++#define _MUXSEL6(a, b...) 0##a << 12 | _MUXSEL7(b)
++#define _MUXSEL5(a, b...) 0##a << 10 | _MUXSEL6(b)
++#define _MUXSEL4(a, b...) 0##a << 8 | _MUXSEL5(b)
++#define _MUXSEL3(a, b...) 0##a << 6 | _MUXSEL4(b)
++#define _MUXSEL2(a, b...) 0##a << 4 | _MUXSEL3(b)
++#define _MUXSEL1(a, b...) 0##a << 2 | _MUXSEL2(b)
++#define MUXSEL(a, b...) (a | _MUXSEL1(b))
++
+ /* identification / initialization of the card */
+ extern void bttv_idcard(struct bttv *btv);
+ extern void bttv_init_card1(struct bttv *btv);
+@@ -264,7 +286,7 @@ extern void bttv_init_card2(struct bttv *btv);
+
+ /* card-specific funtions */
+ extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
+-extern void bttv_tda9880_setnorm(struct bttv *btv, int norm);
++extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits);
+
+ /* extra tweaks for some chipsets */
+ extern void bttv_check_chipset(void);
+@@ -336,7 +358,9 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits);
+ /* ---------------------------------------------------------- */
+ /* i2c */
+
+-extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
++#define bttv_call_all(btv, o, f, args...) \
++ v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args)
++
+ extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
+ extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
+ unsigned char b2, int both);
+diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
+index 199a4d2..9649848 100644
+--- a/drivers/media/video/bt8xx/bttvp.h
++++ b/drivers/media/video/bt8xx/bttvp.h
+@@ -32,7 +32,6 @@
+ #include <linux/wait.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-algo-bit.h>
+-#include <linux/videodev.h>
+ #include <linux/pci.h>
+ #include <linux/input.h>
+ #include <linux/mutex.h>
+@@ -135,7 +134,7 @@ struct bttv_buffer {
+
+ /* bttv specific */
+ const struct bttv_format *fmt;
+- int tvnorm;
++ unsigned int tvnorm;
+ int btformat;
+ int btswap;
+ struct bttv_geometry geo;
+@@ -154,7 +153,7 @@ struct bttv_buffer_set {
+ };
+
+ struct bttv_overlay {
+- int tvnorm;
++ unsigned int tvnorm;
+ struct v4l2_rect w;
+ enum v4l2_field field;
+ struct v4l2_clip *clips;
+@@ -174,7 +173,7 @@ struct bttv_vbi_fmt {
+ };
+
+ /* bttv-vbi.c */
+-void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm);
++void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm);
+
+ struct bttv_crop {
+ /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */
+@@ -329,7 +328,8 @@ struct bttv {
+ unsigned int cardid; /* pci subsystem id (bt878 based ones) */
+ unsigned int tuner_type; /* tuner chip type */
+ unsigned int tda9887_conf;
+- unsigned int svhs;
++ unsigned int svhs, dig;
++ unsigned int has_saa6588:1;
+ struct bttv_pll_info pll;
+ int triton1;
+ int gpioirq;
+@@ -353,8 +353,8 @@ struct bttv {
+ int i2c_state, i2c_rc;
+ int i2c_done;
+ wait_queue_head_t i2c_queue;
+- struct i2c_client *i2c_msp34xx_client;
+- struct i2c_client *i2c_tvaudio_client;
++ struct v4l2_subdev *sd_msp34xx;
++ struct v4l2_subdev *sd_tvaudio;
+
+ /* video4linux (1) */
+ struct video_device *video_dev;
+@@ -378,7 +378,8 @@ struct bttv {
+ unsigned int audio;
+ unsigned int mute;
+ unsigned long freq;
+- int tvnorm,hue,contrast,bright,saturation;
++ unsigned int tvnorm;
++ int hue, contrast, bright, saturation;
+ struct v4l2_framebuffer fbuf;
+ unsigned int field_count;
+
+@@ -458,10 +459,21 @@ struct bttv {
+ __s32 crop_start;
+ };
+
++static inline struct bttv *to_bttv(struct v4l2_device *v4l2_dev)
++{
++ return container_of(v4l2_dev, struct bttv, c.v4l2_dev);
++}
++
+ /* our devices */
+ #define BTTV_MAX 32
+ extern unsigned int bttv_num;
+-extern struct bttv bttvs[BTTV_MAX];
++extern struct bttv *bttvs[BTTV_MAX];
++
++static inline unsigned int bttv_muxsel(const struct bttv *btv,
++ unsigned int input)
++{
++ return (bttv_tvcards[btv->c.type].muxsel >> (input * 2)) & 3;
++}
+
+ #endif
+
+diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
+index 46fd573..7abe94d 100644
+--- a/drivers/media/video/cafe_ccic.c
++++ b/drivers/media/video/cafe_ccic.c
+@@ -11,6 +11,12 @@
+ *
+ * Written by Jonathan Corbet, corbet@lwn.net.
+ *
++ * v4l2_device/v4l2_subdev conversion by:
++ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
++ *
++ * Note: this conversion is untested! Please contact the linux-media
++ * mailinglist if you can test this, together with the test results.
++ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+@@ -25,7 +31,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/spinlock.h>
+ #include <linux/videodev2.h>
+-#include <media/v4l2-common.h>
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+ #include <media/v4l2-chip-ident.h>
+ #include <linux/device.h>
+@@ -33,7 +39,6 @@
+ #include <linux/list.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/delay.h>
+-#include <linux/debugfs.h>
+ #include <linux/jiffies.h>
+ #include <linux/vmalloc.h>
+
+@@ -136,6 +141,7 @@ struct cafe_sio_buffer {
+ */
+ struct cafe_camera
+ {
++ struct v4l2_device v4l2_dev;
+ enum cafe_state state;
+ unsigned long flags; /* Buffer status, mainly (dev_lock) */
+ int users; /* How many open FDs */
+@@ -145,9 +151,10 @@ struct cafe_camera
+ * Subsystem structures.
+ */
+ struct pci_dev *pdev;
+- struct video_device v4ldev;
++ struct video_device vdev;
+ struct i2c_adapter i2c_adapter;
+- struct i2c_client *sensor;
++ struct v4l2_subdev *sensor;
++ unsigned short sensor_addr;
+
+ unsigned char __iomem *regs;
+ struct list_head dev_list; /* link to other devices */
+@@ -180,10 +187,6 @@ struct cafe_camera
+ /* Misc */
+ wait_queue_head_t smbus_wait; /* Waiting on i2c events */
+ wait_queue_head_t iowait; /* Waiting on frame data */
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+- struct dentry *dfs_regs;
+- struct dentry *dfs_cam_regs;
+-#endif
+ };
+
+ /*
+@@ -195,6 +198,13 @@ struct cafe_camera
+ #define CF_DMA_ACTIVE 3 /* A frame is incoming */
+ #define CF_CONFIG_NEEDED 4 /* Must configure hardware */
+
++#define sensor_call(cam, o, f, args...) \
++ v4l2_subdev_call(cam->sensor, o, f, ##args)
++
++static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
++{
++ return container_of(dev, struct cafe_camera, v4l2_dev);
++}
+
+
+ /*
+@@ -238,59 +248,7 @@ static void cafe_set_config_needed(struct cafe_camera *cam, int needed)
+
+
+ /* ---------------------------------------------------------------------*/
+-/*
+- * We keep a simple list of known devices to search at open time.
+- */
+-static LIST_HEAD(cafe_dev_list);
+-static DEFINE_MUTEX(cafe_dev_list_lock);
+-
+-static void cafe_add_dev(struct cafe_camera *cam)
+-{
+- mutex_lock(&cafe_dev_list_lock);
+- list_add_tail(&cam->dev_list, &cafe_dev_list);
+- mutex_unlock(&cafe_dev_list_lock);
+-}
+-
+-static void cafe_remove_dev(struct cafe_camera *cam)
+-{
+- mutex_lock(&cafe_dev_list_lock);
+- list_del(&cam->dev_list);
+- mutex_unlock(&cafe_dev_list_lock);
+-}
+-
+-static struct cafe_camera *cafe_find_dev(int minor)
+-{
+- struct cafe_camera *cam;
+-
+- mutex_lock(&cafe_dev_list_lock);
+- list_for_each_entry(cam, &cafe_dev_list, dev_list) {
+- if (cam->v4ldev.minor == minor)
+- goto done;
+- }
+- cam = NULL;
+- done:
+- mutex_unlock(&cafe_dev_list_lock);
+- return cam;
+-}
+-
+-
+-static struct cafe_camera *cafe_find_by_pdev(struct pci_dev *pdev)
+-{
+- struct cafe_camera *cam;
+
+- mutex_lock(&cafe_dev_list_lock);
+- list_for_each_entry(cam, &cafe_dev_list, dev_list) {
+- if (cam->pdev == pdev)
+- goto done;
+- }
+- cam = NULL;
+- done:
+- mutex_unlock(&cafe_dev_list_lock);
+- return cam;
+-}
+-
+-
+-/* ------------------------------------------------------------------------ */
+ /*
+ * Device register I/O
+ */
+@@ -481,18 +439,11 @@ static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 command,
+ int size, union i2c_smbus_data *data)
+ {
+- struct cafe_camera *cam = i2c_get_adapdata(adapter);
++ struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
++ struct cafe_camera *cam = to_cam(v4l2_dev);
+ int ret = -EINVAL;
+
+ /*
+- * Refuse to talk to anything but OV cam chips. We should
+- * never even see an attempt to do so, but one never knows.
+- */
+- if (cam->sensor && addr != cam->sensor->addr) {
+- cam_err(cam, "funky smbus addr %d\n", addr);
+- return -EINVAL;
+- }
+- /*
+ * This interface would appear to only do byte data ops. OK
+ * it can do word too, but the cam chip has no use for that.
+ */
+@@ -530,38 +481,9 @@ static struct i2c_algorithm cafe_smbus_algo = {
+ };
+
+ /* Somebody is on the bus */
+-static int cafe_cam_init(struct cafe_camera *cam);
+ static void cafe_ctlr_stop_dma(struct cafe_camera *cam);
+ static void cafe_ctlr_power_down(struct cafe_camera *cam);
+
+-static int cafe_smbus_attach(struct i2c_client *client)
+-{
+- struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
+-
+- /*
+- * Don't talk to chips we don't recognize.
+- */
+- if (client->driver->id == I2C_DRIVERID_OV7670) {
+- cam->sensor = client;
+- return cafe_cam_init(cam);
+- }
+- return -EINVAL;
+-}
+-
+-static int cafe_smbus_detach(struct i2c_client *client)
+-{
+- struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
+-
+- if (cam->sensor == client) {
+- cafe_ctlr_stop_dma(cam);
+- cafe_ctlr_power_down(cam);
+- cam_err(cam, "lost the sensor!\n");
+- cam->sensor = NULL; /* Bummer, no camera */
+- cam->state = S_NOTREADY;
+- }
+- return 0;
+-}
+-
+ static int cafe_smbus_setup(struct cafe_camera *cam)
+ {
+ struct i2c_adapter *adap = &cam->i2c_adapter;
+@@ -570,12 +492,10 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
+ cafe_smbus_enable_irq(cam);
+ adap->id = I2C_HW_SMBUS_CAFE;
+ adap->owner = THIS_MODULE;
+- adap->client_register = cafe_smbus_attach;
+- adap->client_unregister = cafe_smbus_detach;
+ adap->algo = &cafe_smbus_algo;
+ strcpy(adap->name, "cafe_ccic");
+ adap->dev.parent = &cam->pdev->dev;
+- i2c_set_adapdata(adap, cam);
++ i2c_set_adapdata(adap, &cam->v4l2_dev);
+ ret = i2c_add_adapter(adap);
+ if (ret)
+ printk(KERN_ERR "Unable to register cafe i2c adapter\n");
+@@ -809,9 +729,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam)
+ * Control 1 is power down, set to 0 to operate.
+ */
+ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
+-// mdelay(1); /* Marvell says 1ms will do it */
++/* mdelay(1); */ /* Marvell says 1ms will do it */
+ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
+-// mdelay(1); /* Enough? */
++/* mdelay(1); */ /* Enough? */
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ msleep(5); /* Just to be sure */
+ }
+@@ -833,23 +753,9 @@ static void cafe_ctlr_power_down(struct cafe_camera *cam)
+ * Communications with the sensor.
+ */
+
+-static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg)
+-{
+- struct i2c_client *sc = cam->sensor;
+- int ret;
+-
+- if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL)
+- return -EINVAL;
+- ret = sc->driver->command(sc, cmd, arg);
+- if (ret == -EPERM) /* Unsupported command */
+- return 0;
+- return ret;
+-}
+-
+ static int __cafe_cam_reset(struct cafe_camera *cam)
+ {
+- int zero = 0;
+- return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero);
++ return sensor_call(cam, core, reset, 0);
+ }
+
+ /*
+@@ -869,14 +775,13 @@ static int cafe_cam_init(struct cafe_camera *cam)
+ if (ret)
+ goto out;
+ chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
+- chip.match.addr = cam->sensor->addr;
+- ret = __cafe_cam_cmd(cam, VIDIOC_DBG_G_CHIP_IDENT, &chip);
++ chip.match.addr = cam->sensor_addr;
++ ret = sensor_call(cam, core, g_chip_ident, &chip);
+ if (ret)
+ goto out;
+ cam->sensor_type = chip.ident;
+-// if (cam->sensor->addr != OV7xx0_SID) {
+ if (cam->sensor_type != V4L2_IDENT_OV7670) {
+- cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
++ cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
+ ret = -EINVAL;
+ goto out;
+ }
+@@ -900,21 +805,21 @@ static int cafe_cam_set_flip(struct cafe_camera *cam)
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_VFLIP;
+ ctrl.value = flip;
+- return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl);
++ return sensor_call(cam, core, s_ctrl, &ctrl);
+ }
+
+
+ static int cafe_cam_configure(struct cafe_camera *cam)
+ {
+ struct v4l2_format fmt;
+- int ret, zero = 0;
++ int ret;
+
+ if (cam->state != S_IDLE)
+ return -EINVAL;
+ fmt.fmt.pix = cam->pix_format;
+- ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
++ ret = sensor_call(cam, core, init, 0);
+ if (ret == 0)
+- ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt);
++ ret = sensor_call(cam, video, s_fmt, &fmt);
+ /*
+ * OV7670 does weird things if flip is set *before* format...
+ */
+@@ -1246,8 +1151,6 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
+ * Make sure it's something we can do. User pointers could be
+ * implemented without great pain, but that's not been done yet.
+ */
+- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+ if (req->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+ /*
+@@ -1311,9 +1214,7 @@ static int cafe_vidioc_querybuf(struct file *filp, void *priv,
+ int ret = -EINVAL;
+
+ mutex_lock(&cam->s_mutex);
+- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- goto out;
+- if (buf->index < 0 || buf->index >= cam->n_sbufs)
++ if (buf->index >= cam->n_sbufs)
+ goto out;
+ *buf = cam->sb_bufs[buf->index].v4lbuf;
+ ret = 0;
+@@ -1331,9 +1232,7 @@ static int cafe_vidioc_qbuf(struct file *filp, void *priv,
+ unsigned long flags;
+
+ mutex_lock(&cam->s_mutex);
+- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- goto out;
+- if (buf->index < 0 || buf->index >= cam->n_sbufs)
++ if (buf->index >= cam->n_sbufs)
+ goto out;
+ sbuf = cam->sb_bufs + buf->index;
+ if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {
+@@ -1364,8 +1263,6 @@ static int cafe_vidioc_dqbuf(struct file *filp, void *priv,
+ unsigned long flags;
+
+ mutex_lock(&cam->s_mutex);
+- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- goto out_unlock;
+ if (cam->state != S_STREAMING)
+ goto out_unlock;
+ if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) {
+@@ -1474,11 +1371,8 @@ static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
+
+ static int cafe_v4l_open(struct file *filp)
+ {
+- struct cafe_camera *cam;
++ struct cafe_camera *cam = video_drvdata(filp);
+
+- cam = cafe_find_dev(video_devdata(filp)->minor);
+- if (cam == NULL)
+- return -ENODEV;
+ filp->private_data = cam;
+
+ mutex_lock(&cam->s_mutex);
+@@ -1532,11 +1426,11 @@ static unsigned int cafe_v4l_poll(struct file *filp,
+ static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
+ struct v4l2_queryctrl *qc)
+ {
+- struct cafe_camera *cam = filp->private_data;
++ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+- ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc);
++ ret = sensor_call(cam, core, queryctrl, qc);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+ }
+@@ -1545,11 +1439,11 @@ static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
+ static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct cafe_camera *cam = filp->private_data;
++ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+- ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl);
++ ret = sensor_call(cam, core, g_ctrl, ctrl);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+ }
+@@ -1558,11 +1452,11 @@ static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
+ static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+ {
+- struct cafe_camera *cam = filp->private_data;
++ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+- ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl);
++ ret = sensor_call(cam, core, s_ctrl, ctrl);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+ }
+@@ -1601,10 +1495,8 @@ static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
+ struct cafe_camera *cam = priv;
+ int ret;
+
+- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+ mutex_lock(&cam->s_mutex);
+- ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt);
++ ret = sensor_call(cam, video, enum_fmt, fmt);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+ }
+@@ -1617,7 +1509,7 @@ static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+- ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt);
++ ret = sensor_call(cam, video, try_fmt, fmt);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+ }
+@@ -1726,7 +1618,7 @@ static int cafe_vidioc_g_parm(struct file *filp, void *priv,
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+- ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms);
++ ret = sensor_call(cam, video, g_parm, parms);
+ mutex_unlock(&cam->s_mutex);
+ parms->parm.capture.readbuffers = n_dma_bufs;
+ return ret;
+@@ -1739,20 +1631,52 @@ static int cafe_vidioc_s_parm(struct file *filp, void *priv,
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+- ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms);
++ ret = sensor_call(cam, video, s_parm, parms);
+ mutex_unlock(&cam->s_mutex);
+ parms->parm.capture.readbuffers = n_dma_bufs;
+ return ret;
+ }
+
++static int cafe_vidioc_g_chip_ident(struct file *file, void *priv,
++ struct v4l2_dbg_chip_ident *chip)
++{
++ struct cafe_camera *cam = priv;
+
+-static void cafe_v4l_dev_release(struct video_device *vd)
++ chip->ident = V4L2_IDENT_NONE;
++ chip->revision = 0;
++ if (v4l2_chip_match_host(&chip->match)) {
++ chip->ident = V4L2_IDENT_CAFE;
++ return 0;
++ }
++ return sensor_call(cam, core, g_chip_ident, chip);
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int cafe_vidioc_g_register(struct file *file, void *priv,
++ struct v4l2_dbg_register *reg)
+ {
+- struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
++ struct cafe_camera *cam = priv;
+
+- kfree(cam);
++ if (v4l2_chip_match_host(&reg->match)) {
++ reg->val = cafe_reg_read(cam, reg->reg);
++ reg->size = 4;
++ return 0;
++ }
++ return sensor_call(cam, core, g_register, reg);
+ }
+
++static int cafe_vidioc_s_register(struct file *file, void *priv,
++ struct v4l2_dbg_register *reg)
++{
++ struct cafe_camera *cam = priv;
++
++ if (v4l2_chip_match_host(&reg->match)) {
++ cafe_reg_write(cam, reg->reg, reg->val);
++ return 0;
++ }
++ return sensor_call(cam, core, s_register, reg);
++}
++#endif
+
+ /*
+ * This template device holds all of those v4l2 methods; we
+@@ -1790,6 +1714,11 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
+ .vidioc_s_ctrl = cafe_vidioc_s_ctrl,
+ .vidioc_g_parm = cafe_vidioc_g_parm,
+ .vidioc_s_parm = cafe_vidioc_s_parm,
++ .vidioc_g_chip_ident = cafe_vidioc_g_chip_ident,
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .vidioc_g_register = cafe_vidioc_g_register,
++ .vidioc_s_register = cafe_vidioc_s_register,
++#endif
+ };
+
+ static struct video_device cafe_v4l_template = {
+@@ -1800,15 +1729,10 @@ static struct video_device cafe_v4l_template = {
+
+ .fops = &cafe_v4l_fops,
+ .ioctl_ops = &cafe_v4l_ioctl_ops,
+- .release = cafe_v4l_dev_release,
++ .release = video_device_release_empty,
+ };
+
+
+-
+-
+-
+-
+-
+ /* ---------------------------------------------------------------------- */
+ /*
+ * Interrupt handler stuff
+@@ -1962,127 +1886,6 @@ static irqreturn_t cafe_irq(int irq, void *data)
+
+
+ /* -------------------------------------------------------------------------- */
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+-/*
+- * Debugfs stuff.
+- */
+-
+-static char cafe_debug_buf[1024];
+-static struct dentry *cafe_dfs_root;
+-
+-static void cafe_dfs_setup(void)
+-{
+- cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL);
+- if (IS_ERR(cafe_dfs_root)) {
+- cafe_dfs_root = NULL; /* Never mind */
+- printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n");
+- }
+-}
+-
+-static void cafe_dfs_shutdown(void)
+-{
+- if (cafe_dfs_root)
+- debugfs_remove(cafe_dfs_root);
+-}
+-
+-static int cafe_dfs_open(struct inode *inode, struct file *file)
+-{
+- file->private_data = inode->i_private;
+- return 0;
+-}
+-
+-static ssize_t cafe_dfs_read_regs(struct file *file,
+- char __user *buf, size_t count, loff_t *ppos)
+-{
+- struct cafe_camera *cam = file->private_data;
+- char *s = cafe_debug_buf;
+- int offset;
+-
+- for (offset = 0; offset < 0x44; offset += 4)
+- s += sprintf(s, "%02x: %08x\n", offset,
+- cafe_reg_read(cam, offset));
+- for (offset = 0x88; offset <= 0x90; offset += 4)
+- s += sprintf(s, "%02x: %08x\n", offset,
+- cafe_reg_read(cam, offset));
+- for (offset = 0xb4; offset <= 0xbc; offset += 4)
+- s += sprintf(s, "%02x: %08x\n", offset,
+- cafe_reg_read(cam, offset));
+- for (offset = 0x3000; offset <= 0x300c; offset += 4)
+- s += sprintf(s, "%04x: %08x\n", offset,
+- cafe_reg_read(cam, offset));
+- return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
+- s - cafe_debug_buf);
+-}
+-
+-static const struct file_operations cafe_dfs_reg_ops = {
+- .owner = THIS_MODULE,
+- .read = cafe_dfs_read_regs,
+- .open = cafe_dfs_open
+-};
+-
+-static ssize_t cafe_dfs_read_cam(struct file *file,
+- char __user *buf, size_t count, loff_t *ppos)
+-{
+- struct cafe_camera *cam = file->private_data;
+- char *s = cafe_debug_buf;
+- int offset;
+-
+- if (! cam->sensor)
+- return -EINVAL;
+- for (offset = 0x0; offset < 0x8a; offset++)
+- {
+- u8 v;
+-
+- cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v);
+- s += sprintf(s, "%02x: %02x\n", offset, v);
+- }
+- return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
+- s - cafe_debug_buf);
+-}
+-
+-static const struct file_operations cafe_dfs_cam_ops = {
+- .owner = THIS_MODULE,
+- .read = cafe_dfs_read_cam,
+- .open = cafe_dfs_open
+-};
+-
+-
+-
+-static void cafe_dfs_cam_setup(struct cafe_camera *cam)
+-{
+- char fname[40];
+-
+- if (!cafe_dfs_root)
+- return;
+- sprintf(fname, "regs-%d", cam->v4ldev.num);
+- cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
+- cam, &cafe_dfs_reg_ops);
+- sprintf(fname, "cam-%d", cam->v4ldev.num);
+- cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
+- cam, &cafe_dfs_cam_ops);
+-}
+-
+-
+-static void cafe_dfs_cam_shutdown(struct cafe_camera *cam)
+-{
+- if (! IS_ERR(cam->dfs_regs))
+- debugfs_remove(cam->dfs_regs);
+- if (! IS_ERR(cam->dfs_cam_regs))
+- debugfs_remove(cam->dfs_cam_regs);
+-}
+-
+-#else
+-
+-#define cafe_dfs_setup()
+-#define cafe_dfs_shutdown()
+-#define cafe_dfs_cam_setup(cam)
+-#define cafe_dfs_cam_shutdown(cam)
+-#endif /* CONFIG_VIDEO_ADV_DEBUG */
+-
+-
+-
+-
+-/* ------------------------------------------------------------------------*/
+ /*
+ * PCI interface stuff.
+ */
+@@ -2100,6 +1903,10 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+ cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
+ if (cam == NULL)
+ goto out;
++ ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
++ if (ret)
++ goto out_free;
++
+ mutex_init(&cam->s_mutex);
+ mutex_lock(&cam->s_mutex);
+ spin_lock_init(&cam->dev_lock);
+@@ -2118,14 +1925,14 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+ */
+ ret = pci_enable_device(pdev);
+ if (ret)
+- goto out_free;
++ goto out_unreg;
+ pci_set_master(pdev);
+
+ ret = -EIO;
+ cam->regs = pci_iomap(pdev, 0, 0);
+ if (! cam->regs) {
+ printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
+- goto out_free;
++ goto out_unreg;
+ }
+ ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
+ if (ret)
+@@ -2145,17 +1952,31 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+ ret = cafe_smbus_setup(cam);
+ if (ret)
+ goto out_freeirq;
++
++ cam->sensor_addr = 0x42;
++ cam->sensor = v4l2_i2c_new_subdev(&cam->i2c_adapter,
++ "ov7670", "ov7670", cam->sensor_addr);
++ if (cam->sensor == NULL) {
++ ret = -ENODEV;
++ goto out_smbus;
++ }
++ ret = cafe_cam_init(cam);
++ if (ret)
++ goto out_smbus;
++
+ /*
+ * Get the v4l2 setup done.
+ */
+ mutex_lock(&cam->s_mutex);
+- cam->v4ldev = cafe_v4l_template;
+- cam->v4ldev.debug = 0;
+-// cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;
+- cam->v4ldev.parent = &pdev->dev;
+- ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
++ cam->vdev = cafe_v4l_template;
++ cam->vdev.debug = 0;
++/* cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/
++ cam->vdev.v4l2_dev = &cam->v4l2_dev;
++ ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto out_smbus;
++ video_set_drvdata(&cam->vdev, cam);
++
+ /*
+ * If so requested, try to get our DMA buffers now.
+ */
+@@ -2165,21 +1986,21 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+ " will try again later.");
+ }
+
+- cafe_dfs_cam_setup(cam);
+ mutex_unlock(&cam->s_mutex);
+- cafe_add_dev(cam);
+ return 0;
+
+- out_smbus:
++out_smbus:
+ cafe_smbus_shutdown(cam);
+- out_freeirq:
++out_freeirq:
+ cafe_ctlr_power_down(cam);
+ free_irq(pdev->irq, cam);
+- out_iounmap:
++out_iounmap:
+ pci_iounmap(pdev, cam->regs);
+- out_free:
++out_free:
++ v4l2_device_unregister(&cam->v4l2_dev);
++out_unreg:
+ kfree(cam);
+- out:
++out:
+ return ret;
+ }
+
+@@ -2190,25 +2011,23 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+ static void cafe_shutdown(struct cafe_camera *cam)
+ {
+ /* FIXME: Make sure we take care of everything here */
+- cafe_dfs_cam_shutdown(cam);
+ if (cam->n_sbufs > 0)
+ /* What if they are still mapped? Shouldn't be, but... */
+ cafe_free_sio_buffers(cam);
+- cafe_remove_dev(cam);
+ cafe_ctlr_stop_dma(cam);
+ cafe_ctlr_power_down(cam);
+ cafe_smbus_shutdown(cam);
+ cafe_free_dma_bufs(cam);
+ free_irq(cam->pdev->irq, cam);
+ pci_iounmap(cam->pdev, cam->regs);
+- video_unregister_device(&cam->v4ldev);
+- /* kfree(cam); done in v4l_release () */
++ video_unregister_device(&cam->vdev);
+ }
+
+
+ static void cafe_pci_remove(struct pci_dev *pdev)
+ {
+- struct cafe_camera *cam = cafe_find_by_pdev(pdev);
++ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
++ struct cafe_camera *cam = to_cam(v4l2_dev);
+
+ if (cam == NULL) {
+ printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
+@@ -2218,6 +2037,8 @@ static void cafe_pci_remove(struct pci_dev *pdev)
+ if (cam->users > 0)
+ cam_warn(cam, "Removing a device with users!\n");
+ cafe_shutdown(cam);
++ v4l2_device_unregister(&cam->v4l2_dev);
++ kfree(cam);
+ /* No unlock - it no longer exists */
+ }
+
+@@ -2228,7 +2049,8 @@ static void cafe_pci_remove(struct pci_dev *pdev)
+ */
+ static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+ {
+- struct cafe_camera *cam = cafe_find_by_pdev(pdev);
++ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
++ struct cafe_camera *cam = to_cam(v4l2_dev);
+ int ret;
+ enum cafe_state cstate;
+
+@@ -2246,7 +2068,8 @@ static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+
+ static int cafe_pci_resume(struct pci_dev *pdev)
+ {
+- struct cafe_camera *cam = cafe_find_by_pdev(pdev);
++ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
++ struct cafe_camera *cam = to_cam(v4l2_dev);
+ int ret = 0;
+
+ ret = pci_restore_state(pdev);
+@@ -2307,13 +2130,11 @@ static int __init cafe_init(void)
+
+ printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
+ CAFE_VERSION);
+- cafe_dfs_setup();
+ ret = pci_register_driver(&cafe_pci_driver);
+ if (ret) {
+ printk(KERN_ERR "Unable to register cafe_ccic driver\n");
+ goto out;
+ }
+- request_module("ov7670"); /* FIXME want something more general */
+ ret = 0;
+
+ out:
+@@ -2324,7 +2145,6 @@ static int __init cafe_init(void)
+ static void __exit cafe_exit(void)
+ {
+ pci_unregister_driver(&cafe_pci_driver);
+- cafe_dfs_shutdown();
+ }
+
+ module_init(cafe_init);
+diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
+index 9c25894..d4099f5 100644
+--- a/drivers/media/video/cpia2/cpia2_v4l.c
++++ b/drivers/media/video/cpia2/cpia2_v4l.c
+@@ -37,6 +37,7 @@
+ #include <linux/sched.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
++#include <linux/videodev.h>
+ #include <media/v4l2-ioctl.h>
+
+ #include "cpia2.h"
+diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
+index 87e9107..9714059 100644
+--- a/drivers/media/video/cs5345.c
++++ b/drivers/media/video/cs5345.c
+@@ -141,11 +141,6 @@ static int cs5345_log_status(struct v4l2_subdev *sd)
+ return 0;
+ }
+
+-static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops cs5345_core_ops = {
+@@ -214,8 +209,6 @@ MODULE_DEVICE_TABLE(i2c, cs5345_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "cs5345",
+- .driverid = I2C_DRIVERID_CS5345,
+- .command = cs5345_command,
+ .probe = cs5345_probe,
+ .remove = cs5345_remove,
+ .id_table = cs5345_id,
+diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
+index 7292a63..5aeb066 100644
+--- a/drivers/media/video/cs53l32a.c
++++ b/drivers/media/video/cs53l32a.c
+@@ -29,7 +29,7 @@
+ #include <linux/videodev2.h>
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-chip-ident.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
+ MODULE_AUTHOR("Martin Vaughan");
+@@ -41,9 +41,6 @@ module_param(debug, bool, 0644);
+
+ MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
+
+-static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+-
+-I2C_CLIENT_INSMOD;
+
+ /* ----------------------------------------------------------------------- */
+
+@@ -122,11 +119,6 @@ static int cs53l32a_log_status(struct v4l2_subdev *sd)
+ return 0;
+ }
+
+-static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
+@@ -218,8 +210,6 @@ MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "cs53l32a",
+- .driverid = I2C_DRIVERID_CS53L32A,
+- .command = cs53l32a_command,
+ .remove = cs53l32a_remove,
+ .probe = cs53l32a_probe,
+ .id_table = cs53l32a_id,
+diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
+index 8940b53..e8a50a6 100644
+--- a/drivers/media/video/cx18/Kconfig
++++ b/drivers/media/video/cx18/Kconfig
+@@ -9,7 +9,7 @@ config VIDEO_CX18
+ select VIDEO_CX2341X
+ select VIDEO_CS5345
+ select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+ ---help---
+ This is a video4linux driver for Conexant cx23418 based
+ PCI combo video recorder devices.
+diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c
+index 57beddf..bb5c516 100644
+--- a/drivers/media/video/cx18/cx18-audio.c
++++ b/drivers/media/video/cx18/cx18-audio.c
+@@ -23,7 +23,6 @@
+
+ #include "cx18-driver.h"
+ #include "cx18-io.h"
+-#include "cx18-i2c.h"
+ #include "cx18-cards.h"
+ #include "cx18-audio.h"
+
+@@ -33,55 +32,32 @@
+ settings. */
+ int cx18_audio_set_io(struct cx18 *cx)
+ {
++ const struct cx18_card_audio_input *in;
+ struct v4l2_routing route;
+- u32 audio_input;
+ u32 val;
+- int mux_input;
+ int err;
+
+ /* Determine which input to use */
+- if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+- audio_input = cx->card->radio_input.audio_input;
+- mux_input = cx->card->radio_input.muxer_input;
+- } else {
+- audio_input =
+- cx->card->audio_inputs[cx->audio_input].audio_input;
+- mux_input =
+- cx->card->audio_inputs[cx->audio_input].muxer_input;
+- }
++ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
++ in = &cx->card->radio_input;
++ else
++ in = &cx->card->audio_inputs[cx->audio_input];
+
+ /* handle muxer chips */
+- route.input = mux_input;
++ route.input = in->muxer_input;
+ route.output = 0;
+- cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
++ v4l2_subdev_call(cx->sd_extmux, audio, s_routing, &route);
+
+- route.input = audio_input;
+- err = cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+- VIDIOC_INT_S_AUDIO_ROUTING, &route);
++ route.input = in->audio_input;
++ err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl,
++ audio, s_routing, &route);
+ if (err)
+ return err;
+
++ /* FIXME - this internal mux should be abstracted to a subdev */
+ val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
+- val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
+- (audio_input << 4);
+- cx18_write_reg(cx, val | 0xb00, CX18_AUDIO_ENABLE);
+- cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
++ val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
++ (in->audio_input << 4);
++ cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30);
+ return 0;
+ }
+-
+-void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
+-{
+- cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+- VIDIOC_INT_S_AUDIO_ROUTING, route);
+-}
+-
+-void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq)
+-{
+- static u32 freqs[3] = { 44100, 48000, 32000 };
+-
+- /* The audio clock of the digitizer must match the codec sample
+- rate otherwise you get some very strange effects. */
+- if (freq > 2)
+- return;
+- cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
+-}
+diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h
+index cb569a6..2731d29 100644
+--- a/drivers/media/video/cx18/cx18-audio.h
++++ b/drivers/media/video/cx18/cx18-audio.h
+@@ -22,5 +22,3 @@
+ */
+
+ int cx18_audio_set_io(struct cx18 *cx);
+-void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route);
+-void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq);
+diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c
+index a2f0ad5..9e30983 100644
+--- a/drivers/media/video/cx18/cx18-av-audio.c
++++ b/drivers/media/video/cx18/cx18-av-audio.c
+@@ -464,82 +464,76 @@ static void set_mute(struct cx18 *cx, int mute)
+ }
+ }
+
+-int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
++int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+ {
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
+ struct cx18_av_state *state = &cx->av_state;
+- struct v4l2_control *ctrl = arg;
+ int retval;
++ u8 v;
+
+- switch (cmd) {
+- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+- {
+- u8 v;
+- if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+- v = cx18_av_read(cx, 0x803) & ~0x10;
+- cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+- cx18_av_write(cx, 0x8d3, 0x1f);
+- }
+- v = cx18_av_read(cx, 0x810) | 0x1;
+- cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
++ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
++ v = cx18_av_read(cx, 0x803) & ~0x10;
++ cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
++ cx18_av_write(cx, 0x8d3, 0x1f);
++ }
++ v = cx18_av_read(cx, 0x810) | 0x1;
++ cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+
+- retval = set_audclk_freq(cx, *(u32 *)arg);
++ retval = set_audclk_freq(cx, freq);
+
+- v = cx18_av_read(cx, 0x810) & ~0x1;
+- cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+- if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+- v = cx18_av_read(cx, 0x803) | 0x10;
+- cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+- }
+- return retval;
++ v = cx18_av_read(cx, 0x810) & ~0x1;
++ cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
++ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
++ v = cx18_av_read(cx, 0x803) | 0x10;
++ cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+ }
++ return retval;
++}
+
+- case VIDIOC_G_CTRL:
+- switch (ctrl->id) {
+- case V4L2_CID_AUDIO_VOLUME:
+- ctrl->value = get_volume(cx);
+- break;
+- case V4L2_CID_AUDIO_BASS:
+- ctrl->value = get_bass(cx);
+- break;
+- case V4L2_CID_AUDIO_TREBLE:
+- ctrl->value = get_treble(cx);
+- break;
+- case V4L2_CID_AUDIO_BALANCE:
+- ctrl->value = get_balance(cx);
+- break;
+- case V4L2_CID_AUDIO_MUTE:
+- ctrl->value = get_mute(cx);
+- break;
+- default:
+- return -EINVAL;
+- }
++int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
++{
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value = get_volume(cx);
+ break;
+-
+- case VIDIOC_S_CTRL:
+- switch (ctrl->id) {
+- case V4L2_CID_AUDIO_VOLUME:
+- set_volume(cx, ctrl->value);
+- break;
+- case V4L2_CID_AUDIO_BASS:
+- set_bass(cx, ctrl->value);
+- break;
+- case V4L2_CID_AUDIO_TREBLE:
+- set_treble(cx, ctrl->value);
+- break;
+- case V4L2_CID_AUDIO_BALANCE:
+- set_balance(cx, ctrl->value);
+- break;
+- case V4L2_CID_AUDIO_MUTE:
+- set_mute(cx, ctrl->value);
+- break;
+- default:
+- return -EINVAL;
+- }
++ case V4L2_CID_AUDIO_BASS:
++ ctrl->value = get_bass(cx);
++ break;
++ case V4L2_CID_AUDIO_TREBLE:
++ ctrl->value = get_treble(cx);
++ break;
++ case V4L2_CID_AUDIO_BALANCE:
++ ctrl->value = get_balance(cx);
++ break;
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value = get_mute(cx);
+ break;
+-
+ default:
+ return -EINVAL;
+ }
++ return 0;
++}
+
++int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
++{
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_VOLUME:
++ set_volume(cx, ctrl->value);
++ break;
++ case V4L2_CID_AUDIO_BASS:
++ set_bass(cx, ctrl->value);
++ break;
++ case V4L2_CID_AUDIO_TREBLE:
++ set_treble(cx, ctrl->value);
++ break;
++ case V4L2_CID_AUDIO_BALANCE:
++ set_balance(cx, ctrl->value);
++ break;
++ case V4L2_CID_AUDIO_MUTE:
++ set_mute(cx, ctrl->value);
++ break;
++ default:
++ return -EINVAL;
++ }
+ return 0;
+ }
+diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
+index 0b1c84b..f4dd9d7 100644
+--- a/drivers/media/video/cx18/cx18-av-core.c
++++ b/drivers/media/video/cx18/cx18-av-core.c
+@@ -22,8 +22,10 @@
+ * 02110-1301, USA.
+ */
+
++#include <media/v4l2-chip-ident.h>
+ #include "cx18-driver.h"
+ #include "cx18-io.h"
++#include "cx18-cards.h"
+
+ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
+ {
+@@ -97,15 +99,6 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
+ or_value);
+ }
+
+-/* ----------------------------------------------------------------------- */
+-
+-static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+- enum cx18_av_audio_input aud_input);
+-static void log_audio_status(struct cx18 *cx);
+-static void log_video_status(struct cx18 *cx);
+-
+-/* ----------------------------------------------------------------------- */
+-
+ static void cx18_av_initialize(struct cx18 *cx)
+ {
+ struct cx18_av_state *state = &cx->av_state;
+@@ -169,9 +162,14 @@ static void cx18_av_initialize(struct cx18 *cx)
+ /* Set VGA_TRACK_RANGE to 0x20 */
+ cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
+
+- /* Enable VBI capture */
+- cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F);
+- /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */
++ /*
++ * Initial VBI setup
++ * VIP-1.1, 10 bit mode, enable Raw, disable sliced,
++ * don't clamp raw samples when codes are in use, 1 byte user D-words,
++ * IDID0 has line #, RP code V bit transition on VBLANK, data during
++ * blanking intervals
++ */
++ cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4013252e);
+
+ /* Set the video input.
+ The setting in MODE_CTRL gets lost when we do the above setup */
+@@ -195,11 +193,61 @@ static void cx18_av_initialize(struct cx18 *cx)
+ state->default_volume = ((state->default_volume / 2) + 23) << 9;
+ }
+
+-/* ----------------------------------------------------------------------- */
++static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
++ cx18_av_initialize(cx);
++ return 0;
++}
++
++static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
++{
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
++ switch (val) {
++ case CX18_AV_INIT_PLLS:
++ /*
++ * The crystal freq used in calculations in this driver will be
++ * 28.636360 MHz.
++ * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
++ */
++
++ /*
++ * VDCLK Integer = 0x0f, Post Divider = 0x04
++ * AIMCLK Integer = 0x0e, Post Divider = 0x16
++ */
++ cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
++
++ /* VDCLK Fraction = 0x2be2fe */
++ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
++ cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
++
++ /* AIMCLK Fraction = 0x05227ad */
++ /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
++ cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
++
++ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
++ cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
++ break;
++
++ case CX18_AV_INIT_NORMAL:
++ default:
++ if (!state->is_initialized) {
++ /* initialize on first use */
++ state->is_initialized = 1;
++ cx18_av_initialize(cx);
++ }
++ break;
++ }
++ return 0;
++}
+
+ void cx18_av_std_setup(struct cx18 *cx)
+ {
+ struct cx18_av_state *state = &cx->av_state;
++ struct v4l2_subdev *sd = &state->sd;
+ v4l2_std_id std = state->std;
+ int hblank, hactive, burst, vblank, vactive, sc;
+ int vblank656, src_decimation;
+@@ -213,6 +261,7 @@ void cx18_av_std_setup(struct cx18 *cx)
+ cx18_av_write(cx, 0x49f, 0x14);
+
+ if (std & V4L2_STD_625_50) {
++ /* FIXME - revisit these for Sliced VBI */
+ hblank = 132;
+ hactive = 720;
+ burst = 93;
+@@ -236,13 +285,40 @@ void cx18_av_std_setup(struct cx18 *cx)
+ sc = 672351;
+ }
+ } else {
++ /*
++ * The following relationships of half line counts should hold:
++ * 525 = vsync + vactive + vblank656
++ * 12 = vblank656 - vblank
++ *
++ * vsync: always 6 half-lines of vsync pulses
++ * vactive: half lines of active video
++ * vblank656: half lines, after line 3/mid-266, of blanked video
++ * vblank: half lines, after line 9/272, of blanked video
++ *
++ * As far as I can tell:
++ * vblank656 starts counting from the falling edge of the first
++ * vsync pulse (start of line 4 or mid-266)
++ * vblank starts counting from the after the 6 vsync pulses and
++ * 6 or 5 equalization pulses (start of line 10 or 272)
++ *
++ * For 525 line systems the driver will extract VBI information
++ * from lines 10-21 and lines 273-284.
++ */
++ vblank656 = 38; /* lines 4 - 22 & 266 - 284 */
++ vblank = 26; /* lines 10 - 22 & 272 - 284 */
++ vactive = 481; /* lines 23 - 263 & 285 - 525 */
++
++ /*
++ * For a 13.5 Mpps clock and 15,734.26 Hz line rate, a line is
++ * is 858 pixels = 720 active + 138 blanking. The Hsync leading
++ * edge should happen 1.2 us * 13.5 Mpps ~= 16 pixels after the
++ * end of active video, leaving 122 pixels of hblank to ignore
++ * before active video starts.
++ */
+ hactive = 720;
+ hblank = 122;
+- vactive = 487;
+ luma_lpf = 1;
+ uv_lpf = 1;
+- vblank = 26;
+- vblank656 = 26;
+
+ src_decimation = 0x21f;
+ if (std == V4L2_STD_PAL_60) {
+@@ -265,33 +341,35 @@ void cx18_av_std_setup(struct cx18 *cx)
+ pll_int = cx18_av_read(cx, 0x108);
+ pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
+ pll_post = cx18_av_read(cx, 0x109);
+- CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
+- pll_int, pll_frac, pll_post);
++ CX18_DEBUG_INFO_DEV(sd, "PLL regs = int: %u, frac: %u, post: %u\n",
++ pll_int, pll_frac, pll_post);
+
+ if (pll_post) {
+ int fin, fsc, pll;
+
+ pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
+ pll /= pll_post;
+- CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
+- pll / 1000000, pll % 1000000);
+- CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
+- pll / 8000000, (pll / 8) % 1000000);
++ CX18_DEBUG_INFO_DEV(sd, "PLL = %d.%06d MHz\n",
++ pll / 1000000, pll % 1000000);
++ CX18_DEBUG_INFO_DEV(sd, "PLL/8 = %d.%06d MHz\n",
++ pll / 8000000, (pll / 8) % 1000000);
+
+ fin = ((u64)src_decimation * pll) >> 12;
+- CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
+- fin / 1000000, fin % 1000000);
++ CX18_DEBUG_INFO_DEV(sd, "ADC Sampling freq = %d.%06d MHz\n",
++ fin / 1000000, fin % 1000000);
+
+ fsc = (((u64)sc) * pll) >> 24L;
+- CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
+- fsc / 1000000, fsc % 1000000);
+-
+- CX18_DEBUG_INFO("hblank %i, hactive %i, "
+- "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+- "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+- " sc 0x%06x\n",
+- hblank, hactive, vblank, vactive, vblank656,
+- src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
++ CX18_DEBUG_INFO_DEV(sd,
++ "Chroma sub-carrier freq = %d.%06d MHz\n",
++ fsc / 1000000, fsc % 1000000);
++
++ CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, "
++ "vactive %i, vblank656 %i, src_dec %i, "
++ "burst 0x%02x, luma_lpf %i, uv_lpf %i, "
++ "comb 0x%02x, sc 0x%06x\n",
++ hblank, hactive, vblank, vactive, vblank656,
++ src_decimation, burst, luma_lpf, uv_lpf,
++ comb, sc);
+ }
+
+ /* Sets horizontal blanking delay and active lines */
+@@ -325,18 +403,16 @@ void cx18_av_std_setup(struct cx18 *cx)
+ cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
+ cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
+
+- /* Sets VBI parameters */
+ if (std & V4L2_STD_625_50) {
+- cx18_av_write(cx, 0x47f, 0x01);
+- state->vbi_line_offset = 5;
++ state->slicer_line_delay = 1;
++ state->slicer_line_offset = (6 + state->slicer_line_delay - 2);
+ } else {
+- cx18_av_write(cx, 0x47f, 0x00);
+- state->vbi_line_offset = 8;
++ state->slicer_line_delay = 0;
++ state->slicer_line_offset = (10 + state->slicer_line_delay - 2);
+ }
++ cx18_av_write(cx, 0x47f, state->slicer_line_delay);
+ }
+
+-/* ----------------------------------------------------------------------- */
+-
+ static void input_change(struct cx18 *cx)
+ {
+ struct cx18_av_state *state = &cx->av_state;
+@@ -382,17 +458,26 @@ static void input_change(struct cx18 *cx)
+ }
+ }
+
++static int cx18_av_s_frequency(struct v4l2_subdev *sd,
++ struct v4l2_frequency *freq)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ input_change(cx);
++ return 0;
++}
++
+ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ enum cx18_av_audio_input aud_input)
+ {
+ struct cx18_av_state *state = &cx->av_state;
++ struct v4l2_subdev *sd = &state->sd;
+ u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
+ vid_input <= CX18_AV_COMPOSITE8);
+ u8 reg;
+ u8 v;
+
+- CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n",
+- vid_input, aud_input);
++ CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n",
++ vid_input, aud_input);
+
+ if (is_composite) {
+ reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+@@ -405,8 +490,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ luma > CX18_AV_SVIDEO_LUMA8 ||
+ chroma < CX18_AV_SVIDEO_CHROMA4 ||
+ chroma > CX18_AV_SVIDEO_CHROMA8) {
+- CX18_ERR("0x%04x is not a valid video input!\n",
+- vid_input);
++ CX18_ERR_DEV(sd, "0x%04x is not a valid video input!\n",
++ vid_input);
+ return -EINVAL;
+ }
+ reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+@@ -431,7 +516,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+
+ default:
+- CX18_ERR("0x%04x is not a valid audio input!\n", aud_input);
++ CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n",
++ aud_input);
+ return -EINVAL;
+ }
+
+@@ -461,14 +547,118 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ return 0;
+ }
+
+-/* ----------------------------------------------------------------------- */
++static int cx18_av_s_video_routing(struct v4l2_subdev *sd,
++ const struct v4l2_routing *route)
++{
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ return set_input(cx, route->input, state->aud_input);
++}
++
++static int cx18_av_s_audio_routing(struct v4l2_subdev *sd,
++ const struct v4l2_routing *route)
++{
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ return set_input(cx, state->vid_input, route->input);
++}
+
+-static int set_v4lstd(struct cx18 *cx)
++static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+ {
+- struct cx18_av_state *state = &cx->av_state;
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ u8 vpres;
++ u8 mode;
++ int val = 0;
++
++ if (state->radio)
++ return 0;
++
++ vpres = cx18_av_read(cx, 0x40e) & 0x20;
++ vt->signal = vpres ? 0xffff : 0x0;
++
++ vt->capability |=
++ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
++ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
++
++ mode = cx18_av_read(cx, 0x804);
++
++ /* get rxsubchans and audmode */
++ if ((mode & 0xf) == 1)
++ val |= V4L2_TUNER_SUB_STEREO;
++ else
++ val |= V4L2_TUNER_SUB_MONO;
++
++ if (mode == 2 || mode == 4)
++ val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
++
++ if (mode & 0x10)
++ val |= V4L2_TUNER_SUB_SAP;
++
++ vt->rxsubchans = val;
++ vt->audmode = state->audmode;
++ return 0;
++}
++
++static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
++{
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ u8 v;
++
++ if (state->radio)
++ return 0;
++
++ v = cx18_av_read(cx, 0x809);
++ v &= ~0xf;
++
++ switch (vt->audmode) {
++ case V4L2_TUNER_MODE_MONO:
++ /* mono -> mono
++ stereo -> mono
++ bilingual -> lang1 */
++ break;
++ case V4L2_TUNER_MODE_STEREO:
++ case V4L2_TUNER_MODE_LANG1:
++ /* mono -> mono
++ stereo -> stereo
++ bilingual -> lang1 */
++ v |= 0x4;
++ break;
++ case V4L2_TUNER_MODE_LANG1_LANG2:
++ /* mono -> mono
++ stereo -> stereo
++ bilingual -> lang1/lang2 */
++ v |= 0x7;
++ break;
++ case V4L2_TUNER_MODE_LANG2:
++ /* mono -> mono
++ stereo -> stereo
++ bilingual -> lang2 */
++ v |= 0x1;
++ break;
++ default:
++ return -EINVAL;
++ }
++ cx18_av_write_expect(cx, 0x809, v, v, 0xff);
++ state->audmode = vt->audmode;
++ return 0;
++}
++
++static int cx18_av_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
++{
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
+ u8 fmt = 0; /* zero is autodetect */
+ u8 pal_m = 0;
+
++ if (state->radio == 0 && state->std == norm)
++ return 0;
++
++ state->radio = 0;
++ state->std = norm;
++
+ /* First tests should be against specific std */
+ if (state->std == V4L2_STD_NTSC_M_JP) {
+ fmt = 0x2;
+@@ -493,7 +683,7 @@ static int set_v4lstd(struct cx18 *cx)
+ fmt = 0xc;
+ }
+
+- CX18_DEBUG_INFO("changing video std to fmt %i\n", fmt);
++ CX18_DEBUG_INFO_DEV(sd, "changing video std to fmt %i\n", fmt);
+
+ /* Follow step 9 of section 3.16 in the cx18_av datasheet.
+ Without this PAL may display a vertical ghosting effect.
+@@ -511,15 +701,22 @@ static int set_v4lstd(struct cx18 *cx)
+ return 0;
+ }
+
+-/* ----------------------------------------------------------------------- */
++static int cx18_av_s_radio(struct v4l2_subdev *sd)
++{
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++ state->radio = 1;
++ return 0;
++}
+
+-static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
++static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ {
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+- CX18_ERR("invalid brightness setting %d\n",
+- ctrl->value);
++ CX18_ERR_DEV(sd, "invalid brightness setting %d\n",
++ ctrl->value);
+ return -ERANGE;
+ }
+
+@@ -528,8 +725,8 @@ static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+- CX18_ERR("invalid contrast setting %d\n",
+- ctrl->value);
++ CX18_ERR_DEV(sd, "invalid contrast setting %d\n",
++ ctrl->value);
+ return -ERANGE;
+ }
+
+@@ -538,8 +735,8 @@ static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+- CX18_ERR("invalid saturation setting %d\n",
+- ctrl->value);
++ CX18_ERR_DEV(sd, "invalid saturation setting %d\n",
++ ctrl->value);
+ return -ERANGE;
+ }
+
+@@ -548,8 +745,9 @@ static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+ break;
+
+ case V4L2_CID_HUE:
+- if (ctrl->value < -127 || ctrl->value > 127) {
+- CX18_ERR("invalid hue setting %d\n", ctrl->value);
++ if (ctrl->value < -128 || ctrl->value > 127) {
++ CX18_ERR_DEV(sd, "invalid hue setting %d\n",
++ ctrl->value);
+ return -ERANGE;
+ }
+
+@@ -561,17 +759,18 @@ static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+- return cx18_av_audio(cx, VIDIOC_S_CTRL, ctrl);
++ return cx18_av_audio_s_ctrl(cx, ctrl);
+
+ default:
+ return -EINVAL;
+ }
+-
+ return 0;
+ }
+
+-static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
++static int cx18_av_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ {
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
+@@ -590,31 +789,57 @@ static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+- return cx18_av_audio(cx, VIDIOC_G_CTRL, ctrl);
++ return cx18_av_audio_g_ctrl(cx, ctrl);
+ default:
+ return -EINVAL;
+ }
+-
+ return 0;
+ }
+
+-/* ----------------------------------------------------------------------- */
+-
+-static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
++static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+ {
+- switch (fmt->type) {
+- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+- return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt);
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++
++ switch (qc->id) {
++ case V4L2_CID_BRIGHTNESS:
++ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
++ case V4L2_CID_HUE:
++ return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
++ default:
++ break;
++ }
++
++ switch (qc->id) {
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 65535,
++ 65535 / 100, state->default_volume);
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
++ case V4L2_CID_AUDIO_BALANCE:
++ case V4L2_CID_AUDIO_BASS:
++ case V4L2_CID_AUDIO_TREBLE:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+ default:
+ return -EINVAL;
+ }
++ return -EINVAL;
++}
+
+- return 0;
++static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
++ return cx18_av_vbi_g_fmt(cx, fmt);
+ }
+
+-static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
++static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+ {
+- struct cx18_av_state *state = &cx->av_state;
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
+ struct v4l2_pix_format *pix;
+ int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
+ int is_50Hz = !(state->std & V4L2_STD_525_60);
+@@ -629,12 +854,26 @@ static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+ Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
+
+- Vlines = pix->height + (is_50Hz ? 4 : 7);
+-
++ /*
++ * This adjustment reflects the excess of vactive, set in
++ * cx18_av_std_setup(), above standard values:
++ *
++ * 480 + 1 for 60 Hz systems
++ * 576 + 4 for 50 Hz systems
++ */
++ Vlines = pix->height + (is_50Hz ? 4 : 1);
++
++ /*
++ * Invalid height and width scaling requests are:
++ * 1. width less than 1/16 of the source width
++ * 2. width greater than the source width
++ * 3. height less than 1/8 of the source height
++ * 4. height greater than the source height
++ */
+ if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+- CX18_ERR("%dx%d is not a valid size!\n",
+- pix->width, pix->height);
++ CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n",
++ pix->width, pix->height);
+ return -ERANGE;
+ }
+
+@@ -651,8 +890,9 @@ static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+ else
+ filter = 3;
+
+- CX18_DEBUG_INFO("decoder set size %dx%d -> scale %ux%u\n",
+- pix->width, pix->height, HSC, VSC);
++ CX18_DEBUG_INFO_DEV(sd,
++ "decoder set size %dx%d -> scale %ux%u\n",
++ pix->width, pix->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx18_av_write(cx, 0x418, HSC & 0xff);
+@@ -666,231 +906,32 @@ static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+- return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
++ return cx18_av_vbi_s_fmt(cx, fmt);
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+- return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
++ return cx18_av_vbi_s_fmt(cx, fmt);
+
+ default:
+ return -EINVAL;
+ }
+-
+ return 0;
+ }
+
+-/* ----------------------------------------------------------------------- */
+-
+-int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
++static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable)
+ {
+- struct cx18_av_state *state = &cx->av_state;
+- struct v4l2_tuner *vt = arg;
+- struct v4l2_routing *route = arg;
+-
+- /* ignore these commands */
+- switch (cmd) {
+- case TUNER_SET_TYPE_ADDR:
+- return 0;
+- }
+-
+- if (!state->is_initialized) {
+- CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd);
+- /* initialize on first use */
+- state->is_initialized = 1;
+- cx18_av_initialize(cx);
+- }
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+- switch (cmd) {
+- case VIDIOC_INT_DECODE_VBI_LINE:
+- return cx18_av_vbi(cx, cmd, arg);
+-
+- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+- return cx18_av_audio(cx, cmd, arg);
+-
+- case VIDIOC_STREAMON:
+- CX18_DEBUG_INFO("enable output\n");
++ CX18_DEBUG_INFO_DEV(sd, "%s output\n", enable ? "enable" : "disable");
++ if (enable) {
+ cx18_av_write(cx, 0x115, 0x8c);
+ cx18_av_write(cx, 0x116, 0x07);
+- break;
+-
+- case VIDIOC_STREAMOFF:
+- CX18_DEBUG_INFO("disable output\n");
++ } else {
+ cx18_av_write(cx, 0x115, 0x00);
+ cx18_av_write(cx, 0x116, 0x00);
+- break;
+-
+- case VIDIOC_LOG_STATUS:
+- log_video_status(cx);
+- log_audio_status(cx);
+- break;
+-
+- case VIDIOC_G_CTRL:
+- return get_v4lctrl(cx, (struct v4l2_control *)arg);
+-
+- case VIDIOC_S_CTRL:
+- return set_v4lctrl(cx, (struct v4l2_control *)arg);
+-
+- case VIDIOC_QUERYCTRL:
+- {
+- struct v4l2_queryctrl *qc = arg;
+-
+- switch (qc->id) {
+- case V4L2_CID_BRIGHTNESS:
+- case V4L2_CID_CONTRAST:
+- case V4L2_CID_SATURATION:
+- case V4L2_CID_HUE:
+- return v4l2_ctrl_query_fill_std(qc);
+- default:
+- break;
+- }
+-
+- switch (qc->id) {
+- case V4L2_CID_AUDIO_VOLUME:
+- return v4l2_ctrl_query_fill(qc, 0, 65535,
+- 65535 / 100, state->default_volume);
+- case V4L2_CID_AUDIO_MUTE:
+- case V4L2_CID_AUDIO_BALANCE:
+- case V4L2_CID_AUDIO_BASS:
+- case V4L2_CID_AUDIO_TREBLE:
+- return v4l2_ctrl_query_fill_std(qc);
+- default:
+- return -EINVAL;
+- }
+- return -EINVAL;
+- }
+-
+- case VIDIOC_G_STD:
+- *(v4l2_std_id *)arg = state->std;
+- break;
+-
+- case VIDIOC_S_STD:
+- if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
+- return 0;
+- state->radio = 0;
+- state->std = *(v4l2_std_id *)arg;
+- return set_v4lstd(cx);
+-
+- case AUDC_SET_RADIO:
+- state->radio = 1;
+- break;
+-
+- case VIDIOC_INT_G_VIDEO_ROUTING:
+- route->input = state->vid_input;
+- route->output = 0;
+- break;
+-
+- case VIDIOC_INT_S_VIDEO_ROUTING:
+- return set_input(cx, route->input, state->aud_input);
+-
+- case VIDIOC_INT_G_AUDIO_ROUTING:
+- route->input = state->aud_input;
+- route->output = 0;
+- break;
+-
+- case VIDIOC_INT_S_AUDIO_ROUTING:
+- return set_input(cx, state->vid_input, route->input);
+-
+- case VIDIOC_S_FREQUENCY:
+- input_change(cx);
+- break;
+-
+- case VIDIOC_G_TUNER:
+- {
+- u8 vpres = cx18_av_read(cx, 0x40e) & 0x20;
+- u8 mode;
+- int val = 0;
+-
+- if (state->radio)
+- break;
+-
+- vt->signal = vpres ? 0xffff : 0x0;
+-
+- vt->capability |=
+- V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+- V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+-
+- mode = cx18_av_read(cx, 0x804);
+-
+- /* get rxsubchans and audmode */
+- if ((mode & 0xf) == 1)
+- val |= V4L2_TUNER_SUB_STEREO;
+- else
+- val |= V4L2_TUNER_SUB_MONO;
+-
+- if (mode == 2 || mode == 4)
+- val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+-
+- if (mode & 0x10)
+- val |= V4L2_TUNER_SUB_SAP;
+-
+- vt->rxsubchans = val;
+- vt->audmode = state->audmode;
+- break;
+- }
+-
+- case VIDIOC_S_TUNER:
+- {
+- u8 v;
+-
+- if (state->radio)
+- break;
+-
+- v = cx18_av_read(cx, 0x809);
+- v &= ~0xf;
+-
+- switch (vt->audmode) {
+- case V4L2_TUNER_MODE_MONO:
+- /* mono -> mono
+- stereo -> mono
+- bilingual -> lang1 */
+- break;
+- case V4L2_TUNER_MODE_STEREO:
+- case V4L2_TUNER_MODE_LANG1:
+- /* mono -> mono
+- stereo -> stereo
+- bilingual -> lang1 */
+- v |= 0x4;
+- break;
+- case V4L2_TUNER_MODE_LANG1_LANG2:
+- /* mono -> mono
+- stereo -> stereo
+- bilingual -> lang1/lang2 */
+- v |= 0x7;
+- break;
+- case V4L2_TUNER_MODE_LANG2:
+- /* mono -> mono
+- stereo -> stereo
+- bilingual -> lang2 */
+- v |= 0x1;
+- break;
+- default:
+- return -EINVAL;
+- }
+- cx18_av_write_expect(cx, 0x809, v, v, 0xff);
+- state->audmode = vt->audmode;
+- break;
+ }
+-
+- case VIDIOC_G_FMT:
+- return get_v4lfmt(cx, (struct v4l2_format *)arg);
+-
+- case VIDIOC_S_FMT:
+- return set_v4lfmt(cx, (struct v4l2_format *)arg);
+-
+- case VIDIOC_INT_RESET:
+- cx18_av_initialize(cx);
+- break;
+-
+- default:
+- return -EINVAL;
+- }
+-
+ return 0;
+ }
+
+-/* ----------------------------------------------------------------------- */
+-
+-/* ----------------------------------------------------------------------- */
+-
+ static void log_video_status(struct cx18 *cx)
+ {
+ static const char *const fmt_strs[] = {
+@@ -903,36 +944,40 @@ static void log_video_status(struct cx18 *cx)
+ };
+
+ struct cx18_av_state *state = &cx->av_state;
++ struct v4l2_subdev *sd = &state->sd;
+ u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf;
+ u8 gen_stat1 = cx18_av_read(cx, 0x40d);
+ u8 gen_stat2 = cx18_av_read(cx, 0x40e);
+ int vid_input = state->vid_input;
+
+- CX18_INFO("Video signal: %spresent\n",
+- (gen_stat2 & 0x20) ? "" : "not ");
+- CX18_INFO("Detected format: %s\n",
+- fmt_strs[gen_stat1 & 0xf]);
++ CX18_INFO_DEV(sd, "Video signal: %spresent\n",
++ (gen_stat2 & 0x20) ? "" : "not ");
++ CX18_INFO_DEV(sd, "Detected format: %s\n",
++ fmt_strs[gen_stat1 & 0xf]);
+
+- CX18_INFO("Specified standard: %s\n",
+- vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
++ CX18_INFO_DEV(sd, "Specified standard: %s\n",
++ vidfmt_sel ? fmt_strs[vidfmt_sel]
++ : "automatic detection");
+
+ if (vid_input >= CX18_AV_COMPOSITE1 &&
+ vid_input <= CX18_AV_COMPOSITE8) {
+- CX18_INFO("Specified video input: Composite %d\n",
+- vid_input - CX18_AV_COMPOSITE1 + 1);
++ CX18_INFO_DEV(sd, "Specified video input: Composite %d\n",
++ vid_input - CX18_AV_COMPOSITE1 + 1);
+ } else {
+- CX18_INFO("Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
+- (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
++ CX18_INFO_DEV(sd, "Specified video input: "
++ "S-Video (Luma In%d, Chroma In%d)\n",
++ (vid_input & 0xf0) >> 4,
++ (vid_input & 0xf00) >> 8);
+ }
+
+- CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq);
++ CX18_INFO_DEV(sd, "Specified audioclock freq: %d Hz\n",
++ state->audclk_freq);
+ }
+
+-/* ----------------------------------------------------------------------- */
+-
+ static void log_audio_status(struct cx18 *cx)
+ {
+ struct cx18_av_state *state = &cx->av_state;
++ struct v4l2_subdev *sd = &state->sd;
+ u8 download_ctl = cx18_av_read(cx, 0x803);
+ u8 mod_det_stat0 = cx18_av_read(cx, 0x804);
+ u8 mod_det_stat1 = cx18_av_read(cx, 0x805);
+@@ -955,7 +1000,7 @@ static void log_audio_status(struct cx18 *cx)
+ case 0xfe: p = "forced mode"; break;
+ default: p = "not defined"; break;
+ }
+- CX18_INFO("Detected audio mode: %s\n", p);
++ CX18_INFO_DEV(sd, "Detected audio mode: %s\n", p);
+
+ switch (mod_det_stat1) {
+ case 0x00: p = "not defined"; break;
+@@ -980,11 +1025,11 @@ static void log_audio_status(struct cx18 *cx)
+ case 0xff: p = "no detected audio standard"; break;
+ default: p = "not defined"; break;
+ }
+- CX18_INFO("Detected audio standard: %s\n", p);
+- CX18_INFO("Audio muted: %s\n",
+- (mute_ctl & 0x2) ? "yes" : "no");
+- CX18_INFO("Audio microcontroller: %s\n",
+- (download_ctl & 0x10) ? "running" : "stopped");
++ CX18_INFO_DEV(sd, "Detected audio standard: %s\n", p);
++ CX18_INFO_DEV(sd, "Audio muted: %s\n",
++ (mute_ctl & 0x2) ? "yes" : "no");
++ CX18_INFO_DEV(sd, "Audio microcontroller: %s\n",
++ (download_ctl & 0x10) ? "running" : "stopped");
+
+ switch (audio_config >> 4) {
+ case 0x00: p = "undefined"; break;
+@@ -1005,7 +1050,7 @@ static void log_audio_status(struct cx18 *cx)
+ case 0x0f: p = "automatic detection"; break;
+ default: p = "undefined"; break;
+ }
+- CX18_INFO("Configured audio standard: %s\n", p);
++ CX18_INFO_DEV(sd, "Configured audio standard: %s\n", p);
+
+ if ((audio_config >> 4) < 0xF) {
+ switch (audio_config & 0xF) {
+@@ -1019,7 +1064,7 @@ static void log_audio_status(struct cx18 *cx)
+ case 0x07: p = "DUAL3 (AB)"; break;
+ default: p = "undefined";
+ }
+- CX18_INFO("Configured audio mode: %s\n", p);
++ CX18_INFO_DEV(sd, "Configured audio mode: %s\n", p);
+ } else {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "BG"; break;
+@@ -1037,14 +1082,14 @@ static void log_audio_status(struct cx18 *cx)
+ case 0x0f: p = "automatic standard and mode detection"; break;
+ default: p = "undefined"; break;
+ }
+- CX18_INFO("Configured audio system: %s\n", p);
++ CX18_INFO_DEV(sd, "Configured audio system: %s\n", p);
+ }
+
+ if (aud_input)
+- CX18_INFO("Specified audio input: Tuner (In%d)\n",
+- aud_input);
++ CX18_INFO_DEV(sd, "Specified audio input: Tuner (In%d)\n",
++ aud_input);
+ else
+- CX18_INFO("Specified audio input: External\n");
++ CX18_INFO_DEV(sd, "Specified audio input: External\n");
+
+ switch (pref_mode & 0xf) {
+ case 0: p = "mono/language A"; break;
+@@ -1057,14 +1102,14 @@ static void log_audio_status(struct cx18 *cx)
+ case 7: p = "language AB"; break;
+ default: p = "undefined"; break;
+ }
+- CX18_INFO("Preferred audio mode: %s\n", p);
++ CX18_INFO_DEV(sd, "Preferred audio mode: %s\n", p);
+
+ if ((audio_config & 0xf) == 0xf) {
+ switch ((afc0 >> 3) & 0x1) {
+ case 0: p = "system DK"; break;
+ case 1: p = "system L"; break;
+ }
+- CX18_INFO("Selected 65 MHz format: %s\n", p);
++ CX18_INFO_DEV(sd, "Selected 65 MHz format: %s\n", p);
+
+ switch (afc0 & 0x7) {
+ case 0: p = "Chroma"; break;
+@@ -1074,6 +1119,131 @@ static void log_audio_status(struct cx18 *cx)
+ case 4: p = "autodetect"; break;
+ default: p = "undefined"; break;
+ }
+- CX18_INFO("Selected 45 MHz format: %s\n", p);
++ CX18_INFO_DEV(sd, "Selected 45 MHz format: %s\n", p);
+ }
+ }
++
++static int cx18_av_log_status(struct v4l2_subdev *sd)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ log_video_status(cx);
++ log_audio_status(cx);
++ return 0;
++}
++
++static inline int cx18_av_dbg_match(const struct v4l2_dbg_match *match)
++{
++ return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 1;
++}
++
++static int cx18_av_g_chip_ident(struct v4l2_subdev *sd,
++ struct v4l2_dbg_chip_ident *chip)
++{
++ struct cx18_av_state *state = to_cx18_av_state(sd);
++
++ if (cx18_av_dbg_match(&chip->match)) {
++ chip->ident = state->id;
++ chip->revision = state->rev;
++ }
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int cx18_av_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
++ if (!cx18_av_dbg_match(&reg->match))
++ return -EINVAL;
++ if ((reg->reg & 0x3) != 0)
++ return -EINVAL;
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ reg->size = 4;
++ reg->val = cx18_av_read4(cx, reg->reg & 0x00000ffc);
++ return 0;
++}
++
++static int cx18_av_s_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
++ if (!cx18_av_dbg_match(&reg->match))
++ return -EINVAL;
++ if ((reg->reg & 0x3) != 0)
++ return -EINVAL;
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ cx18_av_write4(cx, reg->reg & 0x00000ffc, reg->val);
++ return 0;
++}
++#endif
++
++static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
++ .g_chip_ident = cx18_av_g_chip_ident,
++ .log_status = cx18_av_log_status,
++ .init = cx18_av_init,
++ .reset = cx18_av_reset,
++ .queryctrl = cx18_av_queryctrl,
++ .g_ctrl = cx18_av_g_ctrl,
++ .s_ctrl = cx18_av_s_ctrl,
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = cx18_av_g_register,
++ .s_register = cx18_av_s_register,
++#endif
++};
++
++static const struct v4l2_subdev_tuner_ops cx18_av_tuner_ops = {
++ .s_radio = cx18_av_s_radio,
++ .s_frequency = cx18_av_s_frequency,
++ .g_tuner = cx18_av_g_tuner,
++ .s_tuner = cx18_av_s_tuner,
++ .s_std = cx18_av_s_std,
++};
++
++static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = {
++ .s_clock_freq = cx18_av_s_clock_freq,
++ .s_routing = cx18_av_s_audio_routing,
++};
++
++static const struct v4l2_subdev_video_ops cx18_av_video_ops = {
++ .s_routing = cx18_av_s_video_routing,
++ .decode_vbi_line = cx18_av_decode_vbi_line,
++ .s_stream = cx18_av_s_stream,
++ .g_fmt = cx18_av_g_fmt,
++ .s_fmt = cx18_av_s_fmt,
++};
++
++static const struct v4l2_subdev_ops cx18_av_ops = {
++ .core = &cx18_av_general_ops,
++ .tuner = &cx18_av_tuner_ops,
++ .audio = &cx18_av_audio_ops,
++ .video = &cx18_av_video_ops,
++};
++
++int cx18_av_probe(struct cx18 *cx)
++{
++ struct cx18_av_state *state = &cx->av_state;
++ struct v4l2_subdev *sd;
++
++ state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff;
++ state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO)
++ ? V4L2_IDENT_CX23418_843 : V4L2_IDENT_UNKNOWN;
++
++ state->vid_input = CX18_AV_COMPOSITE7;
++ state->aud_input = CX18_AV_AUDIO8;
++ state->audclk_freq = 48000;
++ state->audmode = V4L2_TUNER_MODE_LANG1;
++ state->slicer_line_delay = 0;
++ state->slicer_line_offset = (10 + state->slicer_line_delay - 2);
++
++ sd = &state->sd;
++ v4l2_subdev_init(sd, &cx18_av_ops);
++ v4l2_set_subdevdata(sd, cx);
++ snprintf(sd->name, sizeof(sd->name),
++ "%s %03x", cx->v4l2_dev.name, (state->rev >> 4));
++ sd->grp_id = CX18_HW_418_AV;
++ return v4l2_device_register_subdev(&cx->v4l2_dev, sd);
++}
+diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
+index cf68a60..c458120 100644
+--- a/drivers/media/video/cx18/cx18-av-core.h
++++ b/drivers/media/video/cx18/cx18-av-core.h
+@@ -25,6 +25,8 @@
+ #ifndef _CX18_AV_CORE_H_
+ #define _CX18_AV_CORE_H_
+
++#include <media/v4l2-device.h>
++
+ struct cx18;
+
+ enum cx18_av_video_input {
+@@ -73,17 +75,40 @@ enum cx18_av_audio_input {
+ };
+
+ struct cx18_av_state {
++ struct v4l2_subdev sd;
+ int radio;
+ v4l2_std_id std;
+ enum cx18_av_video_input vid_input;
+ enum cx18_av_audio_input aud_input;
+ u32 audclk_freq;
+ int audmode;
+- int vbi_line_offset;
+ int default_volume;
+ u32 id;
+ u32 rev;
+ int is_initialized;
++
++ /*
++ * The VBI slicer starts operating and counting lines, begining at
++ * slicer line count of 1, at D lines after the deassertion of VRESET.
++ * This staring field line, S, is 6 (& 319) or 10 (& 273) for 625 or 525
++ * line systems respectively. Sliced ancillary data captured on VBI
++ * slicer line M is inserted after the VBI slicer is done with line M,
++ * when VBI slicer line count is N = M+1. Thus when the VBI slicer
++ * reports a VBI slicer line number with ancillary data, the IDID0 byte
++ * indicates VBI slicer line N. The actual field line that the captured
++ * data comes from is
++ *
++ * L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2).
++ *
++ * L is the line in the field, not frame, from which the VBI data came.
++ * N is the line reported by the slicer in the ancillary data.
++ * D is the slicer_line_delay value programmed into register 0x47f.
++ * S is 6 for 625 line systems or 10 for 525 line systems
++ * (S+D-2) is the slicer_line_offset used to convert slicer reported
++ * line counts to actual field lines.
++ */
++ int slicer_line_delay;
++ int slicer_line_offset;
+ };
+
+
+@@ -298,6 +323,16 @@ struct cx18_av_state {
+ #define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */
+ #define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */
+
++static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct cx18_av_state, sd);
++}
++
++enum cx18_av_subdev_init_arg {
++ CX18_AV_INIT_NORMAL = 0,
++ CX18_AV_INIT_PLLS = 1,
++};
++
+ /* ----------------------------------------------------------------------- */
+ /* cx18_av-core.c */
+ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
+@@ -310,20 +345,26 @@ u8 cx18_av_read(struct cx18 *cx, u16 addr);
+ u32 cx18_av_read4(struct cx18 *cx, u16 addr);
+ int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
+ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
+-int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
+ void cx18_av_std_setup(struct cx18 *cx);
+
++int cx18_av_probe(struct cx18 *cx);
++
+ /* ----------------------------------------------------------------------- */
+ /* cx18_av-firmware.c */
+ int cx18_av_loadfw(struct cx18 *cx);
+
+ /* ----------------------------------------------------------------------- */
+ /* cx18_av-audio.c */
+-int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg);
++int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
++int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
++int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
+ void cx18_av_audio_set_path(struct cx18 *cx);
+
+ /* ----------------------------------------------------------------------- */
+ /* cx18_av-vbi.c */
+-int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
++int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
++ struct v4l2_decode_vbi_line *vbi);
++int cx18_av_vbi_g_fmt(struct cx18 *cx, struct v4l2_format *fmt);
++int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt);
+
+ #endif
+diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
+index c64fd0a..49a55cc 100644
+--- a/drivers/media/video/cx18/cx18-av-firmware.c
++++ b/drivers/media/video/cx18/cx18-av-firmware.c
+@@ -29,6 +29,7 @@
+
+ int cx18_av_loadfw(struct cx18 *cx)
+ {
++ struct v4l2_subdev *sd = &cx->av_state.sd;
+ const struct firmware *fw = NULL;
+ u32 size;
+ u32 v;
+@@ -36,8 +37,8 @@ int cx18_av_loadfw(struct cx18 *cx)
+ int i;
+ int retries1 = 0;
+
+- if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
+- CX18_ERR("unable to open firmware %s\n", FWFILE);
++ if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) {
++ CX18_ERR_DEV(sd, "unable to open firmware %s\n", FWFILE);
+ return -EINVAL;
+ }
+
+@@ -88,7 +89,7 @@ int cx18_av_loadfw(struct cx18 *cx)
+ retries1++;
+ }
+ if (retries1 >= 5) {
+- CX18_ERR("unable to load firmware %s\n", FWFILE);
++ CX18_ERR_DEV(sd, "unable to load firmware %s\n", FWFILE);
+ release_firmware(fw);
+ return -EIO;
+ }
+@@ -115,9 +116,9 @@ int cx18_av_loadfw(struct cx18 *cx)
+ are generated) */
+ cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0);
+
+- /* set alt I2s master clock to /16 and enable alt divider i2s
++ /* set alt I2s master clock to /0x16 and enable alt divider i2s
+ passthrough */
+- cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687);
++ cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687);
+
+ cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6,
+ 0x3F00FFFF);
+@@ -131,7 +132,8 @@ int cx18_av_loadfw(struct cx18 *cx)
+ v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+ /* If bit 11 is 1, clear bit 10 */
+ if (v & 0x800)
+- cx18_write_reg(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE);
++ cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
++ 0, 0x400);
+
+ /* Enable WW auto audio standard detection */
+ v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
+@@ -142,6 +144,6 @@ int cx18_av_loadfw(struct cx18 *cx)
+
+ release_firmware(fw);
+
+- CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size);
++ CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
+ return 0;
+ }
+diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c
+index 1527ea4..23b3167 100644
+--- a/drivers/media/video/cx18/cx18-av-vbi.c
++++ b/drivers/media/video/cx18/cx18-av-vbi.c
+@@ -24,6 +24,52 @@
+
+ #include "cx18-driver.h"
+
++/*
++ * For sliced VBI output, we set up to use VIP-1.1, 8-bit mode,
++ * NN counts 1 byte Dwords, an IDID with the VBI line # in it.
++ * Thus, according to the VIP-2 Spec, our VBI ancillary data lines
++ * (should!) look like:
++ * 4 byte EAV code: 0xff 0x00 0x00 0xRP
++ * unknown number of possible idle bytes
++ * 3 byte Anc data preamble: 0x00 0xff 0xff
++ * 1 byte data identifier: ne010iii (parity bits, 010, DID bits)
++ * 1 byte secondary data id: nessssss (parity bits, SDID bits)
++ * 1 byte data word count: necccccc (parity bits, NN Dword count)
++ * 2 byte Internal DID: VBI-line-# 0x80
++ * NN data bytes
++ * 1 byte checksum
++ * Fill bytes needed to fil out to 4*NN bytes of payload
++ *
++ * The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, &
++ * in the vertical blanking interval are:
++ * 0xb0 (Task 0 VerticalBlank HorizontalBlank 0 0 0 0)
++ * 0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0)
++ *
++ * Since the V bit is only allowed to toggle in the EAV RP code, just
++ * before the first active region line and for active lines, they are:
++ * 0x90 (Task 0 0 HorizontalBlank 0 0 0 0)
++ * 0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0)
++ *
++ * The user application DID bytes we care about are:
++ * 0x91 (1 0 010 0 !ActiveLine AncDataPresent)
++ * 0x55 (0 1 010 2ndField !ActiveLine AncDataPresent)
++ *
++ */
++static const u8 sliced_vbi_did[2] = { 0x91, 0x55 };
++
++struct vbi_anc_data {
++ /* u8 eav[4]; */
++ /* u8 idle[]; Variable number of idle bytes */
++ u8 preamble[3];
++ u8 did;
++ u8 sdid;
++ u8 data_count;
++ u8 idid[2];
++ u8 payload[1]; /* data_count of payload */
++ /* u8 checksum; */
++ /* u8 fill[]; Variable number of fill bytes */
++};
++
+ static int odd_parity(u8 c)
+ {
+ c ^= (c >> 4);
+@@ -83,188 +129,189 @@ static int decode_vps(u8 *dst, u8 *p)
+ return err & 0xf0;
+ }
+
+-int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
++int cx18_av_vbi_g_fmt(struct cx18 *cx, struct v4l2_format *fmt)
+ {
+ struct cx18_av_state *state = &cx->av_state;
+- struct v4l2_format *fmt;
+ struct v4l2_sliced_vbi_format *svbi;
++ static const u16 lcr2vbi[] = {
++ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
++ 0, V4L2_SLICED_WSS_625, 0, /* 4 */
++ V4L2_SLICED_CAPTION_525, /* 6 */
++ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
++ 0, 0, 0, 0
++ };
++ int is_pal = !(state->std & V4L2_STD_525_60);
++ int i;
+
+- switch (cmd) {
+- case VIDIOC_G_FMT:
+- {
+- static u16 lcr2vbi[] = {
+- 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+- 0, V4L2_SLICED_WSS_625, 0, /* 4 */
+- V4L2_SLICED_CAPTION_525, /* 6 */
+- 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
+- 0, 0, 0, 0
+- };
+- int is_pal = !(state->std & V4L2_STD_525_60);
+- int i;
+-
+- fmt = arg;
+- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+- return -EINVAL;
+- svbi = &fmt->fmt.sliced;
+- memset(svbi, 0, sizeof(*svbi));
+- /* we're done if raw VBI is active */
+- if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
+- break;
+-
+- if (is_pal) {
+- for (i = 7; i <= 23; i++) {
+- u8 v = cx18_av_read(cx, 0x424 + i - 7);
+-
+- svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+- svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+- svbi->service_set |= svbi->service_lines[0][i] |
+- svbi->service_lines[1][i];
+- }
+- } else {
+- for (i = 10; i <= 21; i++) {
+- u8 v = cx18_av_read(cx, 0x424 + i - 10);
+-
+- svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+- svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+- svbi->service_set |= svbi->service_lines[0][i] |
+- svbi->service_lines[1][i];
+- }
+- }
+- break;
+- }
++ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
++ return -EINVAL;
++ svbi = &fmt->fmt.sliced;
++ memset(svbi, 0, sizeof(*svbi));
++ /* we're done if raw VBI is active */
++ if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
++ return 0;
+
+- case VIDIOC_S_FMT:
+- {
+- int is_pal = !(state->std & V4L2_STD_525_60);
+- int vbi_offset = is_pal ? 1 : 0;
+- int i, x;
+- u8 lcr[24];
+-
+- fmt = arg;
+- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+- fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
+- return -EINVAL;
+- svbi = &fmt->fmt.sliced;
+- if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+- /* raw VBI */
+- memset(svbi, 0, sizeof(*svbi));
+-
+- /* Setup standard */
+- cx18_av_std_setup(cx);
+-
+- /* VBI Offset */
+- cx18_av_write(cx, 0x47f, vbi_offset);
+- cx18_av_write(cx, 0x404, 0x2e);
+- break;
++ if (is_pal) {
++ for (i = 7; i <= 23; i++) {
++ u8 v = cx18_av_read(cx, 0x424 + i - 7);
++
++ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
++ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
++ svbi->service_set |= svbi->service_lines[0][i] |
++ svbi->service_lines[1][i];
++ }
++ } else {
++ for (i = 10; i <= 21; i++) {
++ u8 v = cx18_av_read(cx, 0x424 + i - 10);
++
++ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
++ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
++ svbi->service_set |= svbi->service_lines[0][i] |
++ svbi->service_lines[1][i];
+ }
++ }
++ return 0;
++}
+
+- for (x = 0; x <= 23; x++)
+- lcr[x] = 0x00;
++int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt)
++{
++ struct cx18_av_state *state = &cx->av_state;
++ struct v4l2_sliced_vbi_format *svbi;
++ int is_pal = !(state->std & V4L2_STD_525_60);
++ int i, x;
++ u8 lcr[24];
++
++ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
++ fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
++ return -EINVAL;
++ svbi = &fmt->fmt.sliced;
++ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
++ /* raw VBI */
++ memset(svbi, 0, sizeof(*svbi));
+
+ /* Setup standard */
+ cx18_av_std_setup(cx);
+
+- /* Sliced VBI */
+- cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
+- cx18_av_write(cx, 0x406, 0x13);
+- cx18_av_write(cx, 0x47f, vbi_offset);
+-
+- if (is_pal) {
+- for (i = 0; i <= 6; i++)
+- svbi->service_lines[0][i] =
+- svbi->service_lines[1][i] = 0;
+- } else {
+- for (i = 0; i <= 9; i++)
+- svbi->service_lines[0][i] =
+- svbi->service_lines[1][i] = 0;
+-
+- for (i = 22; i <= 23; i++)
+- svbi->service_lines[0][i] =
+- svbi->service_lines[1][i] = 0;
+- }
++ /* VBI Offset */
++ cx18_av_write(cx, 0x47f, state->slicer_line_delay);
++ cx18_av_write(cx, 0x404, 0x2e);
++ return 0;
++ }
+
+- for (i = 7; i <= 23; i++) {
+- for (x = 0; x <= 1; x++) {
+- switch (svbi->service_lines[1-x][i]) {
+- case V4L2_SLICED_TELETEXT_B:
+- lcr[i] |= 1 << (4 * x);
+- break;
+- case V4L2_SLICED_WSS_625:
+- lcr[i] |= 4 << (4 * x);
+- break;
+- case V4L2_SLICED_CAPTION_525:
+- lcr[i] |= 6 << (4 * x);
+- break;
+- case V4L2_SLICED_VPS:
+- lcr[i] |= 9 << (4 * x);
+- break;
+- }
+- }
+- }
++ for (x = 0; x <= 23; x++)
++ lcr[x] = 0x00;
++
++ /* Setup standard */
++ cx18_av_std_setup(cx);
++
++ /* Sliced VBI */
++ cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
++ cx18_av_write(cx, 0x406, 0x13);
++ cx18_av_write(cx, 0x47f, state->slicer_line_delay);
++
++ /* Force impossible lines to 0 */
++ if (is_pal) {
++ for (i = 0; i <= 6; i++)
++ svbi->service_lines[0][i] =
++ svbi->service_lines[1][i] = 0;
++ } else {
++ for (i = 0; i <= 9; i++)
++ svbi->service_lines[0][i] =
++ svbi->service_lines[1][i] = 0;
++
++ for (i = 22; i <= 23; i++)
++ svbi->service_lines[0][i] =
++ svbi->service_lines[1][i] = 0;
++ }
+
+- if (is_pal) {
+- for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+- cx18_av_write(cx, i, lcr[6 + x]);
+- } else {
+- for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+- cx18_av_write(cx, i, lcr[9 + x]);
+- for (i = 0x431; i <= 0x434; i++)
+- cx18_av_write(cx, i, 0);
++ /* Build register values for requested service lines */
++ for (i = 7; i <= 23; i++) {
++ for (x = 0; x <= 1; x++) {
++ switch (svbi->service_lines[1-x][i]) {
++ case V4L2_SLICED_TELETEXT_B:
++ lcr[i] |= 1 << (4 * x);
++ break;
++ case V4L2_SLICED_WSS_625:
++ lcr[i] |= 4 << (4 * x);
++ break;
++ case V4L2_SLICED_CAPTION_525:
++ lcr[i] |= 6 << (4 * x);
++ break;
++ case V4L2_SLICED_VPS:
++ lcr[i] |= 9 << (4 * x);
++ break;
++ }
+ }
++ }
+
+- cx18_av_write(cx, 0x43c, 0x16);
+- cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22);
+- break;
++ if (is_pal) {
++ for (x = 1, i = 0x424; i <= 0x434; i++, x++)
++ cx18_av_write(cx, i, lcr[6 + x]);
++ } else {
++ for (x = 1, i = 0x424; i <= 0x430; i++, x++)
++ cx18_av_write(cx, i, lcr[9 + x]);
++ for (i = 0x431; i <= 0x434; i++)
++ cx18_av_write(cx, i, 0);
+ }
+
+- case VIDIOC_INT_DECODE_VBI_LINE:
+- {
+- struct v4l2_decode_vbi_line *vbi = arg;
+- u8 *p = vbi->p;
+- int id1, id2, l, err = 0;
++ cx18_av_write(cx, 0x43c, 0x16);
++ /* FIXME - should match vblank set in cx18_av_std_setup() */
++ cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
++ return 0;
++}
++
++int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
++ struct v4l2_decode_vbi_line *vbi)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ struct cx18_av_state *state = &cx->av_state;
++ struct vbi_anc_data *anc = (struct vbi_anc_data *)vbi->p;
++ u8 *p;
++ int did, sdid, l, err = 0;
++
++ /*
++ * Check for the ancillary data header for sliced VBI
++ */
++ if (anc->preamble[0] ||
++ anc->preamble[1] != 0xff || anc->preamble[2] != 0xff ||
++ (anc->did != sliced_vbi_did[0] &&
++ anc->did != sliced_vbi_did[1])) {
++ vbi->line = vbi->type = 0;
++ return 0;
++ }
+
+- if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+- (p[3] != 0x55 && p[3] != 0x91)) {
+- vbi->line = vbi->type = 0;
+- break;
+- }
++ did = anc->did;
++ sdid = anc->sdid & 0xf;
++ l = anc->idid[0] & 0x3f;
++ l += state->slicer_line_offset;
++ p = anc->payload;
+
+- p += 4;
+- id1 = p[-1];
+- id2 = p[0] & 0xf;
+- l = p[2] & 0x3f;
+- l += state->vbi_line_offset;
+- p += 4;
+-
+- switch (id2) {
+- case 1:
+- id2 = V4L2_SLICED_TELETEXT_B;
+- break;
+- case 4:
+- id2 = V4L2_SLICED_WSS_625;
+- break;
+- case 6:
+- id2 = V4L2_SLICED_CAPTION_525;
+- err = !odd_parity(p[0]) || !odd_parity(p[1]);
+- break;
+- case 9:
+- id2 = V4L2_SLICED_VPS;
+- if (decode_vps(p, p) != 0)
+- err = 1;
+- break;
+- default:
+- id2 = 0;
++ /* Decode the SDID set by the slicer */
++ switch (sdid) {
++ case 1:
++ sdid = V4L2_SLICED_TELETEXT_B;
++ break;
++ case 4:
++ sdid = V4L2_SLICED_WSS_625;
++ break;
++ case 6:
++ sdid = V4L2_SLICED_CAPTION_525;
++ err = !odd_parity(p[0]) || !odd_parity(p[1]);
++ break;
++ case 9:
++ sdid = V4L2_SLICED_VPS;
++ if (decode_vps(p, p) != 0)
+ err = 1;
+- break;
+- }
+-
+- vbi->type = err ? 0 : id2;
+- vbi->line = err ? 0 : l;
+- vbi->is_second_field = err ? 0 : (id1 == 0x55);
+- vbi->p = p;
+ break;
+- }
++ default:
++ sdid = 0;
++ err = 1;
++ break;
+ }
+
++ vbi->type = err ? 0 : sdid;
++ vbi->line = err ? 0 : l;
++ vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]);
++ vbi->p = p;
+ return 0;
+ }
+diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
+index e274043..9bc2218 100644
+--- a/drivers/media/video/cx18/cx18-cards.c
++++ b/drivers/media/video/cx18/cx18-cards.c
+@@ -51,12 +51,12 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
+ static const struct cx18_card cx18_card_hvr1600_esmt = {
+ .type = CX18_CARD_HVR_1600_ESMT,
+ .name = "Hauppauge HVR-1600",
+- .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
++ .comment = "Simultaneous Digital and Analog TV capture supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+- .hw_audio_ctrl = CX18_HW_CX23418,
++ .hw_audio_ctrl = CX18_HW_418_AV,
+ .hw_muxer = CX18_HW_CS5345,
+- .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
+- CX18_HW_CS5345 | CX18_HW_DVB,
++ .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
++ CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
+@@ -97,12 +97,12 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
+ static const struct cx18_card cx18_card_hvr1600_samsung = {
+ .type = CX18_CARD_HVR_1600_SAMSUNG,
+ .name = "Hauppauge HVR-1600 (Preproduction)",
+- .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
++ .comment = "Simultaneous Digital and Analog TV capture supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+- .hw_audio_ctrl = CX18_HW_CX23418,
++ .hw_audio_ctrl = CX18_HW_418_AV,
+ .hw_muxer = CX18_HW_CS5345,
+- .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
+- CX18_HW_CS5345 | CX18_HW_DVB,
++ .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
++ CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
+@@ -152,10 +152,10 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
+ static const struct cx18_card cx18_card_h900 = {
+ .type = CX18_CARD_COMPRO_H900,
+ .name = "Compro VideoMate H900",
+- .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
++ .comment = "Analog TV capture supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+- .hw_audio_ctrl = CX18_HW_CX23418,
+- .hw_all = CX18_HW_TUNER,
++ .hw_audio_ctrl = CX18_HW_418_AV,
++ .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+@@ -201,8 +201,8 @@ static const struct cx18_card cx18_card_mpc718 = {
+ .name = "Yuan MPC718",
+ .comment = "Analog video capture works; some audio line in may not.\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+- .hw_audio_ctrl = CX18_HW_CX23418,
+- .hw_all = CX18_HW_TUNER,
++ .hw_audio_ctrl = CX18_HW_418_AV,
++ .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+@@ -249,11 +249,11 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
+ static const struct cx18_card cx18_card_cnxt_raptor_pal = {
+ .type = CX18_CARD_CNXT_RAPTOR_PAL,
+ .name = "Conexant Raptor PAL/SECAM",
+- .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
++ .comment = "Analog TV capture supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+- .hw_audio_ctrl = CX18_HW_CX23418,
+- .hw_muxer = CX18_HW_GPIO,
+- .hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
++ .hw_audio_ctrl = CX18_HW_418_AV,
++ .hw_muxer = CX18_HW_GPIO_MUX,
++ .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+@@ -306,8 +306,8 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
+ .comment = "Experimenters and photos needed for device to work well.\n"
+ "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+- .hw_audio_ctrl = CX18_HW_CX23418,
+- .hw_all = CX18_HW_TUNER,
++ .hw_audio_ctrl = CX18_HW_418_AV,
++ .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE6 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+@@ -339,19 +339,21 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
+ /* Leadtek WinFast PVR2100 */
+
+ static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
+- { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 },
++ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100 */
++ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
+ { 0, 0, 0 }
+ };
+
+ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
+ .type = CX18_CARD_LEADTEK_PVR2100,
+- .name = "Leadtek WinFast PVR2100",
++ .name = "Leadtek WinFast PVR2100/DVR3100 H",
+ .comment = "Experimenters and photos needed for device to work well.\n"
+ "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+- .hw_audio_ctrl = CX18_HW_CX23418,
+- .hw_muxer = CX18_HW_GPIO,
+- .hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
++ .hw_audio_ctrl = CX18_HW_418_AV,
++ .hw_muxer = CX18_HW_GPIO_MUX,
++ .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
++ CX18_HW_GPIO_RESET_CTRL,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
+index 6fa7bcb..3c552b6 100644
+--- a/drivers/media/video/cx18/cx18-cards.h
++++ b/drivers/media/video/cx18/cx18-cards.h
+@@ -22,12 +22,13 @@
+ */
+
+ /* hardware flags */
+-#define CX18_HW_TUNER (1 << 0)
+-#define CX18_HW_TVEEPROM (1 << 1)
+-#define CX18_HW_CS5345 (1 << 2)
+-#define CX18_HW_GPIO (1 << 3)
+-#define CX18_HW_CX23418 (1 << 4)
+-#define CX18_HW_DVB (1 << 5)
++#define CX18_HW_TUNER (1 << 0)
++#define CX18_HW_TVEEPROM (1 << 1)
++#define CX18_HW_CS5345 (1 << 2)
++#define CX18_HW_DVB (1 << 3)
++#define CX18_HW_418_AV (1 << 4)
++#define CX18_HW_GPIO_MUX (1 << 5)
++#define CX18_HW_GPIO_RESET_CTRL (1 << 6)
+
+ /* video inputs */
+ #define CX18_CARD_INPUT_VID_TUNER 1
+@@ -49,8 +50,7 @@
+ /* V4L2 capability aliases */
+ #define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
+- V4L2_CAP_VBI_CAPTURE)
+-/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
++ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)
+
+ struct cx18_card_video_input {
+ u8 video_type; /* video input type */
+@@ -122,7 +122,7 @@ struct cx18_card {
+ char *comment;
+ u32 v4l2_capabilities;
+ u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only
+- 1 dev allowed) */
++ 1 dev allowed currently) */
+ u32 hw_muxer; /* hardware used to multiplex audio input */
+ u32 hw_all; /* all hardware used by the board */
+ struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS];
+diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
+index 17edf30..82fc2f9 100644
+--- a/drivers/media/video/cx18/cx18-controls.c
++++ b/drivers/media/video/cx18/cx18-controls.c
+@@ -22,14 +22,13 @@
+ */
+
+ #include "cx18-driver.h"
+-#include "cx18-av-core.h"
+ #include "cx18-cards.h"
+ #include "cx18-ioctl.h"
+ #include "cx18-audio.h"
+-#include "cx18-i2c.h"
+ #include "cx18-mailbox.h"
+ #include "cx18-controls.h"
+
++/* Must be sorted from low to high control ID! */
+ static const u32 user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+@@ -66,7 +65,7 @@ int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+- if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl))
++ if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+
+@@ -76,7 +75,7 @@ int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+- if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
++ if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+
+@@ -125,7 +124,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+- return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl);
++ return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl);
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+@@ -133,7 +132,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+- return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
++ return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl);
+
+ default:
+ CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
+@@ -150,7 +149,7 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+- return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl);
++ return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl);
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+@@ -158,7 +157,8 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+- return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
++ return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl);
++
+ default:
+ CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
+ return -EINVAL;
+@@ -166,38 +166,57 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+ return 0;
+ }
+
+-static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt)
++static int cx18_setup_vbi_fmt(struct cx18 *cx,
++ enum v4l2_mpeg_stream_vbi_fmt fmt,
++ enum v4l2_mpeg_stream_type type)
+ {
+ if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
+ return -EINVAL;
+ if (atomic_read(&cx->ana_capturing) > 0)
+ return -EBUSY;
+
+- /* First try to allocate sliced VBI buffers if needed. */
+- if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) {
++ if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
++ type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
++ /* We don't do VBI insertion aside from IVTV format in a PS */
++ cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
++ CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
++ "the MPEG stream\n");
++ return 0;
++ }
++
++ /* Allocate sliced VBI buffers if needed. */
++ if (cx->vbi.sliced_mpeg_data[0] == NULL) {
+ int i;
+
+ for (i = 0; i < CX18_VBI_FRAMES; i++) {
+- /* Yuck, hardcoded. Needs to be a define */
+- cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
++ cx->vbi.sliced_mpeg_data[i] =
++ kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
+ if (cx->vbi.sliced_mpeg_data[i] == NULL) {
+ while (--i >= 0) {
+ kfree(cx->vbi.sliced_mpeg_data[i]);
+ cx->vbi.sliced_mpeg_data[i] = NULL;
+ }
++ cx->vbi.insert_mpeg =
++ V4L2_MPEG_STREAM_VBI_FMT_NONE;
++ CX18_WARN("Unable to allocate buffers for "
++ "sliced VBI data insertion\n");
+ return -ENOMEM;
+ }
+ }
+ }
+
+ cx->vbi.insert_mpeg = fmt;
++ CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,"
++ "when sliced VBI is enabled\n");
+
+- if (cx->vbi.insert_mpeg == 0)
+- return 0;
+- /* Need sliced data for mpeg insertion */
++ /*
++ * If our current settings have no lines set for capture, store a valid,
++ * default set of service lines to capture, in our current settings.
++ */
+ if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
+ if (cx->is_60hz)
+- cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
++ cx->vbi.sliced_in->service_set =
++ V4L2_SLICED_CAPTION_525;
+ else
+ cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
+ cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
+@@ -259,10 +278,12 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+ return err;
+ }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
++ static u32 freqs[3] = { 44100, 48000, 32000 };
+ struct cx18_api_func_private priv;
+ struct cx2341x_mpeg_params p = cx->params;
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
+ c, VIDIOC_S_EXT_CTRLS);
++ unsigned int idx;
+
+ if (err)
+ return err;
+@@ -277,16 +298,23 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+ fmt.fmt.pix.width = cx->params.width
+ / (is_mpeg1 ? 2 : 1);
+ fmt.fmt.pix.height = cx->params.height;
+- cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
++ v4l2_subdev_call(cx->sd_av, video, s_fmt, &fmt);
+ }
+ priv.cx = cx;
+ priv.s = &cx->streams[id->type];
+ err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
+- if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
+- err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
++ if (!err &&
++ (cx->params.stream_vbi_fmt != p.stream_vbi_fmt ||
++ cx->params.stream_type != p.stream_type))
++ err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt,
++ p.stream_type);
+ cx->params = p;
+ cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+- cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
++ idx = p.audio_properties & 0x03;
++ /* The audio clock of the digitizer must match the codec sample
++ rate otherwise you get some very strange effects. */
++ if (idx < sizeof(freqs))
++ cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
+ return err;
+ }
+ return -EINVAL;
+diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
+index f50cf21..210c68a 100644
+--- a/drivers/media/video/cx18/cx18-driver.c
++++ b/drivers/media/video/cx18/cx18-driver.c
+@@ -39,10 +39,6 @@
+
+ #include <media/tveeprom.h>
+
+-
+-/* var to keep track of the number of array elements in use */
+-int cx18_cards_active;
+-
+ /* If you have already X v4l cards, then set this to X. This way
+ the device numbers stay matched. Example: you have a WinTV card
+ without radio and a Compro H900 with. Normally this would give a
+@@ -50,12 +46,6 @@ int cx18_cards_active;
+ setting this to 1 you ensure that radio0 is now also radio1. */
+ int cx18_first_minor;
+
+-/* Master variable for all cx18 info */
+-struct cx18 *cx18_cards[CX18_MAX_CARDS];
+-
+-/* Protects cx18_cards_active */
+-DEFINE_SPINLOCK(cx18_cards_lock);
+-
+ /* add your revision and whatnot here */
+ static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
+ {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
+@@ -65,6 +55,8 @@ static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
+
+ MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
+
++static atomic_t cx18_instance = ATOMIC_INIT(0);
++
+ /* Parameter declarations */
+ static int cardtype[CX18_MAX_CARDS];
+ static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+@@ -159,7 +151,7 @@ MODULE_PARM_DESC(cardtype,
+ "\t\t\t 4 = Yuan MPC718\n"
+ "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
+ "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
+- "\t\t\t 7 = Leadtek WinFast PVR2100\n"
++ "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n"
+ "\t\t\t 0 = Autodetect (default)\n"
+ "\t\t\t-1 = Ignore this card\n\t\t");
+ MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
+@@ -277,11 +269,16 @@ static void cx18_iounmap(struct cx18 *cx)
+ /* Hauppauge card? get values from tveeprom */
+ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
+ {
++ struct i2c_client c;
+ u8 eedata[256];
+
+- cx->i2c_client[0].addr = 0xA0 >> 1;
+- tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata));
+- tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata);
++ memset(&c, 0, sizeof(c));
++ strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name));
++ c.adapter = &cx->i2c_adap[0];
++ c.addr = 0xA0 >> 1;
++
++ tveeprom_read(&c, eedata, sizeof(eedata));
++ tveeprom_hauppauge_analog(&c, tv, eedata);
+ }
+
+ static void cx18_process_eeprom(struct cx18 *cx)
+@@ -448,34 +445,38 @@ static void cx18_process_options(struct cx18 *cx)
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize;
+- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = 0; /* computed later */
++ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */
+
+- /* Except for VBI ensure stream_buffers & stream_buf_size are valid */
++ /* Ensure stream_buffers & stream_buf_size are valid */
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+- /* User said to use 0 buffers */
+- if (cx->stream_buffers[i] == 0) {
+- cx->options.megabytes[i] = 0;
+- cx->stream_buf_size[i] = 0;
+- continue;
+- }
+- /* User said to use 0 MB total */
+- if (cx->options.megabytes[i] <= 0) {
++ if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */
++ cx->options.megabytes[i] <= 0 || /* User said 0 MB total */
++ cx->stream_buf_size[i] <= 0) { /* User said buf size 0 */
+ cx->options.megabytes[i] = 0;
+ cx->stream_buffers[i] = 0;
+ cx->stream_buf_size[i] = 0;
+ continue;
+ }
+- /* VBI is computed later or user said buffer has size 0 */
+- if (cx->stream_buf_size[i] <= 0) {
+- if (i != CX18_ENC_STREAM_TYPE_VBI) {
+- cx->options.megabytes[i] = 0;
+- cx->stream_buffers[i] = 0;
+- cx->stream_buf_size[i] = 0;
++ /*
++ * VBI is a special case where the stream_buf_size is fixed
++ * and already in bytes
++ */
++ if (i == CX18_ENC_STREAM_TYPE_VBI) {
++ if (cx->stream_buffers[i] < 0) {
++ cx->stream_buffers[i] =
++ cx->options.megabytes[i] * 1024 * 1024
++ / cx->stream_buf_size[i];
++ } else {
++ /* N.B. This might round down to 0 */
++ cx->options.megabytes[i] =
++ cx->stream_buffers[i]
++ * cx->stream_buf_size[i]/(1024 * 1024);
+ }
+ continue;
+ }
++ /* All other streams have stream_buf_size in kB at this point */
+ if (cx->stream_buffers[i] < 0) {
+ cx->stream_buffers[i] = cx->options.megabytes[i] * 1024
+ / cx->stream_buf_size[i];
+@@ -487,9 +488,9 @@ static void cx18_process_options(struct cx18 *cx)
+ cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */
+ }
+
+- cx->options.cardtype = cardtype[cx->num];
+- cx->options.tuner = tuner[cx->num];
+- cx->options.radio = radio[cx->num];
++ cx->options.cardtype = cardtype[cx->instance];
++ cx->options.tuner = tuner[cx->instance];
++ cx->options.radio = radio[cx->instance];
+
+ cx->std = cx18_parse_std(cx);
+ if (cx->options.cardtype == -1) {
+@@ -502,7 +503,7 @@ static void cx18_process_options(struct cx18 *cx)
+ else if (cx->options.cardtype != 0)
+ CX18_ERR("Unknown user specified type, trying to autodetect card\n");
+ if (cx->card == NULL) {
+- if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
++ if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_INFO("Autodetected Hauppauge card\n");
+ }
+@@ -512,13 +513,13 @@ static void cx18_process_options(struct cx18 *cx)
+ if (cx->card->pci_list == NULL)
+ continue;
+ for (j = 0; cx->card->pci_list[j].device; j++) {
+- if (cx->dev->device !=
++ if (cx->pci_dev->device !=
+ cx->card->pci_list[j].device)
+ continue;
+- if (cx->dev->subsystem_vendor !=
++ if (cx->pci_dev->subsystem_vendor !=
+ cx->card->pci_list[j].subsystem_vendor)
+ continue;
+- if (cx->dev->subsystem_device !=
++ if (cx->pci_dev->subsystem_device !=
+ cx->card->pci_list[j].subsystem_device)
+ continue;
+ CX18_INFO("Autodetected %s card\n", cx->card->name);
+@@ -531,9 +532,10 @@ done:
+ if (cx->card == NULL) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
+- cx->dev->vendor, cx->dev->device);
++ cx->pci_dev->vendor, cx->pci_dev->device);
+ CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n",
+- cx->dev->subsystem_vendor, cx->dev->subsystem_device);
++ cx->pci_dev->subsystem_vendor,
++ cx->pci_dev->subsystem_device);
+ CX18_ERR("Defaulting to %s card\n", cx->card->name);
+ CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+ CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
+@@ -545,7 +547,7 @@ done:
+ }
+
+ /* Precondition: the cx18 structure has been memset to 0. Only
+- the dev and num fields have been filled in.
++ the dev and instance fields have been filled in.
+ No assumptions on the card type may be made here (see cx18_init_struct2
+ for that).
+ */
+@@ -553,18 +555,14 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
+ {
+ int i;
+
+- cx->base_addr = pci_resource_start(cx->dev, 0);
++ cx->base_addr = pci_resource_start(cx->pci_dev, 0);
+
+ mutex_init(&cx->serialize_lock);
+- mutex_init(&cx->i2c_bus_lock[0]);
+- mutex_init(&cx->i2c_bus_lock[1]);
+ mutex_init(&cx->gpio_lock);
+ mutex_init(&cx->epu2apu_mb_lock);
+ mutex_init(&cx->epu2cpu_mb_lock);
+
+- spin_lock_init(&cx->lock);
+-
+- cx->work_queue = create_singlethread_workqueue(cx->name);
++ cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name);
+ if (cx->work_queue == NULL) {
+ CX18_ERR("Unable to create work hander thread\n");
+ return -ENOMEM;
+@@ -587,7 +585,8 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
+ (cx->params.video_temporal_filter_mode << 1) |
+ (cx->params.video_median_filter_type << 2);
+ cx->params.port = CX2341X_PORT_MEMORY;
+- cx->params.capabilities = CX2341X_CAP_HAS_TS;
++ cx->params.capabilities =
++ CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
+ init_waitqueue_head(&cx->cap_w);
+ init_waitqueue_head(&cx->mb_apu_waitq);
+ init_waitqueue_head(&cx->mb_cpu_waitq);
+@@ -597,49 +596,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
+ cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
+
+- /*
+- * The VBI line sizes depend on the pixel clock and the horiz rate
+- *
+- * (1/Fh)*(2*Fp) = Samples/line
+- * = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
+- *
+- * Sliced VBI is sent as ancillary data during horizontal blanking
+- * Raw VBI is sent as active video samples during vertcal blanking
+- *
+- * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
+- * length of 720 pixels @ 4:2:2 sampling. Thus...
+- *
+- * For systems that use a 15.734 kHz horizontal rate, such as
+- * NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
+- *
+- * (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
+- * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
+- *
+- * For systems that use a 15.625 kHz horizontal rate, such as
+- * PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
+- *
+- * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
+- * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
+- *
+- */
+-
+- /* FIXME: init these based on tuner std & modify when std changes */
+- /* CX18-AV-Core number of VBI samples output per horizontal line */
+- cx->vbi.raw_decoder_line_size = 1444; /* 4 byte SAV + 2 * 720 */
+- cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */
+-
+- /* CX18-AV-Core VBI samples/line possibly rounded up */
+- cx->vbi.raw_size = 1444; /* Real max size is 1444 */
+- cx->vbi.sliced_size = 284; /* Real max size is 284 */
+-
+- /*
+- * CX18-AV-Core SAV/EAV RP codes in VIP 1.x mode
+- * Task Field VerticalBlank HorizontalBlank 0 0 0 0
+- */
+- cx->vbi.raw_decoder_sav_odd_field = 0x20; /* V */
+- cx->vbi.raw_decoder_sav_even_field = 0x60; /* FV */
+- cx->vbi.sliced_decoder_sav_odd_field = 0xB0; /* T VH - actually EAV */
+- cx->vbi.sliced_decoder_sav_even_field = 0xF0; /* TFVH - actually EAV */
+ return 0;
+ }
+
+@@ -668,15 +624,9 @@ static void __devinit cx18_init_struct2(struct cx18 *cx)
+ i = 0;
+ cx->active_input = i;
+ cx->audio_input = cx->card->video_inputs[i].audio_index;
+- cx->av_state.vid_input = CX18_AV_COMPOSITE7;
+- cx->av_state.aud_input = CX18_AV_AUDIO8;
+- cx->av_state.audclk_freq = 48000;
+- cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
+- /* FIXME - 8 is NTSC value, investigate */
+- cx->av_state.vbi_line_offset = 8;
+ }
+
+-static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
++static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+ {
+ u16 cmd;
+@@ -684,124 +634,125 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
+
+ CX18_DEBUG_INFO("Enabling pci device\n");
+
+- if (pci_enable_device(dev)) {
+- CX18_ERR("Can't enable device %d!\n", cx->num);
++ if (pci_enable_device(pci_dev)) {
++ CX18_ERR("Can't enable device %d!\n", cx->instance);
+ return -EIO;
+ }
+- if (pci_set_dma_mask(dev, 0xffffffff)) {
+- CX18_ERR("No suitable DMA available on card %d.\n", cx->num);
++ if (pci_set_dma_mask(pci_dev, 0xffffffff)) {
++ CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
+ return -EIO;
+ }
+ if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
+- CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num);
++ CX18_ERR("Cannot request encoder memory region, card %d\n",
++ cx->instance);
+ return -EIO;
+ }
+
+ /* Enable bus mastering and memory mapped IO for the CX23418 */
+- pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+- pci_write_config_word(dev, PCI_COMMAND, cmd);
++ pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
+
+- pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev);
+- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
++ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev);
++ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
+
+ if (pci_latency < 64 && cx18_pci_latency) {
+ CX18_INFO("Unreasonably low latency timer, "
+ "setting to 64 (was %d)\n", pci_latency);
+- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
++ pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64);
++ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
+ }
+
+ CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
+ "irq: %d, latency: %d, memory: 0x%lx\n",
+- cx->dev->device, cx->card_rev, dev->bus->number,
+- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+- cx->dev->irq, pci_latency, (unsigned long)cx->base_addr);
++ cx->pci_dev->device, cx->card_rev, pci_dev->bus->number,
++ PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn),
++ cx->pci_dev->irq, pci_latency, (unsigned long)cx->base_addr);
+
+ return 0;
+ }
+
+-#ifdef MODULE
+-static u32 cx18_request_module(struct cx18 *cx, u32 hw,
+- const char *name, u32 id)
+-{
+- if ((hw & id) == 0)
+- return hw;
+- if (request_module(name) != 0) {
+- CX18_ERR("Failed to load module %s\n", name);
+- return hw & ~id;
+- }
+- CX18_DEBUG_INFO("Loaded module %s\n", name);
+- return hw;
+-}
+-#endif
+-
+-static void cx18_load_and_init_modules(struct cx18 *cx)
++static void cx18_init_subdevs(struct cx18 *cx)
+ {
+ u32 hw = cx->card->hw_all;
++ u32 device;
+ int i;
+
+-#ifdef MODULE
+- /* load modules */
+-#ifdef CONFIG_MEDIA_TUNER_MODULE
+- hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER);
+-#endif
+-#ifdef CONFIG_VIDEO_CS5345_MODULE
+- hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345);
+-#endif
+-#endif
+-
+- /* check which i2c devices are actually found */
+- for (i = 0; i < 32; i++) {
+- u32 device = 1 << i;
++ for (i = 0, device = 1; i < 32; i++, device <<= 1) {
+
+ if (!(device & hw))
+ continue;
+- if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM ||
+- device == CX18_HW_CX23418 || device == CX18_HW_DVB) {
+- /* These 'devices' do not use i2c probing */
++
++ switch (device) {
++ case CX18_HW_DVB:
++ case CX18_HW_TVEEPROM:
++ /* These subordinate devices do not use probing */
+ cx->hw_flags |= device;
+- continue;
+- }
+- cx18_i2c_register(cx, i);
+- if (cx18_i2c_hw_addr(cx, device) > 0)
++ break;
++ case CX18_HW_418_AV:
++ /* The A/V decoder gets probed earlier to set PLLs */
++ /* Just note that the card uses it (i.e. has analog) */
+ cx->hw_flags |= device;
++ break;
++ case CX18_HW_GPIO_RESET_CTRL:
++ /*
++ * The Reset Controller gets probed and added to
++ * hw_flags earlier for i2c adapter/bus initialization
++ */
++ break;
++ case CX18_HW_GPIO_MUX:
++ if (cx18_gpio_register(cx, device) == 0)
++ cx->hw_flags |= device;
++ break;
++ default:
++ if (cx18_i2c_register(cx, i) == 0)
++ cx->hw_flags |= device;
++ break;
++ }
+ }
+
+- hw = cx->hw_flags;
++ if (cx->hw_flags & CX18_HW_418_AV)
++ cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV);
++
++ if (cx->card->hw_muxer != 0)
++ cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer);
+ }
+
+-static int __devinit cx18_probe(struct pci_dev *dev,
++static int __devinit cx18_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+ {
+ int retval = 0;
+ int i;
+- int vbi_buf_size;
+ u32 devtype;
+ struct cx18 *cx;
+
+- spin_lock(&cx18_cards_lock);
+-
+- /* Make sure we've got a place for this card */
+- if (cx18_cards_active == CX18_MAX_CARDS) {
+- printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n",
+- cx18_cards_active);
+- spin_unlock(&cx18_cards_lock);
++ /* FIXME - module parameter arrays constrain max instances */
++ i = atomic_inc_return(&cx18_instance) - 1;
++ if (i >= CX18_MAX_CARDS) {
++ printk(KERN_ERR "cx18: cannot manage card %d, driver has a "
++ "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1);
+ return -ENOMEM;
+ }
+
+ cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
+- if (!cx) {
+- spin_unlock(&cx18_cards_lock);
++ if (cx == NULL) {
++ printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n",
++ i);
+ return -ENOMEM;
+ }
+- cx18_cards[cx18_cards_active] = cx;
+- cx->dev = dev;
+- cx->num = cx18_cards_active++;
+- snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num);
+- CX18_INFO("Initializing card #%d\n", cx->num);
++ cx->pci_dev = pci_dev;
++ cx->instance = i;
+
+- spin_unlock(&cx18_cards_lock);
++ retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev);
++ if (retval) {
++ printk(KERN_ERR "cx18: v4l2_device_register of card %d failed"
++ "\n", cx->instance);
++ kfree(cx);
++ return retval;
++ }
++ snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d",
++ cx->instance);
++ CX18_INFO("Initializing card %d\n", cx->instance);
+
+ cx18_process_options(cx);
+ if (cx->options.cardtype == -1) {
+@@ -816,13 +767,10 @@ static int __devinit cx18_probe(struct pci_dev *dev,
+ CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
+
+ /* PCI Device Setup */
+- retval = cx18_setup_pci(cx, dev, pci_id);
++ retval = cx18_setup_pci(cx, pci_dev, pci_id);
+ if (retval != 0)
+ goto free_workqueue;
+
+- /* save cx in the pci struct for later use */
+- pci_set_drvdata(dev, cx);
+-
+ /* map io memory */
+ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
+ cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
+@@ -856,6 +804,23 @@ static int __devinit cx18_probe(struct pci_dev *dev,
+
+ cx18_gpio_init(cx);
+
++ /* Initialize integrated A/V decoder early to set PLLs, just in case */
++ retval = cx18_av_probe(cx);
++ if (retval) {
++ CX18_ERR("Could not register A/V decoder subdevice\n");
++ goto free_map;
++ }
++ cx18_call_hw(cx, CX18_HW_418_AV, core, init, (u32) CX18_AV_INIT_PLLS);
++
++ /* Initialize GPIO Reset Controller to do chip resets during i2c init */
++ if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
++ if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0)
++ CX18_WARN("Could not register GPIO reset controller"
++ "subdevice; proceeding anyway.\n");
++ else
++ cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL;
++ }
++
+ /* active i2c */
+ CX18_DEBUG_INFO("activating i2c...\n");
+ retval = init_cx18_i2c(cx);
+@@ -864,8 +829,6 @@ static int __devinit cx18_probe(struct pci_dev *dev,
+ goto free_map;
+ }
+
+- CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active);
+-
+ if (cx->card->hw_all & CX18_HW_TVEEPROM) {
+ /* Based on the model number the cardtype may be changed.
+ The PCI IDs are not always reliable. */
+@@ -881,8 +844,9 @@ static int __devinit cx18_probe(struct pci_dev *dev,
+ cx18_init_scb(cx);
+
+ /* Register IRQ */
+- retval = request_irq(cx->dev->irq, cx18_irq_handler,
+- IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx);
++ retval = request_irq(cx->pci_dev->irq, cx18_irq_handler,
++ IRQF_SHARED | IRQF_DISABLED,
++ cx->v4l2_dev.name, (void *)cx);
+ if (retval) {
+ CX18_ERR("Failed to register irq %d\n", retval);
+ goto free_i2c;
+@@ -917,33 +881,14 @@ static int __devinit cx18_probe(struct pci_dev *dev,
+ initialization. */
+ cx18_init_struct2(cx);
+
+- cx18_load_and_init_modules(cx);
++ cx18_init_subdevs(cx);
+
+- if (cx->std & V4L2_STD_525_60) {
++ if (cx->std & V4L2_STD_525_60)
+ cx->is_60hz = 1;
+- cx->is_out_60hz = 1;
+- } else {
++ else
+ cx->is_50hz = 1;
+- cx->is_out_50hz = 1;
+- }
+- cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
+-
+- /*
+- * FIXME: setting the buffer size based on the tuner standard is
+- * suboptimal, as the CVBS and SVideo inputs could use a different std
+- * and the buffer could end up being too small in that case.
+- */
+- vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
+- cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
+
+- if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0)
+- cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] =
+- cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] * 1024 * 1024
+- / vbi_buf_size;
+- else
+- cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] =
+- cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] * vbi_buf_size
+- / (1024 * 1024);
++ cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
+
+ if (cx->options.radio > 0)
+ cx->v4l2_cap |= V4L2_CAP_RADIO;
+@@ -956,7 +901,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
+ setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
+ setup.tuner_callback = (setup.type == TUNER_XC2028) ?
+ cx18_reset_tuner_gpio : NULL;
+- cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup);
++ cx18_call_all(cx, tuner, s_type_addr, &setup);
+ if (setup.type == TUNER_XC2028) {
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+@@ -966,7 +911,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
+ .tuner = cx->options.tuner,
+ .priv = &ctrl,
+ };
+- cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg);
++ cx18_call_all(cx, tuner, s_config, &cfg);
+ }
+ }
+
+@@ -985,14 +930,13 @@ static int __devinit cx18_probe(struct pci_dev *dev,
+ goto free_streams;
+ }
+
+- CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name);
+-
++ CX18_INFO("Initialized card: %s\n", cx->card_name);
+ return 0;
+
+ free_streams:
+ cx18_streams_cleanup(cx, 1);
+ free_irq:
+- free_irq(cx->dev->irq, (void *)cx);
++ free_irq(cx->pci_dev->irq, (void *)cx);
+ free_i2c:
+ exit_cx18_i2c(cx);
+ free_map:
+@@ -1006,11 +950,8 @@ err:
+ retval = -ENODEV;
+ CX18_ERR("Error %d on initialization\n", retval);
+
+- i = cx->num;
+- spin_lock(&cx18_cards_lock);
+- kfree(cx18_cards[i]);
+- cx18_cards[i] = NULL;
+- spin_unlock(&cx18_cards_lock);
++ v4l2_device_unregister(&cx->v4l2_dev);
++ kfree(cx);
+ return retval;
+ }
+
+@@ -1043,8 +984,21 @@ int cx18_init_on_first_open(struct cx18 *cx)
+ }
+ set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
+
+- /* Init the firmware twice to work around a silicon bug
+- * transport related. */
++ /*
++ * Init the firmware twice to work around a silicon bug
++ * with the digital TS.
++ *
++ * The second firmware load requires us to normalize the APU state,
++ * or the audio for the first analog capture will be badly incorrect.
++ *
++ * I can't seem to call APU_RESETAI and have it succeed without the
++ * APU capturing audio, so we start and stop it here to do the reset
++ */
++
++ /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
++ cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
++ cx18_vapi(cx, CX18_APU_RESETAI, 0);
++ cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
+
+ fw_retry_count = 3;
+ while (--fw_retry_count > 0) {
+@@ -1060,6 +1014,22 @@ int cx18_init_on_first_open(struct cx18 *cx)
+ return -ENXIO;
+ }
+
++ /*
++ * The second firmware load requires us to normalize the APU state,
++ * or the audio for the first analog capture will be badly incorrect.
++ *
++ * I can't seem to call APU_RESETAI and have it succeed without the
++ * APU capturing audio, so we start and stop it here to do the reset
++ */
++
++ /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */
++ cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0);
++ cx18_vapi(cx, CX18_APU_RESETAI, 0);
++ cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
++
++ /* Init the A/V decoder, if it hasn't been already */
++ v4l2_subdev_call(cx->sd_av, core, init, (u32) CX18_AV_INIT_NORMAL);
++
+ vf.tuner = 0;
+ vf.type = V4L2_TUNER_ANALOG_TV;
+ vf.frequency = 6400; /* the tuner 'baseline' frequency */
+@@ -1092,9 +1062,11 @@ static void cx18_cancel_epu_work_orders(struct cx18 *cx)
+
+ static void cx18_remove(struct pci_dev *pci_dev)
+ {
+- struct cx18 *cx = pci_get_drvdata(pci_dev);
++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
++ struct cx18 *cx = to_cx18(v4l2_dev);
++ int i;
+
+- CX18_DEBUG_INFO("Removing Card #%d\n", cx->num);
++ CX18_DEBUG_INFO("Removing Card\n");
+
+ /* Stop all captures */
+ CX18_DEBUG_INFO("Stopping all streams\n");
+@@ -1115,15 +1087,22 @@ static void cx18_remove(struct pci_dev *pci_dev)
+
+ exit_cx18_i2c(cx);
+
+- free_irq(cx->dev->irq, (void *)cx);
++ free_irq(cx->pci_dev->irq, (void *)cx);
+
+ cx18_iounmap(cx);
+
+ release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+
+- pci_disable_device(cx->dev);
++ pci_disable_device(cx->pci_dev);
++
++ if (cx->vbi.sliced_mpeg_data[0] != NULL)
++ for (i = 0; i < CX18_VBI_FRAMES; i++)
++ kfree(cx->vbi.sliced_mpeg_data[i]);
++
++ CX18_INFO("Removed %s\n", cx->card_name);
+
+- CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
++ v4l2_device_unregister(v4l2_dev);
++ kfree(cx);
+ }
+
+ /* define a pci_driver for card detection */
+@@ -1138,8 +1117,6 @@ static int module_start(void)
+ {
+ printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION);
+
+- memset(cx18_cards, 0, sizeof(cx18_cards));
+-
+ /* Validate parameters */
+ if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n",
+@@ -1162,16 +1139,7 @@ static int module_start(void)
+
+ static void module_cleanup(void)
+ {
+- int i;
+-
+ pci_unregister_driver(&cx18_pci_driver);
+-
+- for (i = 0; i < cx18_cards_active; i++) {
+- if (cx18_cards[i] == NULL)
+- continue;
+- kfree(cx18_cards[i]);
+- }
+-
+ }
+
+ module_init(module_start);
+diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
+index 0d2edeb..ece4f28 100644
+--- a/drivers/media/video/cx18/cx18-driver.h
++++ b/drivers/media/video/cx18/cx18-driver.h
+@@ -48,6 +48,7 @@
+ #include <linux/dvb/audio.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-ioctl.h>
++#include <media/v4l2-device.h>
+ #include <media/tuner.h>
+ #include "cx18-mailbox.h"
+ #include "cx18-av-core.h"
+@@ -79,7 +80,7 @@
+ #define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
+ #define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */
+ #define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
+-#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */
++#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100/DVR3100 H */
+ #define CX18_CARD_LAST 6
+
+ #define CX18_ENC_STREAM_TYPE_MPG 0
+@@ -143,12 +144,12 @@
+ /* Flag to turn on high volume debugging */
+ #define CX18_DBGFLG_HIGHVOL (1 << 8)
+
+-/* NOTE: extra space before comma in 'cx->num , ## args' is required for
++/* NOTE: extra space before comma in 'fmt , ## args' is required for
+ gcc-2.95, otherwise it won't compile. */
+ #define CX18_DEBUG(x, type, fmt, args...) \
+ do { \
+ if ((x) & cx18_debug) \
+- printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \
++ v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \
+ } while (0)
+ #define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+ #define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args)
+@@ -162,7 +163,7 @@
+ #define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+ do { \
+ if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
+- printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \
++ v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \
+ } while (0)
+ #define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+ #define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args)
+@@ -174,9 +175,58 @@
+ #define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
+
+ /* Standard kernel messages */
+-#define CX18_ERR(fmt, args...) printk(KERN_ERR "cx18-%d: " fmt, cx->num , ## args)
+-#define CX18_WARN(fmt, args...) printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args)
+-#define CX18_INFO(fmt, args...) printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args)
++#define CX18_ERR(fmt, args...) v4l2_err(&cx->v4l2_dev, fmt , ## args)
++#define CX18_WARN(fmt, args...) v4l2_warn(&cx->v4l2_dev, fmt , ## args)
++#define CX18_INFO(fmt, args...) v4l2_info(&cx->v4l2_dev, fmt , ## args)
++
++/* Messages for internal subdevs to use */
++#define CX18_DEBUG_DEV(x, dev, type, fmt, args...) \
++ do { \
++ if ((x) & cx18_debug) \
++ v4l2_info(dev, " " type ": " fmt , ## args); \
++ } while (0)
++#define CX18_DEBUG_WARN_DEV(dev, fmt, args...) \
++ CX18_DEBUG_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args)
++#define CX18_DEBUG_INFO_DEV(dev, fmt, args...) \
++ CX18_DEBUG_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args)
++#define CX18_DEBUG_API_DEV(dev, fmt, args...) \
++ CX18_DEBUG_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args)
++#define CX18_DEBUG_DMA_DEV(dev, fmt, args...) \
++ CX18_DEBUG_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args)
++#define CX18_DEBUG_IOCTL_DEV(dev, fmt, args...) \
++ CX18_DEBUG_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args)
++#define CX18_DEBUG_FILE_DEV(dev, fmt, args...) \
++ CX18_DEBUG_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args)
++#define CX18_DEBUG_I2C_DEV(dev, fmt, args...) \
++ CX18_DEBUG_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args)
++#define CX18_DEBUG_IRQ_DEV(dev, fmt, args...) \
++ CX18_DEBUG_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args)
++
++#define CX18_DEBUG_HIGH_VOL_DEV(x, dev, type, fmt, args...) \
++ do { \
++ if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
++ v4l2_info(dev, " " type ": " fmt , ## args); \
++ } while (0)
++#define CX18_DEBUG_HI_WARN_DEV(dev, fmt, args...) \
++ CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args)
++#define CX18_DEBUG_HI_INFO_DEV(dev, fmt, args...) \
++ CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args)
++#define CX18_DEBUG_HI_API_DEV(dev, fmt, args...) \
++ CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args)
++#define CX18_DEBUG_HI_DMA_DEV(dev, fmt, args...) \
++ CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args)
++#define CX18_DEBUG_HI_IOCTL_DEV(dev, fmt, args...) \
++ CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args)
++#define CX18_DEBUG_HI_FILE_DEV(dev, fmt, args...) \
++ CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args)
++#define CX18_DEBUG_HI_I2C_DEV(dev, fmt, args...) \
++ CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args)
++#define CX18_DEBUG_HI_IRQ_DEV(dev, fmt, args...) \
++ CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args)
++
++#define CX18_ERR_DEV(dev, fmt, args...) v4l2_err(dev, fmt , ## args)
++#define CX18_WARN_DEV(dev, fmt, args...) v4l2_warn(dev, fmt , ## args)
++#define CX18_INFO_DEV(dev, fmt, args...) v4l2_info(dev, fmt , ## args)
+
+ /* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
+ #define MPEG_FRAME_TYPE_IFRAME 1
+@@ -279,7 +329,7 @@ struct cx18_epu_work_order {
+ struct cx18_stream {
+ /* These first four fields are always set, even if the stream
+ is not actually created. */
+- struct video_device *v4l2dev; /* NULL when stream not created */
++ struct video_device *video_dev; /* NULL when stream not created */
+ struct cx18 *cx; /* for ease of use */
+ const char *name; /* name of the stream */
+ int type; /* stream type */
+@@ -292,7 +342,6 @@ struct cx18_stream {
+ int dma; /* can be PCI_DMA_TODEVICE,
+ PCI_DMA_FROMDEVICE or
+ PCI_DMA_NONE */
+- u64 dma_pts;
+ wait_queue_head_t waitq;
+
+ /* Buffer Stats */
+@@ -318,59 +367,121 @@ struct cx18_open_id {
+ /* forward declaration of struct defined in cx18-cards.h */
+ struct cx18_card;
+
++/*
++ * A note about "sliced" VBI data as implemented in this driver:
++ *
++ * Currently we collect the sliced VBI in the form of Ancillary Data
++ * packets, inserted by the AV core decoder/digitizer/slicer in the
++ * horizontal blanking region of the VBI lines, in "raw" mode as far as
++ * the Encoder is concerned. We don't ever tell the Encoder itself
++ * to provide sliced VBI. (AV Core: sliced mode - Encoder: raw mode)
++ *
++ * We then process the ancillary data ourselves to send the sliced data
++ * to the user application directly or build up MPEG-2 private stream 1
++ * packets to splice into (only!) MPEG-2 PS streams for the user app.
++ *
++ * (That's how ivtv essentially does it.)
++ *
++ * The Encoder should be able to extract certain sliced VBI data for
++ * us and provide it in a separate stream or splice it into any type of
++ * MPEG PS or TS stream, but this isn't implemented yet.
++ */
++
++/*
++ * Number of "raw" VBI samples per horizontal line we tell the Encoder to
++ * grab from the decoder/digitizer/slicer output for raw or sliced VBI.
++ * It depends on the pixel clock and the horiz rate:
++ *
++ * (1/Fh)*(2*Fp) = Samples/line
++ * = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
++ *
++ * Sliced VBI data is sent as ancillary data during horizontal blanking
++ * Raw VBI is sent as active video samples during vertcal blanking
++ *
++ * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
++ * length of 720 pixels @ 4:2:2 sampling. Thus...
++ *
++ * For systems that use a 15.734 kHz horizontal rate, such as
++ * NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
++ *
++ * (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
++ * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
++ *
++ * For systems that use a 15.625 kHz horizontal rate, such as
++ * PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
++ *
++ * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
++ * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
++ */
++static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */
++static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */
++static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */
+
+ #define CX18_VBI_FRAMES 32
+
+-/* VBI data */
+ struct vbi_info {
+- u32 enc_size;
+- u32 frame;
+- u8 cc_data_odd[256];
+- u8 cc_data_even[256];
+- int cc_pos;
+- u8 cc_no_update;
+- u8 vps[5];
+- u8 vps_found;
+- int wss;
+- u8 wss_found;
+- u8 wss_no_update;
+- u32 raw_decoder_line_size;
+- u8 raw_decoder_sav_odd_field;
+- u8 raw_decoder_sav_even_field;
+- u32 sliced_decoder_line_size;
+- u8 sliced_decoder_sav_odd_field;
+- u8 sliced_decoder_sav_even_field;
++ /* Current state of v4l2 VBI settings for this device */
+ struct v4l2_format in;
+- /* convenience pointer to sliced struct in vbi_in union */
+- struct v4l2_sliced_vbi_format *sliced_in;
+- u32 service_set_in;
+- int insert_mpeg;
++ struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */
++ u32 count; /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */
++ u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */
+
+- /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
+- One for /dev/vbi0 and one for /dev/vbi8 */
+- struct v4l2_sliced_vbi_data sliced_data[36];
++ u32 frame; /* Count of VBI buffers/frames received from Encoder */
+
+- /* Buffer for VBI data inserted into MPEG stream.
+- The first byte is a dummy byte that's never used.
+- The next 16 bytes contain the MPEG header for the VBI data,
+- the remainder is the actual VBI data.
+- The max size accepted by the MPEG VBI reinsertion turns out
+- to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
+- where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
+- a single line header byte and 2 * 18 is the number of VBI lines per frame.
++ /*
++ * Vars for creation and insertion of MPEG Private Stream 1 packets
++ * of sliced VBI data into an MPEG PS
++ */
+
+- However, it seems that the data must be 1K aligned, so we have to
+- pad the data until the 1 or 2 K boundary.
++ /* Boolean: create and insert Private Stream 1 packets into the PS */
++ int insert_mpeg;
++
++ /*
++ * Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
++ * Used in cx18-vbi.c only for collecting sliced data, and as a source
++ * during conversion of sliced VBI data into MPEG Priv Stream 1 packets.
++ * We don't need to save state here, but the array may have been a bit
++ * too big (2304 bytes) to alloc from the stack.
++ */
++ struct v4l2_sliced_vbi_data sliced_data[36];
+
+- This pointer array will allocate 2049 bytes to store each VBI frame. */
++ /*
++ * A ring buffer of driver-generated MPEG-2 PS
++ * Program Pack/Private Stream 1 packets for sliced VBI data insertion
++ * into the MPEG PS stream.
++ *
++ * In each sliced_mpeg_data[] buffer is:
++ * 16 byte MPEG-2 PS Program Pack Header
++ * 16 byte MPEG-2 Private Stream 1 PES Header
++ * 4 byte magic number: "itv0" or "ITV0"
++ * 4 byte first field line mask, if "itv0"
++ * 4 byte second field line mask, if "itv0"
++ * 36 lines, if "ITV0"; or <36 lines, if "itv0"; of sliced VBI data
++ *
++ * Each line in the payload is
++ * 1 byte line header derived from the SDID (WSS, CC, VPS, etc.)
++ * 42 bytes of line data
++ *
++ * That's a maximum 1552 bytes of payload in the Private Stream 1 packet
++ * which is the payload size a PVR-350 (CX23415) MPEG decoder will
++ * accept for VBI data. So, including the headers, it's a maximum 1584
++ * bytes total.
++ */
++#define CX18_SLICED_MPEG_DATA_MAXSZ 1584
++ /* copy_vbi_buf() needs 8 temp bytes on the end for the worst case */
++#define CX18_SLICED_MPEG_DATA_BUFSZ (CX18_SLICED_MPEG_DATA_MAXSZ+8)
+ u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
+ u32 sliced_mpeg_size[CX18_VBI_FRAMES];
+- struct cx18_buffer sliced_mpeg_buf;
++
++ /* Count of Program Pack/Program Stream 1 packets inserted into PS */
+ u32 inserted_frame;
+
+- u32 start[2], count;
+- u32 raw_size;
+- u32 sliced_size;
++ /*
++ * A dummy driver stream transfer buffer with a copy of the next
++ * sliced_mpeg_data[] buffer for output to userland apps.
++ * Only used in cx18-fileops.c, but its state needs to persist at times.
++ */
++ struct cx18_buffer sliced_mpeg_buf;
+ };
+
+ /* Per cx23418, per I2C bus private algo callback data */
+@@ -383,16 +494,17 @@ struct cx18_i2c_algo_callback_data {
+
+ /* Struct to hold info about cx18 cards */
+ struct cx18 {
+- int num; /* board number, -1 during init! */
+- char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */
+- struct pci_dev *dev; /* PCI device */
++ int instance;
++ struct pci_dev *pci_dev;
++ struct v4l2_device v4l2_dev;
++ struct v4l2_subdev *sd_av; /* A/V decoder/digitizer sub-device */
++ struct v4l2_subdev *sd_extmux; /* External multiplexer sub-dev */
++
+ const struct cx18_card *card; /* card information */
+ const char *card_name; /* full name of the card */
+ const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
+ u8 is_50hz;
+ u8 is_60hz;
+- u8 is_out_50hz;
+- u8 is_out_60hz;
+ u8 nof_inputs; /* number of video inputs */
+ u8 nof_audio_inputs; /* number of audio inputs */
+ u16 buffer_id; /* buffer ID counter */
+@@ -413,10 +525,7 @@ struct cx18 {
+
+ /* dualwatch */
+ unsigned long dualwatch_jiffies;
+- u16 dualwatch_stereo_mode;
+-
+- /* Digitizer type */
+- int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
++ u32 dualwatch_stereo_mode;
+
+ struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
+ struct cx18_options options; /* User options */
+@@ -426,7 +535,6 @@ struct cx18 {
+ unsigned long i_flags; /* global cx18 flags */
+ atomic_t ana_capturing; /* count number of active analog capture streams */
+ atomic_t tot_capturing; /* total count number of active capture streams */
+- spinlock_t lock; /* lock access to this struct */
+ int search_pack_header;
+
+ int open_id; /* incremented each time an open occurs, used as
+@@ -468,30 +576,30 @@ struct cx18 {
+ struct i2c_adapter i2c_adap[2];
+ struct i2c_algo_bit_data i2c_algo[2];
+ struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2];
+- struct i2c_client i2c_client[2];
+- struct mutex i2c_bus_lock[2];
+- struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
+
+ /* gpio */
+ u32 gpio_dir;
+ u32 gpio_val;
+ struct mutex gpio_lock;
++ struct v4l2_subdev sd_gpiomux;
++ struct v4l2_subdev sd_resetctrl;
+
+ /* v4l2 and User settings */
+
+ /* codec settings */
+ u32 audio_input;
+ u32 active_input;
+- u32 active_output;
+ v4l2_std_id std;
+ v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
+ };
+
++static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev)
++{
++ return container_of(v4l2_dev, struct cx18, v4l2_dev);
++}
++
+ /* Globals */
+-extern struct cx18 *cx18_cards[];
+-extern int cx18_cards_active;
+ extern int cx18_first_minor;
+-extern spinlock_t cx18_cards_lock;
+
+ /*==============Prototypes==================*/
+
+@@ -511,4 +619,22 @@ static inline int cx18_raw_vbi(const struct cx18 *cx)
+ return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+ }
+
++/* Call the specified callback for all subdevs with a grp_id bit matching the
++ * mask in hw (if 0, then match them all). Ignore any errors. */
++#define cx18_call_hw(cx, hw, o, f, args...) \
++ __v4l2_device_call_subdevs(&(cx)->v4l2_dev, \
++ !(hw) || (sd->grp_id & (hw)), o, f , ##args)
++
++#define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args)
++
++/* Call the specified callback for all subdevs with a grp_id bit matching the
++ * mask in hw (if 0, then match them all). If the callback returns an error
++ * other than 0 or -ENOIOCTLCMD, then return with that error code. */
++#define cx18_call_hw_err(cx, hw, o, f, args...) \
++ __v4l2_device_call_subdevs_until_err( \
++ &(cx)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
++
++#define cx18_call_all_err(cx, o, f, args...) \
++ cx18_call_hw_err(cx, 0, o, f , ##args)
++
+ #endif /* CX18_DRIVER_H */
+diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
+index bd5e6f3..3b86f57 100644
+--- a/drivers/media/video/cx18/cx18-dvb.c
++++ b/drivers/media/video/cx18/cx18-dvb.c
+@@ -167,7 +167,7 @@ int cx18_dvb_register(struct cx18_stream *stream)
+
+ ret = dvb_register_adapter(&dvb->dvb_adapter,
+ CX18_DRIVER_NAME,
+- THIS_MODULE, &cx->dev->dev, adapter_nr);
++ THIS_MODULE, &cx->pci_dev->dev, adapter_nr);
+ if (ret < 0)
+ goto err_out;
+
+diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
+index 055f6e0..4d7d6d5 100644
+--- a/drivers/media/video/cx18/cx18-fileops.c
++++ b/drivers/media/video/cx18/cx18-fileops.c
+@@ -128,15 +128,15 @@ static void cx18_release_stream(struct cx18_stream *s)
+ static void cx18_dualwatch(struct cx18 *cx)
+ {
+ struct v4l2_tuner vt;
+- u16 new_bitmap;
+- u16 new_stereo_mode;
+- const u16 stereo_mask = 0x0300;
+- const u16 dual = 0x0200;
++ u32 new_bitmap;
++ u32 new_stereo_mode;
++ const u32 stereo_mask = 0x0300;
++ const u32 dual = 0x0200;
+ u32 h;
+
+ new_stereo_mode = cx->params.audio_properties & stereo_mask;
+ memset(&vt, 0, sizeof(vt));
+- cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt);
++ cx18_call_all(cx, tuner, g_tuner, &vt);
+ if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
+ (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
+ new_stereo_mode = dual;
+@@ -176,6 +176,8 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
+ *err = 0;
+ while (1) {
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
++ /* Process pending program info updates and pending
++ VBI data */
+
+ if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
+ cx->dualwatch_jiffies = jiffies;
+@@ -186,7 +188,6 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
+ while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
+ /* byteswap and process VBI data */
+ cx18_process_vbi_data(cx, buf,
+- s_vbi->dma_pts,
+ s_vbi->type);
+ cx18_stream_put_buf_fw(s_vbi, buf);
+ }
+@@ -207,8 +208,7 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
+ cx18_buf_swap(buf);
+ else {
+ /* byteswap and process VBI data */
+- cx18_process_vbi_data(cx, buf,
+- s->dma_pts, s->type);
++ cx18_process_vbi_data(cx, buf, s->type);
+ }
+ return buf;
+ }
+@@ -260,6 +260,20 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
+ len = ucount;
+ if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
++ /*
++ * Try to find a good splice point in the PS, just before
++ * an MPEG-2 Program Pack start code, and provide only
++ * up to that point to the user, so it's easy to insert VBI data
++ * the next time around.
++ */
++ /* FIXME - This only works for an MPEG-2 PS, not a TS */
++ /*
++ * An MPEG-2 Program Stream (PS) is a series of
++ * MPEG-2 Program Packs terminated by an
++ * MPEG Program End Code after the last Program Pack.
++ * A Program Pack may hold a PS System Header packet and any
++ * number of Program Elementary Stream (PES) Packets
++ */
+ const char *start = buf->buf + buf->readpos;
+ const char *p = start + 1;
+ const u8 *q;
+@@ -267,38 +281,54 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
+ int stuffing, i;
+
+ while (start + len > p) {
++ /* Scan for a 0 to find a potential MPEG-2 start code */
+ q = memchr(p, 0, start + len - p);
+ if (q == NULL)
+ break;
+ p = q + 1;
++ /*
++ * Keep looking if not a
++ * MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba
++ * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0
++ */
+ if ((char *)q + 15 >= buf->buf + buf->bytesused ||
+ q[1] != 0 || q[2] != 1 || q[3] != ch)
+ continue;
++
++ /* If expecting the primary video PES */
+ if (!cx->search_pack_header) {
++ /* Continue if it couldn't be a PES packet */
+ if ((q[6] & 0xc0) != 0x80)
+ continue;
+- if (((q[7] & 0xc0) == 0x80 &&
+- (q[9] & 0xf0) == 0x20) ||
+- ((q[7] & 0xc0) == 0xc0 &&
+- (q[9] & 0xf0) == 0x30)) {
+- ch = 0xba;
++ /* Check if a PTS or PTS & DTS follow */
++ if (((q[7] & 0xc0) == 0x80 && /* PTS only */
++ (q[9] & 0xf0) == 0x20) || /* PTS only */
++ ((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */
++ (q[9] & 0xf0) == 0x30)) { /* DTS follows */
++ /* Assume we found the video PES hdr */
++ ch = 0xba; /* next want a Program Pack*/
+ cx->search_pack_header = 1;
+- p = q + 9;
++ p = q + 9; /* Skip this video PES hdr */
+ }
+ continue;
+ }
++
++ /* We may have found a Program Pack start code */
++
++ /* Get the count of stuffing bytes & verify them */
+ stuffing = q[13] & 7;
+ /* all stuffing bytes must be 0xff */
+ for (i = 0; i < stuffing; i++)
+ if (q[14 + i] != 0xff)
+ break;
+- if (i == stuffing &&
+- (q[4] & 0xc4) == 0x44 &&
+- (q[12] & 3) == 3 &&
+- q[14 + stuffing] == 0 &&
++ if (i == stuffing && /* right number of stuffing bytes*/
++ (q[4] & 0xc4) == 0x44 && /* marker check */
++ (q[12] & 3) == 3 && /* marker check */
++ q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */
+ q[15 + stuffing] == 0 &&
+ q[16 + stuffing] == 1) {
+- cx->search_pack_header = 0;
++ /* We declare we actually found a Program Pack*/
++ cx->search_pack_header = 0; /* expect vid PES */
+ len = (char *)q - start;
+ cx18_setup_sliced_vbi_buf(cx);
+ break;
+@@ -578,7 +608,7 @@ int cx18_v4l2_close(struct file *filp)
+ /* Mark that the radio is no longer in use */
+ clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
+ /* Switch tuner to TV */
+- cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
++ cx18_call_all(cx, tuner, s_std, cx->std);
+ /* Select correct audio input (i.e. TV tuner or Line in) */
+ cx18_audio_set_io(cx);
+ if (atomic_read(&cx->ana_capturing) > 0) {
+@@ -641,7 +671,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
+ /* We have the radio */
+ cx18_mute(cx);
+ /* Switch tuner to radio */
+- cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL);
++ cx18_call_all(cx, tuner, s_radio);
+ /* Select the correct audio input (i.e. radio tuner) */
+ cx18_audio_set_io(cx);
+ /* Done! Unmute and continue. */
+@@ -652,38 +682,15 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
+
+ int cx18_v4l2_open(struct file *filp)
+ {
+- int res, x, y = 0;
+- struct cx18 *cx = NULL;
+- struct cx18_stream *s = NULL;
+- int minor = video_devdata(filp)->minor;
+-
+- /* Find which card this open was on */
+- spin_lock(&cx18_cards_lock);
+- for (x = 0; cx == NULL && x < cx18_cards_active; x++) {
+- /* find out which stream this open was on */
+- for (y = 0; y < CX18_MAX_STREAMS; y++) {
+- if (cx18_cards[x] == NULL)
+- continue;
+- s = &cx18_cards[x]->streams[y];
+- if (s->v4l2dev && s->v4l2dev->minor == minor) {
+- cx = cx18_cards[x];
+- break;
+- }
+- }
+- }
+- spin_unlock(&cx18_cards_lock);
+-
+- if (cx == NULL) {
+- /* Couldn't find a device registered
+- on that minor, shouldn't happen! */
+- printk(KERN_WARNING "No cx18 device found on minor %d\n",
+- minor);
+- return -ENXIO;
+- }
++ int res;
++ struct video_device *video_dev = video_devdata(filp);
++ struct cx18_stream *s = video_get_drvdata(video_dev);
++ struct cx18 *cx = s->cx;;
+
+ mutex_lock(&cx->serialize_lock);
+ if (cx18_init_on_first_open(cx)) {
+- CX18_ERR("Failed to initialize on minor %d\n", minor);
++ CX18_ERR("Failed to initialize on minor %d\n",
++ video_dev->minor);
+ mutex_unlock(&cx->serialize_lock);
+ return -ENXIO;
+ }
+diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
+index 1fa95da..83cd559 100644
+--- a/drivers/media/video/cx18/cx18-firmware.c
++++ b/drivers/media/video/cx18/cx18-firmware.c
+@@ -26,7 +26,6 @@
+ #include "cx18-irq.h"
+ #include "cx18-firmware.h"
+ #include "cx18-cards.h"
+-#include "cx18-av-core.h"
+ #include <linux/firmware.h>
+
+ #define CX18_PROC_SOFT_RESET 0xc70010
+@@ -107,7 +106,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
+ u32 __iomem *dst = (u32 __iomem *)mem;
+ const u32 *src;
+
+- if (request_firmware(&fw, fn, &cx->dev->dev)) {
++ if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
+ CX18_ERR("Unable to open firmware %s\n", fn);
+ CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
+ return -ENOMEM;
+@@ -151,7 +150,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
+ u32 apu_version = 0;
+ int sz;
+
+- if (request_firmware(&fw, fn, &cx->dev->dev)) {
++ if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
+ CX18_ERR("unable to open firmware %s\n", fn);
+ CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
+ cx18_setup_page(cx, 0);
+@@ -286,23 +285,6 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
+ cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
+ cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
+
+- /*
+- * VDCLK Integer = 0x0f, Post Divider = 0x04
+- * AIMCLK Integer = 0x0e, Post Divider = 0x16
+- */
+- cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+-
+- /* VDCLK Fraction = 0x2be2fe */
+- /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+- cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+-
+- /* AIMCLK Fraction = 0x05227ad */
+- /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz before post-divide */
+- cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+-
+- /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+- cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+-
+ /* Defaults */
+ /* APU = SC or SC/2 = 125/62.5 */
+ /* EPU = SC = 125 */
+diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
+index 1a99329..5518d14 100644
+--- a/drivers/media/video/cx18/cx18-gpio.c
++++ b/drivers/media/video/cx18/cx18-gpio.c
+@@ -46,6 +46,9 @@
+ * gpio13: cs5345 reset pin
+ */
+
++/*
++ * File scope utility functions
++ */
+ static void gpio_write(struct cx18 *cx)
+ {
+ u32 dir_lo = cx->gpio_dir & 0xffff;
+@@ -63,73 +66,201 @@ static void gpio_write(struct cx18 *cx)
+ CX18_REG_GPIO_OUT2, val_hi, dir_hi);
+ }
+
+-void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
++static void gpio_update(struct cx18 *cx, u32 mask, u32 data)
+ {
+- const struct cx18_gpio_i2c_slave_reset *p;
++ if (mask == 0)
++ return;
+
+- p = &cx->card->gpio_i2c_slave_reset;
++ mutex_lock(&cx->gpio_lock);
++ cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
++ gpio_write(cx);
++ mutex_unlock(&cx->gpio_lock);
++}
++
++static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi,
++ unsigned int assert_msecs,
++ unsigned int recovery_msecs)
++{
++ u32 mask;
+
+- if ((p->active_lo_mask | p->active_hi_mask) == 0)
++ mask = active_lo | active_hi;
++ if (mask == 0)
+ return;
+
+- /* Assuming that the masks are a subset of the bits in gpio_dir */
++ /*
++ * Assuming that active_hi and active_lo are a subsets of the bits in
++ * gpio_dir. Also assumes that active_lo and active_hi don't overlap
++ * in any bit position
++ */
+
+ /* Assert */
+- mutex_lock(&cx->gpio_lock);
+- cx->gpio_val =
+- (cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
+- gpio_write(cx);
+- schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
++ gpio_update(cx, mask, ~active_lo);
++ schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs));
+
+ /* Deassert */
+- cx->gpio_val =
+- (cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
+- gpio_write(cx);
+- schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
++ gpio_update(cx, mask, ~active_hi);
++ schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs));
++}
++
++/*
++ * GPIO Multiplexer - logical device
++ */
++static int gpiomux_log_status(struct v4l2_subdev *sd)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++
++ mutex_lock(&cx->gpio_lock);
++ CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n",
++ cx->gpio_dir, cx->gpio_val);
+ mutex_unlock(&cx->gpio_lock);
++ return 0;
+ }
+
+-void cx18_reset_ir_gpio(void *data)
++static int gpiomux_s_radio(struct v4l2_subdev *sd)
+ {
+- struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+- const struct cx18_gpio_i2c_slave_reset *p;
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+- p = &cx->card->gpio_i2c_slave_reset;
++ /*
++ * FIXME - work out the cx->active/audio_input mess - this is
++ * intended to handle the switch to radio mode and set the
++ * audio routing, but we need to update the state in cx
++ */
++ gpio_update(cx, cx->card->gpio_audio_input.mask,
++ cx->card->gpio_audio_input.radio);
++ return 0;
++}
+
+- if (p->ir_reset_mask == 0)
+- return;
++static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ u32 data;
+
+- CX18_DEBUG_INFO("Resetting IR microcontroller\n");
++ switch (cx->card->audio_inputs[cx->audio_input].muxer_input) {
++ case 1:
++ data = cx->card->gpio_audio_input.linein;
++ break;
++ case 0:
++ data = cx->card->gpio_audio_input.tuner;
++ break;
++ default:
++ /*
++ * FIXME - work out the cx->active/audio_input mess - this is
++ * intended to handle the switch from radio mode and set the
++ * audio routing, but we need to update the state in cx
++ */
++ data = cx->card->gpio_audio_input.tuner;
++ break;
++ }
++ gpio_update(cx, cx->card->gpio_audio_input.mask, data);
++ return 0;
++}
+
+- /*
+- Assert timing for the Z8F0811 on HVR-1600 boards:
+- 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to initiate
+- 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock cycles
+- (6,601,085 nanoseconds ~= 7 milliseconds)
+- 3. DBG pin must be high before chip exits reset for normal operation.
+- DBG is open drain and hopefully pulled high since we don't
+- normally drive it (GPIO 1?) for the HVR-1600
+- 4. Z8F0811 won't exit reset until RESET is deasserted
+- */
+- mutex_lock(&cx->gpio_lock);
+- cx->gpio_val = cx->gpio_val & ~p->ir_reset_mask;
+- gpio_write(cx);
+- mutex_unlock(&cx->gpio_lock);
+- schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
++static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,
++ const struct v4l2_routing *route)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ u32 data;
++
++ switch (route->input) {
++ case 0:
++ data = cx->card->gpio_audio_input.tuner;
++ break;
++ case 1:
++ data = cx->card->gpio_audio_input.linein;
++ break;
++ case 2:
++ data = cx->card->gpio_audio_input.radio;
++ break;
++ default:
++ return -EINVAL;
++ }
++ gpio_update(cx, cx->card->gpio_audio_input.mask, data);
++ return 0;
++}
++
++static const struct v4l2_subdev_core_ops gpiomux_core_ops = {
++ .log_status = gpiomux_log_status,
++};
++
++static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = {
++ .s_std = gpiomux_s_std,
++ .s_radio = gpiomux_s_radio,
++};
++
++static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = {
++ .s_routing = gpiomux_s_audio_routing,
++};
++
++static const struct v4l2_subdev_ops gpiomux_ops = {
++ .core = &gpiomux_core_ops,
++ .tuner = &gpiomux_tuner_ops,
++ .audio = &gpiomux_audio_ops,
++};
++
++/*
++ * GPIO Reset Controller - logical device
++ */
++static int resetctrl_log_status(struct v4l2_subdev *sd)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+- /*
+- Zilog comes out of reset, loads reset vector address and executes
+- from there. Required recovery delay unknown.
+- */
+ mutex_lock(&cx->gpio_lock);
+- cx->gpio_val = cx->gpio_val | p->ir_reset_mask;
+- gpio_write(cx);
++ CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n",
++ cx->gpio_dir, cx->gpio_val);
+ mutex_unlock(&cx->gpio_lock);
+- schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
++ return 0;
+ }
+-EXPORT_SYMBOL(cx18_reset_ir_gpio);
+-/* This symbol is exported for use by an infrared module for the IR-blaster */
+
++static int resetctrl_reset(struct v4l2_subdev *sd, u32 val)
++{
++ struct cx18 *cx = v4l2_get_subdevdata(sd);
++ const struct cx18_gpio_i2c_slave_reset *p;
++
++ p = &cx->card->gpio_i2c_slave_reset;
++ switch (val) {
++ case CX18_GPIO_RESET_I2C:
++ gpio_reset_seq(cx, p->active_lo_mask, p->active_hi_mask,
++ p->msecs_asserted, p->msecs_recovery);
++ break;
++ case CX18_GPIO_RESET_Z8F0811:
++ /*
++ * Assert timing for the Z8F0811 on HVR-1600 boards:
++ * 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to
++ * initiate
++ * 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock
++ * cycles (6,601,085 nanoseconds ~= 7 milliseconds)
++ * 3. DBG pin must be high before chip exits reset for normal
++ * operation. DBG is open drain and hopefully pulled high
++ * since we don't normally drive it (GPIO 1?) for the
++ * HVR-1600
++ * 4. Z8F0811 won't exit reset until RESET is deasserted
++ * 5. Zilog comes out of reset, loads reset vector address and
++ * executes from there. Required recovery delay unknown.
++ */
++ gpio_reset_seq(cx, p->ir_reset_mask, 0,
++ p->msecs_asserted, p->msecs_recovery);
++ break;
++ case CX18_GPIO_RESET_XC2028:
++ if (cx->card->tuners[0].tuner == TUNER_XC2028)
++ gpio_reset_seq(cx, (1 << cx->card->xceive_pin), 0,
++ 1, 1);
++ break;
++ }
++ return 0;
++}
++
++static const struct v4l2_subdev_core_ops resetctrl_core_ops = {
++ .log_status = resetctrl_log_status,
++ .reset = resetctrl_reset,
++};
++
++static const struct v4l2_subdev_ops resetctrl_ops = {
++ .core = &resetctrl_core_ops,
++};
++
++/*
++ * External entry points
++ */
+ void cx18_gpio_init(struct cx18 *cx)
+ {
+ mutex_lock(&cx->gpio_lock);
+@@ -156,6 +287,49 @@ void cx18_gpio_init(struct cx18 *cx)
+ mutex_unlock(&cx->gpio_lock);
+ }
+
++int cx18_gpio_register(struct cx18 *cx, u32 hw)
++{
++ struct v4l2_subdev *sd;
++ const struct v4l2_subdev_ops *ops;
++ char *str;
++
++ switch (hw) {
++ case CX18_HW_GPIO_MUX:
++ sd = &cx->sd_gpiomux;
++ ops = &gpiomux_ops;
++ str = "gpio-mux";
++ break;
++ case CX18_HW_GPIO_RESET_CTRL:
++ sd = &cx->sd_resetctrl;
++ ops = &resetctrl_ops;
++ str = "gpio-reset-ctrl";
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ v4l2_subdev_init(sd, ops);
++ v4l2_set_subdevdata(sd, cx);
++ snprintf(sd->name, sizeof(sd->name), "%s %s", cx->v4l2_dev.name, str);
++ sd->grp_id = hw;
++ return v4l2_device_register_subdev(&cx->v4l2_dev, sd);
++}
++
++void cx18_reset_ir_gpio(void *data)
++{
++ struct cx18 *cx = to_cx18((struct v4l2_device *)data);
++
++ if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0)
++ return;
++
++ CX18_DEBUG_INFO("Resetting IR microcontroller\n");
++
++ v4l2_subdev_call(&cx->sd_resetctrl,
++ core, reset, CX18_GPIO_RESET_Z8F0811);
++}
++EXPORT_SYMBOL(cx18_reset_ir_gpio);
++/* This symbol is exported for use by lirc_pvr150 for the IR-blaster */
++
+ /* Xceive tuner reset function */
+ int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
+ {
+@@ -163,56 +337,11 @@ int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
+ struct cx18_i2c_algo_callback_data *cb_data = algo->data;
+ struct cx18 *cx = cb_data->cx;
+
+- if (cmd != XC2028_TUNER_RESET)
++ if (cmd != XC2028_TUNER_RESET ||
++ cx->card->tuners[0].tuner != TUNER_XC2028)
+ return 0;
+- CX18_DEBUG_INFO("Resetting tuner\n");
+
+- mutex_lock(&cx->gpio_lock);
+- cx->gpio_val &= ~(1 << cx->card->xceive_pin);
+- gpio_write(cx);
+- mutex_unlock(&cx->gpio_lock);
+- schedule_timeout_interruptible(msecs_to_jiffies(1));
+-
+- mutex_lock(&cx->gpio_lock);
+- cx->gpio_val |= 1 << cx->card->xceive_pin;
+- gpio_write(cx);
+- mutex_unlock(&cx->gpio_lock);
+- schedule_timeout_interruptible(msecs_to_jiffies(1));
+- return 0;
+-}
+-
+-int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg)
+-{
+- struct v4l2_routing *route = arg;
+- u32 mask, data;
+-
+- switch (command) {
+- case VIDIOC_INT_S_AUDIO_ROUTING:
+- if (route->input > 2)
+- return -EINVAL;
+- mask = cx->card->gpio_audio_input.mask;
+- switch (route->input) {
+- case 0:
+- data = cx->card->gpio_audio_input.tuner;
+- break;
+- case 1:
+- data = cx->card->gpio_audio_input.linein;
+- break;
+- case 2:
+- default:
+- data = cx->card->gpio_audio_input.radio;
+- break;
+- }
+- break;
+-
+- default:
+- return -EINVAL;
+- }
+- if (mask) {
+- mutex_lock(&cx->gpio_lock);
+- cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
+- gpio_write(cx);
+- mutex_unlock(&cx->gpio_lock);
+- }
+- return 0;
++ CX18_DEBUG_INFO("Resetting XCeive tuner\n");
++ return v4l2_subdev_call(&cx->sd_resetctrl,
++ core, reset, CX18_GPIO_RESET_XC2028);
+ }
+diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
+index 39ffccc..f9a5ca3 100644
+--- a/drivers/media/video/cx18/cx18-gpio.h
++++ b/drivers/media/video/cx18/cx18-gpio.h
+@@ -22,7 +22,13 @@
+ */
+
+ void cx18_gpio_init(struct cx18 *cx);
+-void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
++int cx18_gpio_register(struct cx18 *cx, u32 hw);
++
++enum cx18_gpio_reset_type {
++ CX18_GPIO_RESET_I2C = 0,
++ CX18_GPIO_RESET_Z8F0811 = 1,
++ CX18_GPIO_RESET_XC2028 = 2,
++};
++
+ void cx18_reset_ir_gpio(void *data);
+ int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value);
+-int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);
+diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
+index 83e1c63..d092643 100644
+--- a/drivers/media/video/cx18/cx18-i2c.c
++++ b/drivers/media/video/cx18/cx18-i2c.c
+@@ -26,7 +26,6 @@
+ #include "cx18-io.h"
+ #include "cx18-cards.h"
+ #include "cx18-gpio.h"
+-#include "cx18-av-core.h"
+ #include "cx18-i2c.h"
+ #include "cx18-irq.h"
+
+@@ -43,31 +42,37 @@
+ #define CX18_CS5345_I2C_ADDR 0x4c
+
+ /* This array should match the CX18_HW_ defines */
+-static const u8 hw_driverids[] = {
+- I2C_DRIVERID_TUNER,
+- I2C_DRIVERID_TVEEPROM,
+- I2C_DRIVERID_CS5345,
+- 0, /* CX18_HW_GPIO dummy driver ID */
+- 0 /* CX18_HW_CX23418 dummy driver ID */
+-};
+-
+-/* This array should match the CX18_HW_ defines */
+ static const u8 hw_addrs[] = {
+- 0,
+- 0,
+- CX18_CS5345_I2C_ADDR,
+- 0, /* CX18_HW_GPIO dummy driver ID */
+- 0, /* CX18_HW_CX23418 dummy driver ID */
++ 0, /* CX18_HW_TUNER */
++ 0, /* CX18_HW_TVEEPROM */
++ CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */
++ 0, /* CX18_HW_DVB */
++ 0, /* CX18_HW_418_AV */
++ 0, /* CX18_HW_GPIO_MUX */
++ 0, /* CX18_HW_GPIO_RESET_CTRL */
+ };
+
+ /* This array should match the CX18_HW_ defines */
+ /* This might well become a card-specific array */
+ static const u8 hw_bus[] = {
+- 0,
+- 0,
+- 0,
+- 0, /* CX18_HW_GPIO dummy driver ID */
+- 0, /* CX18_HW_CX23418 dummy driver ID */
++ 1, /* CX18_HW_TUNER */
++ 0, /* CX18_HW_TVEEPROM */
++ 0, /* CX18_HW_CS5345 */
++ 0, /* CX18_HW_DVB */
++ 0, /* CX18_HW_418_AV */
++ 0, /* CX18_HW_GPIO_MUX */
++ 0, /* CX18_HW_GPIO_RESET_CTRL */
++};
++
++/* This array should match the CX18_HW_ defines */
++static const char * const hw_modules[] = {
++ "tuner", /* CX18_HW_TUNER */
++ NULL, /* CX18_HW_TVEEPROM */
++ "cs5345", /* CX18_HW_CS5345 */
++ NULL, /* CX18_HW_DVB */
++ NULL, /* CX18_HW_418_AV */
++ NULL, /* CX18_HW_GPIO_MUX */
++ NULL, /* CX18_HW_GPIO_RESET_CTRL */
+ };
+
+ /* This array should match the CX18_HW_ defines */
+@@ -75,83 +80,67 @@ static const char * const hw_devicenames[] = {
+ "tuner",
+ "tveeprom",
+ "cs5345",
+- "gpio",
+- "cx23418",
++ "cx23418_DTV",
++ "cx23418_AV",
++ "gpio_mux",
++ "gpio_reset_ctrl",
+ };
+
+ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
+ {
+- struct i2c_board_info info;
+- struct i2c_client *c;
+- u8 id, bus;
+- int i;
+-
+- CX18_DEBUG_I2C("i2c client register\n");
+- if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
++ struct v4l2_subdev *sd;
++ int bus = hw_bus[idx];
++ struct i2c_adapter *adap = &cx->i2c_adap[bus];
++ const char *mod = hw_modules[idx];
++ const char *type = hw_devicenames[idx];
++ u32 hw = 1 << idx;
++
++ if (idx >= ARRAY_SIZE(hw_addrs))
+ return -1;
+- id = hw_driverids[idx];
+- bus = hw_bus[idx];
+- memset(&info, 0, sizeof(info));
+- strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
+- info.addr = hw_addrs[idx];
+- for (i = 0; i < I2C_CLIENTS_MAX; i++)
+- if (cx->i2c_clients[i] == NULL)
+- break;
+-
+- if (i == I2C_CLIENTS_MAX) {
+- CX18_ERR("insufficient room for new I2C client!\n");
+- return -ENOMEM;
+- }
+
+- if (id != I2C_DRIVERID_TUNER) {
+- c = i2c_new_device(&cx->i2c_adap[bus], &info);
+- if (c->driver == NULL)
+- i2c_unregister_device(c);
+- else
+- cx->i2c_clients[i] = c;
+- return cx->i2c_clients[i] ? 0 : -ENODEV;
++ if (hw == CX18_HW_TUNER) {
++ /* special tuner group handling */
++ sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
++ cx->card_i2c->radio);
++ if (sd != NULL)
++ sd->grp_id = hw;
++ sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
++ cx->card_i2c->demod);
++ if (sd != NULL)
++ sd->grp_id = hw;
++ sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
++ cx->card_i2c->tv);
++ if (sd != NULL)
++ sd->grp_id = hw;
++ return sd != NULL ? 0 : -1;
+ }
+
+- /* special tuner handling */
+- c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio);
+- if (c && c->driver == NULL)
+- i2c_unregister_device(c);
+- else if (c)
+- cx->i2c_clients[i++] = c;
+- c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod);
+- if (c && c->driver == NULL)
+- i2c_unregister_device(c);
+- else if (c)
+- cx->i2c_clients[i++] = c;
+- c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv);
+- if (c && c->driver == NULL)
+- i2c_unregister_device(c);
+- else if (c)
+- cx->i2c_clients[i++] = c;
+- return 0;
+-}
++ /* Is it not an I2C device or one we do not wish to register? */
++ if (!hw_addrs[idx])
++ return -1;
+
+-static int attach_inform(struct i2c_client *client)
+-{
+- return 0;
++ /* It's an I2C device other than an analog tuner */
++ sd = v4l2_i2c_new_subdev(adap, mod, type, hw_addrs[idx]);
++ if (sd != NULL)
++ sd->grp_id = hw;
++ return sd != NULL ? 0 : -1;
+ }
+
+-static int detach_inform(struct i2c_client *client)
++/* Find the first member of the subdev group id in hw */
++struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw)
+ {
+- int i;
+- struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter);
++ struct v4l2_subdev *result = NULL;
++ struct v4l2_subdev *sd;
+
+- CX18_DEBUG_I2C("i2c client detach\n");
+- for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+- if (cx->i2c_clients[i] == client) {
+- cx->i2c_clients[i] = NULL;
++ spin_lock(&cx->v4l2_dev.lock);
++ v4l2_device_for_each_subdev(sd, &cx->v4l2_dev) {
++ if (sd->grp_id == hw) {
++ result = sd;
+ break;
+ }
+ }
+- CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n",
+- client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
+-
+- return 0;
++ spin_unlock(&cx->v4l2_dev.lock);
++ return result;
+ }
+
+ static void cx18_setscl(void *data, int state)
+@@ -204,8 +193,6 @@ static struct i2c_adapter cx18_i2c_adap_template = {
+ .id = I2C_HW_B_CX2341X,
+ .algo = NULL, /* set by i2c-algo-bit */
+ .algo_data = NULL, /* filled from template */
+- .client_register = attach_inform,
+- .client_unregister = detach_inform,
+ .owner = THIS_MODULE,
+ };
+
+@@ -221,152 +208,28 @@ static struct i2c_algo_bit_data cx18_i2c_algo_template = {
+ .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
+ };
+
+-static struct i2c_client cx18_i2c_client_template = {
+- .name = "cx18 internal",
+-};
+-
+-int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg)
+-{
+- struct i2c_client *client;
+- int retval;
+- int i;
+-
+- CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
+- for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+- client = cx->i2c_clients[i];
+- if (client == NULL || client->driver == NULL ||
+- client->driver->command == NULL)
+- continue;
+- if (addr == client->addr) {
+- retval = client->driver->command(client, cmd, arg);
+- return retval;
+- }
+- }
+- if (cmd != VIDIOC_DBG_G_CHIP_IDENT)
+- CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n",
+- addr, cmd);
+- return -ENODEV;
+-}
+-
+-/* Find the i2c device based on the driver ID and return
+- its i2c address or -ENODEV if no matching device was found. */
+-static int cx18_i2c_id_addr(struct cx18 *cx, u32 id)
+-{
+- struct i2c_client *client;
+- int retval = -ENODEV;
+- int i;
+-
+- for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+- client = cx->i2c_clients[i];
+- if (client == NULL || client->driver == NULL)
+- continue;
+- if (id == client->driver->id) {
+- retval = client->addr;
+- break;
+- }
+- }
+- return retval;
+-}
+-
+-/* Find the i2c device name matching the CX18_HW_ flag */
+-static const char *cx18_i2c_hw_name(u32 hw)
+-{
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+- if (1 << i == hw)
+- return hw_devicenames[i];
+- return "unknown device";
+-}
+-
+-/* Find the i2c device matching the CX18_HW_ flag and return
+- its i2c address or -ENODEV if no matching device was found. */
+-int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw)
+-{
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+- if (1 << i == hw)
+- return cx18_i2c_id_addr(cx, hw_driverids[i]);
+- return -ENODEV;
+-}
+-
+-/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing.
+- If hw == CX18_HW_GPIO then call the gpio handler. */
+-int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
+-{
+- int addr;
+-
+- if (hw == 0)
+- return 0;
+-
+- if (hw == CX18_HW_GPIO)
+- return cx18_gpio(cx, cmd, arg);
+-
+- if (hw == CX18_HW_CX23418)
+- return cx18_av_cmd(cx, cmd, arg);
+-
+- addr = cx18_i2c_hw_addr(cx, hw);
+- if (addr < 0) {
+- CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n",
+- hw, cx18_i2c_hw_name(hw), cmd);
+- return addr;
+- }
+- return cx18_call_i2c_client(cx, addr, cmd, arg);
+-}
+-
+-/* broadcast cmd for all I2C clients and for the gpio subsystem */
+-void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
+-{
+- if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) {
+- CX18_ERR("adapter is not set\n");
+- return;
+- }
+- cx18_av_cmd(cx, cmd, arg);
+- i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
+- i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
+- if (cx->hw_flags & CX18_HW_GPIO)
+- cx18_gpio(cx, cmd, arg);
+-}
+-
+ /* init + register i2c algo-bit adapter */
+ int init_cx18_i2c(struct cx18 *cx)
+ {
+ int i;
+ CX18_DEBUG_I2C("i2c init\n");
+
+- /* Sanity checks for the I2C hardware arrays. They must be the
+- * same size and GPIO/CX23418 must be the last entries.
+- */
+- if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
+- ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
+- CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) ||
+- CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
+- hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+- CX18_ERR("Mismatched I2C hardware arrays\n");
+- return -ENODEV;
+- }
+-
+ for (i = 0; i < 2; i++) {
+- memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
+- sizeof(struct i2c_adapter));
++ /* Setup algorithm for adapter */
+ memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template,
+ sizeof(struct i2c_algo_bit_data));
+ cx->i2c_algo_cb_data[i].cx = cx;
+ cx->i2c_algo_cb_data[i].bus_index = i;
+ cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
+- cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
+
++ /* Setup adapter */
++ memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
++ sizeof(struct i2c_adapter));
++ cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
+ sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
+- " #%d-%d", cx->num, i);
+- i2c_set_adapdata(&cx->i2c_adap[i], cx);
+-
+- memcpy(&cx->i2c_client[i], &cx18_i2c_client_template,
+- sizeof(struct i2c_client));
+- sprintf(cx->i2c_client[i].name +
+- strlen(cx->i2c_client[i].name), "%d", i);
+- cx->i2c_client[i].adapter = &cx->i2c_adap[i];
+- cx->i2c_adap[i].dev.parent = &cx->dev->dev;
++ " #%d-%d", cx->instance, i);
++ i2c_set_adapdata(&cx->i2c_adap[i], &cx->v4l2_dev);
++ cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev;
+ }
+
+ if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
+@@ -402,7 +265,8 @@ int init_cx18_i2c(struct cx18 *cx)
+ cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
+ cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
+
+- cx18_reset_i2c_slaves_gpio(cx);
++ cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
++ core, reset, (u32) CX18_GPIO_RESET_I2C);
+
+ return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
+ i2c_bit_add_bus(&cx->i2c_adap[1]);
+diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h
+index 4869739..bdfd192 100644
+--- a/drivers/media/video/cx18/cx18-i2c.h
++++ b/drivers/media/video/cx18/cx18-i2c.h
+@@ -21,11 +21,8 @@
+ * 02111-1307 USA
+ */
+
+-int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw);
+-int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg);
+-int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg);
+-void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg);
+ int cx18_i2c_register(struct cx18 *cx, unsigned idx);
++struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw);
+
+ /* init + register i2c algo-bit adapter */
+ int init_cx18_i2c(struct cx18 *cx);
+diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
+index 7086aab..e4c9e3d 100644
+--- a/drivers/media/video/cx18/cx18-ioctl.c
++++ b/drivers/media/video/cx18/cx18-ioctl.c
+@@ -58,12 +58,21 @@ u16 cx18_service2vbi(int type)
+ }
+ }
+
++/* Check if VBI services are allowed on the (field, line) for the video std */
+ static int valid_service_line(int field, int line, int is_pal)
+ {
+- return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
++ return (is_pal && line >= 6 &&
++ ((field == 0 && line <= 23) || (field == 1 && line <= 22))) ||
+ (!is_pal && line >= 10 && line < 22);
+ }
+
++/*
++ * For a (field, line, std) and inbound potential set of services for that line,
++ * return the first valid service of those passed in the incoming set for that
++ * line in priority order:
++ * CC, VPS, or WSS over TELETEXT for well known lines
++ * TELETEXT, before VPS, before CC, before WSS, for other lines
++ */
+ static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
+ {
+ u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
+@@ -90,6 +99,10 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
+ return 0;
+ }
+
++/*
++ * Expand the service_set of *fmt into valid service_lines for the std,
++ * and clear the passed in fmt->service_set
++ */
+ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+ {
+ u16 set = fmt->service_set;
+@@ -102,7 +115,25 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+ }
+ }
+
++/*
++ * Sanitize the service_lines in *fmt per the video std, and return 1
++ * if any service_line is left as valid after santization
++ */
++static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
++{
++ int f, l;
++ u16 set = 0;
++
++ for (f = 0; f < 2; f++) {
++ for (l = 0; l < 24; l++) {
++ fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
++ set |= fmt->service_lines[f][l];
++ }
++ }
++ return set != 0;
++}
+
++/* Compute the service_set from the assumed valid service_lines of *fmt */
+ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
+ {
+ int f, l;
+@@ -129,10 +160,8 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
+ pixfmt->priv = 0;
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+ pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+- /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+- pixfmt->sizeimage =
+- pixfmt->height * pixfmt->width +
+- pixfmt->height * (pixfmt->width / 2);
++ /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
++ pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+ pixfmt->bytesperline = 720;
+ } else {
+ pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+@@ -149,8 +178,8 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
+ struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
+
+ vbifmt->sampling_rate = 27000000;
+- vbifmt->offset = 248;
+- vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
++ vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */
++ vbifmt->samples_per_line = vbi_active_samples - 4;
+ vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+ vbifmt->start[0] = cx->vbi.start[0];
+ vbifmt->start[1] = cx->vbi.start[1];
+@@ -164,7 +193,30 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
+ static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+ {
+- return -EINVAL;
++ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
++ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
++
++ /* sane, V4L2 spec compliant, defaults */
++ vbifmt->reserved[0] = 0;
++ vbifmt->reserved[1] = 0;
++ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
++ memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
++ vbifmt->service_set = 0;
++
++ /*
++ * Fetch the configured service_lines and total service_set from the
++ * digitizer/slicer. Note, cx18_av_vbi() wipes the passed in
++ * fmt->fmt.sliced under valid calling conditions
++ */
++ if (v4l2_subdev_call(cx->sd_av, video, g_fmt, fmt))
++ return -EINVAL;
++
++ /* Ensure V4L2 spec compliant output */
++ vbifmt->reserved[0] = 0;
++ vbifmt->reserved[1] = 0;
++ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
++ vbifmt->service_set = cx18_get_service_set(vbifmt);
++ return 0;
+ }
+
+ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
+@@ -174,11 +226,18 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
+ struct cx18 *cx = id->cx;
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
++ int min_h = 2;
+
+ w = min(w, 720);
+- w = max(w, 1);
++ w = max(w, 2);
++ if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
++ /* YUV height must be a multiple of 32 */
++ h &= ~0x1f;
++ min_h = 32;
++ }
+ h = min(h, cx->is_50hz ? 576 : 480);
+- h = max(h, 2);
++ h = max(h, min_h);
++
+ cx18_g_fmt_vid_cap(file, fh, fmt);
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+@@ -194,7 +253,20 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
+ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+ {
+- return -EINVAL;
++ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
++ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
++
++ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
++ vbifmt->reserved[0] = 0;
++ vbifmt->reserved[1] = 0;
++
++ /* If given a service set, expand it validly & clear passed in set */
++ if (vbifmt->service_set)
++ cx18_expand_service_set(vbifmt, cx->is_50hz);
++ /* Sanitize the service_lines, and compute the new set if any valid */
++ if (check_service_set(vbifmt, cx->is_50hz))
++ vbifmt->service_set = cx18_get_service_set(vbifmt);
++ return 0;
+ }
+
+ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
+@@ -223,7 +295,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
+
+ cx->params.width = w;
+ cx->params.height = h;
+- cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
++ v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
+ return cx18_g_fmt_vid_cap(file, fh, fmt);
+ }
+
+@@ -238,54 +310,131 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
+ if (ret)
+ return ret;
+
++ /*
++ * Changing the Encoder's Raw VBI parameters won't have any effect
++ * if any analog capture is ongoing
++ */
+ if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
+ return -EBUSY;
+
++ /*
++ * Set the digitizer registers for raw active VBI.
++ * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid
++ * calling conditions
++ */
++ ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
++ if (ret)
++ return ret;
++
++ /* Store our new v4l2 (non-)sliced VBI state */
+ cx->vbi.sliced_in->service_set = 0;
+ cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+- cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
++
+ return cx18_g_fmt_vbi_cap(file, fh, fmt);
+ }
+
+ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+ {
+- return -EINVAL;
++ struct cx18_open_id *id = fh;
++ struct cx18 *cx = id->cx;
++ int ret;
++ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
++
++ ret = v4l2_prio_check(&cx->prio, &id->prio);
++ if (ret)
++ return ret;
++
++ cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
++
++ /*
++ * Changing the Encoder's Raw VBI parameters won't have any effect
++ * if any analog capture is ongoing
++ */
++ if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
++ return -EBUSY;
++
++ /*
++ * Set the service_lines requested in the digitizer/slicer registers.
++ * Note, cx18_av_vbi() wipes some "impossible" service lines in the
++ * passed in fmt->fmt.sliced under valid calling conditions
++ */
++ ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
++ if (ret)
++ return ret;
++ /* Store our current v4l2 sliced VBI settings */
++ cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
++ memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
++ return 0;
+ }
+
+ static int cx18_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_dbg_chip_ident *chip)
+ {
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
++ int err = 0;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+- if (v4l2_chip_match_host(&chip->match)) {
+- chip->ident = V4L2_IDENT_CX23418;
+- return 0;
++ switch (chip->match.type) {
++ case V4L2_CHIP_MATCH_HOST:
++ switch (chip->match.addr) {
++ case 0:
++ chip->ident = V4L2_IDENT_CX23418;
++ chip->revision = cx18_read_reg(cx, 0xC72028);
++ break;
++ case 1:
++ /*
++ * The A/V decoder is always present, but in the rare
++ * case that the card doesn't have analog, we don't
++ * use it. We find it w/o using the cx->sd_av pointer
++ */
++ cx18_call_hw(cx, CX18_HW_418_AV,
++ core, g_chip_ident, chip);
++ break;
++ default:
++ /*
++ * Could return ident = V4L2_IDENT_UNKNOWN if we had
++ * other host chips at higher addresses, but we don't
++ */
++ err = -EINVAL; /* per V4L2 spec */
++ break;
++ }
++ break;
++ case V4L2_CHIP_MATCH_I2C_DRIVER:
++ /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
++ cx18_call_all(cx, core, g_chip_ident, chip);
++ break;
++ case V4L2_CHIP_MATCH_I2C_ADDR:
++ /*
++ * We could return V4L2_IDENT_UNKNOWN, but we don't do the work
++ * to look if a chip is at the address with no driver. That's a
++ * dangerous thing to do with EEPROMs anyway.
++ */
++ cx18_call_all(cx, core, g_chip_ident, chip);
++ break;
++ default:
++ err = -EINVAL;
++ break;
+ }
+- cx18_call_i2c_clients(cx, VIDIOC_DBG_G_CHIP_IDENT, chip);
+- return 0;
++ return err;
+ }
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
+ {
+ struct v4l2_dbg_register *regs = arg;
+- unsigned long flags;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+ return -EINVAL;
+
+- spin_lock_irqsave(&cx18_cards_lock, flags);
+ regs->size = 4;
+- if (cmd == VIDIOC_DBG_G_REGISTER)
+- regs->val = cx18_read_enc(cx, regs->reg);
+- else
++ if (cmd == VIDIOC_DBG_S_REGISTER)
+ cx18_write_enc(cx, regs->val, regs->reg);
+- spin_unlock_irqrestore(&cx18_cards_lock, flags);
++ else
++ regs->val = cx18_read_enc(cx, regs->reg);
+ return 0;
+ }
+
+@@ -296,7 +445,8 @@ static int cx18_g_register(struct file *file, void *fh,
+
+ if (v4l2_chip_match_host(&reg->match))
+ return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
+- cx18_call_i2c_clients(cx, VIDIOC_DBG_G_REGISTER, reg);
++ /* FIXME - errors shouldn't be ignored */
++ cx18_call_all(cx, core, g_register, reg);
+ return 0;
+ }
+
+@@ -307,7 +457,8 @@ static int cx18_s_register(struct file *file, void *fh,
+
+ if (v4l2_chip_match_host(&reg->match))
+ return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
+- cx18_call_i2c_clients(cx, VIDIOC_DBG_S_REGISTER, reg);
++ /* FIXME - errors shouldn't be ignored */
++ cx18_call_all(cx, core, s_register, reg);
+ return 0;
+ }
+ #endif
+@@ -335,7 +486,8 @@ static int cx18_querycap(struct file *file, void *fh,
+
+ strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+- snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->dev));
++ snprintf(vcap->bus_info, sizeof(vcap->bus_info),
++ "PCI:%s", pci_name(cx->pci_dev));
+ vcap->version = CX18_DRIVER_VERSION; /* version */
+ vcap->capabilities = cx->v4l2_cap; /* capabilities */
+ return 0;
+@@ -403,7 +555,8 @@ static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+- return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);
++ CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n");
++ return -EINVAL;
+ }
+
+ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+@@ -412,7 +565,8 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+- return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);
++ CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n");
++ return -EINVAL;
+ }
+
+ static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
+@@ -483,7 +637,7 @@ static int cx18_g_frequency(struct file *file, void *fh,
+ if (vf->tuner != 0)
+ return -EINVAL;
+
+- cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);
++ cx18_call_all(cx, tuner, g_frequency, vf);
+ return 0;
+ }
+
+@@ -502,7 +656,7 @@ int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+
+ cx18_mute(cx);
+ CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+- cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);
++ cx18_call_all(cx, tuner, s_frequency, vf);
+ cx18_unmute(cx);
+ return 0;
+ }
+@@ -547,12 +701,11 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
+ cx->vbi.count = cx->is_50hz ? 18 : 12;
+ cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
+ cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
+- cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
+ CX18_DEBUG_INFO("Switching standard to %llx.\n",
+ (unsigned long long) cx->std);
+
+ /* Tuner */
+- cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
++ cx18_call_all(cx, tuner, s_std, cx->std);
+ return 0;
+ }
+
+@@ -569,9 +722,7 @@ static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+ if (vt->index != 0)
+ return -EINVAL;
+
+- /* Setting tuner can only set audio mode */
+- cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
+-
++ cx18_call_all(cx, tuner, s_tuner, vt);
+ return 0;
+ }
+
+@@ -582,7 +733,7 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+ if (vt->index != 0)
+ return -EINVAL;
+
+- cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
++ cx18_call_all(cx, tuner, g_tuner, vt);
+
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+@@ -598,7 +749,30 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+ static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_sliced_vbi_cap *cap)
+ {
+- return -EINVAL;
++ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
++ int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
++ int f, l;
++
++ if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
++ return -EINVAL;
++
++ cap->service_set = 0;
++ for (f = 0; f < 2; f++) {
++ for (l = 0; l < 24; l++) {
++ if (valid_service_line(f, l, cx->is_50hz)) {
++ /*
++ * We can find all v4l2 supported vbi services
++ * for the standard, on a valid line for the std
++ */
++ cap->service_lines[f][l] = set;
++ cap->service_set |= set;
++ } else
++ cap->service_lines[f][l] = 0;
++ }
++ }
++ for (f = 0; f < 3; f++)
++ cap->reserved[f] = 0;
++ return 0;
+ }
+
+ static int cx18_g_enc_index(struct file *file, void *fh,
+@@ -708,13 +882,15 @@ static int cx18_log_status(struct file *file, void *fh)
+ struct v4l2_audio audin;
+ int i;
+
+- CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num);
++ CX18_INFO("================= START STATUS CARD #%d "
++ "=================\n", cx->instance);
++ CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name);
+ if (cx->hw_flags & CX18_HW_TVEEPROM) {
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+ }
+- cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
++ cx18_call_all(cx, core, log_status);
+ cx18_get_input(cx, cx->active_input, &vidin);
+ cx18_get_audio_input(cx, cx->audio_input, &audin);
+ CX18_INFO("Video Input: %s\n", vidin.name);
+@@ -725,12 +901,12 @@ static int cx18_log_status(struct file *file, void *fh)
+ mutex_unlock(&cx->gpio_lock);
+ CX18_INFO("Tuner: %s\n",
+ test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV");
+- cx2341x_log_status(&cx->params, cx->name);
++ cx2341x_log_status(&cx->params, cx->v4l2_dev.name);
+ CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+- if (s->v4l2dev == NULL || s->buffers == 0)
++ if (s->video_dev == NULL || s->buffers == 0)
+ continue;
+ CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
+ s->name, s->s_flags,
+@@ -740,7 +916,8 @@ static int cx18_log_status(struct file *file, void *fh)
+ CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
+ (long long)cx->mpg_data_received,
+ (long long)cx->vbi_data_inserted);
+- CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
++ CX18_INFO("================== END STATUS CARD #%d "
++ "==================\n", cx->instance);
+ return 0;
+ }
+
+@@ -754,7 +931,8 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
+
+ CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
+ route->input, route->output);
+- cx18_audio_set_route(cx, route);
++ cx18_call_hw(cx, cx->card->hw_audio_ctrl, audio, s_routing,
++ route);
+ break;
+ }
+
+@@ -762,7 +940,8 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
+ u32 val = *(u32 *)arg;
+
+ if ((val == 0) || (val & 0x01))
+- cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]);
++ cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset,
++ (u32) CX18_GPIO_RESET_Z8F0811);
+ break;
+ }
+
+@@ -782,6 +961,8 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
+
+ mutex_lock(&cx->serialize_lock);
+
++ /* FIXME - consolidate v4l2_prio_check()'s here */
++
+ if (cx18_debug & CX18_DBGFLG_IOCTL)
+ vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+ res = video_ioctl2(filp, cmd, arg);
+diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
+index de5e723..2226e57 100644
+--- a/drivers/media/video/cx18/cx18-mailbox.c
++++ b/drivers/media/video/cx18/cx18-mailbox.c
+@@ -83,6 +83,8 @@ static const struct cx18_api_info api_info[] = {
+ API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
+ API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
+ API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW),
++ API_ENTRY(APU, CX18_APU_START, 0),
++ API_ENTRY(APU, CX18_APU_STOP, 0),
+ API_ENTRY(APU, CX18_APU_RESETAI, 0),
+ API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0),
+ API_ENTRY(0, 0, 0),
+@@ -98,21 +100,30 @@ static const struct cx18_api_info *find_api_info(u32 cmd)
+ return NULL;
+ }
+
+-static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
++/* Call with buf of n*11+1 bytes */
++static char *u32arr2hex(u32 data[], int n, char *buf)
+ {
+- char argstr[MAX_MB_ARGUMENTS*11+1];
+ char *p;
+ int i;
+
++ for (i = 0, p = buf; i < n; i++, p += 11) {
++ /* kernel snprintf() appends '\0' always */
++ snprintf(p, 12, " %#010x", data[i]);
++ }
++ *p = '\0';
++ return buf;
++}
++
++static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
++{
++ char argstr[MAX_MB_ARGUMENTS*11+1];
++
+ if (!(cx18_debug & CX18_DBGFLG_API))
+ return;
+
+- for (i = 0, p = argstr; i < MAX_MB_ARGUMENTS; i++, p += 11) {
+- /* kernel snprintf() appends '\0' always */
+- snprintf(p, 12, " %#010x", mb->args[i]);
+- }
+ CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s"
+- "\n", name, mb->request, mb->ack, mb->cmd, mb->error, argstr);
++ "\n", name, mb->request, mb->ack, mb->cmd, mb->error,
++ u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr));
+ }
+
+
+@@ -439,7 +450,8 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
+ "incoming %s to EPU mailbox (sequence no. %u)"
+ "\n",
+ rpu_str[rpu], rpu_str[rpu], order_mb->request);
+- dump_mb(cx, order_mb, "incoming");
++ if (cx18_debug & CX18_DBGFLG_WARN)
++ dump_mb(cx, order_mb, "incoming");
+ order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT;
+ }
+
+@@ -468,16 +480,24 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
+ struct mutex *mb_lock;
+ long int timeout, ret;
+ int i;
++ char argstr[MAX_MB_ARGUMENTS*11+1];
+
+ if (info == NULL) {
+ CX18_WARN("unknown cmd %x\n", cmd);
+ return -EINVAL;
+ }
+
+- if (cmd == CX18_CPU_DE_SET_MDL)
+- CX18_DEBUG_HI_API("%s\n", info->name);
+- else
+- CX18_DEBUG_API("%s\n", info->name);
++ if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */
++ if (cmd == CX18_CPU_DE_SET_MDL) {
++ if (cx18_debug & CX18_DBGFLG_HIGHVOL)
++ CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n",
++ info->name, cmd,
++ u32arr2hex(data, args, argstr));
++ } else
++ CX18_DEBUG_API("%s\tcmd %#010x args%s\n",
++ info->name, cmd,
++ u32arr2hex(data, args, argstr));
++ }
+
+ switch (info->rpu) {
+ case APU:
+diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
+index 8d9441e..3046b8e 100644
+--- a/drivers/media/video/cx18/cx18-queue.c
++++ b/drivers/media/video/cx18/cx18-queue.c
+@@ -204,7 +204,7 @@ int cx18_stream_alloc(struct cx18_stream *s)
+ }
+ buf->id = cx->buffer_id++;
+ INIT_LIST_HEAD(&buf->list);
+- buf->dma_handle = pci_map_single(s->cx->dev,
++ buf->dma_handle = pci_map_single(s->cx->pci_dev,
+ buf->buf, s->buf_size, s->dma);
+ cx18_buf_sync_for_cpu(s, buf);
+ cx18_enqueue(s, buf, &s->q_free);
+@@ -227,7 +227,7 @@ void cx18_stream_free(struct cx18_stream *s)
+
+ /* empty q_free */
+ while ((buf = cx18_dequeue(s, &s->q_free))) {
+- pci_unmap_single(s->cx->dev, buf->dma_handle,
++ pci_unmap_single(s->cx->pci_dev, buf->dma_handle,
+ s->buf_size, s->dma);
+ kfree(buf->buf);
+ kfree(buf);
+diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
+index 456cec3..4de0626 100644
+--- a/drivers/media/video/cx18/cx18-queue.h
++++ b/drivers/media/video/cx18/cx18-queue.h
+@@ -29,14 +29,14 @@
+ static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+ {
+- pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle,
++ pci_dma_sync_single_for_cpu(s->cx->pci_dev, buf->dma_handle,
+ s->buf_size, s->dma);
+ }
+
+ static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+ {
+- pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle,
++ pci_dma_sync_single_for_device(s->cx->pci_dev, buf->dma_handle,
+ s->buf_size, s->dma);
+ }
+
+diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
+index 89c1ec9..0932b76 100644
+--- a/drivers/media/video/cx18/cx18-streams.c
++++ b/drivers/media/video/cx18/cx18-streams.c
+@@ -32,7 +32,6 @@
+ #include "cx18-streams.h"
+ #include "cx18-cards.h"
+ #include "cx18-scb.h"
+-#include "cx18-av-core.h"
+ #include "cx18-dvb.h"
+
+ #define CX18_DSP0_INTERRUPT_MASK 0xd0004C
+@@ -101,11 +100,11 @@ static struct {
+ static void cx18_stream_init(struct cx18 *cx, int type)
+ {
+ struct cx18_stream *s = &cx->streams[type];
+- struct video_device *dev = s->v4l2dev;
++ struct video_device *video_dev = s->video_dev;
+
+- /* we need to keep v4l2dev, so restore it afterwards */
++ /* we need to keep video_dev, so restore it afterwards */
+ memset(s, 0, sizeof(*s));
+- s->v4l2dev = dev;
++ s->video_dev = video_dev;
+
+ /* initialize cx18_stream fields */
+ s->cx = cx;
+@@ -130,12 +129,12 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
+ struct cx18_stream *s = &cx->streams[type];
+ u32 cap = cx->v4l2_cap;
+ int num_offset = cx18_stream_info[type].num_offset;
+- int num = cx->num + cx18_first_minor + num_offset;
++ int num = cx->instance + cx18_first_minor + num_offset;
+
+- /* These four fields are always initialized. If v4l2dev == NULL, then
++ /* These four fields are always initialized. If video_dev == NULL, then
+ this stream is not in use. In that case no other fields but these
+ four can be used. */
+- s->v4l2dev = NULL;
++ s->video_dev = NULL;
+ s->cx = cx;
+ s->type = type;
+ s->name = cx18_stream_info[type].name;
+@@ -163,22 +162,22 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
+ return 0;
+
+ /* allocate and initialize the v4l2 video device structure */
+- s->v4l2dev = video_device_alloc();
+- if (s->v4l2dev == NULL) {
++ s->video_dev = video_device_alloc();
++ if (s->video_dev == NULL) {
+ CX18_ERR("Couldn't allocate v4l2 video_device for %s\n",
+ s->name);
+ return -ENOMEM;
+ }
+
+- snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d",
+- cx->num);
++ snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s",
++ cx->v4l2_dev.name, s->name);
+
+- s->v4l2dev->num = num;
+- s->v4l2dev->parent = &cx->dev->dev;
+- s->v4l2dev->fops = &cx18_v4l2_enc_fops;
+- s->v4l2dev->release = video_device_release;
+- s->v4l2dev->tvnorms = V4L2_STD_ALL;
+- cx18_set_funcs(s->v4l2dev);
++ s->video_dev->num = num;
++ s->video_dev->v4l2_dev = &cx->v4l2_dev;
++ s->video_dev->fops = &cx18_v4l2_enc_fops;
++ s->video_dev->release = video_device_release;
++ s->video_dev->tvnorms = V4L2_STD_ALL;
++ cx18_set_funcs(s->video_dev);
+ return 0;
+ }
+
+@@ -227,28 +226,30 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
+ }
+ }
+
+- if (s->v4l2dev == NULL)
++ if (s->video_dev == NULL)
+ return 0;
+
+- num = s->v4l2dev->num;
++ num = s->video_dev->num;
+ /* card number + user defined offset + device offset */
+ if (type != CX18_ENC_STREAM_TYPE_MPG) {
+ struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+
+- if (s_mpg->v4l2dev)
+- num = s_mpg->v4l2dev->num + cx18_stream_info[type].num_offset;
++ if (s_mpg->video_dev)
++ num = s_mpg->video_dev->num
++ + cx18_stream_info[type].num_offset;
+ }
++ video_set_drvdata(s->video_dev, s);
+
+ /* Register device. First try the desired minor, then any free one. */
+- ret = video_register_device(s->v4l2dev, vfl_type, num);
++ ret = video_register_device(s->video_dev, vfl_type, num);
+ if (ret < 0) {
+ CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
+ s->name, num);
+- video_device_release(s->v4l2dev);
+- s->v4l2dev = NULL;
++ video_device_release(s->video_dev);
++ s->video_dev = NULL;
+ return ret;
+ }
+- num = s->v4l2dev->num;
++ num = s->video_dev->num;
+
+ switch (vfl_type) {
+ case VFL_TYPE_GRABBER:
+@@ -312,9 +313,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
+ cx->streams[type].dvb.enabled = false;
+ }
+
+- vdev = cx->streams[type].v4l2dev;
++ vdev = cx->streams[type].video_dev;
+
+- cx->streams[type].v4l2dev = NULL;
++ cx->streams[type].video_dev = NULL;
+ if (vdev == NULL)
+ continue;
+
+@@ -346,46 +347,88 @@ static void cx18_vbi_setup(struct cx18_stream *s)
+ }
+
+ /* setup VBI registers */
+- cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+-
+- /* determine number of lines and total number of VBI bytes.
+- A raw line takes 1444 bytes: 4 byte SAV code + 2 * 720
+- A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
+- header, 42 data bytes + checksum (to be confirmed) */
++ v4l2_subdev_call(cx->sd_av, video, s_fmt, &cx->vbi.in);
++
++ /*
++ * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw
++ * VBI when the first analog capture channel starts, as once it starts
++ * (e.g. MPEG), we can't effect any change in the Encoder Raw VBI setup
++ * (i.e. for the VBI capture channels). We also send it for each
++ * analog capture channel anyway just to make sure we get the proper
++ * behavior
++ */
+ if (raw) {
+ lines = cx->vbi.count * 2;
+ } else {
+- lines = cx->is_60hz ? 24 : 38;
+- if (cx->is_60hz)
+- lines += 2;
++ /*
++ * For 525/60 systems, according to the VIP 2 & BT.656 std:
++ * The EAV RP code's Field bit toggles on line 4, a few lines
++ * after the Vertcal Blank bit has already toggled.
++ * Tell the encoder to capture 21-4+1=18 lines per field,
++ * since we want lines 10 through 21.
++ *
++ * FIXME - revisit for 625/50 systems
++ */
++ lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38;
+ }
+
+- cx->vbi.enc_size = lines *
+- (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+-
+ data[0] = s->handle;
+ /* Lines per field */
+ data[1] = (lines / 2) | ((lines / 2) << 16);
+ /* bytes per line */
+- data[2] = (raw ? cx->vbi.raw_decoder_line_size
+- : cx->vbi.sliced_decoder_line_size);
++ data[2] = (raw ? vbi_active_samples
++ : (cx->is_60hz ? vbi_hblank_samples_60Hz
++ : vbi_hblank_samples_50Hz));
+ /* Every X number of frames a VBI interrupt arrives
+ (frames as in 25 or 30 fps) */
+ data[3] = 1;
+- /* Setup VBI for the cx25840 digitizer */
++ /*
++ * Set the SAV/EAV RP codes to look for as start/stop points
++ * when in VIP-1.1 mode
++ */
+ if (raw) {
++ /*
++ * Start codes for beginning of "active" line in vertical blank
++ * 0x20 ( VerticalBlank )
++ * 0x60 ( EvenField VerticalBlank )
++ */
+ data[4] = 0x20602060;
++ /*
++ * End codes for end of "active" raw lines and regular lines
++ * 0x30 ( VerticalBlank HorizontalBlank)
++ * 0x70 ( EvenField VerticalBlank HorizontalBlank)
++ * 0x90 (Task HorizontalBlank)
++ * 0xd0 (Task EvenField HorizontalBlank)
++ */
+ data[5] = 0x307090d0;
+ } else {
++ /*
++ * End codes for active video, we want data in the hblank region
++ * 0xb0 (Task 0 VerticalBlank HorizontalBlank)
++ * 0xf0 (Task EvenField VerticalBlank HorizontalBlank)
++ *
++ * Since the V bit is only allowed to toggle in the EAV RP code,
++ * just before the first active region line, these two
++ * are problematic:
++ * 0x90 (Task HorizontalBlank)
++ * 0xd0 (Task EvenField HorizontalBlank)
++ *
++ * We have set the digitzer such that we don't have to worry
++ * about these problem codes.
++ */
+ data[4] = 0xB0F0B0F0;
++ /*
++ * Start codes for beginning of active line in vertical blank
++ * 0xa0 (Task VerticalBlank )
++ * 0xe0 (Task EvenField VerticalBlank )
++ */
+ data[5] = 0xA0E0A0E0;
+ }
+
+ CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+
+- if (s->type == CX18_ENC_STREAM_TYPE_VBI)
+- cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
++ cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
+ }
+
+ struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
+@@ -434,10 +477,10 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+ u32 data[MAX_MB_ARGUMENTS];
+ struct cx18 *cx = s->cx;
+ struct cx18_buffer *buf;
+- int ts = 0;
+ int captype = 0;
++ struct cx18_api_func_private priv;
+
+- if (s->v4l2dev == NULL && s->dvb.enabled == 0)
++ if (s->video_dev == NULL && s->dvb.enabled == 0)
+ return -EINVAL;
+
+ CX18_DEBUG_INFO("Start encoder stream %s\n", s->name);
+@@ -453,7 +496,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+
+ case CX18_ENC_STREAM_TYPE_TS:
+ captype = CAPTURE_CHANNEL_TYPE_TS;
+- ts = 1;
+ break;
+ case CX18_ENC_STREAM_TYPE_YUV:
+ captype = CAPTURE_CHANNEL_TYPE_YUV;
+@@ -462,8 +504,16 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+ captype = CAPTURE_CHANNEL_TYPE_PCM;
+ break;
+ case CX18_ENC_STREAM_TYPE_VBI:
++#ifdef CX18_ENCODER_PARSES_SLICED
+ captype = cx18_raw_vbi(cx) ?
+ CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI;
++#else
++ /*
++ * Currently we set things up so that Sliced VBI from the
++ * digitizer is handled as Raw VBI by the encoder
++ */
++ captype = CAPTURE_CHANNEL_TYPE_VBI;
++#endif
+ cx->vbi.frame = 0;
+ cx->vbi.inserted_frame = 0;
+ memset(cx->vbi.sliced_mpeg_size,
+@@ -473,10 +523,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+ return -EINVAL;
+ }
+
+- /* mute/unmute video */
+- cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
+- s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags));
+-
+ /* Clear Streamoff flags in case left from last capture */
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+@@ -484,31 +530,63 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+ s->handle = data[0];
+ cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
+
+- if (atomic_read(&cx->ana_capturing) == 0 && !ts) {
+- struct cx18_api_func_private priv;
+-
+- /* Stuff from Windows, we don't know what it is */
++ /*
++ * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and
++ * set up all the parameters, as it is not obvious which parameters the
++ * firmware shares across capture channel types and which it does not.
++ *
++ * Some of the cx18_vapi() calls below apply to only certain capture
++ * channel types. We're hoping there's no harm in calling most of them
++ * anyway, as long as the values are all consistent. Setting some
++ * shared parameters will have no effect once an analog capture channel
++ * has started streaming.
++ */
++ if (captype != CAPTURE_CHANNEL_TYPE_TS) {
+ cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1);
+- cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12);
+
++ /*
++ * Audio related reset according to
++ * Documentation/video4linux/cx2341x/fw-encoder-api.txt
++ */
++ if (atomic_read(&cx->ana_capturing) == 0)
++ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
++ s->handle, 12);
++
++ /*
++ * Number of lines for Field 1 & Field 2 according to
++ * Documentation/video4linux/cx2341x/fw-encoder-api.txt
++ * Field 1 is 312 for 625 line systems in BT.656
++ * Field 2 is 313 for 625 line systems in BT.656
++ */
+ cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3,
+- s->handle, cx->digitizer, cx->digitizer);
++ s->handle, 312, 313);
+
+- /* Setup VBI */
+ if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE)
+ cx18_vbi_setup(s);
+
+- /* assign program index info.
+- Mask 7: select I/P/B, Num_req: 400 max */
++ /*
++ * assign program index info.
++ * Mask 7: select I/P/B, Num_req: 400 max
++ * FIXME - currently we have this hardcoded as disabled
++ */
+ cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
+
+- /* Setup API for Stream */
++ /* Call out to the common CX2341x API setup for user controls */
+ priv.cx = cx;
+ priv.s = s;
+ cx2341x_update(&priv, cx18_api_func, NULL, &cx->params);
++
++ /*
++ * When starting a capture and we're set for radio,
++ * ensure the video is muted, despite the user control.
++ */
++ if (!cx->params.video_mute &&
++ test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
++ cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
++ (cx->params.video_mute_yuv << 8) | 1);
+ }
+
+ if (atomic_read(&cx->tot_capturing) == 0) {
+@@ -552,7 +630,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+ }
+
+ /* you're live! sit back and await interrupts :) */
+- if (!ts)
++ if (captype != CAPTURE_CHANNEL_TYPE_TS)
+ atomic_inc(&cx->ana_capturing);
+ atomic_inc(&cx->tot_capturing);
+ return 0;
+@@ -565,7 +643,7 @@ void cx18_stop_all_captures(struct cx18 *cx)
+ for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) {
+ struct cx18_stream *s = &cx->streams[i];
+
+- if (s->v4l2dev == NULL && s->dvb.enabled == 0)
++ if (s->video_dev == NULL && s->dvb.enabled == 0)
+ continue;
+ if (test_bit(CX18_F_S_STREAMING, &s->s_flags))
+ cx18_stop_v4l2_encode_stream(s, 0);
+@@ -577,7 +655,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
+ struct cx18 *cx = s->cx;
+ unsigned long then;
+
+- if (s->v4l2dev == NULL && s->dvb.enabled == 0)
++ if (s->video_dev == NULL && s->dvb.enabled == 0)
+ return -EINVAL;
+
+ /* This function assumes that you are allowed to stop the capture
+@@ -629,7 +707,7 @@ u32 cx18_find_handle(struct cx18 *cx)
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+- if (s->v4l2dev && (s->handle != CX18_INVALID_TASK_HANDLE))
++ if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE))
+ return s->handle;
+ }
+ return CX18_INVALID_TASK_HANDLE;
+@@ -647,7 +725,7 @@ struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle)
+ s = &cx->streams[i];
+ if (s->handle != handle)
+ continue;
+- if (s->v4l2dev || s->dvb.enabled)
++ if (s->video_dev || s->dvb.enabled)
+ return s;
+ }
+ return NULL;
+diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c
+index fb595bd..c2aef4a 100644
+--- a/drivers/media/video/cx18/cx18-vbi.c
++++ b/drivers/media/video/cx18/cx18-vbi.c
+@@ -25,7 +25,16 @@
+ #include "cx18-vbi.h"
+ #include "cx18-ioctl.h"
+ #include "cx18-queue.h"
+-#include "cx18-av-core.h"
++
++/*
++ * Raster Reference/Protection (RP) bytes, used in Start/End Active
++ * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start
++ * of VBI sample or VBI ancilliary data regions in the digitial ratser line.
++ *
++ * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0
++ */
++static const u8 raw_vbi_sav_rp[2] = { 0x20, 0x60 }; /* __V_, _FV_ */
++static const u8 sliced_vbi_eav_rp[2] = { 0xb0, 0xf0 }; /* T_VH, TFVH */
+
+ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
+ {
+@@ -34,10 +43,17 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
+ u32 linemask[2] = { 0, 0 };
+ unsigned short size;
+ static const u8 mpeg_hdr_data[] = {
+- 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
+- 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
+- 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
+- 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
++ /* MPEG-2 Program Pack */
++ 0x00, 0x00, 0x01, 0xba, /* Prog Pack start code */
++ 0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */
++ 0x01, 0xd1, 0xd3, /* Mux Rate, markers */
++ 0xfa, 0xff, 0xff, /* Res, Suff cnt, Stuff */
++ /* MPEG-2 Private Stream 1 PES Packet */
++ 0x00, 0x00, 0x01, 0xbd, /* Priv Stream 1 start */
++ 0x00, 0x1a, /* length */
++ 0x84, 0x80, 0x07, /* flags, hdr data len */
++ 0x21, 0x00, 0x5d, 0x63, 0xa7, /* PTS, markers */
++ 0xff, 0xff /* stuffing */
+ };
+ const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
+ int idx = cx->vbi.frame % CX18_VBI_FRAMES;
+@@ -71,7 +87,9 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
+ memcpy(dst + sd + 4, dst + sd + 12, line * 43);
+ size = 4 + ((43 * line + 3) & ~3);
+ } else {
+- memcpy(dst + sd, "cx0", 4);
++ memcpy(dst + sd, "itv0", 4);
++ cpu_to_le32s(&linemask[0]);
++ cpu_to_le32s(&linemask[1]);
+ memcpy(dst + sd + 4, &linemask[0], 8);
+ size = 12 + ((43 * line + 3) & ~3);
+ }
+@@ -86,58 +104,76 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
+ }
+
+ /* Compress raw VBI format, removes leading SAV codes and surplus space
+- after the field.
+- Returns new compressed size. */
+-static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
++ after the frame. Returns new compressed size. */
++static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size)
+ {
+- u32 line_size = cx->vbi.raw_decoder_line_size;
+- u32 lines = cx->vbi.count;
+- u8 sav1 = cx->vbi.raw_decoder_sav_odd_field;
+- u8 sav2 = cx->vbi.raw_decoder_sav_even_field;
++ u32 line_size = vbi_active_samples;
++ u32 lines = cx->vbi.count * 2;
+ u8 *q = buf;
+ u8 *p;
+ int i;
+
++ /* Skip the header */
++ buf += hdr_size;
++
+ for (i = 0; i < lines; i++) {
+ p = buf + i * line_size;
+
+ /* Look for SAV code */
+ if (p[0] != 0xff || p[1] || p[2] ||
+- (p[3] != sav1 && p[3] != sav2))
++ (p[3] != raw_vbi_sav_rp[0] &&
++ p[3] != raw_vbi_sav_rp[1]))
+ break;
+- memcpy(q, p + 4, line_size - 4);
+- q += line_size - 4;
++ if (i == lines - 1) {
++ /* last line is hdr_size bytes short - extrapolate it */
++ memcpy(q, p + 4, line_size - 4 - hdr_size);
++ q += line_size - 4 - hdr_size;
++ p += line_size - hdr_size - 1;
++ memset(q, (int) *p, hdr_size);
++ } else {
++ memcpy(q, p + 4, line_size - 4);
++ q += line_size - 4;
++ }
+ }
+ return lines * (line_size - 4);
+ }
+
+-
+-/* Compressed VBI format, all found sliced blocks put next to one another
+- Returns new compressed size */
+-static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
+- u32 size, u8 sav)
++static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size,
++ const u32 hdr_size)
+ {
+- u32 line_size = cx->vbi.sliced_decoder_line_size;
+ struct v4l2_decode_vbi_line vbi;
+ int i;
++ u32 line = 0;
++ u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz
++ : vbi_hblank_samples_50Hz;
+
+ /* find the first valid line */
+- for (i = 0; i < size; i++, buf++) {
+- if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
++ for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) {
++ if (buf[0] == 0xff && !buf[1] && !buf[2] &&
++ (buf[3] == sliced_vbi_eav_rp[0] ||
++ buf[3] == sliced_vbi_eav_rp[1]))
+ break;
+ }
+
+- size -= i;
++ /*
++ * The last line is short by hdr_size bytes, but for the remaining
++ * checks against size, we pretend that it is not, by counting the
++ * header bytes we knowingly skipped
++ */
++ size -= (i - hdr_size);
+ if (size < line_size)
+ return line;
++
+ for (i = 0; i < size / line_size; i++) {
+ u8 *p = buf + i * line_size;
+
+- /* Look for SAV code */
+- if (p[0] != 0xff || p[1] || p[2] || p[3] != sav)
++ /* Look for EAV code */
++ if (p[0] != 0xff || p[1] || p[2] ||
++ (p[3] != sliced_vbi_eav_rp[0] &&
++ p[3] != sliced_vbi_eav_rp[1]))
+ continue;
+ vbi.p = p + 4;
+- cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
++ v4l2_subdev_call(cx->sd_av, video, decode_vbi_line, &vbi);
+ if (vbi.type) {
+ cx->vbi.sliced_data[line].id = vbi.type;
+ cx->vbi.sliced_data[line].field = vbi.is_second_field;
+@@ -150,51 +186,56 @@ static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
+ }
+
+ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+- u64 pts_stamp, int streamtype)
++ int streamtype)
+ {
++ /*
++ * The CX23418 provides a 12 byte header in its raw VBI buffers to us:
++ * 0x3fffffff [4 bytes of something] [4 byte presentation time stamp]
++ */
++ struct vbi_data_hdr {
++ __be32 magic;
++ __be32 unknown;
++ __be32 pts;
++ } *hdr = (struct vbi_data_hdr *) buf->buf;
++
+ u8 *p = (u8 *) buf->buf;
+ u32 size = buf->bytesused;
++ u32 pts;
+ int lines;
+
+ if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
+ return;
+
++ /*
++ * The CX23418 sends us data that is 32 bit little-endian swapped,
++ * but we want the raw VBI bytes in the order they were in the raster
++ * line. This has a side effect of making the header big endian
++ */
++ cx18_buf_swap(buf);
++
+ /* Raw VBI data */
+ if (cx18_raw_vbi(cx)) {
+- u8 type;
+-
+- cx18_buf_swap(buf);
+-
+- /* Skip 12 bytes of header that gets stuffed in */
+- size -= 12;
+- memcpy(p, &buf->buf[12], size);
+- type = p[3];
+
+- size = buf->bytesused = compress_raw_buf(cx, p, size);
++ size = buf->bytesused =
++ compress_raw_buf(cx, p, size, sizeof(struct vbi_data_hdr));
+
+- /* second field of the frame? */
+- if (type == cx->vbi.raw_decoder_sav_even_field) {
+- /* Dirty hack needed for backwards
+- compatibility of old VBI software. */
+- p += size - 4;
+- memcpy(p, &cx->vbi.frame, 4);
+- cx->vbi.frame++;
+- }
++ /*
++ * Hack needed for compatibility with old VBI software.
++ * Write the frame # at the last 4 bytes of the frame
++ */
++ p += size - 4;
++ memcpy(p, &cx->vbi.frame, 4);
++ cx->vbi.frame++;
+ return;
+ }
+
+ /* Sliced VBI data with data insertion */
+- cx18_buf_swap(buf);
+
+- /* first field */
+- lines = compress_sliced_buf(cx, 0, p, size / 2,
+- cx->vbi.sliced_decoder_sav_odd_field);
+- /* second field */
+- /* experimentation shows that the second half does not always
+- begin at the exact address. So start a bit earlier
+- (hence 32). */
+- lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
+- size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field);
++ pts = (be32_to_cpu(hdr->magic) == 0x3fffffff) ? be32_to_cpu(hdr->pts)
++ : 0;
++
++ lines = compress_sliced_buf(cx, p, size, sizeof(struct vbi_data_hdr));
++
+ /* always return at least one empty line */
+ if (lines == 0) {
+ cx->vbi.sliced_data[0].id = 0;
+@@ -206,6 +247,6 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+ memcpy(p, &cx->vbi.sliced_data[0], size);
+
+ if (cx->vbi.insert_mpeg)
+- copy_vbi_data(cx, lines, pts_stamp);
++ copy_vbi_data(cx, lines, pts);
+ cx->vbi.frame++;
+ }
+diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h
+index c56ff7d..e7e1ae4 100644
+--- a/drivers/media/video/cx18/cx18-vbi.h
++++ b/drivers/media/video/cx18/cx18-vbi.h
+@@ -22,5 +22,5 @@
+ */
+
+ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+- u64 pts_stamp, int streamtype);
++ int streamtype);
+ int cx18_used_line(struct cx18 *cx, int line, int field);
+diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h
+index 84c0ff1..bd9bd44 100644
+--- a/drivers/media/video/cx18/cx18-version.h
++++ b/drivers/media/video/cx18/cx18-version.h
+@@ -24,8 +24,8 @@
+
+ #define CX18_DRIVER_NAME "cx18"
+ #define CX18_DRIVER_VERSION_MAJOR 1
+-#define CX18_DRIVER_VERSION_MINOR 0
+-#define CX18_DRIVER_VERSION_PATCHLEVEL 4
++#define CX18_DRIVER_VERSION_MINOR 1
++#define CX18_DRIVER_VERSION_PATCHLEVEL 0
+
+ #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
+ #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
+diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/video/cx18/cx18-video.c
+index 2e5c419..6fdaded 100644
+--- a/drivers/media/video/cx18/cx18-video.c
++++ b/drivers/media/video/cx18/cx18-video.c
+@@ -21,7 +21,6 @@
+
+ #include "cx18-driver.h"
+ #include "cx18-video.h"
+-#include "cx18-av-core.h"
+ #include "cx18-cards.h"
+
+ void cx18_video_set_io(struct cx18 *cx)
+@@ -32,7 +31,7 @@ void cx18_video_set_io(struct cx18 *cx)
+
+ route.input = cx->card->video_inputs[inp].video_input;
+ route.output = 0;
+- cx18_av_cmd(cx, VIDIOC_INT_S_VIDEO_ROUTING, &route);
++ v4l2_subdev_call(cx->sd_av, video, s_routing, &route);
+
+ type = cx->card->video_inputs[inp].video_type;
+
+diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
+index 601f3a2..9956abf 100644
+--- a/drivers/media/video/cx18/cx23418.h
++++ b/drivers/media/video/cx18/cx23418.h
+@@ -56,6 +56,22 @@
+ #define APU_CMD_MASK 0x10000000
+ #define APU_CMD_MASK_ACK (APU_CMD_MASK | 0x80000000)
+
++#define CX18_APU_ENCODING_METHOD_MPEG (0 << 28)
++#define CX18_APU_ENCODING_METHOD_AC3 (1 << 28)
++
++/* Description: Command APU to start audio
++ IN[0] - audio parameters (same as CX18_CPU_SET_AUDIO_PARAMETERS?)
++ IN[1] - caller buffer address, or 0
++ ReturnCode - ??? */
++#define CX18_APU_START (APU_CMD_MASK | 0x01)
++
++/* Description: Command APU to stop audio
++ IN[0] - encoding method to stop
++ ReturnCode - ??? */
++#define CX18_APU_STOP (APU_CMD_MASK | 0x02)
++
++/* Description: Command APU to reset the AI
++ ReturnCode - ??? */
+ #define CX18_APU_RESETAI (APU_CMD_MASK | 0x05)
+
+ /* Description: This command indicates that a Memory Descriptor List has been
+diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
+index cbbe47f..8ded529 100644
+--- a/drivers/media/video/cx2341x.c
++++ b/drivers/media/video/cx2341x.c
+@@ -1,5 +1,5 @@
+ /*
+- * cx2341x - generic code for cx23415/6 based devices
++ * cx2341x - generic code for cx23415/6/8 based devices
+ *
+ * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+@@ -30,7 +30,7 @@
+ #include <media/cx2341x.h>
+ #include <media/v4l2-common.h>
+
+-MODULE_DESCRIPTION("cx23415/6 driver");
++MODULE_DESCRIPTION("cx23415/6/8 driver");
+ MODULE_AUTHOR("Hans Verkuil");
+ MODULE_LICENSE("GPL");
+
+@@ -38,6 +38,7 @@ static int debug;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
++/* Must be sorted from low to high control ID! */
+ const u32 cx2341x_mpeg_ctrls[] = {
+ V4L2_CID_MPEG_CLASS,
+ V4L2_CID_MPEG_STREAM_TYPE,
+@@ -50,6 +51,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
+ V4L2_CID_MPEG_AUDIO_EMPHASIS,
+ V4L2_CID_MPEG_AUDIO_CRC,
+ V4L2_CID_MPEG_AUDIO_MUTE,
++ V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_CID_MPEG_VIDEO_B_FRAMES,
+@@ -94,6 +96,7 @@ static const struct cx2341x_mpeg_params default_params = {
+ .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+ .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
++ .audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K,
+ .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
+ .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+@@ -148,6 +151,9 @@ static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params,
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ ctrl->value = params->audio_l2_bitrate;
+ break;
++ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
++ ctrl->value = params->audio_ac3_bitrate;
++ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ ctrl->value = params->audio_mode;
+ break;
+@@ -256,6 +262,12 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
+ params->audio_sampling_freq = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
++ if (busy)
++ return -EBUSY;
++ if (params->capabilities & CX2341X_CAP_HAS_AC3)
++ if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
++ ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3)
++ return -ERANGE;
+ params->audio_encoding = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+@@ -263,6 +275,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
+ return -EBUSY;
+ params->audio_l2_bitrate = ctrl->value;
+ break;
++ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
++ if (busy)
++ return -EBUSY;
++ if (!(params->capabilities & CX2341X_CAP_HAS_AC3))
++ return -EINVAL;
++ params->audio_ac3_bitrate = ctrl->value;
++ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ params->audio_mode = ctrl->value;
+ break;
+@@ -481,29 +500,106 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
+ int err;
+
+ switch (qctrl->id) {
++ case V4L2_CID_MPEG_STREAM_TYPE:
++ return v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
++ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
++ V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
++
++ case V4L2_CID_MPEG_STREAM_VBI_FMT:
++ if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
++ return v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_STREAM_VBI_FMT_NONE,
++ V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
++ V4L2_MPEG_STREAM_VBI_FMT_NONE);
++ return cx2341x_ctrl_query_fill(qctrl,
++ V4L2_MPEG_STREAM_VBI_FMT_NONE,
++ V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
++ default_params.stream_vbi_fmt);
++
++ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
++ return v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
++ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
++ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
++
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
++ if (params->capabilities & CX2341X_CAP_HAS_AC3) {
++ /*
++ * The state of L2 & AC3 bitrate controls can change
++ * when this control changes, but v4l2_ctrl_query_fill()
++ * already sets V4L2_CTRL_FLAG_UPDATE for
++ * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here.
++ */
++ return v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
++ V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
++ default_params.audio_encoding);
++ }
++
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+ default_params.audio_encoding);
+
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+- return v4l2_ctrl_query_fill(qctrl,
++ err = v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L2_BITRATE_192K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+ default_params.audio_l2_bitrate);
++ if (err)
++ return err;
++ if (params->capabilities & CX2341X_CAP_HAS_AC3 &&
++ params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2)
++ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++ return 0;
+
+- case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+- return -EINVAL;
++ case V4L2_CID_MPEG_AUDIO_MODE:
++ return v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_AUDIO_MODE_STEREO,
++ V4L2_MPEG_AUDIO_MODE_MONO, 1,
++ V4L2_MPEG_AUDIO_MODE_STEREO);
+
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+- err = v4l2_ctrl_query_fill_std(qctrl);
++ err = v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
++ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
++ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+ if (err == 0 &&
+ params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
++ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
++ return v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_AUDIO_EMPHASIS_NONE,
++ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
++ V4L2_MPEG_AUDIO_EMPHASIS_NONE);
++
++ case V4L2_CID_MPEG_AUDIO_CRC:
++ return v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_AUDIO_CRC_NONE,
++ V4L2_MPEG_AUDIO_CRC_CRC16, 1,
++ V4L2_MPEG_AUDIO_CRC_NONE);
++
++ case V4L2_CID_MPEG_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
++
++ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
++ err = v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_AUDIO_AC3_BITRATE_48K,
++ V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1,
++ default_params.audio_ac3_bitrate);
++ if (err)
++ return err;
++ if (params->capabilities & CX2341X_CAP_HAS_AC3) {
++ if (params->audio_encoding !=
++ V4L2_MPEG_AUDIO_ENCODING_AC3)
++ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++ } else
++ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
++ return 0;
++
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ /* this setting is read-only for the cx2341x since the
+ V4L2_CID_MPEG_STREAM_TYPE really determines the
+@@ -516,32 +612,51 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
+ qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ return err;
+
++ case V4L2_CID_MPEG_VIDEO_ASPECT:
++ return v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_VIDEO_ASPECT_1x1,
++ V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
++ V4L2_MPEG_VIDEO_ASPECT_4x3);
++
++ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
++ return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
++
++ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
++ return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
++ params->is_50hz ? 12 : 15);
++
++ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
++ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
++
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+- err = v4l2_ctrl_query_fill_std(qctrl);
++ err = v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ if (err == 0 &&
+ params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
++ case V4L2_CID_MPEG_VIDEO_BITRATE:
++ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
++
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+- err = v4l2_ctrl_query_fill_std(qctrl);
++ err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+ if (err == 0 &&
+ params->video_bitrate_mode ==
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+- case V4L2_CID_MPEG_STREAM_VBI_FMT:
+- if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
+- return v4l2_ctrl_query_fill_std(qctrl);
+- return cx2341x_ctrl_query_fill(qctrl,
+- V4L2_MPEG_STREAM_VBI_FMT_NONE,
+- V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
+- default_params.stream_vbi_fmt);
++ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
++ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+
+- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+- return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
+- params->is_50hz ? 12 : 15);
++ case V4L2_CID_MPEG_VIDEO_MUTE:
++ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
++
++ case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */
++ return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080);
+
+ /* CX23415/6 specific */
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+@@ -643,7 +758,7 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
+ default_params.stream_insert_nav_packets);
+
+ default:
+- return v4l2_ctrl_query_fill_std(qctrl);
++ return -EINVAL;
+
+ }
+ }
+@@ -671,6 +786,15 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
+ NULL
+ };
+
++ static const char *mpeg_audio_encoding_l2_ac3[] = {
++ "",
++ "MPEG-1/2 Layer II",
++ "",
++ "",
++ "AC-3",
++ NULL
++ };
++
+ static const char *cx2341x_video_spatial_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+@@ -711,6 +835,9 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return (p->capabilities & CX2341X_CAP_HAS_TS) ?
+ mpeg_stream_type_with_ts : mpeg_stream_type_without_ts;
++ case V4L2_CID_MPEG_AUDIO_ENCODING:
++ return (p->capabilities & CX2341X_CAP_HAS_AC3) ?
++ mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id);
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return NULL;
+@@ -730,16 +857,34 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
+ }
+ EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+
++/* definitions for audio properties bits 29-28 */
++#define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0
++#define CX2341X_AUDIO_ENCODING_METHOD_AC3 1
++#define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2
++
+ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+ {
+- params->audio_properties = (params->audio_sampling_freq << 0) |
+- ((3 - params->audio_encoding) << 2) |
+- ((1 + params->audio_l2_bitrate) << 4) |
++ params->audio_properties =
++ (params->audio_sampling_freq << 0) |
+ (params->audio_mode << 8) |
+ (params->audio_mode_extension << 10) |
+ (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
+ ? 3 : params->audio_emphasis) << 12) |
+ (params->audio_crc << 14);
++
++ if ((params->capabilities & CX2341X_CAP_HAS_AC3) &&
++ params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
++ params->audio_properties |=
++ /* Not sure if this MPEG Layer II setting is required */
++ ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) |
++ (params->audio_ac3_bitrate << 4) |
++ (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28);
++ } else {
++ /* Assuming MPEG Layer II */
++ params->audio_properties |=
++ ((3 - params->audio_encoding) << 2) |
++ ((1 + params->audio_l2_bitrate) << 4);
++ }
+ }
+
+ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
+@@ -1022,7 +1167,10 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
+- cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
++ cx2341x_menu_item(p,
++ p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3
++ ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE
++ : V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
+ p->audio_mute ? " (muted)" : "");
+ if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
+index 00f1e2e..fd3fc3e 100644
+--- a/drivers/media/video/cx23885/Kconfig
++++ b/drivers/media/video/cx23885/Kconfig
+@@ -15,12 +15,15 @@ config VIDEO_CX23885
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+- select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
+- select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
+- select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+- select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
++ select DVB_TDA10048 if !DVB_FE_CUSTOMISE
++ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
++ select DVB_STV6110 if !DVB_FE_CUSTOMISE
++ select DVB_STV0900 if !DVB_FE_CUSTOMISE
++ select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+ ---help---
+ This is a video4linux driver for Conexant 23885 based
+ TV cards.
+diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
+index 29c23b4..ab8ea35 100644
+--- a/drivers/media/video/cx23885/Makefile
++++ b/drivers/media/video/cx23885/Makefile
+@@ -1,4 +1,6 @@
+-cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o
++cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
++ cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
++ netup-init.o cimax2.o netup-eeprom.o
+
+ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+
+diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c
+new file mode 100644
+index 0000000..9a65369
+--- /dev/null
++++ b/drivers/media/video/cx23885/cimax2.c
+@@ -0,0 +1,472 @@
++/*
++ * cimax2.c
++ *
++ * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
++ *
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
++ *
++ * 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 "cx23885.h"
++#include "dvb_ca_en50221.h"
++/**** Bit definitions for MC417_RWD and MC417_OEN registers ***
++ bits 31-16
+++-----------+
++| Reserved |
+++-----------+
++ bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
+++-------+-------+-------+-------+-------+-------+-------+-------+
++| WR# | RD# | | ACK# | ADHI | ADLO | CS1# | CS0# |
+++-------+-------+-------+-------+-------+-------+-------+-------+
++ bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
+++-------+-------+-------+-------+-------+-------+-------+-------+
++| DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0|
+++-------+-------+-------+-------+-------+-------+-------+-------+
++***/
++/* MC417 */
++#define NETUP_DATA 0x000000ff
++#define NETUP_WR 0x00008000
++#define NETUP_RD 0x00004000
++#define NETUP_ACK 0x00001000
++#define NETUP_ADHI 0x00000800
++#define NETUP_ADLO 0x00000400
++#define NETUP_CS1 0x00000200
++#define NETUP_CS0 0x00000100
++#define NETUP_EN_ALL 0x00001000
++#define NETUP_CTRL_OFF (NETUP_CS1 | NETUP_CS0 | NETUP_WR | NETUP_RD)
++#define NETUP_CI_CTL 0x04
++#define NETUP_CI_RD 1
++
++
++static unsigned int ci_dbg;
++module_param(ci_dbg, int, 0644);
++MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");
++
++#define ci_dbg_print(args...) \
++ do { \
++ if (ci_dbg) \
++ printk(KERN_DEBUG args); \
++ } while (0)
++
++/* stores all private variables for communication with CI */
++struct netup_ci_state {
++ struct dvb_ca_en50221 ca;
++ struct mutex ca_mutex;
++ struct i2c_adapter *i2c_adap;
++ u8 ci_i2c_addr;
++ int status;
++ struct work_struct work;
++ void *priv;
++};
++
++struct mutex gpio_mutex;/* Two CiMax's uses same GPIO lines */
++
++int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
++ u8 *buf, int len)
++{
++ int ret;
++ struct i2c_msg msg[] = {
++ {
++ .addr = addr,
++ .flags = 0,
++ .buf = &reg,
++ .len = 1
++ }, {
++ .addr = addr,
++ .flags = I2C_M_RD,
++ .buf = buf,
++ .len = len
++ }
++ };
++
++ ret = i2c_transfer(i2c_adap, msg, 2);
++
++ if (ret != 2) {
++ ci_dbg_print("%s: i2c read error, Reg = 0x%02x, Status = %d\n",
++ __func__, reg, ret);
++
++ return -1;
++ }
++
++ ci_dbg_print("%s: i2c read Addr=0x%04x, Reg = 0x%02x, data = %02x\n",
++ __func__, addr, reg, buf[0]);
++
++ return 0;
++}
++
++int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
++ u8 *buf, int len)
++{
++ int ret;
++ u8 buffer[len + 1];
++
++ struct i2c_msg msg = {
++ .addr = addr,
++ .flags = 0,
++ .buf = &buffer[0],
++ .len = len + 1
++ };
++
++ buffer[0] = reg;
++ memcpy(&buffer[1], buf, len);
++
++ ret = i2c_transfer(i2c_adap, &msg, 1);
++
++ if (ret != 1) {
++ ci_dbg_print("%s: i2c write error, Reg=[0x%02x], Status=%d\n",
++ __func__, reg, ret);
++ return -1;
++ }
++
++ return 0;
++}
++
++int netup_ci_get_mem(struct cx23885_dev *dev)
++{
++ int mem;
++ unsigned long timeout = jiffies + msecs_to_jiffies(1);
++
++ for (;;) {
++ mem = cx_read(MC417_RWD);
++ if ((mem & NETUP_ACK) == 0)
++ break;
++ if (time_after(jiffies, timeout))
++ break;
++ udelay(1);
++ }
++
++ cx_set(MC417_RWD, NETUP_CTRL_OFF);
++
++ return mem & 0xff;
++}
++
++int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
++ u8 flag, u8 read, int addr, u8 data)
++{
++ struct netup_ci_state *state = en50221->data;
++ struct cx23885_tsport *port = state->priv;
++ struct cx23885_dev *dev = port->dev;
++
++ u8 store;
++ int mem;
++ int ret;
++
++ if (0 != slot)
++ return -EINVAL;
++
++ ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
++ 0, &store, 1);
++ if (ret != 0)
++ return ret;
++
++ store &= ~0x0c;
++ store |= flag;
++
++ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
++ 0, &store, 1);
++ if (ret != 0)
++ return ret;
++
++ mutex_lock(&gpio_mutex);
++
++ /* write addr */
++ cx_write(MC417_OEN, NETUP_EN_ALL);
++ cx_write(MC417_RWD, NETUP_CTRL_OFF |
++ NETUP_ADLO | (0xff & addr));
++ cx_clear(MC417_RWD, NETUP_ADLO);
++ cx_write(MC417_RWD, NETUP_CTRL_OFF |
++ NETUP_ADHI | (0xff & (addr >> 8)));
++ cx_clear(MC417_RWD, NETUP_ADHI);
++
++ if (read) /* data in */
++ cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA);
++ else /* data out */
++ cx_write(MC417_RWD, NETUP_CTRL_OFF | data);
++
++ /* choose chip */
++ cx_clear(MC417_RWD,
++ (state->ci_i2c_addr == 0x40) ? NETUP_CS0 : NETUP_CS1);
++ /* read/write */
++ cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR);
++ mem = netup_ci_get_mem(dev);
++
++ mutex_unlock(&gpio_mutex);
++
++ if (!read)
++ if (mem < 0)
++ return -EREMOTEIO;
++
++ ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__,
++ (read) ? "read" : "write", addr,
++ (flag == NETUP_CI_CTL) ? "ctl" : "mem",
++ (read) ? mem : data);
++
++ if (read)
++ return mem;
++
++ return 0;
++}
++
++int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
++ int slot, int addr)
++{
++ return netup_ci_op_cam(en50221, slot, 0, NETUP_CI_RD, addr, 0);
++}
++
++int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
++ int slot, int addr, u8 data)
++{
++ return netup_ci_op_cam(en50221, slot, 0, 0, addr, data);
++}
++
++int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
++{
++ return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL,
++ NETUP_CI_RD, addr, 0);
++}
++
++int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot,
++ u8 addr, u8 data)
++{
++ return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, 0, addr, data);
++}
++
++int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
++{
++ struct netup_ci_state *state = en50221->data;
++ u8 buf = 0x80;
++ int ret;
++
++ if (0 != slot)
++ return -EINVAL;
++
++ udelay(500);
++ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
++ 0, &buf, 1);
++
++ if (ret != 0)
++ return ret;
++
++ udelay(500);
++
++ buf = 0x00;
++ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
++ 0, &buf, 1);
++
++ msleep(1000);
++ dvb_ca_en50221_camready_irq(&state->ca, 0);
++
++ return 0;
++
++}
++
++int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
++{
++ /* not implemented */
++ return 0;
++}
++
++int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)
++{
++ struct netup_ci_state *state = en50221->data;
++ u8 buf = 0x60;
++
++ if (0 != slot)
++ return -EINVAL;
++
++ return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
++ 0, &buf, 1);
++}
++
++/* work handler */
++static void netup_read_ci_status(struct work_struct *work)
++{
++ struct netup_ci_state *state =
++ container_of(work, struct netup_ci_state, work);
++ u8 buf[33];
++ int ret;
++
++ ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
++ 0, &buf[0], 33);
++
++ if (ret != 0)
++ return;
++
++ ci_dbg_print("%s: Slot Status Addr=[0x%04x], Reg=[0x%02x], data=%02x, "
++ "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0],
++ buf[32]);
++
++ if (buf[0] && 1)
++ state->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
++ DVB_CA_EN50221_POLL_CAM_READY;
++ else
++ state->status = 0;
++}
++
++/* CI irq handler */
++int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status)
++{
++ struct cx23885_tsport *port = NULL;
++ struct netup_ci_state *state = NULL;
++
++ if (pci_status & PCI_MSK_GPIO0)
++ port = &dev->ts1;
++ else if (pci_status & PCI_MSK_GPIO1)
++ port = &dev->ts2;
++ else /* who calls ? */
++ return 0;
++
++ state = port->port_priv;
++
++ schedule_work(&state->work);
++
++ return 1;
++}
++
++int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
++{
++ struct netup_ci_state *state = en50221->data;
++
++ if (0 != slot)
++ return -EINVAL;
++
++ return state->status;
++}
++
++int netup_ci_init(struct cx23885_tsport *port)
++{
++ struct netup_ci_state *state;
++ u8 cimax_init[34] = {
++ 0x00, /* module A control*/
++ 0x00, /* auto select mask high A */
++ 0x00, /* auto select mask low A */
++ 0x00, /* auto select pattern high A */
++ 0x00, /* auto select pattern low A */
++ 0x44, /* memory access time A */
++ 0x00, /* invert input A */
++ 0x00, /* RFU */
++ 0x00, /* RFU */
++ 0x00, /* module B control*/
++ 0x00, /* auto select mask high B */
++ 0x00, /* auto select mask low B */
++ 0x00, /* auto select pattern high B */
++ 0x00, /* auto select pattern low B */
++ 0x44, /* memory access time B */
++ 0x00, /* invert input B */
++ 0x00, /* RFU */
++ 0x00, /* RFU */
++ 0x00, /* auto select mask high Ext */
++ 0x00, /* auto select mask low Ext */
++ 0x00, /* auto select pattern high Ext */
++ 0x00, /* auto select pattern low Ext */
++ 0x00, /* RFU */
++ 0x02, /* destination - module A */
++ 0x01, /* power on (use it like store place) */
++ 0x00, /* RFU */
++ 0x00, /* int status read only */
++ 0x01, /* all int unmasked */
++ 0x04, /* int config */
++ 0x00, /* USCG1 */
++ 0x04, /* ack active low */
++ 0x00, /* LOCK = 0 */
++ 0x33, /* serial mode, rising in, rising out, MSB first*/
++ 0x31, /* syncronization */
++ };
++ int ret;
++
++ ci_dbg_print("%s\n", __func__);
++ state = kzalloc(sizeof(struct netup_ci_state), GFP_KERNEL);
++ if (!state) {
++ ci_dbg_print("%s: Unable create CI structure!\n", __func__);
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ port->port_priv = state;
++
++ switch (port->nr) {
++ case 1:
++ state->ci_i2c_addr = 0x40;
++ mutex_init(&gpio_mutex);
++ break;
++ case 2:
++ state->ci_i2c_addr = 0x41;
++ break;
++ }
++
++ state->i2c_adap = &port->dev->i2c_bus[0].i2c_adap;
++ state->ca.owner = THIS_MODULE;
++ state->ca.read_attribute_mem = netup_ci_read_attribute_mem;
++ state->ca.write_attribute_mem = netup_ci_write_attribute_mem;
++ state->ca.read_cam_control = netup_ci_read_cam_ctl;
++ state->ca.write_cam_control = netup_ci_write_cam_ctl;
++ state->ca.slot_reset = netup_ci_slot_reset;
++ state->ca.slot_shutdown = netup_ci_slot_shutdown;
++ state->ca.slot_ts_enable = netup_ci_slot_ts_ctl;
++ state->ca.poll_slot_status = netup_poll_ci_slot_status;
++ state->ca.data = state;
++ state->priv = port;
++
++ ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
++ 0, &cimax_init[0], 34);
++ /* lock registers */
++ ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
++ 0x1f, &cimax_init[0x18], 1);
++ /* power on slots */
++ ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
++ 0x18, &cimax_init[0x18], 1);
++
++ if (0 != ret)
++ goto err;
++
++ ret = dvb_ca_en50221_init(&port->frontends.adapter,
++ &state->ca,
++ /* flags */ 0,
++ /* n_slots */ 1);
++ if (0 != ret)
++ goto err;
++
++ INIT_WORK(&state->work, netup_read_ci_status);
++
++ ci_dbg_print("%s: CI initialized!\n", __func__);
++
++ return 0;
++err:
++ ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
++ kfree(state);
++ return ret;
++}
++
++void netup_ci_exit(struct cx23885_tsport *port)
++{
++ struct netup_ci_state *state;
++
++ if (NULL == port)
++ return;
++
++ state = (struct netup_ci_state *)port->port_priv;
++ if (NULL == state)
++ return;
++
++ if (NULL == state->ca.data)
++ return;
++
++ dvb_ca_en50221_release(&state->ca);
++ kfree(state);
++}
+diff --git a/drivers/media/video/cx23885/cimax2.h b/drivers/media/video/cx23885/cimax2.h
+new file mode 100644
+index 0000000..518744a
+--- /dev/null
++++ b/drivers/media/video/cx23885/cimax2.h
+@@ -0,0 +1,47 @@
++/*
++ * cimax2.h
++ *
++ * CIMax(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
++ *
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
++ *
++ * 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 CIMAX2_H
++#define CIMAX2_H
++#include "dvb_ca_en50221.h"
++
++extern int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
++ int slot, int addr);
++extern int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
++ int slot, int addr, u8 data);
++extern int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221,
++ int slot, u8 addr);
++extern int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221,
++ int slot, u8 addr, u8 data);
++extern int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot);
++extern int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot);
++extern int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot);
++extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status);
++extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221,
++ int slot, int open);
++extern int netup_ci_init(struct cx23885_tsport *port);
++extern void netup_ci_exit(struct cx23885_tsport *port);
++
++#endif
+diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
+index bfe2584..6f5df90 100644
+--- a/drivers/media/video/cx23885/cx23885-417.c
++++ b/drivers/media/video/cx23885/cx23885-417.c
+@@ -896,7 +896,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
+ if (retval != 0) {
+ printk(KERN_ERR
+ "ERROR: Hotplug firmware request failed (%s).\n",
+- CX2341X_FIRM_ENC_FILENAME);
++ CX23885_FIRM_IMAGE_NAME);
+ printk(KERN_ERR "Please fix your hotplug setup, the board will "
+ "not work without firmware loaded!\n");
+ return -1;
+@@ -1198,21 +1198,16 @@ static int vidioc_enum_input(struct file *file, void *priv,
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+ struct cx23885_input *input;
+- unsigned int n;
++ int n;
+
+- n = i->index;
+-
+- if (n >= 4)
++ if (i->index >= 4)
+ return -EINVAL;
+
+- input = &cx23885_boards[dev->board].input[n];
++ input = &cx23885_boards[dev->board].input[i->index];
+
+ if (input->type == 0)
+ return -EINVAL;
+
+- memset(i, 0, sizeof(*i));
+- i->index = n;
+-
+ /* FIXME
+ * strcpy(i->name, input->name); */
+ strcpy(i->name, "unset");
+@@ -1255,10 +1250,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+- memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Television");
+- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
+- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
++ call_all(dev, tuner, g_tuner, t);
+
+ dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+@@ -1275,7 +1268,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
+ return -EINVAL;
+
+ /* Update the A/V core */
+- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
++ call_all(dev, tuner, s_tuner, t);
+
+ return 0;
+ }
+@@ -1286,14 +1279,12 @@ static int vidioc_g_frequency(struct file *file, void *priv,
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+- memset(f, 0, sizeof(*f));
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->freq;
+
+- /* Assumption that tuner is always on bus 1 */
+- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
++ call_all(dev, tuner, g_frequency, f);
+
+ return 0;
+ }
+@@ -1320,8 +1311,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
+ return -EINVAL;
+ dev->freq = f->frequency;
+
+- /* Assumption that tuner is always on bus 1 */
+- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
++ call_all(dev, tuner, s_frequency, f);
+
+ cx23885_initialize_codec(dev);
+
+@@ -1335,7 +1325,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct cx23885_dev *dev = fh->dev;
+
+ /* Update the A/V core */
+- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, ctl);
++ call_all(dev, core, s_ctrl, ctl);
+ return 0;
+ }
+
+@@ -1346,7 +1336,6 @@ static int vidioc_querycap(struct file *file, void *priv,
+ struct cx23885_dev *dev = fh->dev;
+ struct cx23885_tsport *tsport = &dev->ts1;
+
+- memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, dev->name);
+ strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
+ sizeof(cap->card));
+@@ -1366,16 +1355,10 @@ static int vidioc_querycap(struct file *file, void *priv,
+ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+ {
+- int index;
+-
+- index = f->index;
+- if (index != 0)
++ if (f->index != 0)
+ return -EINVAL;
+
+- memset(f, 0, sizeof(*f));
+- f->index = index;
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+ return 0;
+@@ -1387,8 +1370,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+- memset(f, 0, sizeof(*f));
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+@@ -1408,12 +1389,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+- f->fmt.pix.sizeimage =
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+@@ -1426,7 +1405,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+@@ -1543,12 +1521,7 @@ static int vidioc_log_status(struct file *file, void *priv)
+ printk(KERN_INFO
+ "%s/2: ============ START LOG STATUS ============\n",
+ dev->name);
+- cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS,
+- NULL);
+- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS,
+- NULL);
+- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS,
+- NULL);
++ call_all(dev, core, log_status);
+ cx2341x_log_status(&dev->mpeg_params, name);
+ printk(KERN_INFO
+ "%s/2: ============= END LOG STATUS =============\n",
+diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
+index caa098b..5e4b7e7 100644
+--- a/drivers/media/video/cx23885/cx23885-cards.c
++++ b/drivers/media/video/cx23885/cx23885-cards.c
+@@ -27,6 +27,7 @@
+
+ #include "cx23885.h"
+ #include "tuner-xc2028.h"
++#include "netup-init.h"
+
+ /* ------------------------------------------------------------------ */
+ /* board config info */
+@@ -162,6 +163,24 @@ struct cx23885_board cx23885_boards[] = {
+ .name = "Compro VideoMate E650F",
+ .portc = CX23885_MPEG_DVB,
+ },
++ [CX23885_BOARD_TBS_6920] = {
++ .name = "TurboSight TBS 6920",
++ .portb = CX23885_MPEG_DVB,
++ },
++ [CX23885_BOARD_TEVII_S470] = {
++ .name = "TeVii S470",
++ .portb = CX23885_MPEG_DVB,
++ },
++ [CX23885_BOARD_DVBWORLD_2005] = {
++ .name = "DVBWorld DVB-S2 2005",
++ .portb = CX23885_MPEG_DVB,
++ },
++ [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = {
++ .cimax = 1,
++ .name = "NetUP Dual DVB-S2 CI",
++ .portb = CX23885_MPEG_DVB,
++ .portc = CX23885_MPEG_DVB,
++ },
+ };
+ const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+
+@@ -245,6 +264,22 @@ struct cx23885_subid cx23885_subids[] = {
+ .subvendor = 0x185b,
+ .subdevice = 0xe800,
+ .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F,
++ }, {
++ .subvendor = 0x6920,
++ .subdevice = 0x8888,
++ .card = CX23885_BOARD_TBS_6920,
++ }, {
++ .subvendor = 0xd470,
++ .subdevice = 0x9022,
++ .card = CX23885_BOARD_TEVII_S470,
++ }, {
++ .subvendor = 0x0001,
++ .subdevice = 0x2005,
++ .card = CX23885_BOARD_DVBWORLD_2005,
++ }, {
++ .subvendor = 0x1b55,
++ .subdevice = 0x2a2c,
++ .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
+ },
+ };
+ const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+@@ -552,6 +587,38 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
+ mdelay(20);
+ cx_set(GP0_IO, 0x00040004);
+ break;
++ case CX23885_BOARD_TBS_6920:
++ case CX23885_BOARD_TEVII_S470:
++ cx_write(MC417_CTL, 0x00000036);
++ cx_write(MC417_OEN, 0x00001000);
++ cx_write(MC417_RWD, 0x00001800);
++ break;
++ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
++ /* GPIO-0 INTA from CiMax1
++ GPIO-1 INTB from CiMax2
++ GPIO-2 reset chips
++ GPIO-3 to GPIO-10 data/addr for CA
++ GPIO-11 ~CS0 to CiMax1
++ GPIO-12 ~CS1 to CiMax2
++ GPIO-13 ADL0 load LSB addr
++ GPIO-14 ADL1 load MSB addr
++ GPIO-15 ~RDY from CiMax
++ GPIO-17 ~RD to CiMax
++ GPIO-18 ~WR to CiMax
++ */
++ cx_set(GP0_IO, 0x00040000); /* GPIO as out */
++ /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */
++ cx_clear(GP0_IO, 0x00030004);
++ mdelay(100);/* reset delay */
++ cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */
++ cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
++ /* GPIO-15 IN as ~ACK, rest as OUT */
++ cx_write(MC417_OEN, 0x00001000);
++ /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
++ cx_write(MC417_RWD, 0x0000c300);
++ /* enable irq */
++ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
++ break;
+ }
+ }
+
+@@ -632,6 +699,21 @@ void cx23885_card_setup(struct cx23885_dev *dev)
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
++ case CX23885_BOARD_TEVII_S470:
++ case CX23885_BOARD_TBS_6920:
++ case CX23885_BOARD_DVBWORLD_2005:
++ ts1->gen_ctrl_val = 0x5; /* Parallel */
++ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
++ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
++ break;
++ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
++ ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
++ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
++ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
++ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
++ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
++ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
++ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+@@ -656,7 +738,17 @@ void cx23885_card_setup(struct cx23885_dev *dev)
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+- request_module("cx25840");
++ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
++ dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->i2c_bus[2].i2c_adap,
++ "cx25840", "cx25840", 0x88 >> 1);
++ v4l2_subdev_call(dev->sd_cx25840, core, init, 0);
++ break;
++ }
++
++ /* AUX-PLL 27MHz CLK */
++ switch (dev->board) {
++ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
++ netup_initialize(dev);
+ break;
+ }
+ }
+diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
+index 8f6fb2a..dc7fff2 100644
+--- a/drivers/media/video/cx23885/cx23885-core.c
++++ b/drivers/media/video/cx23885/cx23885-core.c
+@@ -31,6 +31,7 @@
+ #include <asm/div64.h>
+
+ #include "cx23885.h"
++#include "cimax2.h"
+
+ MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
+ MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
+@@ -791,6 +792,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ dev->pci_bus = dev->pci->bus->number;
+ dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+ dev->pci_irqmask = 0x001f00;
++ if (cx23885_boards[dev->board].cimax > 0)
++ dev->pci_irqmask |= 0x01800000; /* for CiMaxes */
+
+ /* External Master 1 Bus */
+ dev->i2c_bus[0].nr = 0;
+@@ -872,7 +875,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ cx23885_i2c_register(&dev->i2c_bus[1]);
+ cx23885_i2c_register(&dev->i2c_bus[2]);
+ cx23885_card_setup(dev);
+- cx23885_call_i2c_clients(&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
++ call_all(dev, core, s_standby, 0);
+ cx23885_ir_init(dev);
+
+ if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
+@@ -1643,7 +1646,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
+ (pci_status & PCI_MSK_VID_B) ||
+ (pci_status & PCI_MSK_VID_A) ||
+ (pci_status & PCI_MSK_AUD_INT) ||
+- (pci_status & PCI_MSK_AUD_EXT)) {
++ (pci_status & PCI_MSK_AUD_EXT) ||
++ (pci_status & PCI_MSK_GPIO0) ||
++ (pci_status & PCI_MSK_GPIO1)) {
+
+ if (pci_status & PCI_MSK_RISC_RD)
+ dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
+@@ -1685,8 +1690,20 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
+ dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n",
+ PCI_MSK_AUD_EXT);
+
++ if (pci_status & PCI_MSK_GPIO0)
++ dprintk(7, " (PCI_MSK_GPIO0 0x%08x)\n",
++ PCI_MSK_GPIO0);
++
++ if (pci_status & PCI_MSK_GPIO1)
++ dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n",
++ PCI_MSK_GPIO1);
+ }
+
++ if (cx23885_boards[dev->board].cimax > 0 &&
++ ((pci_status & PCI_MSK_GPIO0) || (pci_status & PCI_MSK_GPIO1)))
++ /* handled += cx23885_irq_gpio(dev, pci_status); */
++ handled += netup_ci_slot_status(dev, pci_status);
++
+ if (ts1_status) {
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ handled += cx23885_irq_ts(ts1, ts1_status);
+@@ -1722,16 +1739,20 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
+ if (NULL == dev)
+ return -ENOMEM;
+
++ err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
++ if (err < 0)
++ goto fail_free;
++
+ /* pci init */
+ dev->pci = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+ err = -EIO;
+- goto fail_free;
++ goto fail_unreg;
+ }
+
+ if (cx23885_dev_setup(dev) < 0) {
+ err = -EINVAL;
+- goto fail_free;
++ goto fail_unreg;
+ }
+
+ /* print pci info */
+@@ -1758,11 +1779,18 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
+ goto fail_irq;
+ }
+
+- pci_set_drvdata(pci_dev, dev);
++ switch (dev->board) {
++ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
++ cx_set(PCI_INT_MSK, 0x01800000); /* for NetUP */
++ break;
++ }
++
+ return 0;
+
+ fail_irq:
+ cx23885_dev_unregister(dev);
++fail_unreg:
++ v4l2_device_unregister(&dev->v4l2_dev);
+ fail_free:
+ kfree(dev);
+ return err;
+@@ -1770,7 +1798,8 @@ fail_free:
+
+ static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
+ {
+- struct cx23885_dev *dev = pci_get_drvdata(pci_dev);
++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
++ struct cx23885_dev *dev = to_cx23885(v4l2_dev);
+
+ cx23885_shutdown(dev);
+
+@@ -1778,13 +1807,13 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
+
+ /* unregister stuff */
+ free_irq(pci_dev->irq, dev);
+- pci_set_drvdata(pci_dev, NULL);
+
+ mutex_lock(&devlist);
+ list_del(&dev->devlist);
+ mutex_unlock(&devlist);
+
+ cx23885_dev_unregister(dev);
++ v4l2_device_unregister(v4l2_dev);
+ kfree(dev);
+ }
+
+diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
+index 1c45412..d43c743 100644
+--- a/drivers/media/video/cx23885/cx23885-dvb.c
++++ b/drivers/media/video/cx23885/cx23885-dvb.c
+@@ -30,6 +30,7 @@
+ #include "cx23885.h"
+ #include <media/v4l2-common.h>
+
++#include "dvb_ca_en50221.h"
+ #include "s5h1409.h"
+ #include "s5h1411.h"
+ #include "mt2131.h"
+@@ -43,6 +44,13 @@
+ #include "dib7000p.h"
+ #include "dibx000_common.h"
+ #include "zl10353.h"
++#include "stv0900.h"
++#include "stv6110.h"
++#include "lnbh24.h"
++#include "cx24116.h"
++#include "cimax2.h"
++#include "netup-eeprom.h"
++#include "netup-init.h"
+
+ static unsigned int debug;
+
+@@ -308,11 +316,63 @@ static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+ .no_tuner = 1,
+ };
+
++static struct stv0900_config netup_stv0900_config = {
++ .demod_address = 0x68,
++ .xtal = 27000000,
++ .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
++ .diseqc_mode = 2,/* 2/3 PWM */
++ .path1_mode = 2,/*Serial continues clock */
++ .path2_mode = 2,/*Serial continues clock */
++ .tun1_maddress = 0,/* 0x60 */
++ .tun2_maddress = 3,/* 0x63 */
++ .tun1_adc = 1,/* 1 Vpp */
++ .tun2_adc = 1,/* 1 Vpp */
++};
++
++static struct stv6110_config netup_stv6110_tunerconfig_a = {
++ .i2c_address = 0x60,
++ .mclk = 27000000,
++ .iq_wiring = 0,
++};
++
++static struct stv6110_config netup_stv6110_tunerconfig_b = {
++ .i2c_address = 0x63,
++ .mclk = 27000000,
++ .iq_wiring = 1,
++};
++
++static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
++{
++ struct cx23885_tsport *port = fe->dvb->priv;
++ struct cx23885_dev *dev = port->dev;
++
++ if (voltage == SEC_VOLTAGE_18)
++ cx_write(MC417_RWD, 0x00001e00);/* GPIO-13 high */
++ else if (voltage == SEC_VOLTAGE_13)
++ cx_write(MC417_RWD, 0x00001a00);/* GPIO-13 low */
++ else
++ cx_write(MC417_RWD, 0x00001800);/* GPIO-12 low */
++ return 0;
++}
++
++static struct cx24116_config tbs_cx24116_config = {
++ .demod_address = 0x05,
++};
++
++static struct cx24116_config tevii_cx24116_config = {
++ .demod_address = 0x55,
++};
++
++static struct cx24116_config dvbworld_cx24116_config = {
++ .demod_address = 0x05,
++};
++
+ static int dvb_register(struct cx23885_tsport *port)
+ {
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_i2c *i2c_bus = NULL;
+ struct videobuf_dvb_frontend *fe0;
++ int ret;
+
+ /* Get the first frontend */
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+@@ -526,6 +586,78 @@ static int dvb_register(struct cx23885_tsport *port)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
++ case CX23885_BOARD_TBS_6920:
++ i2c_bus = &dev->i2c_bus[0];
++
++ fe0->dvb.frontend = dvb_attach(cx24116_attach,
++ &tbs_cx24116_config,
++ &i2c_bus->i2c_adap);
++ if (fe0->dvb.frontend != NULL)
++ fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage;
++
++ break;
++ case CX23885_BOARD_TEVII_S470:
++ i2c_bus = &dev->i2c_bus[1];
++
++ fe0->dvb.frontend = dvb_attach(cx24116_attach,
++ &tevii_cx24116_config,
++ &i2c_bus->i2c_adap);
++ if (fe0->dvb.frontend != NULL)
++ fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage;
++
++ break;
++ case CX23885_BOARD_DVBWORLD_2005:
++ i2c_bus = &dev->i2c_bus[1];
++
++ fe0->dvb.frontend = dvb_attach(cx24116_attach,
++ &dvbworld_cx24116_config,
++ &i2c_bus->i2c_adap);
++ break;
++ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
++ i2c_bus = &dev->i2c_bus[0];
++ switch (port->nr) {
++ /* port B */
++ case 1:
++ fe0->dvb.frontend = dvb_attach(stv0900_attach,
++ &netup_stv0900_config,
++ &i2c_bus->i2c_adap, 0);
++ if (fe0->dvb.frontend != NULL) {
++ if (dvb_attach(stv6110_attach,
++ fe0->dvb.frontend,
++ &netup_stv6110_tunerconfig_a,
++ &i2c_bus->i2c_adap)) {
++ if (!dvb_attach(lnbh24_attach,
++ fe0->dvb.frontend,
++ &i2c_bus->i2c_adap,
++ LNBH24_PCL, 0, 0x09))
++ printk(KERN_ERR
++ "No LNBH24 found!\n");
++
++ }
++ }
++ break;
++ /* port C */
++ case 2:
++ fe0->dvb.frontend = dvb_attach(stv0900_attach,
++ &netup_stv0900_config,
++ &i2c_bus->i2c_adap, 1);
++ if (fe0->dvb.frontend != NULL) {
++ if (dvb_attach(stv6110_attach,
++ fe0->dvb.frontend,
++ &netup_stv6110_tunerconfig_b,
++ &i2c_bus->i2c_adap)) {
++ if (!dvb_attach(lnbh24_attach,
++ fe0->dvb.frontend,
++ &i2c_bus->i2c_adap,
++ LNBH24_PCL, 0, 0x0a))
++ printk(KERN_ERR
++ "No LNBH24 found!\n");
++
++ }
++ }
++ break;
++ }
++ break;
+ default:
+ printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
+ " isn't supported yet\n",
+@@ -541,15 +673,39 @@ static int dvb_register(struct cx23885_tsport *port)
+ fe0->dvb.frontend->callback = cx23885_tuner_callback;
+
+ /* Put the analog decoder in standby to keep it quiet */
+- cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
++ call_all(dev, core, s_standby, 0);
+
+ if (fe0->dvb.frontend->ops.analog_ops.standby)
+ fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
+
+ /* register everything */
+- return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
++ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+ &dev->pci->dev, adapter_nr, 0);
+
++ /* init CI & MAC */
++ switch (dev->board) {
++ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
++ static struct netup_card_info cinfo;
++
++ netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
++ memcpy(port->frontends.adapter.proposed_mac,
++ cinfo.port[port->nr - 1].mac, 6);
++ printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC="
++ "%02X:%02X:%02X:%02X:%02X:%02X\n",
++ port->nr,
++ port->frontends.adapter.proposed_mac[0],
++ port->frontends.adapter.proposed_mac[1],
++ port->frontends.adapter.proposed_mac[2],
++ port->frontends.adapter.proposed_mac[3],
++ port->frontends.adapter.proposed_mac[4],
++ port->frontends.adapter.proposed_mac[5]);
++
++ netup_ci_init(port);
++ break;
++ }
++ }
++
++ return ret;
+ }
+
+ int cx23885_dvb_register(struct cx23885_tsport *port)
+@@ -622,6 +778,12 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
+ if (fe0->dvb.frontend)
+ videobuf_dvb_unregister_bus(&port->frontends);
+
++ switch (port->dev->board) {
++ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
++ netup_ci_exit(port);
++ break;
++ }
++
+ return 0;
+ }
+
+diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
+index bb7f71a..3421bd1 100644
+--- a/drivers/media/video/cx23885/cx23885-i2c.c
++++ b/drivers/media/video/cx23885/cx23885-i2c.c
+@@ -268,64 +268,6 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
+ return retval;
+ }
+
+-static int attach_inform(struct i2c_client *client)
+-{
+- struct cx23885_i2c *bus = i2c_get_adapdata(client->adapter);
+- struct cx23885_dev *dev = bus->dev;
+- struct tuner_setup tun_setup;
+-
+- dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+- client->driver->driver.name, client->addr, client->name);
+-
+- if (!client->driver->command)
+- return 0;
+-
+- if (dev->tuner_type != UNSET) {
+-
+- dprintk(1, "%s (tuner) i2c attach [addr=0x%x,client=%s]\n",
+- client->driver->driver.name, client->addr,
+- client->name);
+-
+- if ((dev->tuner_addr == ADDR_UNSET) ||
+- (dev->tuner_addr == client->addr)) {
+-
+- dprintk(1, "%s (tuner || addr UNSET)\n",
+- client->driver->driver.name);
+-
+- dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+- client->driver->driver.name,
+- client->addr, client->name);
+-
+- tun_setup.mode_mask = T_ANALOG_TV;
+- tun_setup.type = dev->tuner_type;
+- tun_setup.addr = dev->tuner_addr;
+-
+- client->driver->command(client, TUNER_SET_TYPE_ADDR,
+- &tun_setup);
+- }
+- }
+-
+- return 0;
+-}
+-
+-static int detach_inform(struct i2c_client *client)
+-{
+- struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
+-
+- dprintk(1, "i2c detach [client=%s]\n", client->name);
+-
+- return 0;
+-}
+-
+-void cx23885_call_i2c_clients(struct cx23885_i2c *bus,
+- unsigned int cmd, void *arg)
+-{
+- if (bus->i2c_rc != 0)
+- return;
+-
+- i2c_clients_command(&bus->i2c_adap, cmd, arg);
+-}
+-
+ static u32 cx23885_functionality(struct i2c_adapter *adap)
+ {
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+@@ -343,9 +285,6 @@ static struct i2c_adapter cx23885_i2c_adap_template = {
+ .owner = THIS_MODULE,
+ .id = I2C_HW_B_CX23885,
+ .algo = &cx23885_i2c_algo_template,
+- .class = I2C_CLASS_TV_ANALOG,
+- .client_register = attach_inform,
+- .client_unregister = detach_inform,
+ };
+
+ static struct i2c_client cx23885_i2c_client_template = {
+@@ -402,15 +341,18 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
+
+ bus->i2c_algo.data = bus;
+ bus->i2c_adap.algo_data = bus;
+- i2c_set_adapdata(&bus->i2c_adap, bus);
++ i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
+ i2c_add_adapter(&bus->i2c_adap);
+
+ bus->i2c_client.adapter = &bus->i2c_adap;
+
+ if (0 == bus->i2c_rc) {
+ dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr);
+- if (i2c_scan)
++ if (i2c_scan) {
++ printk(KERN_INFO "%s: scan bus %d:\n",
++ dev->name, bus->nr);
+ do_i2c_scan(dev->name, &bus->i2c_client);
++ }
+ } else
+ printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
+ dev->name, bus->nr);
+diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
+index 20b68a2..eafbe52 100644
+--- a/drivers/media/video/cx23885/cx23885-reg.h
++++ b/drivers/media/video/cx23885/cx23885-reg.h
+@@ -212,6 +212,8 @@ Channel manager Data Structure entry = 20 DWORD
+
+ #define DEV_CNTRL2 0x00040000
+
++#define PCI_MSK_GPIO1 (1 << 24)
++#define PCI_MSK_GPIO0 (1 << 23)
+ #define PCI_MSK_APB_DMA (1 << 12)
+ #define PCI_MSK_AL_WR (1 << 11)
+ #define PCI_MSK_AL_RD (1 << 10)
+diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
+index eaa1189..f0ac62c 100644
+--- a/drivers/media/video/cx23885/cx23885-video.c
++++ b/drivers/media/video/cx23885/cx23885-video.c
+@@ -35,11 +35,6 @@
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-ioctl.h>
+
+-#ifdef CONFIG_VIDEO_V4L1_COMPAT
+-/* Include V4L1 specific functions. Should be removed soon */
+-#include <linux/videodev.h>
+-#endif
+-
+ MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
+ MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
+ MODULE_LICENSE("GPL");
+@@ -244,6 +239,7 @@ static struct cx23885_ctrl cx23885_ctls[] = {
+ };
+ static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
+
++/* Must be sorted from low to high control ID! */
+ static const u32 cx23885_user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+@@ -303,11 +299,7 @@ static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
+
+ dev->tvnorm = norm;
+
+- /* Tell the analog tuner/demods */
+- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm);
+-
+- /* Tell the internal A/V decoder */
+- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm);
++ call_all(dev, tuner, s_std, norm);
+
+ return 0;
+ }
+@@ -324,8 +316,8 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
+ if (NULL == vfd)
+ return NULL;
+ *vfd = *template;
+- vfd->minor = -1;
+- vfd->parent = &pci->dev;
++ vfd->minor = -1;
++ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+ dev->name, type, cx23885_boards[dev->board].name);
+@@ -414,8 +406,7 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
+ route.input = INPUT(input)->vmux;
+
+ /* Tell the internal A/V decoder */
+- cx23885_call_i2c_clients(&dev->i2c_bus[2],
+- VIDIOC_INT_S_VIDEO_ROUTING, &route);
++ v4l2_subdev_call(dev->sd_cx25840, video, s_routing, &route);
+
+ return 0;
+ }
+@@ -891,7 +882,7 @@ static int cx23885_get_control(struct cx23885_dev *dev,
+ struct v4l2_control *ctl)
+ {
+ dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
+- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
++ call_all(dev, core, g_ctrl, ctl);
+ return 0;
+ }
+
+@@ -1005,7 +996,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ fh->vidq.field = f->fmt.pix.field;
+ dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
+ fh->width, fh->height, fh->vidq.field);
+- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f);
++ call_all(dev, video, s_fmt, f);
+ return 0;
+ }
+
+@@ -1285,7 +1276,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
+ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->freq;
+
+- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
++ call_all(dev, tuner, g_frequency, f);
+
+ return 0;
+ }
+@@ -1300,7 +1291,7 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
+ mutex_lock(&dev->lock);
+ dev->freq = f->frequency;
+
+- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
++ call_all(dev, tuner, s_frequency, f);
+
+ /* When changing channels it is required to reset TVAUDIO */
+ msleep(10);
+@@ -1334,7 +1325,7 @@ static int vidioc_g_register(struct file *file, void *fh,
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+
+- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg);
++ call_all(dev, core, g_register, reg);
+
+ return 0;
+ }
+@@ -1347,7 +1338,7 @@ static int vidioc_s_register(struct file *file, void *fh,
+ if (!v4l2_chip_match_host(&reg->match))
+ return -EINVAL;
+
+- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg);
++ call_all(dev, core, s_register, reg);
+
+ return 0;
+ }
+@@ -1528,6 +1519,26 @@ int cx23885_video_register(struct cx23885_dev *dev)
+ /* Don't enable VBI yet */
+ cx_set(PCI_INT_MSK, 1);
+
++ if (TUNER_ABSENT != dev->tuner_type) {
++ struct v4l2_subdev *sd = NULL;
++
++ if (dev->tuner_addr)
++ sd = v4l2_i2c_new_subdev(&dev->i2c_bus[1].i2c_adap,
++ "tuner", "tuner", dev->tuner_addr);
++ else
++ sd = v4l2_i2c_new_probed_subdev(&dev->i2c_bus[1].i2c_adap,
++ "tuner", "tuner", v4l2_i2c_tuner_addrs(ADDRS_TV));
++ if (sd) {
++ struct tuner_setup tun_setup;
++
++ tun_setup.mode_mask = T_ANALOG_TV;
++ tun_setup.type = dev->tuner_type;
++ tun_setup.addr = v4l2_i2c_subdev_addr(sd);
++
++ v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup);
++ }
++ }
++
+
+ /* register v4l devices */
+ dev->video_dev = cx23885_vdev_init(dev, dev->pci,
+diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
+index 6782802..02d980a 100644
+--- a/drivers/media/video/cx23885/cx23885.h
++++ b/drivers/media/video/cx23885/cx23885.h
+@@ -24,7 +24,7 @@
+ #include <linux/i2c-algo-bit.h>
+ #include <linux/kdev_t.h>
+
+-#include <media/v4l2-common.h>
++#include <media/v4l2-device.h>
+ #include <media/tuner.h>
+ #include <media/tveeprom.h>
+ #include <media/videobuf-dma-sg.h>
+@@ -67,6 +67,10 @@
+ #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11
+ #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12
+ #define CX23885_BOARD_COMPRO_VIDEOMATE_E650F 13
++#define CX23885_BOARD_TBS_6920 14
++#define CX23885_BOARD_TEVII_S470 15
++#define CX23885_BOARD_DVBWORLD_2005 16
++#define CX23885_BOARD_NETUP_DUAL_DVBS2_CI 17
+
+ /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
+ #define CX23885_NORMS (\
+@@ -184,6 +188,7 @@ struct cx23885_board {
+ */
+ u32 clk_freq;
+ struct cx23885_input input[MAX_CX23885_INPUT];
++ int cimax; /* for NetUP */
+ };
+
+ struct cx23885_subid {
+@@ -266,11 +271,13 @@ struct cx23885_tsport {
+
+ /* Allow a single tsport to have multiple frontends */
+ u32 num_frontends;
++ void *port_priv;
+ };
+
+ struct cx23885_dev {
+ struct list_head devlist;
+ atomic_t refcount;
++ struct v4l2_device v4l2_dev;
+
+ /* pci stuff */
+ struct pci_dev *pci;
+@@ -316,6 +323,7 @@ struct cx23885_dev {
+ unsigned int radio_type;
+ unsigned char radio_addr;
+ unsigned int has_radio;
++ struct v4l2_subdev *sd_cx25840;
+
+ /* V4l */
+ u32 freq;
+@@ -336,6 +344,14 @@ struct cx23885_dev {
+
+ };
+
++static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev)
++{
++ return container_of(v4l2_dev, struct cx23885_dev, v4l2_dev);
++}
++
++#define call_all(dev, o, f, args...) \
++ v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
++
+ extern struct list_head cx23885_devlist;
+
+ #define SRAM_CH01 0 /* Video A */
+@@ -452,8 +468,6 @@ extern struct videobuf_queue_ops cx23885_vbi_qops;
+ /* cx23885-i2c.c */
+ extern int cx23885_i2c_register(struct cx23885_i2c *bus);
+ extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
+-extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
+- void *arg);
+ extern void cx23885_av_clk(struct cx23885_dev *dev, int enable);
+
+ /* ----------------------------------------------------------- */
+diff --git a/drivers/media/video/cx23885/netup-eeprom.c b/drivers/media/video/cx23885/netup-eeprom.c
+new file mode 100644
+index 0000000..042bbbb
+--- /dev/null
++++ b/drivers/media/video/cx23885/netup-eeprom.c
+@@ -0,0 +1,107 @@
++
++/*
++ * netup-eeprom.c
++ *
++ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
++ *
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
++ *
++ * 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 "cx23885.h"
++#include "netup-eeprom.h"
++
++#define EEPROM_I2C_ADDR 0x50
++
++int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr)
++{
++ int ret;
++ unsigned char buf[2];
++
++ /* Read from EEPROM */
++ struct i2c_msg msg[] = {
++ {
++ .addr = EEPROM_I2C_ADDR,
++ .flags = 0,
++ .buf = &buf[0],
++ .len = 1
++ }, {
++ .addr = EEPROM_I2C_ADDR,
++ .flags = I2C_M_RD,
++ .buf = &buf[1],
++ .len = 1
++ }
++
++ };
++
++ buf[0] = addr;
++ buf[1] = 0x0;
++
++ ret = i2c_transfer(i2c_adap, msg, 2);
++
++ if (ret != 2) {
++ printk(KERN_ERR "eeprom i2c read error, status=%d\n", ret);
++ return -1;
++ }
++
++ return buf[1];
++};
++
++int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data)
++{
++ int ret;
++ unsigned char bufw[2];
++
++ /* Write into EEPROM */
++ struct i2c_msg msg[] = {
++ {
++ .addr = EEPROM_I2C_ADDR,
++ .flags = 0,
++ .buf = &bufw[0],
++ .len = 2
++ }
++ };
++
++ bufw[0] = addr;
++ bufw[1] = data;
++
++ ret = i2c_transfer(i2c_adap, msg, 1);
++
++ if (ret != 1) {
++ printk(KERN_ERR "eeprom i2c write error, status=%d\n", ret);
++ return -1;
++ }
++
++ mdelay(10); /* prophylactic delay, datasheet write cycle time = 5 ms */
++ return 0;
++};
++
++void netup_get_card_info(struct i2c_adapter *i2c_adap,
++ struct netup_card_info *cinfo)
++{
++ int i, j;
++
++ cinfo->rev = netup_eeprom_read(i2c_adap, 13);
++
++ for (i = 0, j = 0; i < 6; i++, j++)
++ cinfo->port[0].mac[j] = netup_eeprom_read(i2c_adap, i);
++
++ for (i = 6, j = 0; i < 12; i++, j++)
++ cinfo->port[1].mac[j] = netup_eeprom_read(i2c_adap, i);
++};
+diff --git a/drivers/media/video/cx23885/netup-eeprom.h b/drivers/media/video/cx23885/netup-eeprom.h
+new file mode 100644
+index 0000000..13926e1
+--- /dev/null
++++ b/drivers/media/video/cx23885/netup-eeprom.h
+@@ -0,0 +1,42 @@
++/*
++ * netup-eeprom.h
++ *
++ * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card
++ *
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
++ *
++ * 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 NETUP_EEPROM_H
++#define NETUP_EEPROM_H
++
++struct netup_port_info {
++ u8 mac[6];/* card MAC address */
++};
++
++struct netup_card_info {
++ struct netup_port_info port[2];/* ports - 1,2 */
++ u8 rev;/* card revision */
++};
++
++extern int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr);
++extern int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data);
++extern void netup_get_card_info(struct i2c_adapter *i2c_adap,
++ struct netup_card_info *cinfo);
++
++#endif
+diff --git a/drivers/media/video/cx23885/netup-init.c b/drivers/media/video/cx23885/netup-init.c
+new file mode 100644
+index 0000000..f4893e6
+--- /dev/null
++++ b/drivers/media/video/cx23885/netup-init.c
+@@ -0,0 +1,125 @@
++/*
++ * netup-init.c
++ *
++ * NetUP Dual DVB-S2 CI driver
++ *
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
++ *
++ * 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 "cx23885.h"
++
++static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val)
++{
++ int ret;
++ u8 buf[3];
++ struct i2c_msg msg = {
++ .addr = 0x88 >> 1,
++ .flags = 0,
++ .buf = buf,
++ .len = 3
++ };
++
++ buf[0] = reg >> 8;
++ buf[1] = reg & 0xff;
++ buf[2] = val;
++
++ ret = i2c_transfer(i2c, &msg, 1);
++
++ if (ret != 1)
++ printk(KERN_ERR "%s: i2c write error!\n", __func__);
++}
++
++static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val)
++{
++ int ret;
++ u8 buf[6];
++ struct i2c_msg msg = {
++ .addr = 0x88 >> 1,
++ .flags = 0,
++ .buf = buf,
++ .len = 6
++ };
++
++ buf[0] = reg >> 8;
++ buf[1] = reg & 0xff;
++ buf[2] = val & 0xff;
++ buf[3] = (val >> 8) & 0xff;
++ buf[4] = (val >> 16) & 0xff;
++ buf[5] = val >> 24;
++
++ ret = i2c_transfer(i2c, &msg, 1);
++
++ if (ret != 1)
++ printk(KERN_ERR "%s: i2c write error!\n", __func__);
++}
++
++static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg)
++{
++ int ret;
++ u8 buf[2];
++ struct i2c_msg msg = {
++ .addr = 0x88 >> 1,
++ .flags = 0,
++ .buf = buf,
++ .len = 2
++ };
++
++ buf[0] = reg >> 8;
++ buf[1] = reg & 0xff;
++
++ ret = i2c_transfer(i2c, &msg, 1);
++
++ if (ret != 1)
++ printk(KERN_ERR "%s: i2c write error!\n", __func__);
++
++ msg.flags = I2C_M_RD;
++ msg.len = 1;
++
++ ret = i2c_transfer(i2c, &msg, 1);
++
++ if (ret != 1)
++ printk(KERN_ERR "%s: i2c read error!\n", __func__);
++
++ return buf[0];
++}
++
++static void i2c_av_and_or(struct i2c_adapter *i2c, u16 reg, unsigned and_mask,
++ u8 or_value)
++{
++ i2c_av_write(i2c, reg, (i2c_av_read(i2c, reg) & and_mask) | or_value);
++}
++/* set 27MHz on AUX_CLK */
++void netup_initialize(struct cx23885_dev *dev)
++{
++ struct cx23885_i2c *i2c_bus = &dev->i2c_bus[2];
++ struct i2c_adapter *i2c = &i2c_bus->i2c_adap;
++
++ /* Stop microcontroller */
++ i2c_av_and_or(i2c, 0x803, ~0x10, 0x00);
++
++ /* Aux PLL frac for 27 MHz */
++ i2c_av_write4(i2c, 0x114, 0xea0eb3);
++
++ /* Aux PLL int for 27 MHz */
++ i2c_av_write4(i2c, 0x110, 0x090319);
++
++ /* start microcontroller */
++ i2c_av_and_or(i2c, 0x803, ~0x10, 0x10);
++}
+diff --git a/drivers/media/video/cx23885/netup-init.h b/drivers/media/video/cx23885/netup-init.h
+new file mode 100644
+index 0000000..d26ae4b
+--- /dev/null
++++ b/drivers/media/video/cx23885/netup-init.h
+@@ -0,0 +1,25 @@
++/*
++ * netup-init.h
++ *
++ * NetUP Dual DVB-S2 CI driver
++ *
++ * Copyright (C) 2009 NetUP Inc.
++ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
++ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
++ *
++ * 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.
++ */
++extern void netup_initialize(struct cx23885_dev *dev);
+diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
+index d199d80..93d74be 100644
+--- a/drivers/media/video/cx25840/cx25840-audio.c
++++ b/drivers/media/video/cx25840/cx25840-audio.c
+@@ -363,75 +363,74 @@ static void set_mute(struct i2c_client *client, int mute)
+ }
+ }
+
+-int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
++int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+ {
+- struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+- struct v4l2_control *ctrl = arg;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct cx25840_state *state = to_state(sd);
+ int retval;
+
+- switch (cmd) {
+- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+- if (!state->is_cx25836)
+- cx25840_and_or(client, 0x810, ~0x1, 1);
+- if (state->aud_input != CX25840_AUDIO_SERIAL) {
+- cx25840_and_or(client, 0x803, ~0x10, 0);
+- cx25840_write(client, 0x8d3, 0x1f);
+- }
+- retval = set_audclk_freq(client, *(u32 *)arg);
+- if (state->aud_input != CX25840_AUDIO_SERIAL) {
+- cx25840_and_or(client, 0x803, ~0x10, 0x10);
+- }
+- if (!state->is_cx25836)
+- cx25840_and_or(client, 0x810, ~0x1, 0);
+- return retval;
+-
+- case VIDIOC_G_CTRL:
+- switch (ctrl->id) {
+- case V4L2_CID_AUDIO_VOLUME:
+- ctrl->value = get_volume(client);
+- break;
+- case V4L2_CID_AUDIO_BASS:
+- ctrl->value = get_bass(client);
+- break;
+- case V4L2_CID_AUDIO_TREBLE:
+- ctrl->value = get_treble(client);
+- break;
+- case V4L2_CID_AUDIO_BALANCE:
+- ctrl->value = get_balance(client);
+- break;
+- case V4L2_CID_AUDIO_MUTE:
+- ctrl->value = get_mute(client);
+- break;
+- default:
+- return -EINVAL;
+- }
+- break;
++ if (!state->is_cx25836)
++ cx25840_and_or(client, 0x810, ~0x1, 1);
++ if (state->aud_input != CX25840_AUDIO_SERIAL) {
++ cx25840_and_or(client, 0x803, ~0x10, 0);
++ cx25840_write(client, 0x8d3, 0x1f);
++ }
++ retval = set_audclk_freq(client, freq);
++ if (state->aud_input != CX25840_AUDIO_SERIAL)
++ cx25840_and_or(client, 0x803, ~0x10, 0x10);
++ if (!state->is_cx25836)
++ cx25840_and_or(client, 0x810, ~0x1, 0);
++ return retval;
++}
+
+- case VIDIOC_S_CTRL:
+- switch (ctrl->id) {
+- case V4L2_CID_AUDIO_VOLUME:
+- set_volume(client, ctrl->value);
+- break;
+- case V4L2_CID_AUDIO_BASS:
+- set_bass(client, ctrl->value);
+- break;
+- case V4L2_CID_AUDIO_TREBLE:
+- set_treble(client, ctrl->value);
+- break;
+- case V4L2_CID_AUDIO_BALANCE:
+- set_balance(client, ctrl->value);
+- break;
+- case V4L2_CID_AUDIO_MUTE:
+- set_mute(client, ctrl->value);
+- break;
+- default:
+- return -EINVAL;
+- }
+- break;
++int cx25840_audio_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_VOLUME:
++ ctrl->value = get_volume(client);
++ break;
++ case V4L2_CID_AUDIO_BASS:
++ ctrl->value = get_bass(client);
++ break;
++ case V4L2_CID_AUDIO_TREBLE:
++ ctrl->value = get_treble(client);
++ break;
++ case V4L2_CID_AUDIO_BALANCE:
++ ctrl->value = get_balance(client);
++ break;
++ case V4L2_CID_AUDIO_MUTE:
++ ctrl->value = get_mute(client);
++ break;
+ default:
+ return -EINVAL;
+ }
++ return 0;
++}
+
++int cx25840_audio_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_VOLUME:
++ set_volume(client, ctrl->value);
++ break;
++ case V4L2_CID_AUDIO_BASS:
++ set_bass(client, ctrl->value);
++ break;
++ case V4L2_CID_AUDIO_TREBLE:
++ set_treble(client, ctrl->value);
++ break;
++ case V4L2_CID_AUDIO_BALANCE:
++ set_balance(client, ctrl->value);
++ break;
++ case V4L2_CID_AUDIO_MUTE:
++ set_mute(client, ctrl->value);
++ break;
++ default:
++ return -EINVAL;
++ }
+ return 0;
+ }
+diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
+index 25eb3be..737ee4e 100644
+--- a/drivers/media/video/cx25840/cx25840-core.c
++++ b/drivers/media/video/cx25840/cx25840-core.c
+@@ -39,7 +39,7 @@
+ #include <linux/delay.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
+ #include <media/cx25840.h>
+
+ #include "cx25840-core.h"
+@@ -48,15 +48,12 @@ MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
+ MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
+ MODULE_LICENSE("GPL");
+
+-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+-
+ static int cx25840_debug;
+
+ module_param_named(debug,cx25840_debug, int, 0644);
+
+ MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
+
+-I2C_CLIENT_INSMOD;
+
+ /* ----------------------------------------------------------------------- */
+
+@@ -763,7 +760,7 @@ static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ break;
+
+ case V4L2_CID_HUE:
+- if (ctrl->value < -127 || ctrl->value > 127) {
++ if (ctrl->value < -128 || ctrl->value > 127) {
+ v4l_err(client, "invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+@@ -778,7 +775,7 @@ static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ case V4L2_CID_AUDIO_MUTE:
+ if (state->is_cx25836)
+ return -EINVAL;
+- return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
++ return cx25840_audio_s_ctrl(sd, ctrl);
+
+ default:
+ return -EINVAL;
+@@ -815,7 +812,7 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ case V4L2_CID_AUDIO_MUTE:
+ if (state->is_cx25836)
+ return -EINVAL;
+- return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
++ return cx25840_audio_g_ctrl(sd, ctrl);
+ default:
+ return -EINVAL;
+ }
+@@ -827,11 +824,9 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+
+ static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+ {
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+-
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+- return cx25840_vbi(client, VIDIOC_G_FMT, fmt);
++ return cx25840_vbi_g_fmt(sd, fmt);
+ default:
+ return -EINVAL;
+ }
+@@ -893,10 +888,10 @@ static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+- return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
++ return cx25840_vbi_s_fmt(sd, fmt);
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+- return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
++ return cx25840_vbi_s_fmt(sd, fmt);
+
+ default:
+ return -EINVAL;
+@@ -1101,6 +1096,16 @@ static void log_audio_status(struct i2c_client *client)
+
+ /* ----------------------------------------------------------------------- */
+
++/* This init operation must be called to load the driver's firmware.
++ Without this the audio standard detection will fail and you will
++ only get mono.
++
++ Since loading the firmware is often problematic when the driver is
++ compiled into the kernel I recommend postponing calling this function
++ until the first open of the video device. Another reason for
++ postponing it is that loading this firmware takes a long time (seconds)
++ due to the slow i2c bus speed. So it will speed up the boot process if
++ you can avoid loading the fw as long as the video device isn't used. */
+ static int cx25840_init(struct v4l2_subdev *sd, u32 val)
+ {
+ struct cx25840_state *state = to_state(sd);
+@@ -1146,20 +1151,6 @@ static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
+ }
+ #endif
+
+-static int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+-
+- return cx25840_vbi(client, VIDIOC_INT_DECODE_VBI_LINE, vbi);
+-}
+-
+-static int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+-
+- return cx25840_audio(client, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freq);
+-}
+-
+ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
+ {
+ struct cx25840_state *state = to_state(sd);
+@@ -1195,10 +1186,12 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
++ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
++ return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
+ case V4L2_CID_HUE:
+- return v4l2_ctrl_query_fill_std(qc);
++ return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+ default:
+ break;
+ }
+@@ -1210,10 +1203,11 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+ return v4l2_ctrl_query_fill(qc, 0, 65535,
+ 65535 / 100, state->default_volume);
+ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+- return v4l2_ctrl_query_fill_std(qc);
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+ default:
+ return -EINVAL;
+ }
+@@ -1380,19 +1374,6 @@ static int cx25840_log_status(struct v4l2_subdev *sd)
+ return 0;
+ }
+
+-static int cx25840_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- /* ignore this command */
+- if (cmd == TUNER_SET_TYPE_ADDR || cmd == TUNER_SET_CONFIG)
+- return 0;
+-
+- /* Old-style drivers rely on initialization on first use, so
+- call the init whenever a command is issued to this driver.
+- New-style drivers using v4l2_subdev should call init explicitly. */
+- cx25840_init(i2c_get_clientdata(client), 0);
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
+@@ -1528,8 +1509,6 @@ MODULE_DEVICE_TABLE(i2c, cx25840_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "cx25840",
+- .driverid = I2C_DRIVERID_CX25840,
+- .command = cx25840_command,
+ .probe = cx25840_probe,
+ .remove = cx25840_remove,
+ .id_table = cx25840_id,
+diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
+index be05582..9ad0eb8 100644
+--- a/drivers/media/video/cx25840/cx25840-core.h
++++ b/drivers/media/video/cx25840/cx25840-core.h
+@@ -75,11 +75,15 @@ int cx25840_loadfw(struct i2c_client *client);
+
+ /* ----------------------------------------------------------------------- */
+ /* cx25850-audio.c */
+-int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg);
+ void cx25840_audio_set_path(struct i2c_client *client);
++int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
++int cx25840_audio_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
++int cx25840_audio_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
+
+ /* ----------------------------------------------------------------------- */
+ /* cx25850-vbi.c */
+-int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg);
++int cx25840_vbi_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt);
++int cx25840_vbi_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt);
++int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi);
+
+ #endif
+diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
+index 03f09b2..35f6592 100644
+--- a/drivers/media/video/cx25840/cx25840-vbi.c
++++ b/drivers/media/video/cx25840/cx25840-vbi.c
+@@ -82,199 +82,181 @@ static int decode_vps(u8 * dst, u8 * p)
+ return err & 0xf0;
+ }
+
+-int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
++int cx25840_vbi_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+ {
+- struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+- struct v4l2_format *fmt;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct cx25840_state *state = to_state(sd);
+ struct v4l2_sliced_vbi_format *svbi;
++ static const u16 lcr2vbi[] = {
++ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
++ 0, V4L2_SLICED_WSS_625, 0, /* 4 */
++ V4L2_SLICED_CAPTION_525, /* 6 */
++ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
++ 0, 0, 0, 0
++ };
++ int is_pal = !(state->std & V4L2_STD_525_60);
++ int i;
+
+- switch (cmd) {
+- case VIDIOC_G_FMT:
+- {
+- static u16 lcr2vbi[] = {
+- 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+- 0, V4L2_SLICED_WSS_625, 0, /* 4 */
+- V4L2_SLICED_CAPTION_525, /* 6 */
+- 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
+- 0, 0, 0, 0
+- };
+- int is_pal = !(state->std & V4L2_STD_525_60);
+- int i;
+-
+- fmt = arg;
+- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+- return -EINVAL;
+- svbi = &fmt->fmt.sliced;
+- memset(svbi, 0, sizeof(*svbi));
+- /* we're done if raw VBI is active */
+- if ((cx25840_read(client, 0x404) & 0x10) == 0)
+- break;
++ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
++ return -EINVAL;
++ svbi = &fmt->fmt.sliced;
++ memset(svbi, 0, sizeof(*svbi));
++ /* we're done if raw VBI is active */
++ if ((cx25840_read(client, 0x404) & 0x10) == 0)
++ return 0;
+
+- if (is_pal) {
+- for (i = 7; i <= 23; i++) {
+- u8 v = cx25840_read(client, 0x424 + i - 7);
++ if (is_pal) {
++ for (i = 7; i <= 23; i++) {
++ u8 v = cx25840_read(client, 0x424 + i - 7);
+
+- svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+- svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+- svbi->service_set |=
+- svbi->service_lines[0][i] | svbi->service_lines[1][i];
+- }
++ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
++ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
++ svbi->service_set |= svbi->service_lines[0][i] |
++ svbi->service_lines[1][i];
+ }
+- else {
+- for (i = 10; i <= 21; i++) {
+- u8 v = cx25840_read(client, 0x424 + i - 10);
+-
+- svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+- svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+- svbi->service_set |=
+- svbi->service_lines[0][i] | svbi->service_lines[1][i];
+- }
++ } else {
++ for (i = 10; i <= 21; i++) {
++ u8 v = cx25840_read(client, 0x424 + i - 10);
++
++ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
++ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
++ svbi->service_set |= svbi->service_lines[0][i] |
++ svbi->service_lines[1][i];
+ }
+- break;
+ }
++ return 0;
++}
+
+- case VIDIOC_S_FMT:
+- {
+- int is_pal = !(state->std & V4L2_STD_525_60);
+- int vbi_offset = is_pal ? 1 : 0;
+- int i, x;
+- u8 lcr[24];
+-
+- fmt = arg;
+- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+- fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
+- return -EINVAL;
+- svbi = &fmt->fmt.sliced;
+- if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+- /* raw VBI */
+- memset(svbi, 0, sizeof(*svbi));
+-
+- /* Setup standard */
+- cx25840_std_setup(client);
+-
+- /* VBI Offset */
+- cx25840_write(client, 0x47f, vbi_offset);
+- cx25840_write(client, 0x404, 0x2e);
+- break;
+- }
+-
+- for (x = 0; x <= 23; x++)
+- lcr[x] = 0x00;
++int cx25840_vbi_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct cx25840_state *state = to_state(sd);
++ struct v4l2_sliced_vbi_format *svbi;
++ int is_pal = !(state->std & V4L2_STD_525_60);
++ int vbi_offset = is_pal ? 1 : 0;
++ int i, x;
++ u8 lcr[24];
++
++ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
++ fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
++ return -EINVAL;
++ svbi = &fmt->fmt.sliced;
++ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
++ /* raw VBI */
++ memset(svbi, 0, sizeof(*svbi));
+
+ /* Setup standard */
+ cx25840_std_setup(client);
+
+- /* Sliced VBI */
+- cx25840_write(client, 0x404, 0x32); /* Ancillary data */
+- cx25840_write(client, 0x406, 0x13);
++ /* VBI Offset */
+ cx25840_write(client, 0x47f, vbi_offset);
++ cx25840_write(client, 0x404, 0x2e);
++ return 0;
++ }
+
+- if (is_pal) {
+- for (i = 0; i <= 6; i++)
+- svbi->service_lines[0][i] =
+- svbi->service_lines[1][i] = 0;
+- } else {
+- for (i = 0; i <= 9; i++)
+- svbi->service_lines[0][i] =
+- svbi->service_lines[1][i] = 0;
+-
+- for (i = 22; i <= 23; i++)
+- svbi->service_lines[0][i] =
+- svbi->service_lines[1][i] = 0;
+- }
+-
+- for (i = 7; i <= 23; i++) {
+- for (x = 0; x <= 1; x++) {
+- switch (svbi->service_lines[1-x][i]) {
+- case V4L2_SLICED_TELETEXT_B:
+- lcr[i] |= 1 << (4 * x);
+- break;
+- case V4L2_SLICED_WSS_625:
+- lcr[i] |= 4 << (4 * x);
+- break;
+- case V4L2_SLICED_CAPTION_525:
+- lcr[i] |= 6 << (4 * x);
+- break;
+- case V4L2_SLICED_VPS:
+- lcr[i] |= 9 << (4 * x);
+- break;
+- }
+- }
+- }
++ for (x = 0; x <= 23; x++)
++ lcr[x] = 0x00;
++
++ /* Setup standard */
++ cx25840_std_setup(client);
++
++ /* Sliced VBI */
++ cx25840_write(client, 0x404, 0x32); /* Ancillary data */
++ cx25840_write(client, 0x406, 0x13);
++ cx25840_write(client, 0x47f, vbi_offset);
++
++ if (is_pal) {
++ for (i = 0; i <= 6; i++)
++ svbi->service_lines[0][i] =
++ svbi->service_lines[1][i] = 0;
++ } else {
++ for (i = 0; i <= 9; i++)
++ svbi->service_lines[0][i] =
++ svbi->service_lines[1][i] = 0;
++
++ for (i = 22; i <= 23; i++)
++ svbi->service_lines[0][i] =
++ svbi->service_lines[1][i] = 0;
++ }
+
+- if (is_pal) {
+- for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+- cx25840_write(client, i, lcr[6 + x]);
+- }
+- }
+- else {
+- for (x = 1, i = 0x424; i <= 0x430; i++, x++) {
+- cx25840_write(client, i, lcr[9 + x]);
+- }
+- for (i = 0x431; i <= 0x434; i++) {
+- cx25840_write(client, i, 0);
++ for (i = 7; i <= 23; i++) {
++ for (x = 0; x <= 1; x++) {
++ switch (svbi->service_lines[1-x][i]) {
++ case V4L2_SLICED_TELETEXT_B:
++ lcr[i] |= 1 << (4 * x);
++ break;
++ case V4L2_SLICED_WSS_625:
++ lcr[i] |= 4 << (4 * x);
++ break;
++ case V4L2_SLICED_CAPTION_525:
++ lcr[i] |= 6 << (4 * x);
++ break;
++ case V4L2_SLICED_VPS:
++ lcr[i] |= 9 << (4 * x);
++ break;
+ }
+ }
++ }
+
+- cx25840_write(client, 0x43c, 0x16);
+-
+- if (is_pal) {
+- cx25840_write(client, 0x474, 0x2a);
+- } else {
+- cx25840_write(client, 0x474, 0x22);
+- }
+- break;
++ if (is_pal) {
++ for (x = 1, i = 0x424; i <= 0x434; i++, x++)
++ cx25840_write(client, i, lcr[6 + x]);
++ } else {
++ for (x = 1, i = 0x424; i <= 0x430; i++, x++)
++ cx25840_write(client, i, lcr[9 + x]);
++ for (i = 0x431; i <= 0x434; i++)
++ cx25840_write(client, i, 0);
+ }
+
+- case VIDIOC_INT_DECODE_VBI_LINE:
+- {
+- struct v4l2_decode_vbi_line *vbi = arg;
+- u8 *p = vbi->p;
+- int id1, id2, l, err = 0;
++ cx25840_write(client, 0x43c, 0x16);
++ cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22);
++ return 0;
++}
+
+- if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+- (p[3] != 0x55 && p[3] != 0x91)) {
+- vbi->line = vbi->type = 0;
+- break;
+- }
++int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
++{
++ struct cx25840_state *state = to_state(sd);
++ u8 *p = vbi->p;
++ int id1, id2, l, err = 0;
++
++ if (p[0] || p[1] != 0xff || p[2] != 0xff ||
++ (p[3] != 0x55 && p[3] != 0x91)) {
++ vbi->line = vbi->type = 0;
++ return 0;
++ }
+
+- p += 4;
+- id1 = p[-1];
+- id2 = p[0] & 0xf;
+- l = p[2] & 0x3f;
+- l += state->vbi_line_offset;
+- p += 4;
++ p += 4;
++ id1 = p[-1];
++ id2 = p[0] & 0xf;
++ l = p[2] & 0x3f;
++ l += state->vbi_line_offset;
++ p += 4;
+
+- switch (id2) {
+- case 1:
+- id2 = V4L2_SLICED_TELETEXT_B;
+- break;
+- case 4:
+- id2 = V4L2_SLICED_WSS_625;
+- break;
+- case 6:
+- id2 = V4L2_SLICED_CAPTION_525;
+- err = !odd_parity(p[0]) || !odd_parity(p[1]);
+- break;
+- case 9:
+- id2 = V4L2_SLICED_VPS;
+- if (decode_vps(p, p) != 0) {
+- err = 1;
+- }
+- break;
+- default:
+- id2 = 0;
++ switch (id2) {
++ case 1:
++ id2 = V4L2_SLICED_TELETEXT_B;
++ break;
++ case 4:
++ id2 = V4L2_SLICED_WSS_625;
++ break;
++ case 6:
++ id2 = V4L2_SLICED_CAPTION_525;
++ err = !odd_parity(p[0]) || !odd_parity(p[1]);
++ break;
++ case 9:
++ id2 = V4L2_SLICED_VPS;
++ if (decode_vps(p, p) != 0)
+ err = 1;
+- break;
+- }
+-
+- vbi->type = err ? 0 : id2;
+- vbi->line = err ? 0 : l;
+- vbi->is_second_field = err ? 0 : (id1 == 0x55);
+- vbi->p = p;
+ break;
+- }
++ default:
++ id2 = 0;
++ err = 1;
++ break;
+ }
+
++ vbi->type = err ? 0 : id2;
++ vbi->line = err ? 0 : l;
++ vbi->is_second_field = err ? 0 : (id1 == 0x55);
++ vbi->p = p;
+ return 0;
+ }
+diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
+index 2d250a2..4995298 100644
+--- a/drivers/media/video/cx88/Kconfig
++++ b/drivers/media/video/cx88/Kconfig
+@@ -61,7 +61,7 @@ config VIDEO_CX88_DVB
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_STV0288 if !DVB_FE_CUSTOMISE
+ select DVB_STB6000 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
++ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
+ ---help---
+ This adds support for DVB/ATSC cards based on the
+ Conexant 2388x chip.
+diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
+index 7f5b8bf..44eacfb 100644
+--- a/drivers/media/video/cx88/cx88-blackbird.c
++++ b/drivers/media/video/cx88/cx88-blackbird.c
+@@ -746,7 +746,6 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
+ return -EINVAL;
+
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+ return 0;
+ }
+@@ -757,7 +756,6 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
+@@ -776,7 +774,6 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+@@ -793,7 +790,6 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
+ struct cx8802_dev *dev = fh->dev;
+ struct cx88_core *core = dev->core;
+
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+@@ -919,7 +915,7 @@ static int vidioc_log_status (struct file *file, void *priv)
+ snprintf(name, sizeof(name), "%s/2", core->name);
+ printk("%s/2: ============ START LOG STATUS ============\n",
+ core->name);
+- cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
++ call_all(core, core, log_status);
+ cx2341x_log_status(&dev->params, name);
+ printk("%s/2: ============= END LOG STATUS =============\n",
+ core->name);
+@@ -974,7 +970,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
+
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = core->freq;
+- cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
++ call_all(core, tuner, g_frequency, f);
+
+ return 0;
+ }
+diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
+index 733ede3..0363971 100644
+--- a/drivers/media/video/cx88/cx88-cards.c
++++ b/drivers/media/video/cx88/cx88-cards.c
+@@ -732,6 +732,8 @@ static const struct cx88_board cx88_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ /* Some variants use a tda9874 and so need the tvaudio module. */
++ .audio_chip = V4L2_IDENT_TVAUDIO,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+@@ -1934,6 +1936,39 @@ static const struct cx88_board cx88_boards[] = {
+ } },
+ .mpeg = CX88_MPEG_DVB,
+ },
++ [CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII] = {
++ .name = "Terratec Cinergy HT PCI MKII",
++ .tuner_type = TUNER_XC2028,
++ .tuner_addr = 0x61,
++ .radio_type = TUNER_XC2028,
++ .radio_addr = 0x61,
++ .input = { {
++ .type = CX88_VMUX_TELEVISION,
++ .vmux = 0,
++ .gpio0 = 0x004ff,
++ .gpio1 = 0x010ff,
++ .gpio2 = 0x00001,
++ }, {
++ .type = CX88_VMUX_COMPOSITE1,
++ .vmux = 1,
++ .gpio0 = 0x004fb,
++ .gpio1 = 0x010ef,
++ .audioroute = 1,
++ }, {
++ .type = CX88_VMUX_SVIDEO,
++ .vmux = 2,
++ .gpio0 = 0x004fb,
++ .gpio1 = 0x010ef,
++ .audioroute = 1,
++ } },
++ .radio = {
++ .type = CX88_RADIO,
++ .gpio0 = 0x004ff,
++ .gpio1 = 0x010ff,
++ .gpio2 = 0x0ff,
++ },
++ .mpeg = CX88_MPEG_DVB,
++ },
+ };
+
+ /* ------------------------------------------------------------------ */
+@@ -2343,6 +2378,10 @@ static const struct cx88_subid cx88_subids[] = {
+ .subvendor = 0xb200,
+ .subdevice = 0x4200,
+ .card = CX88_BOARD_SATTRADE_ST4200,
++ }, {
++ .subvendor = 0x153b,
++ .subdevice = 0x1177,
++ .card = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII,
+ },
+ };
+
+@@ -2819,6 +2858,7 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
+ */
+ break;
+ case CX88_BOARD_PINNACLE_HYBRID_PCTV:
++ case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
+ ctl->demod = XC3028_FE_ZARLINK456;
+ ctl->mts = 1;
+ break;
+@@ -2947,7 +2987,7 @@ static void cx88_card_setup(struct cx88_core *core)
+ tea5767_cfg.tuner = TUNER_TEA5767;
+ tea5767_cfg.priv = &ctl;
+
+- cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
++ call_all(core, tuner, s_config, &tea5767_cfg);
+ break;
+ }
+ case CX88_BOARD_TEVII_S420:
+@@ -2972,7 +3012,7 @@ static void cx88_card_setup(struct cx88_core *core)
+ tun_setup.type = core->board.radio_type;
+ tun_setup.addr = core->board.radio_addr;
+ tun_setup.tuner_callback = cx88_tuner_callback;
+- cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
++ call_all(core, tuner, s_type_addr, &tun_setup);
+ mode_mask &= ~T_RADIO;
+ }
+
+@@ -2982,7 +3022,7 @@ static void cx88_card_setup(struct cx88_core *core)
+ tun_setup.addr = core->board.tuner_addr;
+ tun_setup.tuner_callback = cx88_tuner_callback;
+
+- cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
++ call_all(core, tuner, s_type_addr, &tun_setup);
+ }
+
+ if (core->board.tda9887_conf) {
+@@ -2991,7 +3031,7 @@ static void cx88_card_setup(struct cx88_core *core)
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &core->board.tda9887_conf;
+
+- cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg);
++ call_all(core, tuner, s_config, &tda9887_cfg);
+ }
+
+ if (core->board.tuner_type == TUNER_XC2028) {
+@@ -3007,9 +3047,9 @@ static void cx88_card_setup(struct cx88_core *core)
+ xc2028_cfg.priv = &ctl;
+ info_printk(core, "Asking xc2028/3028 to load firmware %s\n",
+ ctl.fname);
+- cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg);
++ call_all(core, tuner, s_config, &xc2028_cfg);
+ }
+- cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
++ call_all(core, core, s_standby, 0);
+ }
+
+ /* ------------------------------------------------------------------ */
+@@ -3089,6 +3129,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
+ int i;
+
+ core = kzalloc(sizeof(*core), GFP_KERNEL);
++ if (core == NULL)
++ return NULL;
+
+ atomic_inc(&core->refcount);
+ core->pci_bus = pci->bus->number;
+@@ -3100,7 +3142,15 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
+
+ core->nr = nr;
+ sprintf(core->name, "cx88[%d]", core->nr);
++
++ strcpy(core->v4l2_dev.name, core->name);
++ if (v4l2_device_register(NULL, &core->v4l2_dev)) {
++ kfree(core);
++ return NULL;
++ }
++
+ if (0 != cx88_get_resources(core, pci)) {
++ v4l2_device_unregister(&core->v4l2_dev);
+ kfree(core);
+ return NULL;
+ }
+@@ -3111,6 +3161,11 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
+ pci_resource_len(pci, 0));
+ core->bmmio = (u8 __iomem *)core->lmmio;
+
++ if (core->lmmio == NULL) {
++ kfree(core);
++ return NULL;
++ }
++
+ /* board config */
+ core->boardnr = UNSET;
+ if (card[core->nr] < ARRAY_SIZE(cx88_boards))
+@@ -3149,8 +3204,36 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
+ cx88_i2c_init(core, pci);
+
+ /* load tuner module, if needed */
+- if (TUNER_ABSENT != core->board.tuner_type)
+- request_module("tuner");
++ if (TUNER_ABSENT != core->board.tuner_type) {
++ /* Ignore 0x6b and 0x6f on cx88 boards.
++ * FusionHDTV5 RT Gold has an ir receiver at 0x6b
++ * and an RTC at 0x6f which can get corrupted if probed. */
++ static const unsigned short tv_addrs[] = {
++ 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
++ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
++ 0x68, 0x69, 0x6a, 0x6c, 0x6d, 0x6e,
++ I2C_CLIENT_END
++ };
++ int has_demod = (core->board.tda9887_conf & TDA9887_PRESENT);
++
++ /* I don't trust the radio_type as is stored in the card
++ definitions, so we just probe for it.
++ The radio_type is sometimes missing, or set to UNSET but
++ later code configures a tea5767.
++ */
++ v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner", "tuner",
++ v4l2_i2c_tuner_addrs(ADDRS_RADIO));
++ if (has_demod)
++ v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner",
++ "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
++ if (core->board.tuner_addr == ADDR_UNSET) {
++ v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner",
++ "tuner", has_demod ? tv_addrs + 4 : tv_addrs);
++ } else {
++ v4l2_i2c_new_subdev(&core->i2c_adap,
++ "tuner", "tuner", core->board.tuner_addr);
++ }
++ }
+
+ cx88_card_setup(core);
+ cx88_ir_init(core, pci);
+diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
+index b045874..f2fb9f3 100644
+--- a/drivers/media/video/cx88/cx88-core.c
++++ b/drivers/media/video/cx88/cx88-core.c
+@@ -991,7 +991,7 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
+ set_tvaudio(core);
+
+ // tell i2c chips
+- cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
++ call_all(core, tuner, s_std, norm);
+
+ // done
+ return 0;
+@@ -1011,7 +1011,8 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
+ return NULL;
+ *vfd = *template;
+ vfd->minor = -1;
+- vfd->parent = &pci->dev;
++ vfd->v4l2_dev = &core->v4l2_dev;
++ vfd->parent = &pci->dev;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+ core->name, type, core->board.name);
+@@ -1058,12 +1059,16 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
+
+ mutex_lock(&devlist);
+ cx88_ir_fini(core);
+- if (0 == core->i2c_rc)
++ if (0 == core->i2c_rc) {
++ if (core->i2c_rtc)
++ i2c_unregister_device(core->i2c_rtc);
+ i2c_del_adapter(&core->i2c_adap);
++ }
+ list_del(&core->devlist);
+ iounmap(core->lmmio);
+ cx88_devcount--;
+ mutex_unlock(&devlist);
++ v4l2_device_unregister(&core->v4l2_dev);
+ kfree(core);
+ }
+
+diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
+index aef5297..4ff4d9f 100644
+--- a/drivers/media/video/cx88/cx88-dvb.c
++++ b/drivers/media/video/cx88/cx88-dvb.c
+@@ -241,6 +241,12 @@ static struct mt352_config dvico_fusionhdtv_dual = {
+ .demod_init = dvico_dual_demod_init,
+ };
+
++static struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
++ .demod_address = (0x1e >> 1),
++ .no_tuner = 1,
++ .if2 = 45600,
++};
++
+ #if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+ static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
+ {
+@@ -1131,6 +1137,16 @@ static int dvb_register(struct cx8802_dev *dev)
+ if (fe0->dvb.frontend != NULL)
+ fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+ break;
++ case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
++ fe0->dvb.frontend = dvb_attach(zl10353_attach,
++ &cx88_terratec_cinergy_ht_pci_mkii_config,
++ &core->i2c_adap);
++ if (fe0->dvb.frontend) {
++ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
++ if (attach_xc3028(0x61, dev) < 0)
++ goto frontend_detach;
++ }
++ break;
+ default:
+ printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
+ core->name);
+@@ -1152,7 +1168,7 @@ static int dvb_register(struct cx8802_dev *dev)
+ fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
+
+ /* Put the analog decoder in standby to keep it quiet */
+- cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
++ call_all(core, core, s_standby, 0);
+
+ /* register everything */
+ return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
+index c0ff230..996b4ed 100644
+--- a/drivers/media/video/cx88/cx88-i2c.c
++++ b/drivers/media/video/cx88/cx88-i2c.c
+@@ -97,37 +97,6 @@ static int cx8800_bit_getsda(void *data)
+
+ /* ----------------------------------------------------------------------- */
+
+-static int attach_inform(struct i2c_client *client)
+-{
+- struct cx88_core *core = i2c_get_adapdata(client->adapter);
+-
+- dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+- client->driver->driver.name, client->addr, client->name);
+- return 0;
+-}
+-
+-static int detach_inform(struct i2c_client *client)
+-{
+- struct cx88_core *core = i2c_get_adapdata(client->adapter);
+-
+- dprintk(1, "i2c detach [client=%s]\n", client->name);
+- return 0;
+-}
+-
+-void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
+-{
+- if (0 != core->i2c_rc)
+- return;
+-
+- if (core->gate_ctrl)
+- core->gate_ctrl(core, 1);
+-
+- i2c_clients_command(&core->i2c_adap, cmd, arg);
+-
+- if (core->gate_ctrl)
+- core->gate_ctrl(core, 0);
+-}
+-
+ static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
+ .setsda = cx8800_bit_setsda,
+ .setscl = cx8800_bit_setscl,
+@@ -173,20 +142,14 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
+ memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
+ sizeof(core->i2c_algo));
+
+- if (core->board.tuner_type != TUNER_ABSENT)
+- core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
+- if (core->board.mpeg & CX88_MPEG_DVB)
+- core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
+
+ core->i2c_adap.dev.parent = &pci->dev;
+ strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
+ core->i2c_adap.owner = THIS_MODULE;
+ core->i2c_adap.id = I2C_HW_B_CX2388x;
+- core->i2c_adap.client_register = attach_inform;
+- core->i2c_adap.client_unregister = detach_inform;
+ core->i2c_algo.udelay = i2c_udelay;
+ core->i2c_algo.data = core;
+- i2c_set_adapdata(&core->i2c_adap,core);
++ i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
+ core->i2c_adap.algo_data = &core->i2c_algo;
+ core->i2c_client.adapter = &core->i2c_adap;
+ strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
+@@ -222,8 +185,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
+
+ /* ----------------------------------------------------------------------- */
+
+-EXPORT_SYMBOL(cx88_call_i2c_clients);
+-
+ /*
+ * Local variables:
+ * c-basic-offset: 8
+diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
+index 8683d10..ec05312 100644
+--- a/drivers/media/video/cx88/cx88-input.c
++++ b/drivers/media/video/cx88/cx88-input.c
+@@ -48,8 +48,7 @@ struct cx88_IR {
+
+ /* poll external decoder */
+ int polling;
+- struct work_struct work;
+- struct timer_list timer;
++ struct delayed_work work;
+ u32 gpio_addr;
+ u32 last_gpio;
+ u32 mask_keycode;
+@@ -143,27 +142,19 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
+ }
+ }
+
+-static void ir_timer(unsigned long data)
+-{
+- struct cx88_IR *ir = (struct cx88_IR *)data;
+-
+- schedule_work(&ir->work);
+-}
+-
+ static void cx88_ir_work(struct work_struct *work)
+ {
+- struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
++ struct cx88_IR *ir = container_of(work, struct cx88_IR, work.work);
+
+ cx88_ir_handle_key(ir);
+- mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
++ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+ }
+
+ void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
+ {
+ if (ir->polling) {
+- setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
+- INIT_WORK(&ir->work, cx88_ir_work);
+- schedule_work(&ir->work);
++ INIT_DELAYED_WORK(&ir->work, cx88_ir_work);
++ schedule_delayed_work(&ir->work, 0);
+ }
+ if (ir->sampling) {
+ core->pci_irqmask |= PCI_INT_IR_SMPINT;
+@@ -179,10 +170,8 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
+ core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
+ }
+
+- if (ir->polling) {
+- del_timer_sync(&ir->timer);
+- flush_scheduled_work();
+- }
++ if (ir->polling)
++ cancel_delayed_work_sync(&ir->work);
+ }
+
+ /* ---------------------------------------------------------------------- */
+@@ -226,6 +215,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ case CX88_BOARD_HAUPPAUGE_HVR4000:
+ case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
++ case CX88_BOARD_PCHDTV_HD3000:
++ case CX88_BOARD_PCHDTV_HD5500:
+ ir_codes = ir_codes_hauppauge_new;
+ ir_type = IR_TYPE_RC5;
+ ir->sampling = 1;
+@@ -466,6 +457,8 @@ void cx88_ir_irq(struct cx88_core *core)
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ case CX88_BOARD_HAUPPAUGE_HVR4000:
+ case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
++ case CX88_BOARD_PCHDTV_HD3000:
++ case CX88_BOARD_PCHDTV_HD5500:
+ ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
+ ir_dprintk("biphase decoded: %x\n", ircode);
+ /*
+diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
+index 791e69d..434237a 100644
+--- a/drivers/media/video/cx88/cx88-video.c
++++ b/drivers/media/video/cx88/cx88-video.c
+@@ -41,11 +41,6 @@
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-ioctl.h>
+
+-#ifdef CONFIG_VIDEO_V4L1_COMPAT
+-/* Include V4L1 specific functions. Should be removed soon */
+-#include <linux/videodev.h>
+-#endif
+-
+ MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
+ MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+ MODULE_LICENSE("GPL");
+@@ -298,6 +293,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
+ };
+ static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);
+
++/* Must be sorted from low to high control ID! */
+ const u32 cx88_user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+@@ -435,8 +431,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
+ struct v4l2_routing route;
+
+ route.input = INPUT(input).audioroute;
+- cx88_call_i2c_clients(core,
+- VIDIOC_INT_S_AUDIO_ROUTING, &route);
++ call_all(core, audio, s_routing, &route);
+ }
+ /* cx2388's C-ADC is connected to the tuner only.
+ When used with S-Video, that ADC is busy dealing with
+@@ -831,8 +826,7 @@ static int video_open(struct file *file)
+ struct v4l2_routing route;
+
+ route.input = core->board.radio.audioroute;
+- cx88_call_i2c_clients(core,
+- VIDIOC_INT_S_AUDIO_ROUTING, &route);
++ call_all(core, audio, s_routing, &route);
+ }
+ /* "I2S ADC mode" */
+ core->tvaudio = WW_I2SADC;
+@@ -843,7 +837,7 @@ static int video_open(struct file *file)
+ cx88_set_tvaudio(core);
+ cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
+ }
+- cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
++ call_all(core, tuner, s_radio);
+ }
+ unlock_kernel();
+
+@@ -937,7 +931,7 @@ static int video_release(struct file *file)
+ kfree(fh);
+
+ if(atomic_dec_and_test(&dev->core->users))
+- cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
++ call_all(dev->core, core, s_standby, 0);
+
+ return 0;
+ }
+@@ -1276,15 +1270,12 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
+ [ CX88_VMUX_DVB ] = "DVB",
+ [ CX88_VMUX_DEBUG ] = "for debug only",
+ };
+- unsigned int n;
++ unsigned int n = i->index;
+
+- n = i->index;
+ if (n >= 4)
+ return -EINVAL;
+ if (0 == INPUT(n).type)
+ return -EINVAL;
+- memset(i,0,sizeof(*i));
+- i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(i->name,iname[INPUT(n).type]);
+ if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
+@@ -1402,7 +1393,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
+ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->frequency = core->freq;
+
+- cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
++ call_all(core, tuner, g_frequency, f);
+
+ return 0;
+ }
+@@ -1418,7 +1409,7 @@ int cx88_set_freq (struct cx88_core *core,
+ mutex_lock(&core->lock);
+ core->freq = f->frequency;
+ cx88_newstation(core);
+- cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
++ call_all(core, tuner, s_frequency, f);
+
+ /* When changing channels it is required to reset TVAUDIO */
+ msleep (10);
+@@ -1500,7 +1491,7 @@ static int radio_g_tuner (struct file *file, void *priv,
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
+
+- cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
++ call_all(core, tuner, g_tuner, t);
+ return 0;
+ }
+
+@@ -1520,7 +1511,6 @@ static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+ if (unlikely(a->index))
+ return -EINVAL;
+
+- memset(a,0,sizeof(*a));
+ strcpy(a->name,"Radio");
+ return 0;
+ }
+@@ -1535,7 +1525,7 @@ static int radio_s_tuner (struct file *file, void *priv,
+ if (0 != t->index)
+ return -EINVAL;
+
+- cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
++ call_all(core, tuner, s_tuner, t);
+
+ return 0;
+ }
+@@ -1892,12 +1882,30 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
+ /* load and configure helper modules */
+
+ if (core->board.audio_chip == V4L2_IDENT_WM8775)
+- request_module("wm8775");
++ v4l2_i2c_new_subdev(&core->i2c_adap,
++ "wm8775", "wm8775", 0x36 >> 1);
++
++ if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
++ /* This probes for a tda9874 as is used on some
++ Pixelview Ultra boards. */
++ static const unsigned short i2c_addr[] = {
++ 0xb0 >> 1, I2C_CLIENT_END
++ };
++
++ v4l2_i2c_new_probed_subdev(&core->i2c_adap,
++ "tvaudio", "tvaudio", i2c_addr);
++ }
+
+ switch (core->boardnr) {
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+- case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
++ case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: {
++ static struct i2c_board_info rtc_info = {
++ I2C_BOARD_INFO("isl1208", 0x6f)
++ };
++
+ request_module("rtc-isl1208");
++ core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info);
++ }
+ /* break intentionally omitted */
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+ request_module("ir-kbd-i2c");
+diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
+index 6025fdd..9a43fdf 100644
+--- a/drivers/media/video/cx88/cx88.h
++++ b/drivers/media/video/cx88/cx88.h
+@@ -25,7 +25,7 @@
+ #include <linux/videodev2.h>
+ #include <linux/kdev_t.h>
+
+-#include <media/v4l2-common.h>
++#include <media/v4l2-device.h>
+ #include <media/tuner.h>
+ #include <media/tveeprom.h>
+ #include <media/videobuf-dma-sg.h>
+@@ -231,6 +231,7 @@ extern struct sram_channel cx88_sram_channels[];
+ #define CX88_BOARD_SATTRADE_ST4200 76
+ #define CX88_BOARD_TBS_8910 77
+ #define CX88_BOARD_PROF_6200 78
++#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
+
+ enum cx88_itype {
+ CX88_VMUX_COMPOSITE1 = 1,
+@@ -302,7 +303,6 @@ struct cx88_dmaqueue {
+ struct btcx_riscmem stopper;
+ u32 count;
+ };
+-struct cx88_core;
+
+ struct cx88_core {
+ struct list_head devlist;
+@@ -327,6 +327,8 @@ struct cx88_core {
+ u32 i2c_state, i2c_rc;
+
+ /* config info -- analog */
++ struct v4l2_device v4l2_dev;
++ struct i2c_client *i2c_rtc;
+ unsigned int boardnr;
+ struct cx88_board board;
+
+@@ -365,6 +367,22 @@ struct cx88_core {
+ int active_fe_id;
+ };
+
++static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
++{
++ return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
++}
++
++#define call_all(core, o, f, args...) \
++ do { \
++ if (!core->i2c_rc) { \
++ if (core->gate_ctrl) \
++ core->gate_ctrl(core, 1); \
++ v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \
++ if (core->gate_ctrl) \
++ core->gate_ctrl(core, 0); \
++ } \
++ } while (0)
++
+ struct cx8800_dev;
+ struct cx8802_dev;
+
+@@ -610,8 +628,6 @@ extern struct videobuf_queue_ops cx8800_vbi_qops;
+ /* cx88-i2c.c */
+
+ extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
+-extern void cx88_call_i2c_clients(struct cx88_core *core,
+- unsigned int cmd, void *arg);
+
+
+ /* ----------------------------------------------------------- */
+diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
+index 298810d..ba3709b 100644
+--- a/drivers/media/video/dabusb.c
++++ b/drivers/media/video/dabusb.c
+@@ -189,17 +189,20 @@ static void dabusb_iso_complete (struct urb *purb)
+ dst += len;
+ }
+ else
+- err("dabusb_iso_complete: invalid len %d", len);
++ dev_err(&purb->dev->dev,
++ "dabusb_iso_complete: invalid len %d\n", len);
+ }
+ else
+ dev_warn(&purb->dev->dev, "dabusb_iso_complete: corrupted packet status: %d\n", purb->iso_frame_desc[i].status);
+ if (dst != purb->actual_length)
+- err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length);
++ dev_err(&purb->dev->dev,
++ "dst!=purb->actual_length:%d!=%d\n",
++ dst, purb->actual_length);
+ }
+
+ if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) {
+ s->overruns++;
+- err("overrun (%d)", s->overruns);
++ dev_err(&purb->dev->dev, "overrun (%d)\n", s->overruns);
+ }
+ wake_up (&s->wait);
+ }
+@@ -220,13 +223,14 @@ static int dabusb_alloc_buffers (pdabusb_t s)
+ while (transfer_len < (s->total_buffer_size << 10)) {
+ b = kzalloc(sizeof (buff_t), GFP_KERNEL);
+ if (!b) {
+- err("kzalloc(sizeof(buff_t))==NULL");
++ dev_err(&s->usbdev->dev,
++ "kzalloc(sizeof(buff_t))==NULL\n");
+ goto err;
+ }
+ b->s = s;
+ b->purb = usb_alloc_urb(packets, GFP_KERNEL);
+ if (!b->purb) {
+- err("usb_alloc_urb == NULL");
++ dev_err(&s->usbdev->dev, "usb_alloc_urb == NULL\n");
+ kfree (b);
+ goto err;
+ }
+@@ -235,7 +239,8 @@ static int dabusb_alloc_buffers (pdabusb_t s)
+ if (!b->purb->transfer_buffer) {
+ kfree (b->purb);
+ kfree (b);
+- err("kmalloc(%d)==NULL", transfer_buffer_length);
++ dev_err(&s->usbdev->dev,
++ "kmalloc(%d)==NULL\n", transfer_buffer_length);
+ goto err;
+ }
+
+@@ -279,10 +284,11 @@ static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
+
+ ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100);
+ if(ret<0) {
+- err("dabusb: usb_bulk_msg failed(%d)",ret);
++ dev_err(&s->usbdev->dev,
++ "usb_bulk_msg failed(%d)\n", ret);
+
+ if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
+- err("set_interface failed");
++ dev_err(&s->usbdev->dev, "set_interface failed\n");
+ return -EINVAL;
+ }
+
+@@ -291,7 +297,7 @@ static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
+ if( ret == -EPIPE ) {
+ dev_warn(&s->usbdev->dev, "CLEAR_FEATURE request to remove STALL condition.\n");
+ if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
+- err("request failed");
++ dev_err(&s->usbdev->dev, "request failed\n");
+ }
+
+ pb->size = actual_length;
+@@ -305,7 +311,8 @@ static int dabusb_writemem (pdabusb_t s, int pos, const unsigned char *data,
+ unsigned char *transfer_buffer = kmalloc (len, GFP_KERNEL);
+
+ if (!transfer_buffer) {
+- err("dabusb_writemem: kmalloc(%d) failed.", len);
++ dev_err(&s->usbdev->dev,
++ "dabusb_writemem: kmalloc(%d) failed.\n", len);
+ return -ENOMEM;
+ }
+
+@@ -327,13 +334,14 @@ static int dabusb_loadmem (pdabusb_t s, const char *fname)
+ {
+ int ret;
+ const struct ihex_binrec *rec;
+- const struct firmware *fw;
++ const struct firmware *uninitialized_var(fw);
+
+ dbg("Enter dabusb_loadmem (internal)");
+
+ ret = request_ihex_firmware(&fw, "dabusb/firmware.fw", &s->usbdev->dev);
+ if (ret) {
+- err("Failed to load \"dabusb/firmware.fw\": %d\n", ret);
++ dev_err(&s->usbdev->dev,
++ "Failed to load \"dabusb/firmware.fw\": %d\n", ret);
+ goto out;
+ }
+ ret = dabusb_8051_reset (s, 1);
+@@ -346,9 +354,10 @@ static int dabusb_loadmem (pdabusb_t s, const char *fname)
+ ret = dabusb_writemem(s, be32_to_cpu(rec->addr), rec->data,
+ be16_to_cpu(rec->len));
+ if (ret < 0) {
+- err("dabusb_writemem failed (%d %04X %p %d)", ret,
+- be32_to_cpu(rec->addr), rec->data,
+- be16_to_cpu(rec->len));
++ dev_err(&s->usbdev->dev,
++ "dabusb_writemem failed (%d %04X %p %d)\n",
++ ret, be32_to_cpu(rec->addr),
++ rec->data, be16_to_cpu(rec->len));
+ break;
+ }
+ }
+@@ -396,13 +405,15 @@ static int dabusb_fpga_download (pdabusb_t s, const char *fname)
+ dbg("Enter dabusb_fpga_download (internal)");
+
+ if (!b) {
+- err("kmalloc(sizeof(bulk_transfer_t))==NULL");
++ dev_err(&s->usbdev->dev,
++ "kmalloc(sizeof(bulk_transfer_t))==NULL\n");
+ return -ENOMEM;
+ }
+
+ ret = request_firmware(&fw, "dabusb/bitstream.bin", &s->usbdev->dev);
+ if (ret) {
+- err("Failed to load \"dabusb/bitstream.bin\": %d\n", ret);
++ dev_err(&s->usbdev->dev,
++ "Failed to load \"dabusb/bitstream.bin\": %d\n", ret);
+ kfree(b);
+ return ret;
+ }
+@@ -425,7 +436,7 @@ static int dabusb_fpga_download (pdabusb_t s, const char *fname)
+ memcpy (b->data + 4, fw->data + 74 + n, 60);
+ ret = dabusb_bulk (s, b);
+ if (ret < 0) {
+- err("dabusb_bulk failed.");
++ dev_err(&s->usbdev->dev, "dabusb_bulk failed.\n");
+ break;
+ }
+ mdelay (1);
+@@ -478,9 +489,11 @@ static int dabusb_startrek (pdabusb_t s)
+
+ ret = usb_submit_urb (end->purb, GFP_KERNEL);
+ if (ret) {
+- err("usb_submit_urb returned:%d", ret);
++ dev_err(&s->usbdev->dev,
++ "usb_submit_urb returned:%d\n", ret);
+ if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
+- err("startrek: dabusb_add_buf_tail failed");
++ dev_err(&s->usbdev->dev,
++ "startrek: dabusb_add_buf_tail failed\n");
+ break;
+ }
+ else
+@@ -523,7 +536,8 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
+
+ spin_unlock_irqrestore(&s->lock, flags);
+
+- err("error: rec_buf_list is empty");
++ dev_err(&s->usbdev->dev,
++ "error: rec_buf_list is empty\n");
+ goto err;
+ }
+
+@@ -552,7 +566,8 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
+
+ if (list_empty (&s->rec_buff_list)) {
+ spin_unlock_irqrestore(&s->lock, flags);
+- err("error: still no buffer available.");
++ dev_err(&s->usbdev->dev,
++ "error: still no buffer available.\n");
+ goto err;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+@@ -573,7 +588,7 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
+ dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt);
+
+ if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) {
+- err("read: copy_to_user failed");
++ dev_err(&s->usbdev->dev, "read: copy_to_user failed\n");
+ if (!ret)
+ ret = -EFAULT;
+ goto err;
+@@ -587,7 +602,8 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
+ if (s->readptr == purb->actual_length) {
+ // finished, take next buffer
+ if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
+- err("read: dabusb_add_buf_tail failed");
++ dev_err(&s->usbdev->dev,
++ "read: dabusb_add_buf_tail failed\n");
+ s->readptr = 0;
+ }
+ }
+@@ -623,7 +639,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
+ }
+ if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
+ mutex_unlock(&s->mutex);
+- err("set_interface failed");
++ dev_err(&s->usbdev->dev, "set_interface failed\n");
+ return -EINVAL;
+ }
+ s->opened = 1;
+@@ -648,7 +664,7 @@ static int dabusb_release (struct inode *inode, struct file *file)
+
+ if (!s->remove_pending) {
+ if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
+- err("set_interface failed");
++ dev_err(&s->usbdev->dev, "set_interface failed\n");
+ }
+ else
+ wake_up (&s->remove_ok);
+@@ -657,7 +673,7 @@ static int dabusb_release (struct inode *inode, struct file *file)
+ return 0;
+ }
+
+-static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static long dabusb_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ pdabusb_t s = (pdabusb_t) file->private_data;
+ pbulk_transfer_t pbulk;
+@@ -666,13 +682,17 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
+
+ dbg("dabusb_ioctl");
+
+- if (s->remove_pending)
++ lock_kernel();
++ if (s->remove_pending) {
++ unlock_kernel();
+ return -EIO;
++ }
+
+ mutex_lock(&s->mutex);
+
+ if (!s->usbdev) {
+ mutex_unlock(&s->mutex);
++ unlock_kernel();
+ return -EIO;
+ }
+
+@@ -713,6 +733,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
+ break;
+ }
+ mutex_unlock(&s->mutex);
++ unlock_kernel();
+ return ret;
+ }
+
+@@ -721,7 +742,7 @@ static const struct file_operations dabusb_fops =
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = dabusb_read,
+- .ioctl = dabusb_ioctl,
++ .unlocked_ioctl = dabusb_ioctl,
+ .open = dabusb_open,
+ .release = dabusb_release,
+ };
+@@ -764,7 +785,7 @@ static int dabusb_probe (struct usb_interface *intf,
+ s->devnum = intf->minor;
+
+ if (usb_reset_configuration (usbdev) < 0) {
+- err("reset_configuration failed");
++ dev_err(&intf->dev, "reset_configuration failed\n");
+ goto reject;
+ }
+ if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) {
+@@ -775,7 +796,7 @@ static int dabusb_probe (struct usb_interface *intf,
+ dabusb_fpga_download (s, NULL);
+
+ if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) {
+- err("set_interface failed");
++ dev_err(&intf->dev, "set_interface failed\n");
+ goto reject;
+ }
+ }
+diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
+index 2ac738f..6b96275 100644
+--- a/drivers/media/video/em28xx/em28xx-audio.c
++++ b/drivers/media/video/em28xx/em28xx-audio.c
+@@ -56,7 +56,7 @@ MODULE_PARM_DESC(debug, "activates debug info");
+
+ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+
+-static int em28xx_isoc_audio_deinit(struct em28xx *dev)
++static int em28xx_deinit_isoc_audio(struct em28xx *dev)
+ {
+ int i;
+
+@@ -66,6 +66,7 @@ static int em28xx_isoc_audio_deinit(struct em28xx *dev)
+ usb_kill_urb(dev->adev.urb[i]);
+ else
+ usb_unlink_urb(dev->adev.urb[i]);
++
+ usb_free_urb(dev->adev.urb[i]);
+ dev->adev.urb[i] = NULL;
+
+@@ -87,6 +88,20 @@ static void em28xx_audio_isocirq(struct urb *urb)
+ unsigned int stride;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
++
++ switch (urb->status) {
++ case 0: /* success */
++ case -ETIMEDOUT: /* NAK */
++ break;
++ case -ECONNRESET: /* kill */
++ case -ENOENT:
++ case -ESHUTDOWN:
++ return;
++ default: /* error */
++ dprintk("urb completition error %d.\n", urb->status);
++ break;
++ }
++
+ if (dev->adev.capture_pcm_substream) {
+ substream = dev->adev.capture_pcm_substream;
+ runtime = substream->runtime;
+@@ -137,9 +152,6 @@ static void em28xx_audio_isocirq(struct urb *urb)
+ }
+ urb->status = 0;
+
+- if (dev->adev.shutdown)
+- return;
+-
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
+@@ -197,8 +209,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
+ for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+ errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
+ if (errCode) {
+- em28xx_isoc_audio_deinit(dev);
+-
++ em28xx_deinit_isoc_audio(dev);
+ return errCode;
+ }
+ }
+@@ -213,14 +224,16 @@ static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
+
+ switch (cmd) {
+ case EM28XX_CAPTURE_STREAM_EN:
+- if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
++ if (dev->adev.capture_stream == STREAM_OFF &&
++ arg == EM28XX_START_AUDIO) {
+ dev->adev.capture_stream = STREAM_ON;
+ em28xx_init_audio_isoc(dev);
+- } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
++ } else if (dev->adev.capture_stream == STREAM_ON &&
++ arg == EM28XX_STOP_AUDIO) {
+ dev->adev.capture_stream = STREAM_OFF;
+- em28xx_isoc_audio_deinit(dev);
++ em28xx_deinit_isoc_audio(dev);
+ } else {
+- printk(KERN_ERR "An underrun very likely occurred. "
++ em28xx_errdev("An underrun very likely occurred. "
+ "Ignoring it.\n");
+ }
+ return 0;
+@@ -234,7 +247,7 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+ {
+ struct snd_pcm_runtime *runtime = subs->runtime;
+
+- dprintk("Alocating vbuffer\n");
++ dprintk("Allocating vbuffer\n");
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+@@ -302,7 +315,9 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
+ dprintk("changing alternate number to 7\n");
+ }
+
++ mutex_lock(&dev->lock);
+ dev->adev.users++;
++ mutex_unlock(&dev->lock);
+
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ dev->adev.capture_pcm_substream = substream;
+@@ -317,22 +332,15 @@ err:
+ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
+ {
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+- dev->adev.users--;
+
+ dprintk("closing device\n");
+
+ dev->mute = 1;
+ mutex_lock(&dev->lock);
++ dev->adev.users--;
+ em28xx_audio_analog_set(dev);
+ mutex_unlock(&dev->lock);
+
+- if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
+- dprintk("audio users: %d\n", dev->adev.users);
+- dprintk("disabling audio stream!\n");
+- dev->adev.shutdown = 0;
+- dprintk("released lock\n");
+- em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
+- }
+ return 0;
+ }
+
+@@ -363,7 +371,7 @@ static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
+ dprintk("Stop capture, if needed\n");
+
+ if (dev->adev.capture_stream == STREAM_ON)
+- em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
++ em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_STOP_AUDIO);
+
+ return 0;
+ }
+@@ -377,33 +385,40 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+ {
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
++ int retval;
+
+- dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)?
+- "start": "stop");
++ dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
++ "start" : "stop");
++
++ spin_lock(&dev->adev.slock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+- em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1);
+- return 0;
++ em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_START_AUDIO);
++ retval = 0;
++ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+- dev->adev.shutdown = 1;
+- return 0;
++ em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_STOP_AUDIO);
++ retval = 0;
++ break;
+ default:
+- return -EINVAL;
++ retval = -EINVAL;
+ }
++
++ spin_unlock(&dev->adev.slock);
++ return retval;
+ }
+
+ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
+ *substream)
+ {
+- unsigned long flags;
+-
++ unsigned long flags;
+ struct em28xx *dev;
+ snd_pcm_uframes_t hwptr_done;
+
+ dev = snd_pcm_substream_chip(substream);
+- spin_lock_irqsave(&dev->adev.slock, flags);
++ spin_lock_irqsave(&dev->adev.slock, flags);
+ hwptr_done = dev->adev.hwptr_done_capture;
+- spin_unlock_irqrestore(&dev->adev.slock, flags);
++ spin_unlock_irqrestore(&dev->adev.slock, flags);
+
+ return hwptr_done;
+ }
+diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
+index 3b3ca3f..0f48c0f 100644
+--- a/drivers/media/video/em28xx/em28xx-cards.c
++++ b/drivers/media/video/em28xx/em28xx-cards.c
+@@ -122,6 +122,22 @@ static struct em28xx_reg_seq default_tuner_gpio[] = {
+ { -1, -1, -1, -1},
+ };
+
++/* Mute/unmute */
++static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
++ {EM28XX_R08_GPIO, 5, 7, 10},
++ { -1, -1, -1, -1},
++};
++
++static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
++ {EM28XX_R08_GPIO, 4, 7, 10},
++ { -1, -1, -1, -1},
++};
++
++static struct em28xx_reg_seq compro_mute_gpio[] = {
++ {EM28XX_R08_GPIO, 6, 7, 10},
++ { -1, -1, -1, -1},
++};
++
+ /*
+ * Board definitions
+ */
+@@ -183,6 +199,25 @@ struct em28xx_board em28xx_boards[] = {
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+ },
++ [EM2820_BOARD_GADMEI_TVR200] = {
++ .name = "Gadmei TVR200",
++ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
++ .tda9887_conf = TDA9887_PRESENT,
++ .decoder = EM28XX_SAA711X,
++ .input = { {
++ .type = EM28XX_VMUX_TELEVISION,
++ .vmux = SAA7115_COMPOSITE2,
++ .amux = EM28XX_AMUX_LINE_IN,
++ }, {
++ .type = EM28XX_VMUX_COMPOSITE1,
++ .vmux = SAA7115_COMPOSITE0,
++ .amux = EM28XX_AMUX_LINE_IN,
++ }, {
++ .type = EM28XX_VMUX_SVIDEO,
++ .vmux = SAA7115_SVIDEO3,
++ .amux = EM28XX_AMUX_LINE_IN,
++ } },
++ },
+ [EM2820_BOARD_TERRATEC_CINERGY_250] = {
+ .name = "Terratec Cinergy 250 USB",
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+@@ -225,7 +260,7 @@ struct em28xx_board em28xx_boards[] = {
+ .name = "Hauppauge WinTV USB 2",
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .tda9887_conf = TDA9887_PRESENT |
+- TDA9887_PORT1_ACTIVE|
++ TDA9887_PORT1_ACTIVE |
+ TDA9887_PORT2_ACTIVE,
+ .decoder = EM28XX_TVP5150,
+ .has_msp34xx = 1,
+@@ -350,26 +385,6 @@ struct em28xx_board em28xx_boards[] = {
+ .amux = EM28XX_AMUX_VIDEO,
+ } },
+ },
+- [EM2821_BOARD_PROLINK_PLAYTV_USB2] = {
+- .name = "SIIG AVTuner-PVR/Prolink PlayTV USB 2.0",
+- .valid = EM28XX_BOARD_NOT_VALIDATED,
+- .tuner_type = TUNER_LG_PAL_NEW_TAPC, /* unknown? */
+- .tda9887_conf = TDA9887_PRESENT, /* unknown? */
+- .decoder = EM28XX_SAA711X,
+- .input = { {
+- .type = EM28XX_VMUX_TELEVISION,
+- .vmux = SAA7115_COMPOSITE2,
+- .amux = EM28XX_AMUX_LINE_IN,
+- }, {
+- .type = EM28XX_VMUX_COMPOSITE1,
+- .vmux = SAA7115_COMPOSITE0,
+- .amux = EM28XX_AMUX_LINE_IN,
+- }, {
+- .type = EM28XX_VMUX_SVIDEO,
+- .vmux = SAA7115_SVIDEO3,
+- .amux = EM28XX_AMUX_LINE_IN,
+- } },
+- },
+ [EM2821_BOARD_SUPERCOMP_USB_2] = {
+ .name = "Supercomp USB 2.0 TV",
+ .valid = EM28XX_BOARD_NOT_VALIDATED,
+@@ -498,7 +513,7 @@ struct em28xx_board em28xx_boards[] = {
+ },
+ [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = {
+ .name = "Yakumo MovieMixer",
+- .tuner_type = TUNER_ABSENT, /* Capture only device */
++ .tuner_type = TUNER_ABSENT, /* Capture only device */
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+@@ -604,6 +619,7 @@ struct em28xx_board em28xx_boards[] = {
+ .mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900_digital,
++ .ir_codes = ir_codes_hauppauge_new,
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+@@ -628,6 +644,7 @@ struct em28xx_board em28xx_boards[] = {
+ .tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
+ .mts_firmware = 1,
++ .ir_codes = ir_codes_hauppauge_new,
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+@@ -842,11 +859,11 @@ struct em28xx_board em28xx_boards[] = {
+ } },
+ },
+ [EM2800_BOARD_GRABBEEX_USB2800] = {
+- .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder",
+- .is_em2800 = 1,
+- .decoder = EM28XX_SAA711X,
+- .tuner_type = TUNER_ABSENT, /* capture only board */
+- .input = { {
++ .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder",
++ .is_em2800 = 1,
++ .decoder = EM28XX_SAA711X,
++ .tuner_type = TUNER_ABSENT, /* capture only board */
++ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_LINE_IN,
+@@ -897,7 +914,7 @@ struct em28xx_board em28xx_boards[] = {
+ } },
+ },
+ [EM2820_BOARD_PINNACLE_DVC_90] = {
+- .name = "Pinnacle Dazzle DVC 90/DVC 100",
++ .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker",
+ .tuner_type = TUNER_ABSENT, /* capture only board */
+ .decoder = EM28XX_SAA711X,
+ .input = { {
+@@ -952,7 +969,7 @@ struct em28xx_board em28xx_boards[] = {
+ } },
+ },
+ [EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
+- .name = "Pixelview Prolink PlayTV USB 2.0",
++ .name = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0",
+ .has_snapshot_button = 1,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_YMEC_TVF_5533MF,
+@@ -1198,7 +1215,9 @@ struct em28xx_board em28xx_boards[] = {
+ .has_dvb = 1,
+ .dvb_gpio = kworld_330u_digital,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
+- .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_EEPROM_ON_BOARD | EM28XX_I2C_EEPROM_KEY_VALID,
++ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
++ EM28XX_I2C_EEPROM_ON_BOARD |
++ EM28XX_I2C_EEPROM_KEY_VALID,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+@@ -1223,21 +1242,88 @@ struct em28xx_board em28xx_boards[] = {
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .decoder = EM28XX_TVP5150,
++ .adecoder = EM28XX_TVAUDIO,
++ .mute_gpio = compro_mute_gpio,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
++ .amux = EM28XX_AMUX_VIDEO,
++ .gpio = compro_unmute_tv_gpio,
++ }, {
++ .type = EM28XX_VMUX_SVIDEO,
++ .vmux = TVP5150_SVIDEO,
++ .amux = EM28XX_AMUX_LINE_IN,
++ .gpio = compro_unmute_svid_gpio,
++ } },
++ },
++ [EM2860_BOARD_KAIOMY_TVNPC_U2] = {
++ .name = "Kaiomy TVnPC U2",
++ .vchannels = 3,
++ .tuner_type = TUNER_XC2028,
++ .tuner_addr = 0x61,
++ .mts_firmware = 1,
++ .decoder = EM28XX_TVP5150,
++ .tuner_gpio = default_tuner_gpio,
++ .ir_codes = ir_codes_kaiomy,
++ .input = { {
++ .type = EM28XX_VMUX_TELEVISION,
++ .vmux = TVP5150_COMPOSITE0,
++ .amux = EM28XX_AMUX_VIDEO,
++
++ }, {
++ .type = EM28XX_VMUX_COMPOSITE1,
++ .vmux = TVP5150_COMPOSITE1,
+ .amux = EM28XX_AMUX_LINE_IN,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
++ .radio = {
++ .type = EM28XX_RADIO,
++ .amux = EM28XX_AMUX_LINE_IN,
++ }
++ },
++ [EM2860_BOARD_EASYCAP] = {
++ .name = "Easy Cap Capture DC-60",
++ .vchannels = 2,
++ .tuner_type = TUNER_ABSENT,
++ .decoder = EM28XX_SAA711X,
++ .input = { {
++ .type = EM28XX_VMUX_COMPOSITE1,
++ .vmux = SAA7115_COMPOSITE0,
++ .amux = EM28XX_AMUX_LINE_IN,
++ }, {
++ .type = EM28XX_VMUX_SVIDEO,
++ .vmux = SAA7115_SVIDEO3,
++ .amux = EM28XX_AMUX_LINE_IN,
++ } },
++ },
++ [EM2820_BOARD_IODATA_GVMVP_SZ] = {
++ .name = "IO-DATA GV-MVP/SZ",
++ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
++ .tuner_gpio = default_tuner_gpio,
++ .tda9887_conf = TDA9887_PRESENT,
++ .decoder = EM28XX_TVP5150,
++ .input = { {
++ .type = EM28XX_VMUX_TELEVISION,
++ .vmux = TVP5150_COMPOSITE0,
++ .amux = EM28XX_AMUX_VIDEO,
++ }, { /* Composite has not been tested yet */
++ .type = EM28XX_VMUX_COMPOSITE1,
++ .vmux = TVP5150_COMPOSITE1,
++ .amux = EM28XX_AMUX_VIDEO,
++ }, { /* S-video has not been tested yet */
++ .type = EM28XX_VMUX_SVIDEO,
++ .vmux = TVP5150_SVIDEO,
++ .amux = EM28XX_AMUX_VIDEO,
++ } },
+ },
+ };
+ const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+
+ /* table of devices that work with this driver */
+-struct usb_device_id em28xx_id_table [] = {
++struct usb_device_id em28xx_id_table[] = {
+ { USB_DEVICE(0xeb1a, 0x2750),
+ .driver_info = EM2750_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2751),
+@@ -1260,6 +1346,8 @@ struct usb_device_id em28xx_id_table [] = {
+ .driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0xe300),
+ .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U },
++ { USB_DEVICE(0xeb1a, 0xe303),
++ .driver_info = EM2860_BOARD_KAIOMY_TVNPC_U2 },
+ { USB_DEVICE(0xeb1a, 0xe305),
+ .driver_info = EM2880_BOARD_KWORLD_DVB_305U },
+ { USB_DEVICE(0xeb1a, 0xe310),
+@@ -1278,6 +1366,8 @@ struct usb_device_id em28xx_id_table [] = {
+ .driver_info = EM2800_BOARD_GRABBEEX_USB2800 },
+ { USB_DEVICE(0xeb1a, 0xe357),
+ .driver_info = EM2870_BOARD_KWORLD_355U },
++ { USB_DEVICE(0x1b80, 0xe302),
++ .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */
+ { USB_DEVICE(0x0ccd, 0x0036),
+ .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+ { USB_DEVICE(0x0ccd, 0x004c),
+@@ -1330,6 +1420,8 @@ struct usb_device_id em28xx_id_table [] = {
+ .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
+ { USB_DEVICE(0x093b, 0xa005),
+ .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
++ { USB_DEVICE(0x04bb, 0x0515),
++ .driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
+ { },
+ };
+ MODULE_DEVICE_TABLE(usb, em28xx_id_table);
+@@ -1337,7 +1429,7 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table);
+ /*
+ * EEPROM hash table for devices with generic USB IDs
+ */
+-static struct em28xx_hash_table em28xx_eeprom_hash [] = {
++static struct em28xx_hash_table em28xx_eeprom_hash[] = {
+ /* P/N: SA 60002070465 Tuner: TVF7533-MF */
+ {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
+ {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
+@@ -1349,6 +1441,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
+ {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
+ {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
+ {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT},
++ {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
+ };
+
+ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
+@@ -1368,7 +1461,7 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
+ }
+ EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
+
+-static void inline em28xx_set_model(struct em28xx *dev)
++static inline void em28xx_set_model(struct em28xx *dev)
+ {
+ memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board));
+
+@@ -1504,6 +1597,34 @@ void em28xx_pre_card_setup(struct em28xx *dev)
+ /* enables audio for that devices */
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+ break;
++
++ case EM2860_BOARD_KAIOMY_TVNPC_U2:
++ em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1);
++ em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
++ em28xx_write_regs(dev, 0x0d, "\x42", 1);
++ em28xx_write_regs(dev, 0x08, "\xfd", 1);
++ msleep(10);
++ em28xx_write_regs(dev, 0x08, "\xff", 1);
++ msleep(10);
++ em28xx_write_regs(dev, 0x08, "\x7f", 1);
++ msleep(10);
++ em28xx_write_regs(dev, 0x08, "\x6b", 1);
++
++ break;
++ case EM2860_BOARD_EASYCAP:
++ em28xx_write_regs(dev, 0x08, "\xf8", 1);
++ break;
++
++ case EM2820_BOARD_IODATA_GVMVP_SZ:
++ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
++ msleep(70);
++ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
++ msleep(10);
++ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
++ msleep(70);
++ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
++ msleep(70);
++ break;
+ }
+
+ em28xx_gpio_set(dev, dev->board.tuner_gpio);
+@@ -1610,7 +1731,7 @@ static int em28xx_hint_board(struct em28xx *dev)
+ em28xx_errdev("If the board were missdetected, "
+ "please email this log to:\n");
+ em28xx_errdev("\tV4L Mailing List "
+- " <video4linux-list@redhat.com>\n");
++ " <linux-media@vger.kernel.org>\n");
+ em28xx_errdev("Board detected as %s\n",
+ em28xx_boards[dev->model].name);
+
+@@ -1642,7 +1763,7 @@ static int em28xx_hint_board(struct em28xx *dev)
+ em28xx_errdev("If the board were missdetected, "
+ "please email this log to:\n");
+ em28xx_errdev("\tV4L Mailing List "
+- " <video4linux-list@redhat.com>\n");
++ " <linux-media@vger.kernel.org>\n");
+ em28xx_errdev("Board detected as %s\n",
+ em28xx_boards[dev->model].name);
+
+@@ -1655,7 +1776,7 @@ static int em28xx_hint_board(struct em28xx *dev)
+ em28xx_errdev("You may try to use card=<n> insmod option to "
+ "workaround that.\n");
+ em28xx_errdev("Please send an email with this log to:\n");
+- em28xx_errdev("\tV4L Mailing List <video4linux-list@redhat.com>\n");
++ em28xx_errdev("\tV4L Mailing List <linux-media@vger.kernel.org>\n");
+ em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash);
+ em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash);
+
+@@ -1800,6 +1921,8 @@ void em28xx_card_setup(struct em28xx *dev)
+ request_module("tvp5150");
+ if (dev->board.tuner_type != TUNER_ABSENT)
+ request_module("tuner");
++ if (dev->board.adecoder == EM28XX_TVAUDIO)
++ request_module("tvaudio");
+ #endif
+
+ em28xx_config_tuner(dev);
+diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
+index 94fb1b6..8f1999c 100644
+--- a/drivers/media/video/em28xx/em28xx-core.c
++++ b/drivers/media/video/em28xx/em28xx-core.c
+@@ -33,8 +33,8 @@
+ /* #define ENABLE_DEBUG_ISOC_FRAMES */
+
+ static unsigned int core_debug;
+-module_param(core_debug,int,0644);
+-MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
++module_param(core_debug, int, 0644);
++MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
+
+ #define em28xx_coredbg(fmt, arg...) do {\
+ if (core_debug) \
+@@ -42,8 +42,8 @@ MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+ dev->name, __func__ , ##arg); } while (0)
+
+ static unsigned int reg_debug;
+-module_param(reg_debug,int,0644);
+-MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
++module_param(reg_debug, int, 0644);
++MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
+
+ #define em28xx_regdbg(fmt, arg...) do {\
+ if (reg_debug) \
+@@ -77,7 +77,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+ return -EINVAL;
+
+ if (reg_debug) {
+- printk( KERN_DEBUG "(pipe 0x%08x): "
++ printk(KERN_DEBUG "(pipe 0x%08x): "
+ "IN: %02x %02x %02x %02x %02x %02x %02x %02x ",
+ pipe,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+@@ -154,7 +154,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+ if (reg_debug) {
+ int byte;
+
+- printk( KERN_DEBUG "(pipe 0x%08x): "
++ printk(KERN_DEBUG "(pipe 0x%08x): "
+ "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
+ pipe,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+@@ -378,6 +378,11 @@ static int em28xx_set_audio_source(struct em28xx *dev)
+ }
+ }
+
++ if (dev->board.mute_gpio && dev->mute)
++ em28xx_gpio_set(dev, dev->board.mute_gpio);
++ else
++ em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
++
+ ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
+ if (ret < 0)
+ return ret;
+@@ -424,7 +429,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
+
+ xclk = dev->board.xclk & 0x7f;
+ if (!dev->mute)
+- xclk |= 0x80;
++ xclk |= EM28XX_XCLK_AUDIO_UNMUTE;
+
+ ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
+ if (ret < 0)
+@@ -462,7 +467,8 @@ int em28xx_audio_analog_set(struct em28xx *dev)
+ if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) {
+ int sel = ac97_return_record_select(dev->ctl_aoutput);
+
+- /* Use the same input for both left and right channels */
++ /* Use the same input for both left and right
++ channels */
+ sel |= (sel << 8);
+
+ em28xx_write_ac97(dev, AC97_RECORD_SELECT, sel);
+@@ -698,7 +704,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+ em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+ /* it seems that both H and V scalers must be active
+ to work correctly */
+- mode = (h || v)? 0x30: 0x00;
++ mode = (h || v) ? 0x30 : 0x00;
+ }
+ return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
+ }
+@@ -827,6 +833,19 @@ static void em28xx_irq_callback(struct urb *urb)
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+ int rc, i;
+
++ switch (urb->status) {
++ case 0: /* success */
++ case -ETIMEDOUT: /* NAK */
++ break;
++ case -ECONNRESET: /* kill */
++ case -ENOENT:
++ case -ESHUTDOWN:
++ return;
++ default: /* error */
++ em28xx_isocdbg("urb completition error %d.\n", urb->status);
++ break;
++ }
++
+ /* Copy data from URB */
+ spin_lock(&dev->slock);
+ rc = dev->isoc_ctl.isoc_copy(dev, urb);
+@@ -945,7 +964,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+ em28xx_err("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+- in_interrupt()?" while in int":"");
++ in_interrupt() ? " while in int" : "");
+ em28xx_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+@@ -963,7 +982,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+ em28xx_irq_callback, dma_q, 1);
+
+ urb->number_of_packets = max_packets;
+- urb->transfer_flags = URB_ISO_ASAP;
++ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+ k = 0;
+ for (j = 0; j < max_packets; j++) {
+diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
+index 9ad8527..fcd2551 100644
+--- a/drivers/media/video/em28xx/em28xx-dvb.c
++++ b/drivers/media/video/em28xx/em28xx-dvb.c
+@@ -29,9 +29,6 @@
+ #include "lgdt330x.h"
+ #include "zl10353.h"
+ #include "s5h1409.h"
+-#ifdef EM28XX_DRX397XD_SUPPORT
+-#include "drx397xD.h"
+-#endif
+
+ MODULE_DESCRIPTION("driver for em28xx based DVB cards");
+ MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
+index d69f0ef..02c12fe 100644
+--- a/drivers/media/video/em28xx/em28xx-i2c.c
++++ b/drivers/media/video/em28xx/em28xx-i2c.c
+@@ -402,10 +402,12 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+ dev->name);
+ break;
+ case 2:
+- printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n", dev->name);
++ printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
++ dev->name);
+ break;
+ case 3:
+- printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n", dev->name);
++ printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
++ dev->name);
+ break;
+ }
+
+@@ -508,12 +510,17 @@ static int attach_inform(struct i2c_client *client)
+ dprintk1(1, "attach_inform: tvp5150 detected.\n");
+ break;
+
++ case 0xb0:
++ dprintk1(1, "attach_inform: tda9874 detected\n");
++ break;
++
+ default:
+ if (!dev->tuner_addr)
+ dev->tuner_addr = client->addr;
+
+ dprintk1(1, "attach inform: detected I2C address %x\n",
+ client->addr << 1);
++ dprintk1(1, "driver id %d\n", client->driver->id);
+
+ }
+
+@@ -552,6 +559,7 @@ static char *i2c_devs[128] = {
+ [0x80 >> 1] = "msp34xx",
+ [0x88 >> 1] = "msp34xx",
+ [0xa0 >> 1] = "eeprom",
++ [0xb0 >> 1] = "tda9874",
+ [0xb8 >> 1] = "tvp5150a",
+ [0xba >> 1] = "tvp5150a",
+ [0xc0 >> 1] = "tuner (analog)",
+diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
+index 0443afe..a5abfd7 100644
+--- a/drivers/media/video/em28xx/em28xx-input.c
++++ b/drivers/media/video/em28xx/em28xx-input.c
+@@ -68,8 +68,7 @@ struct em28xx_IR {
+
+ /* poll external decoder */
+ int polling;
+- struct work_struct work;
+- struct timer_list timer;
++ struct delayed_work work;
+ unsigned int last_toggle:1;
+ unsigned int last_readcount;
+ unsigned int repeat_interval;
+@@ -292,32 +291,23 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
+ return;
+ }
+
+-static void ir_timer(unsigned long data)
+-{
+- struct em28xx_IR *ir = (struct em28xx_IR *)data;
+-
+- schedule_work(&ir->work);
+-}
+-
+ static void em28xx_ir_work(struct work_struct *work)
+ {
+- struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work);
++ struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
+
+ em28xx_ir_handle_key(ir);
+- mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
++ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+ }
+
+ static void em28xx_ir_start(struct em28xx_IR *ir)
+ {
+- setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
+- INIT_WORK(&ir->work, em28xx_ir_work);
+- schedule_work(&ir->work);
++ INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
++ schedule_delayed_work(&ir->work, 0);
+ }
+
+ static void em28xx_ir_stop(struct em28xx_IR *ir)
+ {
+- del_timer_sync(&ir->timer);
+- flush_scheduled_work();
++ cancel_delayed_work_sync(&ir->work);
+ }
+
+ int em28xx_ir_init(struct em28xx *dev)
+diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
+index 8e61b2c..575472f 100644
+--- a/drivers/media/video/em28xx/em28xx-video.c
++++ b/drivers/media/video/em28xx/em28xx-video.c
+@@ -186,7 +186,8 @@ static void em28xx_copy_video(struct em28xx *dev,
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+- lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite;
++ remain = (char *)outp + buf->vb.size - (char *)startwrite;
++ lencopy = remain;
+ }
+ if (lencopy <= 0)
+ return;
+@@ -202,7 +203,8 @@ static void em28xx_copy_video(struct em28xx *dev,
+ else
+ lencopy = bytesperline;
+
+- if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
++ if ((char *)startwrite + lencopy > (char *)outp +
++ buf->vb.size) {
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+@@ -347,7 +349,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
+ }
+ if (p[0] == 0x22 && p[1] == 0x5a) {
+ em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
+- len, (p[2] & 1)? "odd" : "even");
++ len, (p[2] & 1) ? "odd" : "even");
+
+ if (!(p[2] & 1)) {
+ if (buf != NULL)
+@@ -476,7 +478,9 @@ fail:
+ static void
+ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ {
+- struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
++ struct em28xx_buffer *buf = container_of(vb,
++ struct em28xx_buffer,
++ vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_dmaqueue *vidq = &dev->vidq;
+@@ -489,7 +493,9 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+ {
+- struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
++ struct em28xx_buffer *buf = container_of(vb,
++ struct em28xx_buffer,
++ vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = (struct em28xx *)fh->dev;
+
+@@ -534,6 +540,13 @@ static void video_mux(struct em28xx *dev, int index)
+ &route);
+ }
+
++ if (dev->board.adecoder != EM28XX_NOADECODER) {
++ route.input = dev->ctl_ainput;
++ route.output = dev->ctl_aoutput;
++ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
++ &route);
++ }
++
+ em28xx_audio_analog_set(dev);
+ }
+
+@@ -557,7 +570,7 @@ static int res_get(struct em28xx_fh *fh)
+
+ static int res_check(struct em28xx_fh *fh)
+ {
+- return (fh->stream_on);
++ return fh->stream_on;
+ }
+
+ static void res_free(struct em28xx_fh *fh)
+@@ -791,7 +804,7 @@ out:
+ return rc;
+ }
+
+-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
++static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+ {
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+@@ -1008,8 +1021,13 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+
+ if (dev->board.has_msp34xx)
+ em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
+- else
++ else {
+ rc = em28xx_get_ctrl(dev, ctrl);
++ if (rc < 0) {
++ em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
++ rc = 0;
++ }
++ }
+
+ mutex_unlock(&dev->lock);
+ return rc;
+@@ -1345,7 +1363,7 @@ static int vidioc_querycap(struct file *file, void *priv,
+
+ strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+ strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
+- strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
++ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+ cap->version = EM28XX_VERSION_CODE;
+
+@@ -1431,7 +1449,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
+ if (rc < 0)
+ return rc;
+
+- return (videobuf_reqbufs(&fh->vb_vidq, rb));
++ return videobuf_reqbufs(&fh->vb_vidq, rb);
+ }
+
+ static int vidioc_querybuf(struct file *file, void *priv,
+@@ -1445,7 +1463,7 @@ static int vidioc_querybuf(struct file *file, void *priv,
+ if (rc < 0)
+ return rc;
+
+- return (videobuf_querybuf(&fh->vb_vidq, b));
++ return videobuf_querybuf(&fh->vb_vidq, b);
+ }
+
+ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+@@ -1458,7 +1476,7 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+ if (rc < 0)
+ return rc;
+
+- return (videobuf_qbuf(&fh->vb_vidq, b));
++ return videobuf_qbuf(&fh->vb_vidq, b);
+ }
+
+ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+@@ -1471,8 +1489,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+ if (rc < 0)
+ return rc;
+
+- return (videobuf_dqbuf(&fh->vb_vidq, b,
+- file->f_flags & O_NONBLOCK));
++ return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+ }
+
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
+@@ -1496,7 +1513,7 @@ static int radio_querycap(struct file *file, void *priv,
+
+ strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+ strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
+- strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
++ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+ cap->version = EM28XX_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_TUNER;
+@@ -1781,7 +1798,7 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ * em28xx_v4l2_poll()
+ * will allocate buffers when called for the first time
+ */
+-static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
++static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
+ {
+ struct em28xx_fh *fh = filp->private_data;
+ struct em28xx *dev = fh->dev;
+@@ -1934,8 +1951,8 @@ static struct video_device em28xx_radio_template = {
+
+
+ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
+- const struct video_device *template,
+- const char *type_name)
++ const struct video_device *template,
++ const char *type_name)
+ {
+ struct video_device *vfd;
+
+@@ -1984,8 +2001,9 @@ int em28xx_register_analog_devices(struct em28xx *dev)
+ /* enable vbi capturing */
+
+ /* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
+- val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
+- em28xx_write_reg(dev, EM28XX_R0F_XCLK, (EM28XX_XCLK_AUDIO_UNMUTE | val));
++ val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
++ em28xx_write_reg(dev, EM28XX_R0F_XCLK,
++ (EM28XX_XCLK_AUDIO_UNMUTE | val));
+ em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
+
+ em28xx_set_outfmt(dev);
+@@ -2020,7 +2038,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
+ }
+
+ if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
+- dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio");
++ dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
++ "radio");
+ if (!dev->radio_dev) {
+ em28xx_errdev("cannot allocate video_device.\n");
+ return -ENODEV;
+diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
+index dd2cd36..a33a58d 100644
+--- a/drivers/media/video/em28xx/em28xx.h
++++ b/drivers/media/video/em28xx/em28xx.h
+@@ -70,7 +70,6 @@
+ #define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30
+ #define EM2821_BOARD_USBGEAR_VD204 31
+ #define EM2821_BOARD_SUPERCOMP_USB_2 32
+-#define EM2821_BOARD_PROLINK_PLAYTV_USB2 33
+ #define EM2860_BOARD_TERRATEC_HYBRID_XS 34
+ #define EM2860_BOARD_TYPHOON_DVD_MAKER 35
+ #define EM2860_BOARD_NETGMBH_CAM 36
+@@ -98,6 +97,10 @@
+ #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
+ #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
+ #define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61
++#define EM2820_BOARD_GADMEI_TVR200 62
++#define EM2860_BOARD_KAIOMY_TVNPC_U2 63
++#define EM2860_BOARD_EASYCAP 64
++#define EM2820_BOARD_IODATA_GVMVP_SZ 65
+
+ /* Limits minimum and default number of buffers */
+ #define EM28XX_MIN_BUF 4
+@@ -110,6 +113,10 @@
+ #define EM28XX_BOARD_NOT_VALIDATED 1
+ #define EM28XX_BOARD_VALIDATED 0
+
++/* Params for em28xx_cmd() audio */
++#define EM28XX_START_AUDIO 1
++#define EM28XX_STOP_AUDIO 0
++
+ /* maximum number of em28xx boards */
+ #define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
+
+@@ -154,7 +161,8 @@
+ */
+
+ /* time to wait when stopping the isoc transfer */
+-#define EM28XX_URB_TIMEOUT msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
++#define EM28XX_URB_TIMEOUT \
++ msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
+
+ /* time in msecs to wait for i2c writes to finish */
+ #define EM2800_I2C_WRITE_TIMEOUT 20
+@@ -348,6 +356,11 @@ enum em28xx_decoder {
+ EM28XX_SAA711X,
+ };
+
++enum em28xx_adecoder {
++ EM28XX_NOADECODER = 0,
++ EM28XX_TVAUDIO,
++};
++
+ struct em28xx_board {
+ char *name;
+ int vchannels;
+@@ -361,6 +374,7 @@ struct em28xx_board {
+ struct em28xx_reg_seq *dvb_gpio;
+ struct em28xx_reg_seq *suspend_gpio;
+ struct em28xx_reg_seq *tuner_gpio;
++ struct em28xx_reg_seq *mute_gpio;
+
+ unsigned int is_em2800:1;
+ unsigned int has_msp34xx:1;
+@@ -373,6 +387,7 @@ struct em28xx_board {
+ unsigned char xclk, i2c_speed;
+
+ enum em28xx_decoder decoder;
++ enum em28xx_adecoder adecoder;
+
+ struct em28xx_input input[MAX_EM28XX_INPUT];
+ struct em28xx_input radio;
+@@ -420,7 +435,7 @@ struct em28xx_audio {
+ unsigned int hwptr_done_capture;
+ struct snd_card *sndcard;
+
+- int users, shutdown;
++ int users;
+ enum em28xx_stream_state capture_stream;
+ spinlock_t slock;
+ };
+@@ -523,7 +538,8 @@ struct em28xx {
+ int num_alt; /* Number of alternative settings */
+ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+ struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */
+- char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */
++ char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc
++ transfer */
+ char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
+
+ /* helper funcs that call usb_control_msg */
+diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
+index ee6a691..578dc4f 100644
+--- a/drivers/media/video/gspca/Kconfig
++++ b/drivers/media/video/gspca/Kconfig
+@@ -56,6 +56,15 @@ config USB_GSPCA_MARS
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_mars.
+
++config USB_GSPCA_MR97310A
++ tristate "Mars-Semi MR97310A USB Camera Driver"
++ depends on VIDEO_V4L2 && USB_GSPCA
++ help
++ Say Y here if you want support for cameras based on the MR97310A chip.
++
++ To compile this driver as a module, choose M here: the
++ module will be called gspca_mr97310a.
++
+ config USB_GSPCA_OV519
+ tristate "OV519 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+@@ -167,6 +176,24 @@ config USB_GSPCA_SPCA561
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca561.
+
++config USB_GSPCA_SQ905
++ tristate "SQ Technologies SQ905 based USB Camera Driver"
++ depends on VIDEO_V4L2 && USB_GSPCA
++ help
++ Say Y here if you want support for cameras based on the SQ905 chip.
++
++ To compile this driver as a module, choose M here: the
++ module will be called gspca_sq905.
++
++config USB_GSPCA_SQ905C
++ tristate "SQ Technologies SQ905C based USB Camera Driver"
++ depends on VIDEO_V4L2 && USB_GSPCA
++ help
++ Say Y here if you want support for cameras based on the SQ905C chip.
++
++ To compile this driver as a module, choose M here: the
++ module will be called gspca_sq905c.
++
+ config USB_GSPCA_STK014
+ tristate "Syntek DV4000 (STK014) USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
+index bd8d9ee..8a6643e 100644
+--- a/drivers/media/video/gspca/Makefile
++++ b/drivers/media/video/gspca/Makefile
+@@ -1,50 +1,56 @@
+-obj-$(CONFIG_USB_GSPCA) += gspca_main.o
+-obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o
+-obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
+-obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
+-obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
+-obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o
+-obj-$(CONFIG_USB_GSPCA_OV534) += gspca_ov534.o
+-obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o
+-obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o
+-obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o
+-obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o
+-obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o
+-obj-$(CONFIG_USB_GSPCA_SPCA501) += gspca_spca501.o
+-obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o
+-obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o
+-obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o
+-obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o
+-obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o
+-obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o
+-obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o
+-obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o
+-obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o
+-obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o
++obj-$(CONFIG_USB_GSPCA) += gspca_main.o
++obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o
++obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
++obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
++obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
++obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
++obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o
++obj-$(CONFIG_USB_GSPCA_OV534) += gspca_ov534.o
++obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o
++obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o
++obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o
++obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o
++obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o
++obj-$(CONFIG_USB_GSPCA_SPCA501) += gspca_spca501.o
++obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o
++obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o
++obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o
++obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o
++obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o
++obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o
++obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o
++obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o
++obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o
++obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o
++obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o
++obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o
+
+-gspca_main-objs := gspca.o
+-gspca_conex-objs := conex.o
+-gspca_etoms-objs := etoms.o
+-gspca_finepix-objs := finepix.o
+-gspca_mars-objs := mars.o
+-gspca_ov519-objs := ov519.o
+-gspca_ov534-objs := ov534.o
+-gspca_pac207-objs := pac207.o
+-gspca_pac7311-objs := pac7311.o
+-gspca_sonixb-objs := sonixb.o
+-gspca_sonixj-objs := sonixj.o
+-gspca_spca500-objs := spca500.o
+-gspca_spca501-objs := spca501.o
+-gspca_spca505-objs := spca505.o
+-gspca_spca506-objs := spca506.o
+-gspca_spca508-objs := spca508.o
+-gspca_spca561-objs := spca561.o
+-gspca_stk014-objs := stk014.o
+-gspca_sunplus-objs := sunplus.o
+-gspca_t613-objs := t613.o
+-gspca_tv8532-objs := tv8532.o
+-gspca_vc032x-objs := vc032x.o
+-gspca_zc3xx-objs := zc3xx.o
++gspca_main-objs := gspca.o
++gspca_conex-objs := conex.o
++gspca_etoms-objs := etoms.o
++gspca_finepix-objs := finepix.o
++gspca_mars-objs := mars.o
++gspca_mr97310a-objs := mr97310a.o
++gspca_ov519-objs := ov519.o
++gspca_ov534-objs := ov534.o
++gspca_pac207-objs := pac207.o
++gspca_pac7311-objs := pac7311.o
++gspca_sonixb-objs := sonixb.o
++gspca_sonixj-objs := sonixj.o
++gspca_spca500-objs := spca500.o
++gspca_spca501-objs := spca501.o
++gspca_spca505-objs := spca505.o
++gspca_spca506-objs := spca506.o
++gspca_spca508-objs := spca508.o
++gspca_spca561-objs := spca561.o
++gspca_sq905-objs := sq905.o
++gspca_sq905c-objs := sq905c.o
++gspca_stk014-objs := stk014.o
++gspca_sunplus-objs := sunplus.o
++gspca_t613-objs := t613.o
++gspca_tv8532-objs := tv8532.o
++gspca_vc032x-objs := vc032x.o
++gspca_zc3xx-objs := zc3xx.o
+
+-obj-$(CONFIG_USB_M5602) += m5602/
+-obj-$(CONFIG_USB_STV06XX) += stv06xx/
++obj-$(CONFIG_USB_M5602) += m5602/
++obj-$(CONFIG_USB_STV06XX) += stv06xx/
+diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
+index 1753f5b..219cfa6 100644
+--- a/drivers/media/video/gspca/conex.c
++++ b/drivers/media/video/gspca/conex.c
+@@ -36,8 +36,12 @@ struct sd {
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
++ u8 quality;
++#define QUALITY_MIN 30
++#define QUALITY_MAX 60
++#define QUALITY_DEF 40
+
+- unsigned char qindex;
++ u8 *jpeg_hdr;
+ };
+
+ /* V4L2 controls supported by the driver */
+@@ -815,14 +819,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+
+- sd->qindex = 0; /* set the quantization */
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
++ sd->quality = QUALITY_DEF;
+ return 0;
+ }
+
+@@ -839,6 +842,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
+
+ static int sd_start(struct gspca_dev *gspca_dev)
+ {
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ /* create the JPEG header */
++ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
++ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
++ 0x22); /* JPEG 411 */
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++
+ cx11646_initsize(gspca_dev);
+ cx11646_fw(gspca_dev);
+ cx_sensor(gspca_dev);
+@@ -849,8 +860,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ /* called on streamoff with alt 0 and on disconnect */
+ static void sd_stop0(struct gspca_dev *gspca_dev)
+ {
++ struct sd *sd = (struct sd *) gspca_dev;
+ int retry = 50;
+
++ kfree(sd->jpeg_hdr);
++
+ if (!gspca_dev->present)
+ return;
+ reg_w_val(gspca_dev, 0x0000, 0x00);
+@@ -876,6 +890,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+ {
++ struct sd *sd = (struct sd *) gspca_dev;
++
+ if (data[0] == 0xff && data[1] == 0xd8) {
+
+ /* start of frame */
+@@ -883,9 +899,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ data, 0);
+
+ /* put the JPEG header in the new frame */
+- jpeg_put_header(gspca_dev, frame,
+- ((struct sd *) gspca_dev)->qindex,
+- 0x22);
++ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
++ sd->jpeg_hdr, JPEG_HDR_SZ);
+ data += 2;
+ len -= 2;
+ }
+@@ -988,6 +1003,34 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+ return 0;
+ }
+
++static int sd_set_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ if (jcomp->quality < QUALITY_MIN)
++ sd->quality = QUALITY_MIN;
++ else if (jcomp->quality > QUALITY_MAX)
++ sd->quality = QUALITY_MAX;
++ else
++ sd->quality = jcomp->quality;
++ if (gspca_dev->streaming)
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++ return 0;
++}
++
++static int sd_get_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ memset(jcomp, 0, sizeof *jcomp);
++ jcomp->quality = sd->quality;
++ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
++ | V4L2_JPEG_MARKER_DQT;
++ return 0;
++}
++
+ /* sub-driver description */
+ static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+@@ -998,6 +1041,8 @@ static struct sd_desc sd_desc = {
+ .start = sd_start,
+ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
++ .get_jcomp = sd_get_jcomp,
++ .set_jcomp = sd_set_jcomp,
+ };
+
+ /* -- module initialisation -- */
+@@ -1029,8 +1074,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
+index f3cd8ff..2c20d06 100644
+--- a/drivers/media/video/gspca/etoms.c
++++ b/drivers/media/video/gspca/etoms.c
+@@ -472,19 +472,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ reg_w_val(gspca_dev, ET_O_RED + i, brightness);
+ }
+
+-static void getbrightness(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+- int i;
+- int brightness = 0;
+-
+- for (i = 0; i < 4; i++) {
+- reg_r(gspca_dev, ET_O_RED + i, 1);
+- brightness += gspca_dev->usb_buf[0];
+- }
+- sd->brightness = brightness >> 3;
+-}
+-
+ static void setcontrast(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -495,19 +482,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
+ reg_w(gspca_dev, ET_G_RED, RGBG, 6);
+ }
+
+-static void getcontrast(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+- int i;
+- int contrast = 0;
+-
+- for (i = 0; i < 4; i++) {
+- reg_r(gspca_dev, ET_G_RED + i, 1);
+- contrast += gspca_dev->usb_buf[0];
+- }
+- sd->contrast = contrast >> 2;
+-}
+-
+ static void setcolors(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -658,7 +632,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 1;
+ sd->sensor = id->driver_info;
+ if (sd->sensor == SENSOR_PAS106) {
+ cam->cam_mode = sif_mode;
+@@ -821,7 +794,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+ }
+@@ -840,7 +812,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+ }
+@@ -859,7 +830,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+ }
+@@ -928,8 +898,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c
+index afc8b2d..00e6863 100644
+--- a/drivers/media/video/gspca/finepix.c
++++ b/drivers/media/video/gspca/finepix.c
+@@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver");
+ MODULE_LICENSE("GPL");
+
+ /* Default timeout, in ms */
+-#define FPIX_TIMEOUT (HZ / 10)
++#define FPIX_TIMEOUT 250
+
+ /* Maximum transfer size to use. The windows driver reads by chunks of
+ * 0x2000 bytes, so do the same. Note: reading more seems to work
+@@ -38,38 +38,15 @@ MODULE_LICENSE("GPL");
+ struct usb_fpix {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+- /*
+- * USB stuff
+- */
+- struct usb_ctrlrequest ctrlreq;
+- struct urb *control_urb;
+- struct timer_list bulk_timer;
+-
+- enum {
+- FPIX_NOP, /* inactive, else streaming */
+- FPIX_RESET, /* must reset */
+- FPIX_REQ_FRAME, /* requesting a frame */
+- FPIX_READ_FRAME, /* reading frame */
+- } state;
+-
+- /*
+- * Driver stuff
+- */
+- struct delayed_work wqe;
+- struct completion can_close;
+- int streaming;
++ struct work_struct work_struct;
++ struct workqueue_struct *work_thread;
+ };
+
+ /* Delay after which claim the next frame. If the delay is too small,
+ * the camera will return old frames. On the 4800Z, 20ms is bad, 25ms
+- * will fail every 4 or 5 frames, but 30ms is perfect. */
+-#define NEXT_FRAME_DELAY (((HZ * 30) + 999) / 1000)
+-
+-#define dev_new_state(new_state) { \
+- PDEBUG(D_STREAM, "new state from %d to %d at %s:%d", \
+- dev->state, new_state, __func__, __LINE__); \
+- dev->state = new_state; \
+-}
++ * will fail every 4 or 5 frames, but 30ms is perfect. On the A210,
++ * 30ms is bad while 35ms is perfect. */
++#define NEXT_FRAME_DELAY 35
+
+ /* These cameras only support 320x200. */
+ static const struct v4l2_pix_format fpix_mode[1] = {
+@@ -80,316 +57,183 @@ static const struct v4l2_pix_format fpix_mode[1] = {
+ .priv = 0}
+ };
+
+-/* Reads part of a frame */
+-static void read_frame_part(struct usb_fpix *dev)
++/* send a command to the webcam */
++static int command(struct gspca_dev *gspca_dev,
++ int order) /* 0: reset, 1: frame request */
+ {
+- int ret;
++ static u8 order_values[2][12] = {
++ {0xc6, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0}, /* reset */
++ {0xd3, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0}, /* fr req */
++ };
+
+- PDEBUG(D_STREAM, "read_frame_part");
+-
+- /* Reads part of a frame */
+- ret = usb_submit_urb(dev->gspca_dev.urb[0], GFP_ATOMIC);
+- if (ret) {
+- dev_new_state(FPIX_RESET);
+- schedule_delayed_work(&dev->wqe, 1);
+- PDEBUG(D_STREAM, "usb_submit_urb failed with %d",
+- ret);
+- } else {
+- /* Sometimes we never get a callback, so use a timer.
+- * Is this masking a bug somewhere else? */
+- dev->bulk_timer.expires = jiffies + msecs_to_jiffies(150);
+- add_timer(&dev->bulk_timer);
+- }
++ memcpy(gspca_dev->usb_buf, order_values[order], 12);
++ return usb_control_msg(gspca_dev->dev,
++ usb_sndctrlpipe(gspca_dev->dev, 0),
++ USB_REQ_GET_STATUS,
++ USB_DIR_OUT | USB_TYPE_CLASS |
++ USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
++ 12, FPIX_TIMEOUT);
+ }
+
+-/* Callback for URBs. */
+-static void urb_callback(struct urb *urb)
++/* workqueue */
++static void dostream(struct work_struct *work)
+ {
+- struct gspca_dev *gspca_dev = urb->context;
+- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+-
+- PDEBUG(D_PACK,
+- "enter urb_callback - status=%d, length=%d",
+- urb->status, urb->actual_length);
+-
+- if (dev->state == FPIX_READ_FRAME)
+- del_timer(&dev->bulk_timer);
+-
+- if (urb->status != 0) {
+- /* We kill a stuck urb every 50 frames on average, so don't
+- * display a log message for that. */
+- if (urb->status != -ECONNRESET)
+- PDEBUG(D_STREAM, "bad URB status %d", urb->status);
+- dev_new_state(FPIX_RESET);
+- schedule_delayed_work(&dev->wqe, 1);
+- }
+-
+- switch (dev->state) {
+- case FPIX_REQ_FRAME:
+- dev_new_state(FPIX_READ_FRAME);
+- read_frame_part(dev);
+- break;
+-
+- case FPIX_READ_FRAME: {
+- unsigned char *data = urb->transfer_buffer;
+- struct gspca_frame *frame;
+-
+- frame = gspca_get_i_frame(&dev->gspca_dev);
+- if (frame == NULL)
+- gspca_dev->last_packet_type = DISCARD_PACKET;
+- if (urb->actual_length < FPIX_MAX_TRANSFER ||
+- (data[urb->actual_length-2] == 0xff &&
+- data[urb->actual_length-1] == 0xd9)) {
+-
+- /* If the result is less than what was asked
+- * for, then it's the end of the
+- * frame. Sometime the jpeg is not complete,
+- * but there's nothing we can do. We also end
+- * here if the the jpeg ends right at the end
+- * of the frame. */
+- if (frame)
+- gspca_frame_add(gspca_dev, LAST_PACKET,
+- frame,
+- data, urb->actual_length);
+- dev_new_state(FPIX_REQ_FRAME);
+- schedule_delayed_work(&dev->wqe, NEXT_FRAME_DELAY);
+- } else {
++ struct usb_fpix *dev = container_of(work, struct usb_fpix, work_struct);
++ struct gspca_dev *gspca_dev = &dev->gspca_dev;
++ struct urb *urb = gspca_dev->urb[0];
++ u8 *data = urb->transfer_buffer;
++ struct gspca_frame *frame;
++ int ret = 0;
++ int len;
++
++ /* synchronize with the main driver */
++ mutex_lock(&gspca_dev->usb_lock);
++ mutex_unlock(&gspca_dev->usb_lock);
++ PDEBUG(D_STREAM, "dostream started");
++
++ /* loop reading a frame */
++again:
++ while (gspca_dev->present && gspca_dev->streaming) {
++
++ /* request a frame */
++ mutex_lock(&gspca_dev->usb_lock);
++ ret = command(gspca_dev, 1);
++ mutex_unlock(&gspca_dev->usb_lock);
++ if (ret < 0)
++ break;
++ if (!gspca_dev->present || !gspca_dev->streaming)
++ break;
++
++ /* the frame comes in parts */
++ for (;;) {
++ ret = usb_bulk_msg(gspca_dev->dev,
++ urb->pipe,
++ data,
++ FPIX_MAX_TRANSFER,
++ &len, FPIX_TIMEOUT);
++ if (ret < 0) {
++ /* Most of the time we get a timeout
++ * error. Just restart. */
++ goto again;
++ }
++ if (!gspca_dev->present || !gspca_dev->streaming)
++ goto out;
++ frame = gspca_get_i_frame(&dev->gspca_dev);
++ if (frame == NULL)
++ gspca_dev->last_packet_type = DISCARD_PACKET;
++
++ if (len < FPIX_MAX_TRANSFER ||
++ (data[len - 2] == 0xff &&
++ data[len - 1] == 0xd9)) {
++
++ /* If the result is less than what was asked
++ * for, then it's the end of the
++ * frame. Sometimes the jpeg is not complete,
++ * but there's nothing we can do. We also end
++ * here if the the jpeg ends right at the end
++ * of the frame. */
++ if (frame)
++ frame = gspca_frame_add(gspca_dev,
++ LAST_PACKET,
++ frame,
++ data, len);
++ break;
++ }
+
+ /* got a partial image */
+ if (frame)
+ gspca_frame_add(gspca_dev,
+ gspca_dev->last_packet_type
+- == LAST_PACKET
++ == LAST_PACKET
+ ? FIRST_PACKET : INTER_PACKET,
+- frame,
+- data, urb->actual_length);
+- read_frame_part(dev);
++ frame, data, len);
+ }
+- break;
+- }
+-
+- case FPIX_NOP:
+- case FPIX_RESET:
+- PDEBUG(D_STREAM, "invalid state %d", dev->state);
+- break;
+- }
+-}
+
+-/* Request a new frame */
+-static void request_frame(struct usb_fpix *dev)
+-{
+- int ret;
+- struct gspca_dev *gspca_dev = &dev->gspca_dev;
+-
+- /* Setup command packet */
+- memset(gspca_dev->usb_buf, 0, 12);
+- gspca_dev->usb_buf[0] = 0xd3;
+- gspca_dev->usb_buf[7] = 0x01;
+-
+- /* Request a frame */
+- dev->ctrlreq.bRequestType =
+- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+- dev->ctrlreq.bRequest = USB_REQ_GET_STATUS;
+- dev->ctrlreq.wValue = 0;
+- dev->ctrlreq.wIndex = 0;
+- dev->ctrlreq.wLength = cpu_to_le16(12);
+-
+- usb_fill_control_urb(dev->control_urb,
+- gspca_dev->dev,
+- usb_sndctrlpipe(gspca_dev->dev, 0),
+- (unsigned char *) &dev->ctrlreq,
+- gspca_dev->usb_buf,
+- 12, urb_callback, gspca_dev);
+-
+- ret = usb_submit_urb(dev->control_urb, GFP_ATOMIC);
+- if (ret) {
+- dev_new_state(FPIX_RESET);
+- schedule_delayed_work(&dev->wqe, 1);
+- PDEBUG(D_STREAM, "usb_submit_urb failed with %d", ret);
+- }
+-}
+-
+-/*--------------------------------------------------------------------------*/
+-
+-/* State machine. */
+-static void fpix_sm(struct work_struct *work)
+-{
+- struct usb_fpix *dev = container_of(work, struct usb_fpix, wqe.work);
+-
+- PDEBUG(D_STREAM, "fpix_sm state %d", dev->state);
+-
+- /* verify that the device wasn't unplugged */
+- if (!dev->gspca_dev.present) {
+- PDEBUG(D_STREAM, "device is gone");
+- dev_new_state(FPIX_NOP);
+- complete(&dev->can_close);
+- return;
+- }
+-
+- if (!dev->streaming) {
+- PDEBUG(D_STREAM, "stopping state machine");
+- dev_new_state(FPIX_NOP);
+- complete(&dev->can_close);
+- return;
++ /* We must wait before trying reading the next
++ * frame. If we don't, or if the delay is too short,
++ * the camera will disconnect. */
++ msleep(NEXT_FRAME_DELAY);
+ }
+
+- switch (dev->state) {
+- case FPIX_RESET:
+- dev_new_state(FPIX_REQ_FRAME);
+- schedule_delayed_work(&dev->wqe, HZ / 10);
+- break;
+-
+- case FPIX_REQ_FRAME:
+- /* get an image */
+- request_frame(dev);
+- break;
+-
+- case FPIX_NOP:
+- case FPIX_READ_FRAME:
+- PDEBUG(D_STREAM, "invalid state %d", dev->state);
+- break;
+- }
++out:
++ PDEBUG(D_STREAM, "dostream stopped");
+ }
+
+ /* this function is called at probe time */
+ static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+ {
++ struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
+
+ cam->cam_mode = fpix_mode;
+ cam->nmodes = 1;
+- cam->epaddr = 0x01; /* todo: correct for all cams? */
+ cam->bulk_size = FPIX_MAX_TRANSFER;
+
+-/* gspca_dev->nbalt = 1; * use bulk transfer */
+- return 0;
+-}
+-
+-/* Stop streaming and free the ressources allocated by sd_start. */
+-static void sd_stopN(struct gspca_dev *gspca_dev)
+-{
+- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+-
+- dev->streaming = 0;
+-
+- /* Stop the state machine */
+- if (dev->state != FPIX_NOP)
+- wait_for_completion(&dev->can_close);
+-}
+-
+-/* called on streamoff with alt 0 and disconnect */
+-static void sd_stop0(struct gspca_dev *gspca_dev)
+-{
+- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+-
+- usb_free_urb(dev->control_urb);
+- dev->control_urb = NULL;
+-}
+-
+-/* Kill an URB that hasn't completed. */
+-static void timeout_kill(unsigned long data)
+-{
+- struct urb *urb = (struct urb *) data;
++ INIT_WORK(&dev->work_struct, dostream);
+
+- usb_unlink_urb(urb);
++ return 0;
+ }
+
+ /* this function is called at probe and resume time */
+ static int sd_init(struct gspca_dev *gspca_dev)
+ {
+- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+-
+- INIT_DELAYED_WORK(&dev->wqe, fpix_sm);
+-
+- init_timer(&dev->bulk_timer);
+- dev->bulk_timer.function = timeout_kill;
+-
+ return 0;
+ }
+
++/* start the camera */
+ static int sd_start(struct gspca_dev *gspca_dev)
+ {
+ struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+- int ret;
+- int size_ret;
++ int ret, len;
+
+ /* Init the device */
+- memset(gspca_dev->usb_buf, 0, 12);
+- gspca_dev->usb_buf[0] = 0xc6;
+- gspca_dev->usb_buf[8] = 0x20;
+-
+- ret = usb_control_msg(gspca_dev->dev,
+- usb_sndctrlpipe(gspca_dev->dev, 0),
+- USB_REQ_GET_STATUS,
+- USB_DIR_OUT | USB_TYPE_CLASS |
+- USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+- 12, FPIX_TIMEOUT);
+-
+- if (ret != 12) {
+- PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
+- ret = -EIO;
+- goto error;
++ ret = command(gspca_dev, 0);
++ if (ret < 0) {
++ PDEBUG(D_STREAM, "init failed %d", ret);
++ return ret;
+ }
+
+ /* Read the result of the command. Ignore the result, for it
+ * varies with the device. */
+ ret = usb_bulk_msg(gspca_dev->dev,
+- usb_rcvbulkpipe(gspca_dev->dev,
+- gspca_dev->cam.epaddr),
+- gspca_dev->usb_buf, FPIX_MAX_TRANSFER, &size_ret,
++ gspca_dev->urb[0]->pipe,
++ gspca_dev->urb[0]->transfer_buffer,
++ FPIX_MAX_TRANSFER, &len,
+ FPIX_TIMEOUT);
+- if (ret != 0) {
+- PDEBUG(D_STREAM, "usb_bulk_msg failed (%d)", ret);
+- ret = -EIO;
+- goto error;
++ if (ret < 0) {
++ PDEBUG(D_STREAM, "usb_bulk_msg failed %d", ret);
++ return ret;
+ }
+
+ /* Request a frame, but don't read it */
+- memset(gspca_dev->usb_buf, 0, 12);
+- gspca_dev->usb_buf[0] = 0xd3;
+- gspca_dev->usb_buf[7] = 0x01;
+-
+- ret = usb_control_msg(gspca_dev->dev,
+- usb_sndctrlpipe(gspca_dev->dev, 0),
+- USB_REQ_GET_STATUS,
+- USB_DIR_OUT | USB_TYPE_CLASS |
+- USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+- 12, FPIX_TIMEOUT);
+- if (ret != 12) {
+- PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
+- ret = -EIO;
+- goto error;
++ ret = command(gspca_dev, 1);
++ if (ret < 0) {
++ PDEBUG(D_STREAM, "frame request failed %d", ret);
++ return ret;
+ }
+
+ /* Again, reset bulk in endpoint */
+- usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr);
+-
+- /* Allocate a control URB */
+- dev->control_urb = usb_alloc_urb(0, GFP_KERNEL);
+- if (!dev->control_urb) {
+- PDEBUG(D_STREAM, "No free urbs available");
+- ret = -EIO;
+- goto error;
+- }
+-
+- /* Various initializations. */
+- init_completion(&dev->can_close);
+- dev->bulk_timer.data = (unsigned long)dev->gspca_dev.urb[0];
+- dev->gspca_dev.urb[0]->complete = urb_callback;
+- dev->streaming = 1;
++ usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
+
+- /* Schedule a frame request. */
+- dev_new_state(FPIX_REQ_FRAME);
+- schedule_delayed_work(&dev->wqe, 1);
++ /* Start the workqueue function to do the streaming */
++ dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
++ queue_work(dev->work_thread, &dev->work_struct);
+
+ return 0;
++}
++
++/* called on streamoff with alt==0 and on disconnect */
++/* the usb_lock is held at entry - restore on exit */
++static void sd_stop0(struct gspca_dev *gspca_dev)
++{
++ struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+
+-error:
+- /* Free the ressources */
+- sd_stopN(gspca_dev);
+- sd_stop0(gspca_dev);
+- return ret;
++ /* wait for the work queue to terminate */
++ mutex_unlock(&gspca_dev->usb_lock);
++ destroy_workqueue(dev->work_thread);
++ mutex_lock(&gspca_dev->usb_lock);
++ dev->work_thread = NULL;
+ }
+
+ /* Table of supported USB devices */
+@@ -424,12 +268,11 @@ MODULE_DEVICE_TABLE(usb, device_table);
+
+ /* sub-driver description */
+ static const struct sd_desc sd_desc = {
+- .name = MODULE_NAME,
++ .name = MODULE_NAME,
+ .config = sd_config,
+- .init = sd_init,
+- .start = sd_start,
+- .stopN = sd_stopN,
+- .stop0 = sd_stop0,
++ .init = sd_init,
++ .start = sd_start,
++ .stop0 = sd_stop0,
+ };
+
+ /* -- device connect -- */
+@@ -443,24 +286,28 @@ static int sd_probe(struct usb_interface *intf,
+ }
+
+ static struct usb_driver sd_driver = {
+- .name = MODULE_NAME,
+- .id_table = device_table,
+- .probe = sd_probe,
++ .name = MODULE_NAME,
++ .id_table = device_table,
++ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+ #ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+- .resume = gspca_resume,
++ .resume = gspca_resume,
+ #endif
+ };
+
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
++
+ static void __exit sd_mod_exit(void)
+ {
+ usb_deregister(&sd_driver);
+diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
+index 65e4901..a75c1ca 100644
+--- a/drivers/media/video/gspca/gspca.c
++++ b/drivers/media/video/gspca/gspca.c
+@@ -38,15 +38,16 @@
+ #include "gspca.h"
+
+ /* global values */
+-#define DEF_NURBS 2 /* default number of URBs */
++#define DEF_NURBS 3 /* default number of URBs */
++#if DEF_NURBS > MAX_NURBS
++#error "DEF_NURBS too big"
++#endif
+
+ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+ MODULE_DESCRIPTION("GSPCA USB Camera Driver");
+ MODULE_LICENSE("GPL");
+
+-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 4, 0)
+-
+-static int video_nr = -1;
++#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 5, 0)
+
+ #ifdef GSPCA_DEBUG
+ int gspca_debug = D_ERR | D_PROBE;
+@@ -126,16 +127,18 @@ static void fill_frame(struct gspca_dev *gspca_dev,
+ struct urb *urb)
+ {
+ struct gspca_frame *frame;
+- __u8 *data; /* address of data in the iso message */
++ u8 *data; /* address of data in the iso message */
+ int i, len, st;
+ cam_pkt_op pkt_scan;
+
+ if (urb->status != 0) {
++ if (urb->status == -ESHUTDOWN)
++ return; /* disconnection */
+ #ifdef CONFIG_PM
+ if (!gspca_dev->frozen)
+ #endif
+ PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+- return; /* disconnection ? */
++ return;
+ }
+ pkt_scan = gspca_dev->sd_desc->pkt_scan;
+ for (i = 0; i < urb->number_of_packets; i++) {
+@@ -166,7 +169,7 @@ static void fill_frame(struct gspca_dev *gspca_dev,
+ /* let the packet be analyzed by the subdriver */
+ PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
+ i, urb->iso_frame_desc[i].offset, len);
+- data = (__u8 *) urb->transfer_buffer
++ data = (u8 *) urb->transfer_buffer
+ + urb->iso_frame_desc[i].offset;
+ pkt_scan(gspca_dev, frame, data, len);
+ }
+@@ -182,8 +185,7 @@ static void fill_frame(struct gspca_dev *gspca_dev,
+ *
+ * Analyse each packet and call the subdriver for copy to the frame buffer.
+ */
+-static void isoc_irq(struct urb *urb
+-)
++static void isoc_irq(struct urb *urb)
+ {
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+
+@@ -196,8 +198,7 @@ static void isoc_irq(struct urb *urb
+ /*
+ * bulk message interrupt from the USB device
+ */
+-static void bulk_irq(struct urb *urb
+-)
++static void bulk_irq(struct urb *urb)
+ {
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+ struct gspca_frame *frame;
+@@ -209,6 +210,8 @@ static void bulk_irq(struct urb *urb
+ switch (urb->status) {
+ case 0:
+ break;
++ case -ESHUTDOWN:
++ return; /* disconnection */
+ case -ECONNRESET:
+ urb->status = 0;
+ break;
+@@ -217,7 +220,7 @@ static void bulk_irq(struct urb *urb
+ if (!gspca_dev->frozen)
+ #endif
+ PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+- return; /* disconnection ? */
++ return;
+ }
+
+ /* check the availability of the frame buffer */
+@@ -322,6 +325,7 @@ static int gspca_is_compressed(__u32 format)
+ case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_SPCA561:
+ case V4L2_PIX_FMT_PAC207:
++ case V4L2_PIX_FMT_MR97310A:
+ return 1;
+ }
+ return 0;
+@@ -422,10 +426,8 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
+ if (urb == NULL)
+ break;
+
+- BUG_ON(!gspca_dev->dev);
+ gspca_dev->urb[i] = NULL;
+- if (!gspca_dev->present)
+- usb_kill_urb(urb);
++ usb_kill_urb(urb);
+ if (urb->transfer_buffer != NULL)
+ usb_buffer_free(gspca_dev->dev,
+ urb->transfer_buffer_length,
+@@ -439,22 +441,16 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
+ * look for an input transfer endpoint in an alternate setting
+ */
+ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
+- __u8 epaddr,
+ __u8 xfer)
+ {
+ struct usb_host_endpoint *ep;
+ int i, attr;
+
+- epaddr |= USB_DIR_IN;
+ for (i = 0; i < alt->desc.bNumEndpoints; i++) {
+ ep = &alt->endpoint[i];
+- if (ep->desc.bEndpointAddress == epaddr) {
+- attr = ep->desc.bmAttributes
+- & USB_ENDPOINT_XFERTYPE_MASK;
+- if (attr == xfer)
+- return ep;
+- break;
+- }
++ attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
++ if (attr == xfer)
++ return ep;
+ }
+ return NULL;
+ }
+@@ -478,23 +474,23 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
+ i = gspca_dev->alt; /* previous alt setting */
+
+ /* try isoc */
+- while (--i > 0) { /* alt 0 is unusable */
++ while (--i >= 0) {
+ ep = alt_xfer(&intf->altsetting[i],
+- gspca_dev->cam.epaddr,
+ USB_ENDPOINT_XFER_ISOC);
+ if (ep)
+ break;
+ }
+
+- /* if no isoc, try bulk */
++ /* if no isoc, try bulk (alt 0 only) */
+ if (ep == NULL) {
+ ep = alt_xfer(&intf->altsetting[0],
+- gspca_dev->cam.epaddr,
+ USB_ENDPOINT_XFER_BULK);
+ if (ep == NULL) {
+ err("no transfer endpoint found");
+ return NULL;
+ }
++ i = 0;
++ gspca_dev->bulk = 1;
+ }
+ PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
+ i, ep->desc.bEndpointAddress);
+@@ -521,7 +517,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
+ /* calculate the packet size and the number of packets */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+
+- if (gspca_dev->alt != 0) { /* isoc */
++ if (!gspca_dev->bulk) { /* isoc */
+
+ /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+@@ -601,6 +597,11 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+
++ if (!gspca_dev->present) {
++ ret = -ENODEV;
++ goto out;
++ }
++
+ /* set the higher alternate setting and
+ * loop until urb submit succeeds */
+ gspca_dev->alt = gspca_dev->nbalt;
+@@ -616,10 +617,9 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
+ goto out;
+
+ /* clear the bulk endpoint */
+- if (gspca_dev->alt == 0) /* if bulk transfer */
++ if (gspca_dev->bulk)
+ usb_clear_halt(gspca_dev->dev,
+- usb_rcvintpipe(gspca_dev->dev,
+- gspca_dev->cam.epaddr));
++ gspca_dev->urb[0]->pipe);
+
+ /* start the cam */
+ ret = gspca_dev->sd_desc->start(gspca_dev);
+@@ -630,7 +630,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
+ gspca_dev->streaming = 1;
+
+ /* some bulk transfers are started by the subdriver */
+- if (gspca_dev->alt == 0 && gspca_dev->cam.bulk_nurbs == 0)
++ if (gspca_dev->bulk && gspca_dev->cam.bulk_nurbs == 0)
+ break;
+
+ /* submit the URBs */
+@@ -671,11 +671,14 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
+ static void gspca_stream_off(struct gspca_dev *gspca_dev)
+ {
+ gspca_dev->streaming = 0;
+- if (gspca_dev->present
+- && gspca_dev->sd_desc->stopN)
+- gspca_dev->sd_desc->stopN(gspca_dev);
+- destroy_urbs(gspca_dev);
+- gspca_set_alt0(gspca_dev);
++ if (gspca_dev->present) {
++ if (gspca_dev->sd_desc->stopN)
++ gspca_dev->sd_desc->stopN(gspca_dev);
++ destroy_urbs(gspca_dev);
++ gspca_set_alt0(gspca_dev);
++ }
++
++ /* always call stop0 to free the subdriver's resources */
+ if (gspca_dev->sd_desc->stop0)
+ gspca_dev->sd_desc->stop0(gspca_dev);
+ PDEBUG(D_STREAM, "stream off OK");
+@@ -762,7 +765,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ fmtdesc->pixelformat = fmt_tb[index];
+ if (gspca_is_compressed(fmt_tb[index]))
+ fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
+- fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
+ fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
+ fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff;
+@@ -957,8 +959,15 @@ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+ {
+ struct gspca_dev *gspca_dev = priv;
++ int ret;
+
+- memset(cap, 0, sizeof *cap);
++ /* protect the access to the usb device */
++ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
++ return -ERESTARTSYS;
++ if (!gspca_dev->present) {
++ ret = -ENODEV;
++ goto out;
++ }
+ strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);
+ if (gspca_dev->dev->product != NULL) {
+ strncpy(cap->card, gspca_dev->dev->product,
+@@ -969,13 +978,15 @@ static int vidioc_querycap(struct file *file, void *priv,
+ le16_to_cpu(gspca_dev->dev->descriptor.idVendor),
+ le16_to_cpu(gspca_dev->dev->descriptor.idProduct));
+ }
+- strncpy(cap->bus_info, gspca_dev->dev->bus->bus_name,
+- sizeof cap->bus_info);
++ usb_make_path(gspca_dev->dev, cap->bus_info, sizeof(cap->bus_info));
+ cap->version = DRIVER_VERSION_NUMBER;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_STREAMING
+ | V4L2_CAP_READWRITE;
+- return 0;
++ ret = 0;
++out:
++ mutex_unlock(&gspca_dev->usb_lock);
++ return ret;
+ }
+
+ static int vidioc_queryctrl(struct file *file, void *priv,
+@@ -1038,7 +1049,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+ PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+- ret = ctrls->set(gspca_dev, ctrl->value);
++ if (gspca_dev->present)
++ ret = ctrls->set(gspca_dev, ctrl->value);
++ else
++ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+@@ -1062,7 +1076,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+- ret = ctrls->get(gspca_dev, &ctrl->value);
++ if (gspca_dev->present)
++ ret = ctrls->get(gspca_dev, &ctrl->value);
++ else
++ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+@@ -1081,7 +1098,6 @@ static int vidioc_s_audio(struct file *file, void *priv,
+ static int vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+ {
+- memset(audio, 0, sizeof *audio);
+ strcpy(audio->name, "Microphone");
+ return 0;
+ }
+@@ -1115,7 +1131,6 @@ static int vidioc_enum_input(struct file *file, void *priv,
+
+ if (input->index != 0)
+ return -EINVAL;
+- memset(input, 0, sizeof *input);
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ strncpy(input->name, gspca_dev->sd_desc->name,
+ sizeof input->name);
+@@ -1224,10 +1239,7 @@ static int vidioc_streamon(struct file *file, void *priv,
+ return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+- if (!gspca_dev->present) {
+- ret = -ENODEV;
+- goto out;
+- }
++
+ if (gspca_dev->nframes == 0
+ || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) {
+ ret = -EINVAL;
+@@ -1295,7 +1307,10 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv,
+ return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+- ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
++ if (gspca_dev->present)
++ ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
++ else
++ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+@@ -1310,7 +1325,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
+ return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+- ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
++ if (gspca_dev->present)
++ ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
++ else
++ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+@@ -1320,8 +1338,6 @@ static int vidioc_g_parm(struct file *filp, void *priv,
+ {
+ struct gspca_dev *gspca_dev = priv;
+
+- memset(parm, 0, sizeof *parm);
+- parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ parm->parm.capture.readbuffers = gspca_dev->nbufread;
+
+ if (gspca_dev->sd_desc->get_streamparm) {
+@@ -1329,7 +1345,11 @@ static int vidioc_g_parm(struct file *filp, void *priv,
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+- ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
++ if (gspca_dev->present)
++ ret = gspca_dev->sd_desc->get_streamparm(gspca_dev,
++ parm);
++ else
++ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+@@ -1354,7 +1374,11 @@ static int vidioc_s_parm(struct file *filp, void *priv,
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+- ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
++ if (gspca_dev->present)
++ ret = gspca_dev->sd_desc->set_streamparm(gspca_dev,
++ parm);
++ else
++ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+@@ -1382,7 +1406,6 @@ static int vidiocgmbuf(struct file *file, void *priv,
+ {
+ struct v4l2_format fmt;
+
+- memset(&fmt, 0, sizeof fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ i = gspca_dev->cam.nmodes - 1; /* highest mode */
+ fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
+@@ -1528,7 +1551,8 @@ static int frame_wait(struct gspca_dev *gspca_dev,
+
+ if (gspca_dev->sd_desc->dq_callback) {
+ mutex_lock(&gspca_dev->usb_lock);
+- gspca_dev->sd_desc->dq_callback(gspca_dev);
++ if (gspca_dev->present)
++ gspca_dev->sd_desc->dq_callback(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+ return j;
+@@ -1550,6 +1574,9 @@ static int vidioc_dqbuf(struct file *file, void *priv,
+ if (v4l2_buf->memory != gspca_dev->memory)
+ return -EINVAL;
+
++ if (!gspca_dev->present)
++ return -ENODEV;
++
+ /* if not streaming, be sure the application will not loop forever */
+ if (!(file->f_flags & O_NONBLOCK)
+ && !gspca_dev->streaming && gspca_dev->users == 1)
+@@ -1700,8 +1727,6 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
+ PDEBUG(D_FRAM, "poll");
+
+ poll_wait(file, &gspca_dev->wq, wait);
+- if (!gspca_dev->present)
+- return POLLERR;
+
+ /* if reqbufs is not done, the user would use read() */
+ if (gspca_dev->nframes == 0) {
+@@ -1714,10 +1739,6 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
+ return POLLERR;
+- if (!gspca_dev->present) {
+- ret = POLLERR;
+- goto out;
+- }
+
+ /* check the next incoming buffer */
+ i = gspca_dev->fr_o;
+@@ -1726,8 +1747,9 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
+ ret = POLLIN | POLLRDNORM; /* something to read */
+ else
+ ret = 0;
+-out:
+ mutex_unlock(&gspca_dev->queue_lock);
++ if (!gspca_dev->present)
++ return POLLHUP;
+ return ret;
+ }
+
+@@ -1925,7 +1947,7 @@ int gspca_dev_probe(struct usb_interface *intf,
+ gspca_dev->present = 1;
+ ret = video_register_device(&gspca_dev->vdev,
+ VFL_TYPE_GRABBER,
+- video_nr);
++ -1);
+ if (ret < 0) {
+ err("video_register_device err %d", ret);
+ goto out;
+@@ -1953,10 +1975,16 @@ void gspca_disconnect(struct usb_interface *intf)
+
+ mutex_lock(&gspca_dev->usb_lock);
+ gspca_dev->present = 0;
+- mutex_unlock(&gspca_dev->usb_lock);
+
+- destroy_urbs(gspca_dev);
++ if (gspca_dev->streaming) {
++ destroy_urbs(gspca_dev);
++ wake_up_interruptible(&gspca_dev->wq);
++ }
++
++ /* the device is freed at exit of this function */
+ gspca_dev->dev = NULL;
++ mutex_unlock(&gspca_dev->usb_lock);
++
+ usb_set_intfdata(intf, NULL);
+
+ /* release the device */
+diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
+index c90af9c..e4d4cf6 100644
+--- a/drivers/media/video/gspca/gspca.h
++++ b/drivers/media/video/gspca/gspca.h
+@@ -33,19 +33,13 @@ extern int gspca_debug;
+ #endif
+ #undef err
+ #define err(fmt, args...) \
+- do {\
+- printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args); \
+- } while (0)
++ printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args)
+ #undef info
+ #define info(fmt, args...) \
+- do {\
+- printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \
+- } while (0)
++ printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args)
+ #undef warn
+ #define warn(fmt, args...) \
+- do {\
+- printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args); \
+- } while (0)
++ printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args)
+
+ #define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */
+ /* image transfers */
+@@ -62,7 +56,6 @@ struct cam {
+ * - cannot be > MAX_NURBS
+ * - when 0 and bulk_size != 0 means
+ * 1 URB and submit done by subdriver */
+- __u8 epaddr;
+ };
+
+ struct gspca_dev;
+@@ -174,6 +167,7 @@ struct gspca_dev {
+ __u8 iface; /* USB interface number */
+ __u8 alt; /* USB alternate setting */
+ __u8 nbalt; /* number of USB alternate settings */
++ u8 bulk; /* image transfer by 0:isoc / 1:bulk */
+ };
+
+ int gspca_dev_probe(struct usb_interface *intf,
+diff --git a/drivers/media/video/gspca/jpeg.h b/drivers/media/video/gspca/jpeg.h
+index d823b47..de63c36 100644
+--- a/drivers/media/video/gspca/jpeg.h
++++ b/drivers/media/video/gspca/jpeg.h
+@@ -24,171 +24,39 @@
+ *
+ */
+
+-/* start of jpeg frame + quantization table */
+-static const unsigned char quant[][0x88] = {
+-/* index 0 - Q40*/
+- {
++/*
++ * generation options
++ * CONEX_CAM Conexant if present
++ */
++
++/* JPEG header */
++static const u8 jpeg_head[] = {
+ 0xff, 0xd8, /* jpeg */
+- 0xff, 0xdb, 0x00, 0x84, /* DQT */
+-0, /* quantization table part 1 */
+- 20, 14, 15, 18, 15, 13, 20, 18, 16, 18, 23, 21, 20, 24, 30, 50,
+- 33, 30, 28, 28, 30, 61, 44, 46, 36, 50, 73, 64, 76, 75, 71, 64,
+- 70, 69, 80, 90, 115, 98, 80, 85, 109, 86, 69, 70, 100, 136, 101,
+- 109,
+- 119, 123, 129, 130, 129, 78, 96, 141, 151, 140, 125, 150, 115,
+- 126, 129, 124,
+-1, /* quantization table part 2 */
+- 21, 23, 23, 30, 26, 30, 59, 33, 33, 59, 124, 83, 70, 83, 124, 124,
+- 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+- 124, 124, 124,
+- 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+- 124, 124, 124,
+- 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+- 124, 124, 124},
+-/* index 1 - Q50 */
+- {
+- 0xff, 0xd8,
+- 0xff, 0xdb, 0x00, 0x84, /* DQT */
+-0,
+- 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40,
+- 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51,
+- 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81, 87,
+- 95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92, 101,
+- 103, 99,
+-1,
+- 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66, 99, 99,
+- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99},
+-/* index 2 Q60 */
+- {
+- 0xff, 0xd8,
+- 0xff, 0xdb, 0x00, 0x84, /* DQT */
+-0,
+- 13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32,
+- 21, 19, 18, 18, 19, 39, 28, 30, 23, 32, 46, 41, 49, 48, 46, 41,
+- 45, 44, 51, 58, 74, 62, 51, 54, 70, 55, 44, 45, 64, 87, 65, 70,
+- 76, 78, 82, 83, 82, 50, 62, 90, 97, 90, 80, 96, 74, 81, 82, 79,
+-1,
+- 14, 14, 14, 19, 17, 19, 38, 21, 21, 38, 79, 53, 45, 53, 79, 79,
+- 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+- 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+- 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79},
+-/* index 3 - Q70 */
+- {
+- 0xff, 0xd8,
+- 0xff, 0xdb, 0x00, 0x84, /* DQT */
+-0,
+- 10, 7, 7, 8, 7, 6, 10, 8, 8, 8, 11, 10, 10, 11, 14, 24,
+- 16, 14, 13, 13, 14, 29, 21, 22, 17, 24, 35, 31, 37, 36, 34, 31,
+- 34, 33, 38, 43, 55, 47, 38, 41, 52, 41, 33, 34, 48, 65, 49, 52,
+- 57, 59, 62, 62, 62, 37, 46, 68, 73, 67, 60, 72, 55, 61, 62, 59,
+-1,
+- 10, 11, 11, 14, 13, 14, 28, 16, 16, 28, 59, 40, 34, 40, 59, 59,
+- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59},
+-/* index 4 - Q80 */
+- {
+- 0xff, 0xd8,
+- 0xff, 0xdb, 0x00, 0x84, /* DQT */
+-0,
+- 6, 4, 5, 6, 5, 4, 6, 6, 5, 6, 7, 7, 6, 8, 10, 16,
+- 10, 10, 9, 9, 10, 20, 14, 15, 12, 16, 23, 20, 24, 24, 23, 20,
+- 22, 22, 26, 29, 37, 31, 26, 27, 35, 28, 22, 22, 32, 44, 32, 35,
+- 38, 39, 41, 42, 41, 25, 31, 45, 48, 45, 40, 48, 37, 40, 41, 40,
+-1,
+- 7, 7, 7, 10, 8, 10, 19, 10, 10, 19, 40, 26, 22, 26, 40, 40,
+- 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+- 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+- 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40},
+-/* index 5 - Q85 */
+- {
+- 0xff, 0xd8,
+- 0xff, 0xdb, 0x00, 0x84, /* DQT */
+-0,
+- 5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6, 7, 12,
+- 8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18, 18, 17, 15,
+- 17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17, 24, 33, 24, 26,
+- 29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30, 36, 28, 30, 31, 30,
+-1,
+- 5, 5, 5, 7, 6, 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30,
+- 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+- 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+- 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+-/* index 6 - 86 */
+-{
+- 0xff, 0xd8,
+- 0xff, 0xdb, 0x00, 0x84, /* DQT */
+-0,
+- 0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04,
+- 0x04, 0x04, 0x05, 0x05, 0x04, 0x05, 0x07, 0x0B,
+- 0x07, 0x07, 0x06, 0x06, 0x07, 0x0E, 0x0A, 0x0A,
+- 0x08, 0x0B, 0x10, 0x0E, 0x11, 0x11, 0x10, 0x0E,
+- 0x10, 0x0F, 0x12, 0x14, 0x1A, 0x16, 0x12, 0x13,
+- 0x18, 0x13, 0x0F, 0x10, 0x16, 0x1F, 0x17, 0x18,
+- 0x1B, 0x1B, 0x1D, 0x1D, 0x1D, 0x11, 0x16, 0x20,
+- 0x22, 0x1F, 0x1C, 0x22, 0x1A, 0x1C, 0x1D, 0x1C,
+-1,
+- 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0D, 0x07,
+- 0x07, 0x0D, 0x1C, 0x12, 0x10, 0x12, 0x1C, 0x1C,
+- 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+- 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+- 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+- 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+- 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+- 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+- },
+-/* index 7 - 88 */
+-{
+- 0xff, 0xd8,
+- 0xff, 0xdb, 0x00, 0x84, /* DQT */
+-0,
+- 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x04, 0x03,
+- 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x06, 0x0A,
+- 0x06, 0x06, 0x05, 0x05, 0x06, 0x0C, 0x08, 0x09,
+- 0x07, 0x0A, 0x0E, 0x0C, 0x0F, 0x0E, 0x0E, 0x0C,
+- 0x0D, 0x0D, 0x0F, 0x11, 0x16, 0x13, 0x0F, 0x10,
+- 0x15, 0x11, 0x0D, 0x0D, 0x13, 0x1A, 0x13, 0x15,
+- 0x17, 0x18, 0x19, 0x19, 0x19, 0x0F, 0x12, 0x1B,
+- 0x1D, 0x1B, 0x18, 0x1D, 0x16, 0x18, 0x19, 0x18,
+-1,
+- 0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0B, 0x06,
+- 0x06, 0x0B, 0x18, 0x10, 0x0D, 0x10, 0x18, 0x18,
+- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+-},
+-/* index 8 - ?? */
+-{
+- 0xff, 0xd8,
++
++/* quantization table quality 50% */
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+ 0,
+- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x05,
+- 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05,
+- 0x04, 0x05, 0x07, 0x06, 0x08, 0x08, 0x07, 0x06,
+- 0x07, 0x07, 0x08, 0x09, 0x0C, 0x0A, 0x08, 0x09,
+- 0x0B, 0x09, 0x07, 0x07, 0x0A, 0x0E, 0x0A, 0x0B,
+- 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x08, 0x0A, 0x0E,
+- 0x0F, 0x0E, 0x0D, 0x0F, 0x0C, 0x0D, 0x0D, 0x0C,
++#define JPEG_QT0_OFFSET 7
++ 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,
+ 1,
+- 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03,
+- 0x03, 0x06, 0x0C, 0x08, 0x07, 0x08, 0x0C, 0x0C,
+- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+- 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
+-}
+-};
++#define JPEG_QT1_OFFSET 72
++ 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,
+
+-/* huffman table + start of SOF0 */
+-static unsigned char huffman[] = {
++/* huffman table */
+ 0xff, 0xc4, 0x01, 0xa2,
+ 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+@@ -244,58 +112,57 @@ static unsigned char huffman[] = {
+ 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
+ #ifdef CONEX_CAM
+ /* the Conexant frames start with SOF0 */
++#define JPEG_HDR_SZ 556
+ #else
+ 0xff, 0xc0, 0x00, 0x11, /* SOF0 (start of frame 0 */
+ 0x08, /* data precision */
+-#endif
+-};
+-
+-#ifndef CONEX_CAM
+-/* variable part:
+- * 0x01, 0xe0, height
+- * 0x02, 0x80, width
+- * 0x03, component number
+- * 0x01,
+- * 0x21, samples Y
+- */
+-
+-/* end of header */
+-static unsigned char eoh[] = {
++#define JPEG_HEIGHT_OFFSET 561
++ 0x01, 0xe0, /* height */
++ 0x02, 0x80, /* width */
++ 0x03, /* component number */
++ 0x01,
++ 0x21, /* samples Y */
+ 0x00, /* quant Y */
+ 0x02, 0x11, 0x01, /* samples CbCr - quant CbCr */
+ 0x03, 0x11, 0x01,
+
+ 0xff, 0xda, 0x00, 0x0c, /* SOS (start of scan) */
+ 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+-};
++#define JPEG_HDR_SZ 589
+ #endif
++};
+
+-/* -- output the JPEG header -- */
+-static void jpeg_put_header(struct gspca_dev *gspca_dev,
+- struct gspca_frame *frame,
+- int qindex,
+- int samplesY)
++/* define the JPEG header */
++static void jpeg_define(u8 *jpeg_hdr,
++ int height,
++ int width,
++ int samplesY)
+ {
++ memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head);
+ #ifndef CONEX_CAM
+- unsigned char tmpbuf[8];
++ jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8;
++ jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height & 0xff;
++ jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8;
++ jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width & 0xff;
++ jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY;
+ #endif
++}
+
+- gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+- (unsigned char *) quant[qindex], sizeof quant[0]);
+- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+- (unsigned char *) huffman, sizeof huffman);
+-#ifndef CONEX_CAM
+- tmpbuf[0] = gspca_dev->height >> 8;
+- tmpbuf[1] = gspca_dev->height & 0xff;
+- tmpbuf[2] = gspca_dev->width >> 8;
+- tmpbuf[3] = gspca_dev->width & 0xff;
+- tmpbuf[4] = 0x03; /* component number */
+- tmpbuf[5] = 0x01; /* first component */
+- tmpbuf[6] = samplesY;
+- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+- tmpbuf, 7);
+- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+- eoh, sizeof eoh);
+-#endif
++/* set the JPEG quality */
++static void jpeg_set_qual(u8 *jpeg_hdr,
++ int quality)
++{
++ int i, sc;
++
++ if (quality < 50)
++ sc = 5000 / quality;
++ else
++ sc = 200 - quality * 2;
++ for (i = 0; i < 64; i++) {
++ jpeg_hdr[JPEG_QT0_OFFSET + i] =
++ (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
++ jpeg_hdr[JPEG_QT1_OFFSET + i] =
++ (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
++ }
+ }
+ #endif
+diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
+index ed906fe..b35e483 100644
+--- a/drivers/media/video/gspca/m5602/m5602_core.c
++++ b/drivers/media/video/gspca/m5602/m5602_core.c
+@@ -332,7 +332,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
+ int err;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = M5602_ISOC_ENDPOINT_ADDR;
+ sd->desc = &sd_desc;
+
+ if (dump_bridge)
+@@ -374,8 +373,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init mod_m5602_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
+index 3d2090e..75e8d14 100644
+--- a/drivers/media/video/gspca/mars.c
++++ b/drivers/media/video/gspca/mars.c
+@@ -32,17 +32,91 @@ MODULE_LICENSE("GPL");
+ struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+- char qindex;
++ u8 brightness;
++ u8 colors;
++ u8 gamma;
++ u8 sharpness;
++ u8 quality;
++#define QUALITY_MIN 40
++#define QUALITY_MAX 70
++#define QUALITY_DEF 50
++
++ u8 *jpeg_hdr;
+ };
+
+ /* V4L2 controls supported by the driver */
++static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
++static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
++static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
++static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
++static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
++static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
++static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
++static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
++
+ static struct ctrl sd_ctrls[] = {
++ {
++ {
++ .id = V4L2_CID_BRIGHTNESS,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Brightness",
++ .minimum = 0,
++ .maximum = 30,
++ .step = 1,
++#define BRIGHTNESS_DEF 15
++ .default_value = BRIGHTNESS_DEF,
++ },
++ .set = sd_setbrightness,
++ .get = sd_getbrightness,
++ },
++ {
++ {
++ .id = V4L2_CID_SATURATION,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Color",
++ .minimum = 1,
++ .maximum = 255,
++ .step = 1,
++#define COLOR_DEF 200
++ .default_value = COLOR_DEF,
++ },
++ .set = sd_setcolors,
++ .get = sd_getcolors,
++ },
++ {
++ {
++ .id = V4L2_CID_GAMMA,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Gamma",
++ .minimum = 0,
++ .maximum = 3,
++ .step = 1,
++#define GAMMA_DEF 1
++ .default_value = GAMMA_DEF,
++ },
++ .set = sd_setgamma,
++ .get = sd_getgamma,
++ },
++ {
++ {
++ .id = V4L2_CID_SHARPNESS,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Sharpness",
++ .minimum = 0,
++ .maximum = 2,
++ .step = 1,
++#define SHARPNESS_DEF 1
++ .default_value = SHARPNESS_DEF,
++ },
++ .set = sd_setsharpness,
++ .get = sd_getsharpness,
++ },
+ };
+
+ static const struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+- .sizeimage = 320 * 240 * 3 / 8 + 589,
++ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+@@ -52,65 +126,45 @@ static const struct v4l2_pix_format vga_mode[] = {
+ .priv = 1},
+ };
+
+-/* MI Register table //elvis */
+-enum {
+- REG_HW_MI_0,
+- REG_HW_MI_1,
+- REG_HW_MI_2,
+- REG_HW_MI_3,
+- REG_HW_MI_4,
+- REG_HW_MI_5,
+- REG_HW_MI_6,
+- REG_HW_MI_7,
+- REG_HW_MI_9 = 0x09,
+- REG_HW_MI_B = 0x0B,
+- REG_HW_MI_C,
+- REG_HW_MI_D,
+- REG_HW_MI_1E = 0x1E,
+- REG_HW_MI_20 = 0x20,
+- REG_HW_MI_2B = 0x2B,
+- REG_HW_MI_2C,
+- REG_HW_MI_2D,
+- REG_HW_MI_2E,
+- REG_HW_MI_35 = 0x35,
+- REG_HW_MI_5F = 0x5f,
+- REG_HW_MI_60,
+- REG_HW_MI_61,
+- REG_HW_MI_62,
+- REG_HW_MI_63,
+- REG_HW_MI_64,
+- REG_HW_MI_F1 = 0xf1,
+- ATTR_TOTAL_MI_REG = 0xf2
++static const __u8 mi_data[0x20] = {
++/* 01 02 03 04 05 06 07 08 */
++ 0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00,
++/* 09 0a 0b 0c 0d 0e 0f 10 */
++ 0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01,
++/* 11 12 13 14 15 16 17 18 */
++ 0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02,
++/* 19 1a 1b 1c 1d 1e 1f 20 */
++ 0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00
+ };
+
+-/* the bytes to write are in gspca_dev->usb_buf */
++/* write <len> bytes from gspca_dev->usb_buf */
+ static int reg_w(struct gspca_dev *gspca_dev,
+- __u16 index, int len)
++ int len)
+ {
+- int rc;
+-
+- rc = usb_control_msg(gspca_dev->dev,
+- usb_sndbulkpipe(gspca_dev->dev, 4),
+- 0x12,
+- 0xc8, /* ?? */
+- 0, /* value */
+- index, gspca_dev->usb_buf, len, 500);
+- if (rc < 0)
+- PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
+- return rc;
++ int alen, ret;
++
++ ret = usb_bulk_msg(gspca_dev->dev,
++ usb_sndbulkpipe(gspca_dev->dev, 4),
++ gspca_dev->usb_buf,
++ len,
++ &alen,
++ 500); /* timeout in milliseconds */
++ if (ret < 0)
++ PDEBUG(D_ERR, "reg write [%02x] error %d",
++ gspca_dev->usb_buf[0], ret);
++ return ret;
+ }
+
+-static void bulk_w(struct gspca_dev *gspca_dev,
+- __u16 *pch,
+- __u16 Address)
++static void mi_w(struct gspca_dev *gspca_dev,
++ u8 addr,
++ u8 value)
+ {
+ gspca_dev->usb_buf[0] = 0x1f;
+ gspca_dev->usb_buf[1] = 0; /* control byte */
+- gspca_dev->usb_buf[2] = Address;
+- gspca_dev->usb_buf[3] = *pch >> 8; /* high byte */
+- gspca_dev->usb_buf[4] = *pch; /* low byte */
++ gspca_dev->usb_buf[2] = addr;
++ gspca_dev->usb_buf[3] = value;
+
+- reg_w(gspca_dev, Address, 5);
++ reg_w(gspca_dev, 4);
+ }
+
+ /* this function is called at probe time */
+@@ -121,10 +175,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+- sd->qindex = 1; /* set the quantization table */
++ sd->brightness = BRIGHTNESS_DEF;
++ sd->colors = COLOR_DEF;
++ sd->gamma = GAMMA_DEF;
++ sd->sharpness = SHARPNESS_DEF;
++ sd->quality = QUALITY_DEF;
++ gspca_dev->nbalt = 9; /* use the altsetting 08 */
+ return 0;
+ }
+
+@@ -136,24 +194,22 @@ static int sd_init(struct gspca_dev *gspca_dev)
+
+ static int sd_start(struct gspca_dev *gspca_dev)
+ {
++ struct sd *sd = (struct sd *) gspca_dev;
+ int err_code;
+- __u8 *data;
+- __u16 *MI_buf;
+- int h_size, v_size;
+- int intpipe;
+-
+- PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
+- err_code = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8);
+- if (err_code < 0) {
+- PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
+- return err_code;
+- }
++ u8 *data;
++ int i;
++
++ /* create the JPEG header */
++ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
++ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
++ 0x21); /* JPEG 422 */
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
+ data = gspca_dev->usb_buf;
++
+ data[0] = 0x01; /* address */
+ data[1] = 0x01;
+-
+- err_code = reg_w(gspca_dev, data[0], 2);
++ err_code = reg_w(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
+
+@@ -163,30 +219,28 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ data[0] = 0x00; /* address */
+ data[1] = 0x0c | 0x01; /* reg 0 */
+ data[2] = 0x01; /* reg 1 */
+- h_size = gspca_dev->width;
+- v_size = gspca_dev->height;
+- data[3] = h_size / 8; /* h_size , reg 2 */
+- data[4] = v_size / 8; /* v_size , reg 3 */
++ data[3] = gspca_dev->width / 8; /* h_size , reg 2 */
++ data[4] = gspca_dev->height / 8; /* v_size , reg 3 */
+ data[5] = 0x30; /* reg 4, MI, PAS5101 :
+ * 0x30 for 24mhz , 0x28 for 12mhz */
+- data[6] = 4; /* reg 5, H start */
+- data[7] = 0xc0; /* reg 6, gamma 1.5 */
+- data[8] = 3; /* reg 7, V start */
++ data[6] = 0x02; /* reg 5, H start - was 0x04 */
++ data[7] = sd->gamma * 0x40; /* reg 0x06: gamma */
++ data[8] = 0x01; /* reg 7, V start - was 0x03 */
+ /* if (h_size == 320 ) */
+ /* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */
+ /* else */
+ data[9] = 0x52; /* reg 8, 24MHz, no scale down */
+- data[10] = 0x5d; /* reg 9, I2C device address
+- * [for PAS5101 (0x40)] [for MI (0x5d)] */
++/*jfm: from win trace*/
++ data[10] = 0x18;
+
+- err_code = reg_w(gspca_dev, data[0], 11);
++ err_code = reg_w(gspca_dev, 11);
+ if (err_code < 0)
+ return err_code;
+
+ data[0] = 0x23; /* address */
+ data[1] = 0x09; /* reg 35, append frame header */
+
+- err_code = reg_w(gspca_dev, data[0], 2);
++ err_code = reg_w(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
+
+@@ -197,137 +251,57 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ /* else */
+ data[1] = 50; /* 50 reg 60, pc-cam frame size
+ * (unit: 4KB) 200KB */
+- err_code = reg_w(gspca_dev, data[0], 2);
++ err_code = reg_w(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
+
+- if (0) { /* fixed dark-gain */
+- data[1] = 0; /* reg 94, Y Gain (1.75) */
+- data[2] = 0; /* reg 95, UV Gain (1.75) */
+- data[3] = 0x3f; /* reg 96, Y Gain/UV Gain/disable
+- * auto dark-gain */
+- data[4] = 0; /* reg 97, set fixed dark level */
+- data[5] = 0; /* reg 98, don't care */
+- } else { /* auto dark-gain */
+- data[1] = 0; /* reg 94, Y Gain (auto) */
+- data[2] = 0; /* reg 95, UV Gain (1.75) */
+- data[3] = 0x78; /* reg 96, Y Gain/UV Gain/disable
+- * auto dark-gain */
+- switch (gspca_dev->width) {
+-/* case 1280: */
+-/* data[4] = 154;
+- * reg 97, %3 shadow point (unit: 256 pixel) */
+-/* data[5] = 51;
+- * reg 98, %1 highlight point
+- * (uint: 256 pixel) */
+-/* break; */
+- default:
+-/* case 640: */
+- data[4] = 36; /* reg 97, %3 shadow point
+- * (unit: 256 pixel) */
+- data[5] = 12; /* reg 98, %1 highlight point
+- * (uint: 256 pixel) */
+- break;
+- case 320:
+- data[4] = 9; /* reg 97, %3 shadow point
+- * (unit: 256 pixel) */
+- data[5] = 3; /* reg 98, %1 highlight point
+- * (uint: 256 pixel) */
+- break;
+- }
+- }
+ /* auto dark-gain */
+ data[0] = 0x5e; /* address */
+-
+- err_code = reg_w(gspca_dev, data[0], 6);
++ data[1] = 0; /* reg 94, Y Gain (auto) */
++/*jfm: from win trace*/
++ /* reg 0x5f/0x60 (LE) = saturation */
++ /* h (60): xxxx x100
++ * l (5f): xxxx x000 */
++ data[2] = sd->colors << 3;
++ data[3] = ((sd->colors >> 2) & 0xf8) | 0x04;
++ data[4] = sd->brightness; /* reg 0x61 = brightness */
++ data[5] = 0x00;
++
++ err_code = reg_w(gspca_dev, 6);
+ if (err_code < 0)
+ return err_code;
+
+ data[0] = 0x67;
+- data[1] = 0x13; /* reg 103, first pixel B, disable sharpness */
+- err_code = reg_w(gspca_dev, data[0], 2);
++/*jfm: from win trace*/
++ data[1] = sd->sharpness * 4 + 3;
++ data[2] = 0x14;
++ err_code = reg_w(gspca_dev, 3);
+ if (err_code < 0)
+ return err_code;
+
+- /*
+- * initialize the value of MI sensor...
+- */
+- MI_buf = kzalloc(ATTR_TOTAL_MI_REG * sizeof *MI_buf, GFP_KERNEL);
+- MI_buf[REG_HW_MI_1] = 0x000a;
+- MI_buf[REG_HW_MI_2] = 0x000c;
+- MI_buf[REG_HW_MI_3] = 0x0405;
+- MI_buf[REG_HW_MI_4] = 0x0507;
+- /* mi_Attr_Reg_[REG_HW_MI_5] = 0x01ff;//13 */
+- MI_buf[REG_HW_MI_5] = 0x0013; /* 13 */
+- MI_buf[REG_HW_MI_6] = 0x001f; /* vertical blanking */
+- /* mi_Attr_Reg_[REG_HW_MI_6] = 0x0400; // vertical blanking */
+- MI_buf[REG_HW_MI_7] = 0x0002;
+- /* mi_Attr_Reg_[REG_HW_MI_9] = 0x015f; */
+- /* mi_Attr_Reg_[REG_HW_MI_9] = 0x030f; */
+- MI_buf[REG_HW_MI_9] = 0x0374;
+- MI_buf[REG_HW_MI_B] = 0x0000;
+- MI_buf[REG_HW_MI_C] = 0x0000;
+- MI_buf[REG_HW_MI_D] = 0x0000;
+- MI_buf[REG_HW_MI_1E] = 0x8000;
+-/* mi_Attr_Reg_[REG_HW_MI_20] = 0x1104; */
+- MI_buf[REG_HW_MI_20] = 0x1104; /* 0x111c; */
+- MI_buf[REG_HW_MI_2B] = 0x0008;
+-/* mi_Attr_Reg_[REG_HW_MI_2C] = 0x000f; */
+- MI_buf[REG_HW_MI_2C] = 0x001f; /* lita suggest */
+- MI_buf[REG_HW_MI_2D] = 0x0008;
+- MI_buf[REG_HW_MI_2E] = 0x0008;
+- MI_buf[REG_HW_MI_35] = 0x0051;
+- MI_buf[REG_HW_MI_5F] = 0x0904; /* fail to write */
+- MI_buf[REG_HW_MI_60] = 0x0000;
+- MI_buf[REG_HW_MI_61] = 0x0000;
+- MI_buf[REG_HW_MI_62] = 0x0498;
+- MI_buf[REG_HW_MI_63] = 0x0000;
+- MI_buf[REG_HW_MI_64] = 0x0000;
+- MI_buf[REG_HW_MI_F1] = 0x0001;
+- /* changing while setting up the different value of dx/dy */
+-
+- if (gspca_dev->width != 1280) {
+- MI_buf[0x01] = 0x010a;
+- MI_buf[0x02] = 0x014c;
+- MI_buf[0x03] = 0x01e5;
+- MI_buf[0x04] = 0x0287;
+- }
+- MI_buf[0x20] = 0x1104;
+-
+- bulk_w(gspca_dev, MI_buf + 1, 1);
+- bulk_w(gspca_dev, MI_buf + 2, 2);
+- bulk_w(gspca_dev, MI_buf + 3, 3);
+- bulk_w(gspca_dev, MI_buf + 4, 4);
+- bulk_w(gspca_dev, MI_buf + 5, 5);
+- bulk_w(gspca_dev, MI_buf + 6, 6);
+- bulk_w(gspca_dev, MI_buf + 7, 7);
+- bulk_w(gspca_dev, MI_buf + 9, 9);
+- bulk_w(gspca_dev, MI_buf + 0x0b, 0x0b);
+- bulk_w(gspca_dev, MI_buf + 0x0c, 0x0c);
+- bulk_w(gspca_dev, MI_buf + 0x0d, 0x0d);
+- bulk_w(gspca_dev, MI_buf + 0x1e, 0x1e);
+- bulk_w(gspca_dev, MI_buf + 0x20, 0x20);
+- bulk_w(gspca_dev, MI_buf + 0x2b, 0x2b);
+- bulk_w(gspca_dev, MI_buf + 0x2c, 0x2c);
+- bulk_w(gspca_dev, MI_buf + 0x2d, 0x2d);
+- bulk_w(gspca_dev, MI_buf + 0x2e, 0x2e);
+- bulk_w(gspca_dev, MI_buf + 0x35, 0x35);
+- bulk_w(gspca_dev, MI_buf + 0x5f, 0x5f);
+- bulk_w(gspca_dev, MI_buf + 0x60, 0x60);
+- bulk_w(gspca_dev, MI_buf + 0x61, 0x61);
+- bulk_w(gspca_dev, MI_buf + 0x62, 0x62);
+- bulk_w(gspca_dev, MI_buf + 0x63, 0x63);
+- bulk_w(gspca_dev, MI_buf + 0x64, 0x64);
+- bulk_w(gspca_dev, MI_buf + 0xf1, 0xf1);
+- kfree(MI_buf);
+-
+- intpipe = usb_sndintpipe(gspca_dev->dev, 0);
+- err_code = usb_clear_halt(gspca_dev->dev, intpipe);
++ data[0] = 0x69;
++ data[1] = 0x2f;
++ data[2] = 0x28;
++ data[3] = 0x42;
++ err_code = reg_w(gspca_dev, 4);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x63;
++ data[1] = 0x07;
++ err_code = reg_w(gspca_dev, 2);
++/*jfm: win trace - many writes here to reg 0x64*/
++ if (err_code < 0)
++ return err_code;
++
++ /* initialize the MI sensor */
++ for (i = 0; i < sizeof mi_data; i++)
++ mi_w(gspca_dev, i + 1, mi_data[i]);
+
+ data[0] = 0x00;
+ data[1] = 0x4d; /* ISOC transfering enable... */
+- reg_w(gspca_dev, data[0], 2);
+- return err_code;
++ reg_w(gspca_dev, 2);
++ return 0;
+ }
+
+ static void sd_stopN(struct gspca_dev *gspca_dev)
+@@ -336,11 +310,18 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
+
+ gspca_dev->usb_buf[0] = 1;
+ gspca_dev->usb_buf[1] = 0;
+- result = reg_w(gspca_dev, gspca_dev->usb_buf[0], 2);
++ result = reg_w(gspca_dev, 2);
+ if (result < 0)
+ PDEBUG(D_ERR, "Camera Stop failed");
+ }
+
++static void sd_stop0(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ kfree(sd->jpeg_hdr);
++}
++
+ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+@@ -363,16 +344,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ || data[5 + p] == 0x65
+ || data[5 + p] == 0x66
+ || data[5 + p] == 0x67) {
+- PDEBUG(D_PACK, "sof offset: %d leng: %d",
++ PDEBUG(D_PACK, "sof offset: %d len: %d",
+ p, len);
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+- frame, data, 0);
++ frame, data, p);
+
+ /* put the JPEG header */
+- jpeg_put_header(gspca_dev, frame,
+- sd->qindex, 0x21);
+- data += 16;
+- len -= 16;
++ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
++ sd->jpeg_hdr, JPEG_HDR_SZ);
++ data += p + 16;
++ len -= p + 16;
+ break;
+ }
+ }
+@@ -380,6 +361,121 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ }
+
++static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ sd->brightness = val;
++ if (gspca_dev->streaming) {
++ gspca_dev->usb_buf[0] = 0x61;
++ gspca_dev->usb_buf[1] = val;
++ reg_w(gspca_dev, 2);
++ }
++ return 0;
++}
++
++static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ *val = sd->brightness;
++ return 0;
++}
++
++static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ sd->colors = val;
++ if (gspca_dev->streaming) {
++
++ /* see sd_start */
++ gspca_dev->usb_buf[0] = 0x5f;
++ gspca_dev->usb_buf[1] = sd->colors << 3;
++ gspca_dev->usb_buf[2] = ((sd->colors >> 2) & 0xf8) | 0x04;
++ reg_w(gspca_dev, 3);
++ }
++ return 0;
++}
++
++static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ *val = sd->colors;
++ return 0;
++}
++
++static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ sd->gamma = val;
++ if (gspca_dev->streaming) {
++ gspca_dev->usb_buf[0] = 0x06;
++ gspca_dev->usb_buf[1] = val * 0x40;
++ reg_w(gspca_dev, 2);
++ }
++ return 0;
++}
++
++static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ *val = sd->gamma;
++ return 0;
++}
++
++static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ sd->sharpness = val;
++ if (gspca_dev->streaming) {
++ gspca_dev->usb_buf[0] = 0x67;
++ gspca_dev->usb_buf[1] = val * 4 + 3;
++ reg_w(gspca_dev, 2);
++ }
++ return 0;
++}
++
++static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ *val = sd->sharpness;
++ return 0;
++}
++
++static int sd_set_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ if (jcomp->quality < QUALITY_MIN)
++ sd->quality = QUALITY_MIN;
++ else if (jcomp->quality > QUALITY_MAX)
++ sd->quality = QUALITY_MAX;
++ else
++ sd->quality = jcomp->quality;
++ if (gspca_dev->streaming)
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++ return 0;
++}
++
++static int sd_get_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ memset(jcomp, 0, sizeof *jcomp);
++ jcomp->quality = sd->quality;
++ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
++ | V4L2_JPEG_MARKER_DQT;
++ return 0;
++}
++
+ /* sub-driver description */
+ static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+@@ -389,7 +485,10 @@ static const struct sd_desc sd_desc = {
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
++ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
++ .get_jcomp = sd_get_jcomp,
++ .set_jcomp = sd_set_jcomp,
+ };
+
+ /* -- module initialisation -- */
+@@ -421,8 +520,11 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c
+new file mode 100644
+index 0000000..2a901a4
+--- /dev/null
++++ b/drivers/media/video/gspca/mr97310a.c
+@@ -0,0 +1,362 @@
++/*
++ * Mars MR97310A library
++ *
++ * Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#define MODULE_NAME "mr97310a"
++
++#include "gspca.h"
++
++MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>");
++MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
++MODULE_LICENSE("GPL");
++
++/* specific webcam descriptor */
++struct sd {
++ struct gspca_dev gspca_dev; /* !! must be the first item */
++ u8 sof_read;
++};
++
++/* V4L2 controls supported by the driver */
++static struct ctrl sd_ctrls[] = {
++};
++
++static const struct v4l2_pix_format vga_mode[] = {
++ {160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
++ .bytesperline = 160,
++ .sizeimage = 160 * 120,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 4},
++ {176, 144, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
++ .bytesperline = 176,
++ .sizeimage = 176 * 144,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 3},
++ {320, 240, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
++ .bytesperline = 320,
++ .sizeimage = 320 * 240,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 2},
++ {352, 288, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
++ .bytesperline = 352,
++ .sizeimage = 352 * 288,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 1},
++ {640, 480, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
++ .bytesperline = 640,
++ .sizeimage = 640 * 480,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 0},
++};
++
++/* the bytes to write are in gspca_dev->usb_buf */
++static int reg_w(struct gspca_dev *gspca_dev, int len)
++{
++ int rc;
++
++ rc = usb_bulk_msg(gspca_dev->dev,
++ usb_sndbulkpipe(gspca_dev->dev, 4),
++ gspca_dev->usb_buf, len, NULL, 500);
++ if (rc < 0)
++ PDEBUG(D_ERR, "reg write [%02x] error %d",
++ gspca_dev->usb_buf[0], rc);
++ return rc;
++}
++
++/* this function is called at probe time */
++static int sd_config(struct gspca_dev *gspca_dev,
++ const struct usb_device_id *id)
++{
++ struct cam *cam;
++
++ cam = &gspca_dev->cam;
++ cam->cam_mode = vga_mode;
++ cam->nmodes = ARRAY_SIZE(vga_mode);
++ return 0;
++}
++
++/* this function is called at probe and resume time */
++static int sd_init(struct gspca_dev *gspca_dev)
++{
++ return 0;
++}
++
++static int sd_start(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++ __u8 *data = gspca_dev->usb_buf;
++ int err_code;
++
++ sd->sof_read = 0;
++
++ /* Note: register descriptions guessed from MR97113A driver */
++
++ data[0] = 0x01;
++ data[1] = 0x01;
++ err_code = reg_w(gspca_dev, 2);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x00;
++ data[1] = 0x0d;
++ data[2] = 0x01;
++ data[5] = 0x2b;
++ data[7] = 0x00;
++ data[9] = 0x50; /* reg 8, no scale down */
++ data[10] = 0xc0;
++
++ switch (gspca_dev->width) {
++ case 160:
++ data[9] |= 0x0c; /* reg 8, 4:1 scale down */
++ /* fall thru */
++ case 320:
++ data[9] |= 0x04; /* reg 8, 2:1 scale down */
++ /* fall thru */
++ case 640:
++ default:
++ data[3] = 0x50; /* reg 2, H size */
++ data[4] = 0x78; /* reg 3, V size */
++ data[6] = 0x04; /* reg 5, H start */
++ data[8] = 0x03; /* reg 7, V start */
++ break;
++
++ case 176:
++ data[9] |= 0x04; /* reg 8, 2:1 scale down */
++ /* fall thru */
++ case 352:
++ data[3] = 0x2c; /* reg 2, H size */
++ data[4] = 0x48; /* reg 3, V size */
++ data[6] = 0x94; /* reg 5, H start */
++ data[8] = 0x63; /* reg 7, V start */
++ break;
++ }
++
++ err_code = reg_w(gspca_dev, 11);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x0a;
++ data[1] = 0x80;
++ err_code = reg_w(gspca_dev, 2);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x14;
++ data[1] = 0x0a;
++ err_code = reg_w(gspca_dev, 2);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x1b;
++ data[1] = 0x00;
++ err_code = reg_w(gspca_dev, 2);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x15;
++ data[1] = 0x16;
++ err_code = reg_w(gspca_dev, 2);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x16;
++ data[1] = 0x10;
++ err_code = reg_w(gspca_dev, 2);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x17;
++ data[1] = 0x3a;
++ err_code = reg_w(gspca_dev, 2);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x18;
++ data[1] = 0x68;
++ err_code = reg_w(gspca_dev, 2);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x1f;
++ data[1] = 0x00;
++ data[2] = 0x02;
++ data[3] = 0x06;
++ data[4] = 0x59;
++ data[5] = 0x0c;
++ data[6] = 0x16;
++ data[7] = 0x00;
++ data[8] = 0x07;
++ data[9] = 0x00;
++ data[10] = 0x01;
++ err_code = reg_w(gspca_dev, 11);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x1f;
++ data[1] = 0x04;
++ data[2] = 0x11;
++ data[3] = 0x01;
++ err_code = reg_w(gspca_dev, 4);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x1f;
++ data[1] = 0x00;
++ data[2] = 0x0a;
++ data[3] = 0x00;
++ data[4] = 0x01;
++ data[5] = 0x00;
++ data[6] = 0x00;
++ data[7] = 0x01;
++ data[8] = 0x00;
++ data[9] = 0x0a;
++ err_code = reg_w(gspca_dev, 10);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x1f;
++ data[1] = 0x04;
++ data[2] = 0x11;
++ data[3] = 0x01;
++ err_code = reg_w(gspca_dev, 4);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x1f;
++ data[1] = 0x00;
++ data[2] = 0x12;
++ data[3] = 0x00;
++ data[4] = 0x63;
++ data[5] = 0x00;
++ data[6] = 0x70;
++ data[7] = 0x00;
++ data[8] = 0x00;
++ err_code = reg_w(gspca_dev, 9);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x1f;
++ data[1] = 0x04;
++ data[2] = 0x11;
++ data[3] = 0x01;
++ err_code = reg_w(gspca_dev, 4);
++ if (err_code < 0)
++ return err_code;
++
++ data[0] = 0x00;
++ data[1] = 0x4d; /* ISOC transfering enable... */
++ err_code = reg_w(gspca_dev, 2);
++ return err_code;
++}
++
++static void sd_stopN(struct gspca_dev *gspca_dev)
++{
++ int result;
++
++ gspca_dev->usb_buf[0] = 1;
++ gspca_dev->usb_buf[1] = 0;
++ result = reg_w(gspca_dev, 2);
++ if (result < 0)
++ PDEBUG(D_ERR, "Camera Stop failed");
++}
++
++/* Include pac common sof detection functions */
++#include "pac_common.h"
++
++static void sd_pkt_scan(struct gspca_dev *gspca_dev,
++ struct gspca_frame *frame, /* target */
++ __u8 *data, /* isoc packet */
++ int len) /* iso packet length */
++{
++ unsigned char *sof;
++
++ sof = pac_find_sof(gspca_dev, data, len);
++ if (sof) {
++ int n;
++
++ /* finish decoding current frame */
++ n = sof - data;
++ if (n > sizeof pac_sof_marker)
++ n -= sizeof pac_sof_marker;
++ else
++ n = 0;
++ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
++ data, n);
++ /* Start next frame. */
++ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
++ pac_sof_marker, sizeof pac_sof_marker);
++ len -= sof - data;
++ data = sof;
++ }
++ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
++}
++
++/* sub-driver description */
++static const struct sd_desc sd_desc = {
++ .name = MODULE_NAME,
++ .ctrls = sd_ctrls,
++ .nctrls = ARRAY_SIZE(sd_ctrls),
++ .config = sd_config,
++ .init = sd_init,
++ .start = sd_start,
++ .stopN = sd_stopN,
++ .pkt_scan = sd_pkt_scan,
++};
++
++/* -- module initialisation -- */
++static const __devinitdata struct usb_device_id device_table[] = {
++ {USB_DEVICE(0x08ca, 0x0111)},
++ {}
++};
++MODULE_DEVICE_TABLE(usb, device_table);
++
++/* -- device connect -- */
++static int sd_probe(struct usb_interface *intf,
++ const struct usb_device_id *id)
++{
++ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
++ THIS_MODULE);
++}
++
++static struct usb_driver sd_driver = {
++ .name = MODULE_NAME,
++ .id_table = device_table,
++ .probe = sd_probe,
++ .disconnect = gspca_disconnect,
++#ifdef CONFIG_PM
++ .suspend = gspca_suspend,
++ .resume = gspca_resume,
++#endif
++};
++
++/* -- module insert / remove -- */
++static int __init sd_mod_init(void)
++{
++ if (usb_register(&sd_driver) < 0)
++ return -1;
++ PDEBUG(D_PROBE, "registered");
++ return 0;
++}
++static void __exit sd_mod_exit(void)
++{
++ usb_deregister(&sd_driver);
++ PDEBUG(D_PROBE, "deregistered");
++}
++
++module_init(sd_mod_init);
++module_exit(sd_mod_exit);
+diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
+index ee23295..1fff37b 100644
+--- a/drivers/media/video/gspca/ov519.c
++++ b/drivers/media/video/gspca/ov519.c
+@@ -1360,7 +1360,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ }
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = OV511_ENDPOINT_ADDRESS;
+ if (!sd->sif) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+@@ -2177,8 +2176,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
+index 3bf15e4..19e0bc6 100644
+--- a/drivers/media/video/gspca/ov534.c
++++ b/drivers/media/video/gspca/ov534.c
+@@ -1,7 +1,8 @@
+ /*
+- * ov534/ov772x gspca driver
++ * ov534 gspca driver
+ * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
+ * Copyright (C) 2008 Jim Paris <jim@jtan.com>
++ * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr
+ *
+ * Based on a prototype written by Mark Ferrell <majortrips@gmail.com>
+ * USB protocol reverse engineered by Jim Paris <jim@jtan.com>
+@@ -26,7 +27,7 @@
+
+ #include "gspca.h"
+
+-#define OV534_REG_ADDRESS 0xf1 /* ? */
++#define OV534_REG_ADDRESS 0xf1 /* sensor address */
+ #define OV534_REG_SUBADDR 0xf2
+ #define OV534_REG_WRITE 0xf3
+ #define OV534_REG_READ 0xf4
+@@ -46,9 +47,13 @@ MODULE_LICENSE("GPL");
+ /* specific webcam descriptor */
+ struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+- __u32 last_fid;
+ __u32 last_pts;
+- int frame_rate;
++ u16 last_fid;
++ u8 frame_rate;
++
++ u8 sensor;
++#define SENSOR_OV772X 0
++#define SENSOR_OV965X 1
+ };
+
+ /* V4L2 controls supported by the driver */
+@@ -63,114 +68,7 @@ static const struct v4l2_pix_format vga_mode[] = {
+ .priv = 0},
+ };
+
+-static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
+-{
+- struct usb_device *udev = gspca_dev->dev;
+- int ret;
+-
+- PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
+- gspca_dev->usb_buf[0] = val;
+- ret = usb_control_msg(udev,
+- usb_sndctrlpipe(udev, 0),
+- 0x1,
+- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+- 0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+- if (ret < 0)
+- PDEBUG(D_ERR, "write failed");
+-}
+-
+-static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+-{
+- struct usb_device *udev = gspca_dev->dev;
+- int ret;
+-
+- ret = usb_control_msg(udev,
+- usb_rcvctrlpipe(udev, 0),
+- 0x1,
+- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+- 0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+- PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
+- if (ret < 0)
+- PDEBUG(D_ERR, "read failed");
+- return gspca_dev->usb_buf[0];
+-}
+-
+-/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
+- * (direction and output)? */
+-static void ov534_set_led(struct gspca_dev *gspca_dev, int status)
+-{
+- u8 data;
+-
+- PDEBUG(D_CONF, "led status: %d", status);
+-
+- data = ov534_reg_read(gspca_dev, 0x21);
+- data |= 0x80;
+- ov534_reg_write(gspca_dev, 0x21, data);
+-
+- data = ov534_reg_read(gspca_dev, 0x23);
+- if (status)
+- data |= 0x80;
+- else
+- data &= ~(0x80);
+-
+- ov534_reg_write(gspca_dev, 0x23, data);
+-}
+-
+-static int sccb_check_status(struct gspca_dev *gspca_dev)
+-{
+- u8 data;
+- int i;
+-
+- for (i = 0; i < 5; i++) {
+- data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
+-
+- switch (data) {
+- case 0x00:
+- return 1;
+- case 0x04:
+- return 0;
+- case 0x03:
+- break;
+- default:
+- PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
+- data, i + 1);
+- }
+- }
+- return 0;
+-}
+-
+-static void sccb_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
+-{
+- PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%02x", reg, val);
+- ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+- ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
+- ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
+-
+- if (!sccb_check_status(gspca_dev))
+- PDEBUG(D_ERR, "sccb_reg_write failed");
+-}
+-
+-#ifdef GSPCA_DEBUG
+-static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+-{
+- ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+- ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
+- if (!sccb_check_status(gspca_dev))
+- PDEBUG(D_ERR, "sccb_reg_read failed 1");
+-
+- ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
+- if (!sccb_check_status(gspca_dev))
+- PDEBUG(D_ERR, "sccb_reg_read failed 2");
+-
+- return ov534_reg_read(gspca_dev, OV534_REG_READ);
+-}
+-#endif
+-
+-static const __u8 ov534_reg_initdata[][2] = {
+- { 0xe7, 0x3a },
+-
+- { OV534_REG_ADDRESS, 0x42 }, /* select OV772x sensor */
+-
++static const u8 bridge_init_ov722x[][2] = {
+ { 0xc2, 0x0c },
+ { 0x88, 0xf8 },
+ { 0xc3, 0x69 },
+@@ -228,7 +126,7 @@ static const __u8 ov534_reg_initdata[][2] = {
+ { 0xc2, 0x0c },
+ };
+
+-static const __u8 ov772x_reg_initdata[][2] = {
++static const u8 sensor_init_ov722x[][2] = {
+ { 0x12, 0x80 },
+ { 0x11, 0x01 },
+
+@@ -311,6 +209,456 @@ static const __u8 ov772x_reg_initdata[][2] = {
+ { 0x0c, 0xd0 }
+ };
+
++static const u8 bridge_init_ov965x[][2] = {
++ {0x88, 0xf8},
++ {0x89, 0xff},
++ {0x76, 0x03},
++ {0x92, 0x03},
++ {0x95, 0x10},
++ {0xe2, 0x00},
++ {0xe7, 0x3e},
++ {0x8d, 0x1c},
++ {0x8e, 0x00},
++ {0x8f, 0x00},
++ {0x1f, 0x00},
++ {0xc3, 0xf9},
++ {0x89, 0xff},
++ {0x88, 0xf8},
++ {0x76, 0x03},
++ {0x92, 0x01},
++ {0x93, 0x18},
++ {0x1c, 0x0a},
++ {0x1d, 0x48},
++ {0xc0, 0x50},
++ {0xc1, 0x3c},
++ {0x34, 0x05},
++ {0xc2, 0x0c},
++ {0xc3, 0xf9},
++ {0x34, 0x05},
++ {0xe7, 0x2e},
++ {0x31, 0xf9},
++ {0x35, 0x02},
++ {0xd9, 0x10},
++ {0x25, 0x42},
++ {0x94, 0x11},
++};
++
++static const u8 sensor_init_ov965x[][2] = {
++ {0x12, 0x80}, /* com7 - reset */
++ {0x00, 0x00}, /* gain */
++ {0x01, 0x80}, /* blue */
++ {0x02, 0x80}, /* red */
++ {0x03, 0x1b}, /* vref */
++ {0x04, 0x03}, /* com1 - exposure low bits */
++ {0x0b, 0x57}, /* ver */
++ {0x0e, 0x61}, /* com5 */
++ {0x0f, 0x42}, /* com6 */
++ {0x11, 0x00}, /* clkrc */
++ {0x12, 0x02}, /* com7 */
++ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
++ {0x14, 0x28}, /* com9 */
++ {0x16, 0x24}, /* rsvd16 */
++ {0x17, 0x1d}, /* hstart*/
++ {0x18, 0xbd}, /* hstop */
++ {0x19, 0x01}, /* vstrt */
++ {0x1a, 0x81}, /* vstop*/
++ {0x1e, 0x04}, /* mvfp */
++ {0x24, 0x3c}, /* aew */
++ {0x25, 0x36}, /* aeb */
++ {0x26, 0x71}, /* vpt */
++ {0x27, 0x08}, /* bbias */
++ {0x28, 0x08}, /* gbbias */
++ {0x29, 0x15}, /* gr com */
++ {0x2a, 0x00},
++ {0x2b, 0x00},
++ {0x2c, 0x08}, /* rbias */
++ {0x32, 0xff}, /* href */
++ {0x33, 0x00}, /* chlf */
++ {0x34, 0x3f}, /* arblm */
++ {0x35, 0x00}, /* rsvd35 */
++ {0x36, 0xf8}, /* rsvd36 */
++ {0x38, 0x72}, /* acom38 */
++ {0x39, 0x57}, /* ofon */
++ {0x3a, 0x80}, /* tslb */
++ {0x3b, 0xc4},
++ {0x3d, 0x99}, /* com13 */
++ {0x3f, 0xc1},
++ {0x40, 0xc0}, /* com15 */
++ {0x41, 0x40}, /* com16 */
++ {0x42, 0xc0},
++ {0x43, 0x0a},
++ {0x44, 0xf0},
++ {0x45, 0x46},
++ {0x46, 0x62},
++ {0x47, 0x2a},
++ {0x48, 0x3c},
++ {0x4a, 0xfc},
++ {0x4b, 0xfc},
++ {0x4c, 0x7f},
++ {0x4d, 0x7f},
++ {0x4e, 0x7f},
++ {0x4f, 0x98},
++ {0x50, 0x98},
++ {0x51, 0x00},
++ {0x52, 0x28},
++ {0x53, 0x70},
++ {0x54, 0x98},
++ {0x58, 0x1a},
++ {0x59, 0x85},
++ {0x5a, 0xa9},
++ {0x5b, 0x64},
++ {0x5c, 0x84},
++ {0x5d, 0x53},
++ {0x5e, 0x0e},
++ {0x5f, 0xf0},
++ {0x60, 0xf0},
++ {0x61, 0xf0},
++ {0x62, 0x00}, /* lcc1 */
++ {0x63, 0x00}, /* lcc2 */
++ {0x64, 0x02}, /* lcc3 */
++ {0x65, 0x16}, /* lcc4 */
++ {0x66, 0x01}, /* lcc5 */
++ {0x69, 0x02}, /* hv */
++ {0x6b, 0x5a}, /* dbvl */
++ {0x6c, 0x04},
++ {0x6d, 0x55},
++ {0x6e, 0x00},
++ {0x6f, 0x9d},
++ {0x70, 0x21},
++ {0x71, 0x78},
++ {0x72, 0x00},
++ {0x73, 0x01},
++ {0x74, 0x3a},
++ {0x75, 0x35},
++ {0x76, 0x01},
++ {0x77, 0x02},
++ {0x7a, 0x12},
++ {0x7b, 0x08},
++ {0x7c, 0x16},
++ {0x7d, 0x30},
++ {0x7e, 0x5e},
++ {0x7f, 0x72},
++ {0x80, 0x82},
++ {0x81, 0x8e},
++ {0x82, 0x9a},
++ {0x83, 0xa4},
++ {0x84, 0xac},
++ {0x85, 0xb8},
++ {0x86, 0xc3},
++ {0x87, 0xd6},
++ {0x88, 0xe6},
++ {0x89, 0xf2},
++ {0x8a, 0x03},
++ {0x8c, 0x89},
++ {0x14, 0x28}, /* com9 */
++ {0x90, 0x7d},
++ {0x91, 0x7b},
++ {0x9d, 0x03},
++ {0x9e, 0x04},
++ {0x9f, 0x7a},
++ {0xa0, 0x79},
++ {0xa1, 0x40}, /* aechm */
++ {0xa4, 0x50},
++ {0xa5, 0x68}, /* com26 */
++ {0xa6, 0x4a},
++ {0xa8, 0xc1}, /* acoma8 */
++ {0xa9, 0xef}, /* acoma9 */
++ {0xaa, 0x92},
++ {0xab, 0x04},
++ {0xac, 0x80},
++ {0xad, 0x80},
++ {0xae, 0x80},
++ {0xaf, 0x80},
++ {0xb2, 0xf2},
++ {0xb3, 0x20},
++ {0xb4, 0x20},
++ {0xb5, 0x00},
++ {0xb6, 0xaf},
++ {0xbb, 0xae},
++ {0xbc, 0x7f},
++ {0xdb, 0x7f},
++ {0xbe, 0x7f},
++ {0xbf, 0x7f},
++ {0xc0, 0xe2},
++ {0xc1, 0xc0},
++ {0xc2, 0x01},
++ {0xc3, 0x4e},
++ {0xc6, 0x85},
++ {0xc7, 0x80},
++ {0xc9, 0xe0},
++ {0xca, 0xe8},
++ {0xcb, 0xf0},
++ {0xcc, 0xd8},
++ {0xcd, 0xf1},
++ {0x4f, 0x98},
++ {0x50, 0x98},
++ {0x51, 0x00},
++ {0x52, 0x28},
++ {0x53, 0x70},
++ {0x54, 0x98},
++ {0x58, 0x1a},
++ {0xff, 0x41}, /* read 41, write ff 00 */
++ {0x41, 0x40}, /* com16 */
++ {0xc5, 0x03},
++ {0x6a, 0x02},
++
++ {0x12, 0x62}, /* com7 - VGA + CIF */
++ {0x36, 0xfa}, /* rsvd36 */
++ {0x69, 0x0a}, /* hv */
++ {0x8c, 0x89}, /* com22 */
++ {0x14, 0x28}, /* com9 */
++ {0x3e, 0x0c},
++ {0x41, 0x40}, /* com16 */
++ {0x72, 0x00},
++ {0x73, 0x00},
++ {0x74, 0x3a},
++ {0x75, 0x35},
++ {0x76, 0x01},
++ {0xc7, 0x80},
++ {0x03, 0x12}, /* vref */
++ {0x17, 0x16}, /* hstart */
++ {0x18, 0x02}, /* hstop */
++ {0x19, 0x01}, /* vstrt */
++ {0x1a, 0x3d}, /* vstop */
++ {0x32, 0xff}, /* href */
++ {0xc0, 0xaa},
++};
++
++static const u8 bridge_init_ov965x_2[][2] = {
++ {0x94, 0xaa},
++ {0xf1, 0x60},
++ {0xe5, 0x04},
++ {0xc0, 0x50},
++ {0xc1, 0x3c},
++ {0x8c, 0x00},
++ {0x8d, 0x1c},
++ {0x34, 0x05},
++
++ {0xc2, 0x0c},
++ {0xc3, 0xf9},
++ {0xda, 0x01},
++ {0x50, 0x00},
++ {0x51, 0xa0},
++ {0x52, 0x3c},
++ {0x53, 0x00},
++ {0x54, 0x00},
++ {0x55, 0x00},
++ {0x57, 0x00},
++ {0x5c, 0x00},
++ {0x5a, 0xa0},
++ {0x5b, 0x78},
++ {0x35, 0x02},
++ {0xd9, 0x10},
++ {0x94, 0x11},
++};
++
++static const u8 sensor_init_ov965x_2[][2] = {
++ {0x3b, 0xc4},
++ {0x1e, 0x04}, /* mvfp */
++ {0x13, 0xe0}, /* com8 */
++ {0x00, 0x00}, /* gain */
++ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
++ {0x11, 0x03}, /* clkrc */
++ {0x6b, 0x5a}, /* dblv */
++ {0x6a, 0x05},
++ {0xc5, 0x07},
++ {0xa2, 0x4b},
++ {0xa3, 0x3e},
++ {0x2d, 0x00},
++ {0xff, 0x42}, /* read 42, write ff 00 */
++ {0x42, 0xc0},
++ {0x2d, 0x00},
++ {0xff, 0x42}, /* read 42, write ff 00 */
++ {0x42, 0xc1},
++ {0x3f, 0x01},
++ {0xff, 0x42}, /* read 42, write ff 00 */
++ {0x42, 0xc1},
++ {0x4f, 0x98},
++ {0x50, 0x98},
++ {0x51, 0x00},
++ {0x52, 0x28},
++ {0x53, 0x70},
++ {0x54, 0x98},
++ {0x58, 0x1a},
++ {0xff, 0x41}, /* read 41, write ff 00 */
++ {0x41, 0x40}, /* com16 */
++ {0x56, 0x40},
++ {0x55, 0x8f},
++ {0x10, 0x25}, /* aech - exposure high bits */
++ {0xff, 0x13}, /* read 13, write ff 00 */
++ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
++};
++
++static const u8 bridge_start_ov965x[][2] = {
++ {0xc2, 0x4c},
++ {0xc3, 0xf9},
++ {0x50, 0x00},
++ {0x51, 0xa0},
++ {0x52, 0x78},
++ {0x53, 0x00},
++ {0x54, 0x00},
++ {0x55, 0x00},
++ {0x57, 0x00},
++ {0x5c, 0x00},
++ {0x5a, 0x28},
++ {0x5b, 0x1e},
++ {0x35, 0x00},
++ {0xd9, 0x21},
++ {0x94, 0x11},
++};
++
++static const u8 sensor_start_ov965x[][2] = {
++ {0x3b, 0xe4},
++ {0x1e, 0x04}, /* mvfp */
++ {0x13, 0xe0}, /* com8 */
++ {0x00, 0x00},
++ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
++ {0x11, 0x01}, /* clkrc */
++ {0x6b, 0x5a}, /* dblv */
++ {0x6a, 0x02},
++ {0xc5, 0x03},
++ {0xa2, 0x96},
++ {0xa3, 0x7d},
++ {0xff, 0x13}, /* read 13, write ff 00 */
++ {0x13, 0xe7},
++ {0x3a, 0x80},
++ {0xff, 0x42}, /* read 42, write ff 00 */
++ {0x42, 0xc1},
++};
++
++
++static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
++{
++ struct usb_device *udev = gspca_dev->dev;
++ int ret;
++
++ PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
++ gspca_dev->usb_buf[0] = val;
++ ret = usb_control_msg(udev,
++ usb_sndctrlpipe(udev, 0),
++ 0x01,
++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
++ if (ret < 0)
++ PDEBUG(D_ERR, "write failed");
++}
++
++static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
++{
++ struct usb_device *udev = gspca_dev->dev;
++ int ret;
++
++ ret = usb_control_msg(udev,
++ usb_rcvctrlpipe(udev, 0),
++ 0x01,
++ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
++ PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
++ if (ret < 0)
++ PDEBUG(D_ERR, "read failed");
++ return gspca_dev->usb_buf[0];
++}
++
++/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
++ * (direction and output)? */
++static void ov534_set_led(struct gspca_dev *gspca_dev, int status)
++{
++ u8 data;
++
++ PDEBUG(D_CONF, "led status: %d", status);
++
++ data = ov534_reg_read(gspca_dev, 0x21);
++ data |= 0x80;
++ ov534_reg_write(gspca_dev, 0x21, data);
++
++ data = ov534_reg_read(gspca_dev, 0x23);
++ if (status)
++ data |= 0x80;
++ else
++ data &= ~0x80;
++
++ ov534_reg_write(gspca_dev, 0x23, data);
++
++ if (!status) {
++ data = ov534_reg_read(gspca_dev, 0x21);
++ data &= ~0x80;
++ ov534_reg_write(gspca_dev, 0x21, data);
++ }
++}
++
++static int sccb_check_status(struct gspca_dev *gspca_dev)
++{
++ u8 data;
++ int i;
++
++ for (i = 0; i < 5; i++) {
++ data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
++
++ switch (data) {
++ case 0x00:
++ return 1;
++ case 0x04:
++ return 0;
++ case 0x03:
++ break;
++ default:
++ PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
++ data, i + 1);
++ }
++ }
++ return 0;
++}
++
++static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
++{
++ PDEBUG(D_USBO, "reg: 0x%02x, val: 0x%02x", reg, val);
++ ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
++ ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
++ ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
++
++ if (!sccb_check_status(gspca_dev))
++ PDEBUG(D_ERR, "sccb_reg_write failed");
++}
++
++static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
++{
++ ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
++ ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
++ if (!sccb_check_status(gspca_dev))
++ PDEBUG(D_ERR, "sccb_reg_read failed 1");
++
++ ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
++ if (!sccb_check_status(gspca_dev))
++ PDEBUG(D_ERR, "sccb_reg_read failed 2");
++
++ return ov534_reg_read(gspca_dev, OV534_REG_READ);
++}
++
++/* output a bridge sequence (reg - val) */
++static void reg_w_array(struct gspca_dev *gspca_dev,
++ const u8 (*data)[2], int len)
++{
++ while (--len >= 0) {
++ ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]);
++ data++;
++ }
++}
++
++/* output a sensor sequence (reg - val) */
++static void sccb_w_array(struct gspca_dev *gspca_dev,
++ const u8 (*data)[2], int len)
++{
++ while (--len >= 0) {
++ if ((*data)[0] != 0xff) {
++ sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]);
++ } else {
++ sccb_reg_read(gspca_dev, (*data)[1]);
++ sccb_reg_write(gspca_dev, 0xff, 0x00);
++ }
++ data++;
++ }
++}
++
+ /* set framerate */
+ static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
+ {
+@@ -346,40 +694,17 @@ static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
+ PDEBUG(D_PROBE, "frame_rate: %d", fr);
+ }
+
+-/* setup method */
+-static void ov534_setup(struct gspca_dev *gspca_dev)
+-{
+- int i;
+-
+- /* Initialize bridge chip */
+- for (i = 0; i < ARRAY_SIZE(ov534_reg_initdata); i++)
+- ov534_reg_write(gspca_dev, ov534_reg_initdata[i][0],
+- ov534_reg_initdata[i][1]);
+-
+- PDEBUG(D_PROBE, "sensor is ov%02x%02x",
+- sccb_reg_read(gspca_dev, 0x0a),
+- sccb_reg_read(gspca_dev, 0x0b));
+-
+- ov534_set_led(gspca_dev, 1);
+-
+- /* Initialize sensor */
+- for (i = 0; i < ARRAY_SIZE(ov772x_reg_initdata); i++)
+- sccb_reg_write(gspca_dev, ov772x_reg_initdata[i][0],
+- ov772x_reg_initdata[i][1]);
+-
+- ov534_reg_write(gspca_dev, 0xe0, 0x09);
+- ov534_set_led(gspca_dev, 0);
+-}
+-
+ /* this function is called at probe time */
+ static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+ {
++ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
++ sd->sensor = id->driver_info;
++
+ cam = &gspca_dev->cam;
+
+- cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+
+@@ -392,26 +717,102 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ /* this function is called at probe and resume time */
+ static int sd_init(struct gspca_dev *gspca_dev)
+ {
+- ov534_setup(gspca_dev);
+- ov534_set_frame_rate(gspca_dev);
++ struct sd *sd = (struct sd *) gspca_dev;
++ u16 sensor_id;
++ static const u8 sensor_addr[2] = {
++ 0x42, /* 0 SENSOR_OV772X */
++ 0x60, /* 1 SENSOR_OV965X */
++ };
++
++ /* reset bridge */
++ ov534_reg_write(gspca_dev, 0xe7, 0x3a);
++ ov534_reg_write(gspca_dev, 0xe0, 0x08);
++ msleep(100);
++
++ /* initialize the sensor address */
++ ov534_reg_write(gspca_dev, OV534_REG_ADDRESS,
++ sensor_addr[sd->sensor]);
++
++ /* reset sensor */
++ sccb_reg_write(gspca_dev, 0x12, 0x80);
++ msleep(10);
++
++ /* probe the sensor */
++ sccb_reg_read(gspca_dev, 0x0a);
++ sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8;
++ sccb_reg_read(gspca_dev, 0x0b);
++ sensor_id |= sccb_reg_read(gspca_dev, 0x0b);
++ PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id);
++
++ /* initialize */
++ switch (sd->sensor) {
++ case SENSOR_OV772X:
++ reg_w_array(gspca_dev, bridge_init_ov722x,
++ ARRAY_SIZE(bridge_init_ov722x));
++ ov534_set_led(gspca_dev, 1);
++ sccb_w_array(gspca_dev, sensor_init_ov722x,
++ ARRAY_SIZE(sensor_init_ov722x));
++ ov534_reg_write(gspca_dev, 0xe0, 0x09);
++ ov534_set_led(gspca_dev, 0);
++ ov534_set_frame_rate(gspca_dev);
++ break;
++ default:
++/* case SENSOR_OV965X: */
++ reg_w_array(gspca_dev, bridge_init_ov965x,
++ ARRAY_SIZE(bridge_init_ov965x));
++ sccb_w_array(gspca_dev, sensor_init_ov965x,
++ ARRAY_SIZE(sensor_init_ov965x));
++ reg_w_array(gspca_dev, bridge_init_ov965x_2,
++ ARRAY_SIZE(bridge_init_ov965x_2));
++ sccb_w_array(gspca_dev, sensor_init_ov965x_2,
++ ARRAY_SIZE(sensor_init_ov965x_2));
++ ov534_reg_write(gspca_dev, 0xe0, 0x00);
++ ov534_reg_write(gspca_dev, 0xe0, 0x01);
++ ov534_set_led(gspca_dev, 0);
++ ov534_reg_write(gspca_dev, 0xe0, 0x00);
++ }
+
+ return 0;
+ }
+
+ static int sd_start(struct gspca_dev *gspca_dev)
+ {
+- /* start streaming data */
+- ov534_set_led(gspca_dev, 1);
+- ov534_reg_write(gspca_dev, 0xe0, 0x00);
++ struct sd *sd = (struct sd *) gspca_dev;
+
++ switch (sd->sensor) {
++ case SENSOR_OV772X:
++ ov534_set_led(gspca_dev, 1);
++ ov534_reg_write(gspca_dev, 0xe0, 0x00);
++ break;
++ default:
++/* case SENSOR_OV965X: */
++ reg_w_array(gspca_dev, bridge_start_ov965x,
++ ARRAY_SIZE(bridge_start_ov965x));
++ sccb_w_array(gspca_dev, sensor_start_ov965x,
++ ARRAY_SIZE(sensor_start_ov965x));
++ ov534_reg_write(gspca_dev, 0xe0, 0x00);
++ ov534_set_led(gspca_dev, 1);
++/*fixme: other sensor start omitted*/
++ }
+ return 0;
+ }
+
+ static void sd_stopN(struct gspca_dev *gspca_dev)
+ {
+- /* stop streaming data */
+- ov534_reg_write(gspca_dev, 0xe0, 0x09);
+- ov534_set_led(gspca_dev, 0);
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ switch (sd->sensor) {
++ case SENSOR_OV772X:
++ ov534_reg_write(gspca_dev, 0xe0, 0x09);
++ ov534_set_led(gspca_dev, 0);
++ break;
++ default:
++/* case SENSOR_OV965X: */
++ ov534_reg_write(gspca_dev, 0xe0, 0x01);
++ ov534_set_led(gspca_dev, 0);
++ ov534_reg_write(gspca_dev, 0xe0, 0x00);
++ break;
++ }
+ }
+
+ /* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+@@ -429,75 +830,75 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u32 this_pts;
+- int this_fid;
++ u16 this_fid;
+ int remaining_len = len;
+- __u8 *next_data = data;
+
+-scan_next:
+- if (remaining_len <= 0)
+- return;
+-
+- data = next_data;
+- len = min(remaining_len, 2048);
+- remaining_len -= len;
+- next_data += len;
+-
+- /* Payloads are prefixed with a UVC-style header. We
+- consider a frame to start when the FID toggles, or the PTS
+- changes. A frame ends when EOF is set, and we've received
+- the correct number of bytes. */
+-
+- /* Verify UVC header. Header length is always 12 */
+- if (data[0] != 12 || len < 12) {
+- PDEBUG(D_PACK, "bad header");
+- goto discard;
+- }
+-
+- /* Check errors */
+- if (data[1] & UVC_STREAM_ERR) {
+- PDEBUG(D_PACK, "payload error");
+- goto discard;
+- }
++ do {
++ len = min(remaining_len, 2040); /*fixme: was 2048*/
+
+- /* Extract PTS and FID */
+- if (!(data[1] & UVC_STREAM_PTS)) {
+- PDEBUG(D_PACK, "PTS not present");
+- goto discard;
+- }
+- this_pts = (data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2];
+- this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
+-
+- /* If PTS or FID has changed, start a new frame. */
+- if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
+- gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
+- sd->last_pts = this_pts;
+- sd->last_fid = this_fid;
+- }
++ /* Payloads are prefixed with a UVC-style header. We
++ consider a frame to start when the FID toggles, or the PTS
++ changes. A frame ends when EOF is set, and we've received
++ the correct number of bytes. */
+
+- /* Add the data from this payload */
+- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+- data + 12, len - 12);
++ /* Verify UVC header. Header length is always 12 */
++ if (data[0] != 12 || len < 12) {
++ PDEBUG(D_PACK, "bad header");
++ goto discard;
++ }
+
+- /* If this packet is marked as EOF, end the frame */
+- if (data[1] & UVC_STREAM_EOF) {
+- sd->last_pts = 0;
++ /* Check errors */
++ if (data[1] & UVC_STREAM_ERR) {
++ PDEBUG(D_PACK, "payload error");
++ goto discard;
++ }
+
+- if ((frame->data_end - frame->data) !=
+- (gspca_dev->width * gspca_dev->height * 2)) {
+- PDEBUG(D_PACK, "short frame");
++ /* Extract PTS and FID */
++ if (!(data[1] & UVC_STREAM_PTS)) {
++ PDEBUG(D_PACK, "PTS not present");
+ goto discard;
+ }
++ this_pts = (data[5] << 24) | (data[4] << 16)
++ | (data[3] << 8) | data[2];
++ this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
++
++ /* If PTS or FID has changed, start a new frame. */
++ if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
++ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
++ NULL, 0);
++ sd->last_pts = this_pts;
++ sd->last_fid = this_fid;
++ }
+
+- gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0);
+- }
++ /* Add the data from this payload */
++ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
++ data + 12, len - 12);
+
+- /* Done this payload */
+- goto scan_next;
++ /* If this packet is marked as EOF, end the frame */
++ if (data[1] & UVC_STREAM_EOF) {
++ sd->last_pts = 0;
++
++ if (frame->data_end - frame->data !=
++ gspca_dev->width * gspca_dev->height * 2) {
++ PDEBUG(D_PACK, "short frame");
++ goto discard;
++ }
++
++ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
++ NULL, 0);
++ }
++
++ /* Done this payload */
++ goto scan_next;
+
+ discard:
+- /* Discard data until a new frame starts. */
+- gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
+- goto scan_next;
++ /* Discard data until a new frame starts. */
++ gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
++
++scan_next:
++ remaining_len -= len;
++ data += len;
++ } while (remaining_len > 0);
+ }
+
+ /* get stream parameters (framerate) */
+@@ -556,9 +957,8 @@ static const struct sd_desc sd_desc = {
+
+ /* -- module initialisation -- */
+ static const __devinitdata struct usb_device_id device_table[] = {
+- {USB_DEVICE(0x06f8, 0x3002)}, /* Hercules Blog Webcam */
+- {USB_DEVICE(0x06f8, 0x3003)}, /* Hercules Dualpix HD Weblog */
+- {USB_DEVICE(0x1415, 0x2000)}, /* Sony HD Eye for PS3 (SLEH 00201) */
++ {USB_DEVICE(0x06f8, 0x3003), .driver_info = SENSOR_OV965X},
++ {USB_DEVICE(0x1415, 0x2000), .driver_info = SENSOR_OV772X},
+ {}
+ };
+
+@@ -585,8 +985,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
+index c90ac85..95a97ab 100644
+--- a/drivers/media/video/gspca/pac207.c
++++ b/drivers/media/video/gspca/pac207.c
+@@ -256,7 +256,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x05;
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
+@@ -536,6 +535,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x093a, 0x2470)},
+ {USB_DEVICE(0x093a, 0x2471)},
+ {USB_DEVICE(0x093a, 0x2472)},
++ {USB_DEVICE(0x093a, 0x2474)},
+ {USB_DEVICE(0x093a, 0x2476)},
+ {USB_DEVICE(0x145f, 0x013a)},
+ {USB_DEVICE(0x2001, 0xf115)},
+@@ -565,8 +565,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
+index a9c95cb..e1e3a3a 100644
+--- a/drivers/media/video/gspca/pac7311.c
++++ b/drivers/media/video/gspca/pac7311.c
+@@ -498,7 +498,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x05;
+
+ sd->sensor = id->driver_info;
+ if (sd->sensor == SENSOR_PAC7302) {
+@@ -1097,8 +1096,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
+index b3e4e06..153d0a9 100644
+--- a/drivers/media/video/gspca/sonixb.c
++++ b/drivers/media/video/gspca/sonixb.c
+@@ -870,7 +870,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ if (!(sensor_data[sd->sensor].flags & F_SIF)) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+@@ -1272,8 +1271,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
+index 3373b8d..c72e19d 100644
+--- a/drivers/media/video/gspca/sonixj.c
++++ b/drivers/media/video/gspca/sonixj.c
+@@ -35,36 +35,47 @@ struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ atomic_t avg_lum;
+- unsigned int exposure;
+-
+- __u16 brightness;
+- __u8 contrast;
+- __u8 colors;
+- __u8 autogain;
+- __u8 blue;
+- __u8 red;
+- __u8 vflip; /* ov7630 only */
+- __u8 infrared; /* mi0360 only */
+-
+- __s8 ag_cnt;
++ u32 exposure;
++
++ u16 brightness;
++ u8 contrast;
++ u8 colors;
++ u8 autogain;
++ u8 blue;
++ u8 red;
++ u8 gamma;
++ u8 vflip; /* ov7630/ov7648 only */
++ u8 infrared; /* mt9v111 only */
++ u8 quality; /* image quality */
++#define QUALITY_MIN 60
++#define QUALITY_MAX 95
++#define QUALITY_DEF 80
++ u8 jpegqual; /* webcam quality */
++
++ u8 reg18;
++
++ s8 ag_cnt;
+ #define AG_CNT_START 13
+
+- __u8 qindex;
+- __u8 bridge;
++ u8 bridge;
+ #define BRIDGE_SN9C102P 0
+ #define BRIDGE_SN9C105 1
+ #define BRIDGE_SN9C110 2
+ #define BRIDGE_SN9C120 3
+ #define BRIDGE_SN9C325 4
+- __u8 sensor; /* Type of image sensor chip */
++ u8 sensor; /* Type of image sensor chip */
+ #define SENSOR_HV7131R 0
+ #define SENSOR_MI0360 1
+ #define SENSOR_MO4000 2
+-#define SENSOR_OM6802 3
+-#define SENSOR_OV7630 4
+-#define SENSOR_OV7648 5
+-#define SENSOR_OV7660 6
+- __u8 i2c_base;
++#define SENSOR_MT9V111 3
++#define SENSOR_OM6802 4
++#define SENSOR_OV7630 5
++#define SENSOR_OV7648 6
++#define SENSOR_OV7660 7
++#define SENSOR_SP80708 8
++ u8 i2c_base;
++
++ u8 *jpeg_hdr;
+ };
+
+ /* V4L2 controls supported by the driver */
+@@ -78,6 +89,8 @@ static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
+ static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+ static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
+ static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
++static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
++static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+@@ -158,6 +171,20 @@ static struct ctrl sd_ctrls[] = {
+ .set = sd_setred_balance,
+ .get = sd_getred_balance,
+ },
++ {
++ {
++ .id = V4L2_CID_GAMMA,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Gamma",
++ .minimum = 0,
++ .maximum = 40,
++ .step = 1,
++#define GAMMA_DEF 20
++ .default_value = GAMMA_DEF,
++ },
++ .set = sd_setgamma,
++ .get = sd_getgamma,
++ },
+ #define AUTOGAIN_IDX 5
+ {
+ {
+@@ -173,7 +200,7 @@ static struct ctrl sd_ctrls[] = {
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+-/* ov7630 only */
++/* ov7630/ov7648 only */
+ #define VFLIP_IDX 6
+ {
+ {
+@@ -183,13 +210,13 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+-#define VFLIP_DEF 1
++#define VFLIP_DEF 0 /* vflip def = 1 for ov7630 */
+ .default_value = VFLIP_DEF,
+ },
+ .set = sd_setvflip,
+ .get = sd_getvflip,
+ },
+-/* mi0360 only */
++/* mt9v111 only */
+ #define INFRARED_IDX 7
+ {
+ {
+@@ -211,18 +238,22 @@ static struct ctrl sd_ctrls[] = {
+ static __u32 ctrl_dis[] = {
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ /* SENSOR_HV7131R 0 */
+- (1 << VFLIP_IDX),
++ (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ /* SENSOR_MI0360 1 */
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ /* SENSOR_MO4000 2 */
++ (1 << VFLIP_IDX),
++ /* SENSOR_MT9V111 3 */
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+- /* SENSOR_OM6802 3 */
++ /* SENSOR_OM6802 4 */
+ (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX),
+- /* SENSOR_OV7630 4 */
++ /* SENSOR_OV7630 5 */
++ (1 << INFRARED_IDX),
++ /* SENSOR_OV7648 6 */
+ (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+- /* SENSOR_OV7648 5 */
++ /* SENSOR_OV7660 7 */
+ (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+- /* SENSOR_OV7660 6 */
++ /* SENSOR_SP80708 8 */
+ };
+
+ static const struct v4l2_pix_format vga_mode[] = {
+@@ -243,196 +274,228 @@ static const struct v4l2_pix_format vga_mode[] = {
+ .priv = 0},
+ };
+
+-/*Data from sn9c102p+hv71331r */
+-static const __u8 sn_hv7131[] = {
++/*Data from sn9c102p+hv7131r */
++static const u8 sn_hv7131[0x1c] = {
+ /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x03, 0x64, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ /* reg8 reg9 rega regb regc regd rege regf */
+ 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10,
+ /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41,
+-/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+- 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++/* reg18 reg19 reg1a reg1b */
++ 0x0a, 0x00, 0x00, 0x00
+ };
+
+-static const __u8 sn_mi0360[] = {
++static const u8 sn_mi0360[0x1c] = {
+ /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ /* reg8 reg9 rega regb regc regd rege regf */
+ 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10,
+ /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61,
+-/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+- 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++/* reg18 reg19 reg1a reg1b */
++ 0x06, 0x00, 0x00, 0x00
+ };
+
+-static const __u8 sn_mo4000[] = {
++static const u8 sn_mo4000[0x1c] = {
+ /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+- 0x12, 0x23, 0x60, 0x00, 0x1a, 0x00, 0x20, 0x18,
++ 0x00, 0x23, 0x60, 0x00, 0x1a, 0x00, 0x20, 0x18,
+ /* reg8 reg9 rega regb regc regd rege regf */
+ 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40,
+-/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+- 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++/* reg18 reg19 reg1a reg1b */
++ 0x08, 0x00, 0x00, 0x00
+ };
+
+-static const __u8 sn_om6802[] = {
++static const u8 sn_mt9v111[0x1c] = {
++/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
++ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
++/* reg8 reg9 rega regb regc regd rege regf */
++ 0x81, 0x5c, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
++ 0x03, 0x00, 0x00, 0x02, 0x1c, 0x28, 0x1e, 0x40,
++/* reg18 reg19 reg1a reg1b */
++ 0x06, 0x00, 0x00, 0x00
++};
++
++static const u8 sn_om6802[0x1c] = {
+ /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x23, 0x72, 0x00, 0x1a, 0x34, 0x27, 0x20,
+ /* reg8 reg9 rega regb regc regd rege regf */
+ 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x51, 0x01, 0x00, 0x28, 0x1e, 0x40,
+-/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+- 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+- 0x08, 0x22, 0x44, 0x63, 0x7d, 0x92, 0xa3, 0xaf,
+- 0xbc, 0xc4, 0xcd, 0xd5, 0xdc, 0xe1, 0xe8, 0xef,
+- 0xf7
++/* reg18 reg19 reg1a reg1b */
++ 0x05, 0x00, 0x00, 0x00
+ };
+
+-static const __u8 sn_ov7630[] = {
++static const u8 sn_ov7630[0x1c] = {
+ /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x21, 0x40, 0x00, 0x1a, 0x20, 0x1f, 0x20,
+ /* reg8 reg9 rega regb regc regd rege regf */
+ 0xa1, 0x21, 0x76, 0x21, 0x00, 0x00, 0x00, 0x10,
+ /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x04, 0x01, 0x0a, 0x28, 0x1e, 0xc2,
+-/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+- 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00
++/* reg18 reg19 reg1a reg1b */
++ 0x0b, 0x00, 0x00, 0x00
+ };
+
+-static const __u8 sn_ov7648[] = {
++static const u8 sn_ov7648[0x1c] = {
+ /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x63, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ /* reg8 reg9 rega regb regc regd rege regf */
+ 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x00, 0x01, 0x00, 0x28, 0x1e, 0x00,
+-/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+- 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00
++/* reg18 reg19 reg1a reg1b */
++ 0x0b, 0x00, 0x00, 0x00
+ };
+
+-static const __u8 sn_ov7660[] = {
++static const u8 sn_ov7660[0x1c] = {
+ /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ /* reg8 reg9 rega regb regc regd rege regf */
+ 0x81, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10,
+ /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20,
+-/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+- 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* reg18 reg19 reg1a reg1b */
++ 0x07, 0x00, 0x00, 0x00
++};
++
++static const u8 sn_sp80708[0x1c] = {
++/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
++ 0x00, 0x63, 0x60, 0x00, 0x1a, 0x20, 0x20, 0x20,
++/* reg8 reg9 rega regb regc regd rege regf */
++ 0x81, 0x18, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
++ 0x03, 0x00, 0x00, 0x03, 0x04, 0x28, 0x1e, 0x00,
++/* reg18 reg19 reg1a reg1b */
++ 0x07, 0x00, 0x00, 0x00
+ };
+
+ /* sequence specific to the sensors - !! index = SENSOR_xxx */
+-static const __u8 *sn_tb[] = {
++static const u8 *sn_tb[] = {
+ sn_hv7131,
+ sn_mi0360,
+ sn_mo4000,
++ sn_mt9v111,
+ sn_om6802,
+ sn_ov7630,
+ sn_ov7648,
+- sn_ov7660
++ sn_ov7660,
++ sn_sp80708
+ };
+
+-static const __u8 gamma_def[] = {
++/* default gamma table */
++static const u8 gamma_def[17] = {
+ 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
+ 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
+ };
++/* gamma for sensors HV7131R and MT9V111 */
++static const u8 gamma_spec_1[17] = {
++ 0x08, 0x3a, 0x52, 0x65, 0x75, 0x83, 0x91, 0x9d,
++ 0xa9, 0xb4, 0xbe, 0xc8, 0xd2, 0xdb, 0xe4, 0xed, 0xf5
++};
++/* gamma for sensor SP80708 */
++static const u8 gamma_spec_2[17] = {
++ 0x0a, 0x2d, 0x4e, 0x68, 0x7d, 0x8f, 0x9f, 0xab,
++ 0xb7, 0xc2, 0xcc, 0xd3, 0xd8, 0xde, 0xe2, 0xe5, 0xe6
++};
+
+ /* color matrix and offsets */
+-static const __u8 reg84[] = {
++static const u8 reg84[] = {
+ 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, /* YR YG YB gains */
+ 0xe8, 0x0f, 0xda, 0x0f, 0x40, 0x00, /* UR UG UB */
+ 0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f, /* VR VG VB */
+ 0x00, 0x00, 0x00 /* YUV offsets */
+ };
+-static const __u8 hv7131r_sensor_init[][8] = {
+- {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
+- {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
+- {0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
+- {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
+- {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+-
+- {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+- {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+- {0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
+- {0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
+- {0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
+- {0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
+- {0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
+- {0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
+-
+- {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+- {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+- {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
+-
+- {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+- {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+- {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
++static const u8 hv7131r_sensor_init[][8] = {
++ {0xc1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
++ {0xb1, 0x11, 0x34, 0x17, 0x7f, 0x00, 0x00, 0x10},
++ {0xd1, 0x11, 0x40, 0xff, 0x7f, 0x7f, 0x7f, 0x10},
++/* {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10}, */
++ {0xd1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x11, 0x14, 0x01, 0xe2, 0x02, 0x82, 0x10},
++/* {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, */
++
++ {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
++ {0xc1, 0x11, 0x25, 0x00, 0x61, 0xa8, 0x00, 0x10},
++ {0xa1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
++ {0xc1, 0x11, 0x31, 0x20, 0x2e, 0x20, 0x00, 0x10},
++ {0xc1, 0x11, 0x25, 0x00, 0xc3, 0x50, 0x00, 0x10},
++ {0xa1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
++ {0xc1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
++
++ {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
++
++ {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x11, 0x21, 0xd0, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
+ {}
+ };
+-static const __u8 mi0360_sensor_init[][8] = {
+- {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+- {0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
+- {0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
+- {0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
+- {0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
+- {0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
+- {0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
+- {0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
+- {0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
+- {0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
+- {0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
+- {0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
+-
+- {0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+- {0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+- {0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
+- {0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
+- {0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
+-
+- {0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
+- {0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
+- {0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
+- {0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
+-
+- {0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
+- {0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
+-/* {0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
+-/* {0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
+- {0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
+- {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
++static const u8 mi0360_sensor_init[][8] = {
++ {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
++ {0xb1, 0x5d, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10},
++ {0xb1, 0x5d, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
++ {0xd1, 0x5d, 0x03, 0x01, 0xe2, 0x02, 0x82, 0x10},
++ {0xd1, 0x5d, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
++ {0xb1, 0x5d, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xb1, 0x5d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
++ {0xd1, 0x5d, 0x2f, 0xf7, 0xB0, 0x00, 0x04, 0x10},
++ {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
++ {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x40, 0x01, 0xe0, 0x00, 0xd1, 0x10},
++ {0xb1, 0x5d, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
++ {0xd1, 0x5d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x5e, 0x00, 0x00, 0xa3, 0x1d, 0x10},
++ {0xb1, 0x5d, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
++
++ {0xb1, 0x5d, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
++ {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
++ {0xb1, 0x5d, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
++ {0xd1, 0x5d, 0x2b, 0x00, 0xa0, 0x00, 0xb0, 0x10},
++ {0xd1, 0x5d, 0x2d, 0x00, 0xa0, 0x00, 0xa0, 0x10},
++
++ {0xb1, 0x5d, 0x0a, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
++ {0xb1, 0x5d, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
++ {0xb1, 0x5d, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x10},
++ {0xb1, 0x5d, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
++
++ {0xd1, 0x5d, 0x2b, 0x00, 0xb9, 0x00, 0xe3, 0x10},
++ {0xd1, 0x5d, 0x2d, 0x00, 0x5f, 0x00, 0xb9, 0x10}, /* 42 */
++/* {0xb1, 0x5d, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
++/* {0xb1, 0x5d, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
++ {0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
++ {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
+ {}
+ };
+-static const __u8 mo4000_sensor_init[][8] = {
++static const u8 mo4000_sensor_init[][8] = {
+ {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+@@ -455,7 +518,49 @@ static const __u8 mo4000_sensor_init[][8] = {
+ {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+ {}
+ };
+-static __u8 om6802_sensor_init[][8] = {
++static const u8 mt9v111_sensor_init[][8] = {
++ {0xb1, 0x5c, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, /* reset? */
++ /* delay 20 ms */
++ {0xb1, 0x5c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x10}, /* IFP select */
++ {0xb1, 0x5c, 0x08, 0x04, 0x80, 0x00, 0x00, 0x10}, /* output fmt ctrl */
++ {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, /* op mode ctrl */
++ {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x03, 0x01, 0xe1, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x04, 0x02, 0x81, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10}, /* sensor select */
++ {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x03, 0x01, 0xe6, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x04, 0x02, 0x86, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x08, 0x00, 0x08, 0x00, 0x00, 0x10}, /* row start */
++ {0xb1, 0x5c, 0x0e, 0x00, 0x08, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10}, /* col start */
++ {0xb1, 0x5c, 0x03, 0x01, 0xe7, 0x00, 0x00, 0x10}, /* window height */
++ {0xb1, 0x5c, 0x04, 0x02, 0x87, 0x00, 0x00, 0x10}, /* window width */
++ {0xb1, 0x5c, 0x07, 0x30, 0x02, 0x00, 0x00, 0x10}, /* output ctrl */
++ {0xb1, 0x5c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10}, /* shutter delay */
++ {0xb1, 0x5c, 0x12, 0x00, 0xb0, 0x00, 0x00, 0x10}, /* zoom col start */
++ {0xb1, 0x5c, 0x13, 0x00, 0x7c, 0x00, 0x00, 0x10}, /* zoom row start */
++ {0xb1, 0x5c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* digital zoom */
++ {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, /* read mode */
++ {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
++ /*******/
++ {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xb1, 0x5c, 0x09, 0x01, 0x2c, 0x00, 0x00, 0x10},
++ {0xd1, 0x5c, 0x2b, 0x00, 0x33, 0x00, 0xa0, 0x10}, /* green1 gain */
++ {0xd1, 0x5c, 0x2d, 0x00, 0xa0, 0x00, 0x33, 0x10}, /* red gain */
++ /*******/
++ {0xb1, 0x5c, 0x06, 0x00, 0x1e, 0x00, 0x00, 0x10}, /* vert blanking */
++ {0xb1, 0x5c, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x10}, /* horiz blanking */
++ {0xd1, 0x5c, 0x2c, 0x00, 0xad, 0x00, 0xad, 0x10}, /* blue gain */
++ {0xb1, 0x5c, 0x35, 0x01, 0xc0, 0x00, 0x00, 0x10}, /* global gain */
++ {}
++};
++static const u8 om6802_sensor_init[][8] = {
+ {0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10},
+@@ -489,7 +594,7 @@ static __u8 om6802_sensor_init[][8] = {
+ /* {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */
+ {}
+ };
+-static const __u8 ov7630_sensor_init[][8] = {
++static const u8 ov7630_sensor_init[][8] = {
+ {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
+ /* win: delay 20ms */
+@@ -543,7 +648,7 @@ static const __u8 ov7630_sensor_init[][8] = {
+ {}
+ };
+
+-static const __u8 ov7648_sensor_init[][8] = {
++static const u8 ov7648_sensor_init[][8] = {
+ {0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */
+ {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+@@ -572,7 +677,8 @@ static const __u8 ov7648_sensor_init[][8] = {
+ {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10},
+ /*...*/
+ /* {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */
+-/* {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, jfm done */
++/* {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, * COMN
++ * set by setvflip */
+ {0xa1, 0x21, 0x19, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
+ /* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
+@@ -589,7 +695,7 @@ static const __u8 ov7648_sensor_init[][8] = {
+ {}
+ };
+
+-static const __u8 ov7660_sensor_init[][8] = {
++static const u8 ov7660_sensor_init[][8] = {
+ {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
+ /* (delay 20ms) */
+ {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
+@@ -678,28 +784,92 @@ static const __u8 ov7660_sensor_init[][8] = {
+ {}
+ };
+
+-static const __u8 qtable4[] = {
+- 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
+- 0x06, 0x08, 0x0A, 0x11,
+- 0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
+- 0x19, 0x19, 0x17, 0x15,
+- 0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
+- 0x21, 0x2E, 0x21, 0x23,
+- 0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
+- 0x25, 0x29, 0x2C, 0x29,
+- 0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
+- 0x17, 0x1B, 0x29, 0x29,
+- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+- 0x29, 0x29, 0x29, 0x29,
+- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+- 0x29, 0x29, 0x29, 0x29,
+- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+- 0x29, 0x29, 0x29, 0x29
++static const u8 sp80708_sensor_init[][8] = {
++ {0xa1, 0x18, 0x06, 0xf9, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x09, 0x1f, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x10, 0x40, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x12, 0x53, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x15, 0x80, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x19, 0x18, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x1a, 0x10, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x1c, 0x28, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x1d, 0x02, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x26, 0x04, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x27, 0x1e, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x28, 0x5a, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x29, 0x28, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x2a, 0x78, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x2c, 0xf7, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x2d, 0x2d, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x2e, 0xd5, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x39, 0x42, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x3a, 0x67, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x3b, 0x87, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x3c, 0xa3, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x3d, 0xb0, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x3e, 0xbc, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x3f, 0xc8, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x40, 0xd4, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x41, 0xdf, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x42, 0xea, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x43, 0xf5, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x45, 0x80, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x46, 0x60, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x47, 0x50, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x48, 0x30, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x49, 0x01, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x4d, 0xae, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x4e, 0x03, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x4f, 0x66, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x50, 0x1c, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x44, 0x10, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x4a, 0x30, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x51, 0x80, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x52, 0x80, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x53, 0x80, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x54, 0x80, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x55, 0x80, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x56, 0x80, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x57, 0xe0, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x58, 0xc0, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x59, 0xab, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x5a, 0xa0, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x5b, 0x99, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x5c, 0x90, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x5e, 0x24, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x61, 0x73, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x63, 0x42, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x64, 0x42, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x65, 0x42, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x66, 0x24, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x67, 0x24, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x68, 0x08, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x2f, 0xc9, 0x00, 0x00, 0x00, 0x10},
++ /********/
++ {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x03, 0x01, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x04, 0xa4, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x14, 0x3f, 0x00, 0x00, 0x00, 0x10},
++ {0xa1, 0x18, 0x5d, 0x80, 0x00, 0x00, 0x00, 0x10},
++ {0xb1, 0x18, 0x11, 0x40, 0x40, 0x00, 0x00, 0x10},
++ {}
+ };
+
+ /* read <len> bytes to gspca_dev->usb_buf */
+ static void reg_r(struct gspca_dev *gspca_dev,
+- __u16 value, int len)
++ u16 value, int len)
+ {
+ #ifdef GSPCA_DEBUG
+ if (len > USB_BUF_SZ) {
+@@ -718,10 +888,10 @@ static void reg_r(struct gspca_dev *gspca_dev,
+ }
+
+ static void reg_w1(struct gspca_dev *gspca_dev,
+- __u16 value,
+- __u8 data)
++ u16 value,
++ u8 data)
+ {
+- PDEBUG(D_USBO, "reg_w1 [%02x] = %02x", value, data);
++ PDEBUG(D_USBO, "reg_w1 [%04x] = %02x", value, data);
+ gspca_dev->usb_buf[0] = data;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+@@ -733,11 +903,11 @@ static void reg_w1(struct gspca_dev *gspca_dev,
+ 500);
+ }
+ static void reg_w(struct gspca_dev *gspca_dev,
+- __u16 value,
+- const __u8 *buffer,
++ u16 value,
++ const u8 *buffer,
+ int len)
+ {
+- PDEBUG(D_USBO, "reg_w [%02x] = %02x %02x ..",
++ PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..",
+ value, buffer[0], buffer[1]);
+ #ifdef GSPCA_DEBUG
+ if (len > USB_BUF_SZ) {
+@@ -756,7 +926,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
+ }
+
+ /* I2C write 1 byte */
+-static void i2c_w1(struct gspca_dev *gspca_dev, __u8 reg, __u8 val)
++static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+@@ -781,7 +951,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, __u8 reg, __u8 val)
+
+ /* I2C write 8 bytes */
+ static void i2c_w8(struct gspca_dev *gspca_dev,
+- const __u8 *buffer)
++ const u8 *buffer)
+ {
+ memcpy(gspca_dev->usb_buf, buffer, 8);
+ usb_control_msg(gspca_dev->dev,
+@@ -795,10 +965,10 @@ static void i2c_w8(struct gspca_dev *gspca_dev,
+ }
+
+ /* read 5 bytes in gspca_dev->usb_buf */
+-static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
++static void i2c_r5(struct gspca_dev *gspca_dev, u8 reg)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- __u8 mode[8];
++ u8 mode[8];
+
+ mode[0] = 0x81 | 0x10;
+ mode[1] = sd->i2c_base;
+@@ -817,7 +987,7 @@ static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
+ reg_r(gspca_dev, 0x0a, 5);
+ }
+
+-static int probesensor(struct gspca_dev *gspca_dev)
++static int hv7131r_probe(struct gspca_dev *gspca_dev)
+ {
+ i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */
+ msleep(10);
+@@ -839,16 +1009,66 @@ static int probesensor(struct gspca_dev *gspca_dev)
+ return -ENODEV;
+ }
+
++static void mi0360_probe(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++ int i, j;
++ u16 val = 0;
++ static const u8 probe_tb[][4][8] = {
++ { /* mi0360 */
++ {0xb0, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
++ {0x90, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xa2, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xb0, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10}
++ },
++ { /* mt9v111 */
++ {0xb0, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10},
++ {0x90, 0x5c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {0xa2, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
++ {}
++ },
++ };
++
++ for (i = 0; i < ARRAY_SIZE(probe_tb); i++) {
++ reg_w1(gspca_dev, 0x17, 0x62);
++ reg_w1(gspca_dev, 0x01, 0x08);
++ for (j = 0; j < 3; j++)
++ i2c_w8(gspca_dev, probe_tb[i][j]);
++ msleep(2);
++ reg_r(gspca_dev, 0x0a, 5);
++ val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
++ if (probe_tb[i][3][0] != 0)
++ i2c_w8(gspca_dev, probe_tb[i][3]);
++ reg_w1(gspca_dev, 0x01, 0x29);
++ reg_w1(gspca_dev, 0x17, 0x42);
++ if (val != 0xffff)
++ break;
++ }
++ switch (val) {
++ case 0x823a:
++ PDEBUG(D_PROBE, "Sensor mt9v111");
++ sd->sensor = SENSOR_MT9V111;
++ sd->i2c_base = 0x5c;
++ break;
++ case 0x8243:
++ PDEBUG(D_PROBE, "Sensor mi0360");
++ break;
++ default:
++ PDEBUG(D_PROBE, "Unknown sensor %04x - forced to mi0360", val);
++ break;
++ }
++}
++
+ static int configure_gpio(struct gspca_dev *gspca_dev,
+- const __u8 *sn9c1xx)
++ const u8 *sn9c1xx)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- const __u8 *reg9a;
+- static const __u8 reg9a_def[] =
++ const u8 *reg9a;
++ static const u8 reg9a_def[] =
+ {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
+- static const __u8 reg9a_sn9c325[] =
++ static const u8 reg9a_sn9c325[] =
+ {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+- static const __u8 regd4[] = {0x60, 0x00, 0x00};
++ static const u8 regd4[] = {0x60, 0x00, 0x00};
+
+ reg_w1(gspca_dev, 0xf1, 0x00);
+ reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
+@@ -872,6 +1092,12 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
+ reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
+
+ switch (sd->sensor) {
++ case SENSOR_MT9V111:
++ reg_w1(gspca_dev, 0x01, 0x61);
++ reg_w1(gspca_dev, 0x17, 0x61);
++ reg_w1(gspca_dev, 0x01, 0x60);
++ reg_w1(gspca_dev, 0x01, 0x40);
++ break;
+ case SENSOR_OM6802:
+ reg_w1(gspca_dev, 0x02, 0x71);
+ reg_w1(gspca_dev, 0x01, 0x42);
+@@ -900,12 +1126,20 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
+ break;
+ }
+ /* fall thru */
++ case SENSOR_SP80708:
++ reg_w1(gspca_dev, 0x01, 0x63);
++ reg_w1(gspca_dev, 0x17, 0x20);
++ reg_w1(gspca_dev, 0x01, 0x62);
++ reg_w1(gspca_dev, 0x01, 0x42);
++ mdelay(100);
++ reg_w1(gspca_dev, 0x02, 0x62);
++ break;
+ default:
+ reg_w1(gspca_dev, 0x01, 0x43);
+ reg_w1(gspca_dev, 0x17, 0x61);
+ reg_w1(gspca_dev, 0x01, 0x42);
+ if (sd->sensor == SENSOR_HV7131R) {
+- if (probesensor(gspca_dev) < 0)
++ if (hv7131r_probe(gspca_dev) < 0)
+ return -ENODEV;
+ }
+ break;
+@@ -916,7 +1150,7 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
+ static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
+ {
+ int i = 0;
+- static const __u8 SetSensorClk[] = /* 0x08 Mclk */
++ static const u8 SetSensorClk[] = /* 0x08 Mclk */
+ { 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
+
+ while (hv7131r_sensor_init[i][0]) {
+@@ -946,6 +1180,19 @@ static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
+ }
+ }
+
++static void mt9v111_InitSensor(struct gspca_dev *gspca_dev)
++{
++ int i = 0;
++
++ i2c_w8(gspca_dev, mt9v111_sensor_init[i]);
++ i++;
++ msleep(20);
++ while (mt9v111_sensor_init[i][0]) {
++ i2c_w8(gspca_dev, mt9v111_sensor_init[i]);
++ i++;
++ }
++}
++
+ static void om6802_InitSensor(struct gspca_dev *gspca_dev)
+ {
+ int i = 0;
+@@ -1010,6 +1257,19 @@ static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
+ }
+ }
+
++static void sp80708_InitSensor(struct gspca_dev *gspca_dev)
++{
++ int i = 0;
++
++ i2c_w8(gspca_dev, sp80708_sensor_init[i]); /* reset SCCB */
++ i++;
++ msleep(20);
++ while (sp80708_sensor_init[i][0]) {
++ i2c_w8(gspca_dev, sp80708_sensor_init[i]);
++ i++;
++ }
++}
++
+ /* this function is called at probe time */
+ static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+@@ -1018,7 +1278,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+
+@@ -1026,16 +1285,21 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ sd->sensor = id->driver_info >> 8;
+ sd->i2c_base = id->driver_info;
+
+- sd->qindex = 4; /* set the quantization table */
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->blue = BLUE_BALANCE_DEF;
+ sd->red = RED_BALANCE_DEF;
++ sd->gamma = GAMMA_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ sd->ag_cnt = -1;
+- sd->vflip = VFLIP_DEF;
++ if (sd->sensor != SENSOR_OV7630)
++ sd->vflip = 0;
++ else
++ sd->vflip = 1;
+ sd->infrared = INFRARED_DEF;
++ sd->quality = QUALITY_DEF;
++ sd->jpegqual = 80;
+
+ gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
+ return 0;
+@@ -1045,8 +1309,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ static int sd_init(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- __u8 regGpio[] = { 0x29, 0x74 };
+- __u8 regF1;
++ u8 regGpio[] = { 0x29, 0x74 };
++ u8 regF1;
+
+ /* setup a selector by bridge */
+ reg_w1(gspca_dev, 0xf1, 0x01);
+@@ -1064,11 +1328,15 @@ static int sd_init(struct gspca_dev *gspca_dev)
+ case BRIDGE_SN9C105:
+ if (regF1 != 0x11)
+ return -ENODEV;
++ if (sd->sensor == SENSOR_MI0360)
++ mi0360_probe(gspca_dev);
+ reg_w(gspca_dev, 0x01, regGpio, 2);
+ break;
+ case BRIDGE_SN9C120:
+ if (regF1 != 0x12)
+ return -ENODEV;
++ if (sd->sensor == SENSOR_MI0360)
++ mi0360_probe(gspca_dev);
+ regGpio[1] = 0x70;
+ reg_w(gspca_dev, 0x01, regGpio, 2);
+ break;
+@@ -1086,20 +1354,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
+ return 0;
+ }
+
+-static unsigned int setexposure(struct gspca_dev *gspca_dev,
+- unsigned int expo)
++static u32 setexposure(struct gspca_dev *gspca_dev,
++ u32 expo)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- static const __u8 doit[] = /* update sensor */
+- { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
+- static const __u8 sensorgo[] = /* sensor on */
+- { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
+- static const __u8 gainMo[] =
+- { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R: {
+- __u8 Expodoit[] =
++ u8 Expodoit[] =
+ { 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
+
+ Expodoit[3] = expo >> 16;
+@@ -1109,8 +1371,12 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
+ break;
+ }
+ case SENSOR_MI0360: {
+- __u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */
++ u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */
+ { 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
++ static const u8 doit[] = /* update sensor */
++ { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
++ static const u8 sensorgo[] = /* sensor on */
++ { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
+
+ if (expo > 0x0635)
+ expo = 0x0635;
+@@ -1124,10 +1390,12 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
+ break;
+ }
+ case SENSOR_MO4000: {
+- __u8 expoMof[] =
++ u8 expoMof[] =
+ { 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
+- __u8 expoMo10[] =
++ u8 expoMo10[] =
+ { 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
++ static const u8 gainMo[] =
++ { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
+
+ if (expo > 0x1fff)
+ expo = 0x1fff;
+@@ -1139,14 +1407,27 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
+ | ((expo & 0x0003) << 4);
+ i2c_w8(gspca_dev, expoMo10);
+ i2c_w8(gspca_dev, gainMo);
+- PDEBUG(D_CONF, "set exposure %d",
++ PDEBUG(D_FRAM, "set exposure %d",
+ ((expoMo10[3] & 0x07) << 10)
+ | (expoMof[3] << 2)
+ | ((expoMo10[3] & 0x30) >> 4));
+ break;
+ }
++ case SENSOR_MT9V111: {
++ u8 expo_c1[] =
++ { 0xb1, 0x5c, 0x09, 0x00, 0x00, 0x00, 0x00, 0x10 };
++
++ if (expo > 0x0280)
++ expo = 0x0280;
++ else if (expo < 0x0040)
++ expo = 0x0040;
++ expo_c1[3] = expo >> 8;
++ expo_c1[4] = expo;
++ i2c_w8(gspca_dev, expo_c1);
++ break;
++ }
+ case SENSOR_OM6802: {
+- __u8 gainOm[] =
++ u8 gainOm[] =
+ { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 };
+
+ if (expo > 0x03ff)
+@@ -1156,7 +1437,7 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
+ gainOm[3] = expo >> 2;
+ i2c_w8(gspca_dev, gainOm);
+ reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f);
+- PDEBUG(D_CONF, "set exposure %d", gainOm[3]);
++ PDEBUG(D_FRAM, "set exposure %d", gainOm[3]);
+ break;
+ }
+ }
+@@ -1167,7 +1448,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned int expo;
+- __u8 k2;
++ u8 k2;
+
+ k2 = ((int) sd->brightness - 0x8000) >> 10;
+ switch (sd->sensor) {
+@@ -1184,6 +1465,10 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ expo = sd->brightness >> 4;
+ sd->exposure = setexposure(gspca_dev, expo);
+ break;
++ case SENSOR_MT9V111:
++ expo = sd->brightness >> 8;
++ sd->exposure = setexposure(gspca_dev, expo);
++ break;
+ case SENSOR_OM6802:
+ expo = sd->brightness >> 6;
+ sd->exposure = setexposure(gspca_dev, expo);
+@@ -1191,14 +1476,15 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ break;
+ }
+
+- reg_w1(gspca_dev, 0x96, k2); /* color matrix Y offset */
++ if (sd->sensor != SENSOR_MT9V111)
++ reg_w1(gspca_dev, 0x96, k2); /* color matrix Y offset */
+ }
+
+ static void setcontrast(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- __u8 k2;
+- __u8 contrast[6];
++ u8 k2;
++ u8 contrast[6];
+
+ k2 = sd->contrast * 0x30 / (CONTRAST_MAX + 1) + 0x10; /* 10..40 */
+ contrast[0] = (k2 + 1) / 2; /* red */
+@@ -1214,8 +1500,8 @@ static void setcolors(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, v;
+- __u8 reg8a[12]; /* U & V gains */
+- static __s16 uv[6] = { /* same as reg84 in signed decimal */
++ u8 reg8a[12]; /* U & V gains */
++ static s16 uv[6] = { /* same as reg84 in signed decimal */
+ -24, -38, 64, /* UR UG UB */
+ 62, -51, -9 /* VR VG VB */
+ };
+@@ -1236,22 +1522,75 @@ static void setredblue(struct gspca_dev *gspca_dev)
+ reg_w1(gspca_dev, 0x06, sd->blue);
+ }
+
++static void setgamma(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++ int i;
++ u8 gamma[17];
++ const u8 *gamma_base;
++ static const u8 delta[17] = {
++ 0x00, 0x14, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1a,
++ 0x18, 0x13, 0x10, 0x0e, 0x08, 0x07, 0x04, 0x02, 0x00
++ };
++
++ switch (sd->sensor) {
++ case SENSOR_HV7131R:
++ case SENSOR_MT9V111:
++ gamma_base = gamma_spec_1;
++ break;
++ case SENSOR_SP80708:
++ gamma_base = gamma_spec_2;
++ break;
++ default:
++ gamma_base = gamma_def;
++ break;
++ }
++
++ for (i = 0; i < sizeof gamma; i++)
++ gamma[i] = gamma_base[i]
++ + delta[i] * (sd->gamma - GAMMA_DEF) / 32;
++ reg_w(gspca_dev, 0x20, gamma, sizeof gamma);
++}
++
+ static void setautogain(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+ return;
++ switch (sd->sensor) {
++ case SENSOR_OV7630:
++ case SENSOR_OV7648: {
++ u8 comb;
++
++ if (sd->sensor == SENSOR_OV7630)
++ comb = 0xc0;
++ else
++ comb = 0xa0;
++ if (sd->autogain)
++ comb |= 0x02;
++ i2c_w1(&sd->gspca_dev, 0x13, comb);
++ return;
++ }
++ }
+ if (sd->autogain)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+ }
+
++/* ov7630/ov7648 only */
+ static void setvflip(struct sd *sd)
+ {
+- i2c_w1(&sd->gspca_dev, 0x75, /* COMN */
+- sd->vflip ? 0x82 : 0x02);
++ u8 comn;
++
++ if (sd->sensor == SENSOR_OV7630)
++ comn = 0x02;
++ else
++ comn = 0x06;
++ if (sd->vflip)
++ comn |= 0x80;
++ i2c_w1(&sd->gspca_dev, 0x75, comn);
+ }
+
+ static void setinfrared(struct sd *sd)
+@@ -1262,20 +1601,63 @@ static void setinfrared(struct sd *sd)
+ sd->infrared ? 0x66 : 0x64);
+ }
+
++static void setjpegqual(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++ int i, sc;
++
++ if (sd->jpegqual < 50)
++ sc = 5000 / sd->jpegqual;
++ else
++ sc = 200 - sd->jpegqual * 2;
++#if USB_BUF_SZ < 64
++#error "No room enough in usb_buf for quantization table"
++#endif
++ for (i = 0; i < 64; i++)
++ gspca_dev->usb_buf[i] =
++ (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
++ usb_control_msg(gspca_dev->dev,
++ usb_sndctrlpipe(gspca_dev->dev, 0),
++ 0x08,
++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
++ 0x0100, 0,
++ gspca_dev->usb_buf, 64,
++ 500);
++ for (i = 0; i < 64; i++)
++ gspca_dev->usb_buf[i] =
++ (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
++ usb_control_msg(gspca_dev->dev,
++ usb_sndctrlpipe(gspca_dev->dev, 0),
++ 0x08,
++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
++ 0x0140, 0,
++ gspca_dev->usb_buf, 64,
++ 500);
++
++ sd->reg18 ^= 0x40;
++ reg_w1(gspca_dev, 0x18, sd->reg18);
++}
++
+ /* -- start the camera -- */
+ static int sd_start(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+- __u8 reg1, reg17, reg18;
+- const __u8 *sn9c1xx;
++ u8 reg1, reg17;
++ const u8 *sn9c1xx;
+ int mode;
+- static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
+- static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
+- static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
+- static const __u8 CE_ov76xx[] =
++ static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
++ static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
++ static const u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
++ static const u8 CE_ov76xx[] =
+ { 0x32, 0xdd, 0x32, 0xdd };
+
++ /* create the JPEG header */
++ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
++ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
++ 0x21); /* JPEG 422 */
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++
+ sn9c1xx = sn_tb[(int) sd->sensor];
+ configure_gpio(gspca_dev, sn9c1xx);
+
+@@ -1292,6 +1674,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ reg_w1(gspca_dev, 0xc9, 0x3c);
+ reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
+ switch (sd->sensor) {
++ case SENSOR_MT9V111:
++ reg17 = 0xe0;
++ break;
+ case SENSOR_OV7630:
+ reg17 = 0xe2;
+ break;
+@@ -1315,14 +1700,24 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ reg_w1(gspca_dev, 0x07, sn9c1xx[7]); /* green */
+ reg_w1(gspca_dev, 0x06, sn9c1xx[6]); /* blue */
+ reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
+- reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
++
++ setgamma(gspca_dev);
++
+ for (i = 0; i < 8; i++)
+ reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+ switch (sd->sensor) {
++ case SENSOR_MT9V111:
++ reg_w1(gspca_dev, 0x9a, 0x07);
++ reg_w1(gspca_dev, 0x99, 0x59);
++ break;
+ case SENSOR_OV7648:
+ reg_w1(gspca_dev, 0x9a, 0x0a);
+ reg_w1(gspca_dev, 0x99, 0x60);
+ break;
++ case SENSOR_SP80708:
++ reg_w1(gspca_dev, 0x9a, 0x05);
++ reg_w1(gspca_dev, 0x99, 0x59);
++ break;
+ case SENSOR_OV7660:
+ if (sd->bridge == BRIDGE_SN9C120) {
+ reg_w1(gspca_dev, 0x9a, 0x05);
+@@ -1358,6 +1753,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ /* reg1 = 0x06; * 640 clk 24Mz (done) */
+ }
+ break;
++ case SENSOR_MT9V111:
++ mt9v111_InitSensor(gspca_dev);
++ if (mode) {
++ reg1 = 0x04; /* 320 clk 48Mhz */
++ } else {
++/* reg1 = 0x06; * 640 clk 24Mz (done) */
++ reg17 = 0xc2;
++ }
++ break;
+ case SENSOR_OM6802:
+ om6802_InitSensor(gspca_dev);
+ reg17 = 0x64; /* 640 MCKSIZE */
+@@ -1373,8 +1777,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ reg17 = 0x21;
+ /* reg1 = 0x42; * 42 - 46? */
+ break;
+- default:
+-/* case SENSOR_OV7660: */
++ case SENSOR_OV7660:
+ ov7660_InitSensor(gspca_dev);
+ if (sd->bridge == BRIDGE_SN9C120) {
+ if (mode) { /* 320x240 - 160x120 */
+@@ -1387,6 +1790,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ * inverse power down */
+ }
+ break;
++ default:
++/* case SENSOR_SP80708: */
++ sp80708_InitSensor(gspca_dev);
++ if (mode) {
++/*?? reg1 = 0x04; * 320 clk 48Mhz */
++ } else {
++ reg1 = 0x46; /* 640 clk 48Mz */
++ reg17 = 0xa2;
++ }
++ break;
+ }
+ reg_w(gspca_dev, 0xc0, C0, 6);
+ reg_w(gspca_dev, 0xca, CA, 4);
+@@ -1403,20 +1816,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ }
+
+ /* here change size mode 0 -> VGA; 1 -> CIF */
+- reg18 = sn9c1xx[0x18] | (mode << 4);
+- reg_w1(gspca_dev, 0x18, reg18 | 0x40);
+-
+- reg_w(gspca_dev, 0x100, qtable4, 0x40);
+- reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40);
+-
+- reg_w1(gspca_dev, 0x18, reg18);
++ sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40;
++ reg_w1(gspca_dev, 0x18, sd->reg18);
++ setjpegqual(gspca_dev);
+
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg_w1(gspca_dev, 0x01, reg1);
+ switch (sd->sensor) {
+- case SENSOR_MI0360:
+- setinfrared(sd);
+- break;
+ case SENSOR_OV7630:
+ setvflip(sd);
+ break;
+@@ -1430,14 +1836,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ static void sd_stopN(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- static const __u8 stophv7131[] =
++ static const u8 stophv7131[] =
+ { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
+- static const __u8 stopmi0360[] =
++ static const u8 stopmi0360[] =
+ { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
+- static const __u8 stopov7648[] =
++ static const u8 stopov7648[] =
+ { 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 };
+- __u8 data;
+- const __u8 *sn9c1xx;
++ u8 data;
++ const u8 *sn9c1xx;
+
+ data = 0x0b;
+ switch (sd->sensor) {
+@@ -1452,6 +1858,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
+ case SENSOR_OV7648:
+ i2c_w8(gspca_dev, stopov7648);
+ /* fall thru */
++ case SENSOR_MT9V111:
+ case SENSOR_OV7630:
+ data = 0x29;
+ break;
+@@ -1468,13 +1875,20 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
+ reg_w1(gspca_dev, 0xf1, 0x00);
+ }
+
++static void sd_stop0(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ kfree(sd->jpeg_hdr);
++}
++
+ static void do_autogain(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+ int delta;
+ int expotimes;
+- __u8 luma_mean = 130;
+- __u8 luma_delta = 20;
++ u8 luma_mean = 130;
++ u8 luma_delta = 20;
+
+ /* Thanks S., without your advice, autobright should not work :) */
+ if (sd->ag_cnt < 0)
+@@ -1499,6 +1913,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
+ default:
+ /* case SENSOR_MO4000: */
+ /* case SENSOR_MI0360: */
++/* case SENSOR_MT9V111: */
+ /* case SENSOR_OM6802: */
+ expotimes = sd->exposure;
+ expotimes += (luma_mean - delta) >> 6;
+@@ -1516,7 +1931,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
+ /* This function is run at interrupt level. */
+ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+- __u8 *data, /* isoc packet */
++ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -1550,7 +1965,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ if (gspca_dev->last_packet_type == LAST_PACKET) {
+
+ /* put the JPEG 422 header */
+- jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
++ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
++ sd->jpeg_hdr, JPEG_HDR_SZ);
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ }
+@@ -1645,6 +2061,24 @@ static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
+ return 0;
+ }
+
++static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ sd->gamma = val;
++ if (gspca_dev->streaming)
++ setgamma(gspca_dev);
++ return 0;
++}
++
++static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ *val = sd->gamma;
++ return 0;
++}
++
+ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -1699,6 +2133,34 @@ static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
+ return 0;
+ }
+
++static int sd_set_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ if (jcomp->quality < QUALITY_MIN)
++ sd->quality = QUALITY_MIN;
++ else if (jcomp->quality > QUALITY_MAX)
++ sd->quality = QUALITY_MAX;
++ else
++ sd->quality = jcomp->quality;
++ if (gspca_dev->streaming)
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++ return 0;
++}
++
++static int sd_get_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ memset(jcomp, 0, sizeof *jcomp);
++ jcomp->quality = sd->quality;
++ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
++ | V4L2_JPEG_MARKER_DQT;
++ return 0;
++}
++
+ /* sub-driver description */
+ static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+@@ -1708,8 +2170,11 @@ static const struct sd_desc sd_desc = {
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
++ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
+ .dq_callback = do_autogain,
++ .get_jcomp = sd_get_jcomp,
++ .set_jcomp = sd_set_jcomp,
+ };
+
+ /* -- module initialisation -- */
+@@ -1724,9 +2189,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
+ #endif
+ {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
+ {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
+-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
+-#endif
+ {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
+ {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
+ {USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
+@@ -1764,10 +2227,10 @@ static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)},
+ #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
++#endif
+ {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
+ /* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */
+-#endif
+- {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, MI0360, 0x5d)},
++ {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)},
+ {}
+ };
+ MODULE_DEVICE_TABLE(usb, device_table);
+@@ -1794,8 +2257,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ info("registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
+index 942f04c..6f38fa6 100644
+--- a/drivers/media/video/gspca/spca500.c
++++ b/drivers/media/video/gspca/spca500.c
+@@ -38,8 +38,11 @@ struct sd {
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
++ u8 quality;
++#define QUALITY_MIN 70
++#define QUALITY_MAX 95
++#define QUALITY_DEF 85
+
+- char qindex;
+ char subtype;
+ #define AgfaCl20 0
+ #define AiptekPocketDV 1
+@@ -56,6 +59,8 @@ struct sd {
+ #define Optimedia 12
+ #define PalmPixDC85 13
+ #define ToptroIndus 14
++
++ u8 *jpeg_hdr;
+ };
+
+ /* V4L2 controls supported by the driver */
+@@ -629,7 +634,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ sd->subtype = id->driver_info;
+ if (sd->subtype != LogitechClickSmart310) {
+ cam->cam_mode = vga_mode;
+@@ -638,10 +642,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ }
+- sd->qindex = 5;
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
++ sd->quality = QUALITY_DEF;
+ return 0;
+ }
+
+@@ -667,6 +671,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ __u8 Data;
+ __u8 xmult, ymult;
+
++ /* create the JPEG header */
++ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
++ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
++ 0x22); /* JPEG 411 */
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++
+ if (sd->subtype == LogitechClickSmart310) {
+ xmult = 0x16;
+ ymult = 0x12;
+@@ -713,7 +723,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ write_vector(gspca_dev, spca500_visual_defaults);
+ spca500_setmode(gspca_dev, xmult, ymult);
+ /* enable drop packet */
+- reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
++ err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
++ if (err < 0)
+ PDEBUG(D_ERR, "failed to enable drop packet");
+ reg_w(gspca_dev, 0x00, 0x8880, 3);
+ err = spca50x_setup_qtable(gspca_dev,
+@@ -881,6 +892,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
+ gspca_dev->usb_buf[0]);
+ }
+
++static void sd_stop0(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ kfree(sd->jpeg_hdr);
++}
++
+ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+@@ -901,7 +919,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ ffd9, 2);
+
+ /* put the JPEG header in the new frame */
+- jpeg_put_header(gspca_dev, frame, sd->qindex, 0x22);
++ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
++ sd->jpeg_hdr, JPEG_HDR_SZ);
+
+ data += SPCA500_OFFSET_DATA;
+ len -= SPCA500_OFFSET_DATA;
+@@ -937,16 +956,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ (__u8) (sd->brightness - 128));
+ }
+
+-static void getbrightness(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+- int ret;
+-
+- ret = reg_r_12(gspca_dev, 0x00, 0x8167, 1);
+- if (ret >= 0)
+- sd->brightness = ret + 128;
+-}
+-
+ static void setcontrast(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -954,16 +963,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
+ reg_w(gspca_dev, 0x00, 0x8168, sd->contrast);
+ }
+
+-static void getcontrast(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+- int ret;
+-
+- ret = reg_r_12(gspca_dev, 0x0, 0x8168, 1);
+- if (ret >= 0)
+- sd->contrast = ret;
+-}
+-
+ static void setcolors(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -971,16 +970,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
+ reg_w(gspca_dev, 0x00, 0x8169, sd->colors);
+ }
+
+-static void getcolors(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+- int ret;
+-
+- ret = reg_r_12(gspca_dev, 0x0, 0x8169, 1);
+- if (ret >= 0)
+- sd->colors = ret;
+-}
+-
+ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -995,7 +984,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+ }
+@@ -1014,7 +1002,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+ }
+@@ -1033,11 +1020,38 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+ }
+
++static int sd_set_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ if (jcomp->quality < QUALITY_MIN)
++ sd->quality = QUALITY_MIN;
++ else if (jcomp->quality > QUALITY_MAX)
++ sd->quality = QUALITY_MAX;
++ else
++ sd->quality = jcomp->quality;
++ if (gspca_dev->streaming)
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++ return 0;
++}
++
++static int sd_get_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ memset(jcomp, 0, sizeof *jcomp);
++ jcomp->quality = sd->quality;
++ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
++ | V4L2_JPEG_MARKER_DQT;
++ return 0;
++}
++
+ /* sub-driver description */
+ static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+@@ -1047,7 +1061,10 @@ static struct sd_desc sd_desc = {
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
++ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
++ .get_jcomp = sd_get_jcomp,
++ .set_jcomp = sd_set_jcomp,
+ };
+
+ /* -- module initialisation -- */
+@@ -1093,8 +1110,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
+index 82e3e3e..d48b27c 100644
+--- a/drivers/media/video/gspca/spca501.c
++++ b/drivers/media/video/gspca/spca501.c
+@@ -1883,10 +1883,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness);
+ }
+
+-static void getbrightness(struct gspca_dev *gspca_dev)
+-{
+-}
+-
+ static void setcontrast(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -1897,10 +1893,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
+ sd->contrast & 0xff);
+ }
+
+-static void getcontrast(struct gspca_dev *gspca_dev)
+-{
+-}
+-
+ static void setcolors(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -1908,10 +1900,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors);
+ }
+
+-static void getcolors(struct gspca_dev *gspca_dev)
+-{
+-}
+-
+ static void setblue_balance(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -1934,7 +1922,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ sd->subtype = id->driver_info;
+@@ -2084,7 +2071,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+ }
+@@ -2103,7 +2089,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+ }
+@@ -2122,7 +2107,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+ }
+@@ -2211,8 +2195,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
+index 2a33a29..2acec58 100644
+--- a/drivers/media/video/gspca/spca505.c
++++ b/drivers/media/video/gspca/spca505.c
+@@ -31,9 +31,9 @@ MODULE_LICENSE("GPL");
+ struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+- unsigned char brightness;
++ u8 brightness;
+
+- char subtype;
++ u8 subtype;
+ #define IntelPCCameraPro 0
+ #define Nxultra 1
+ };
+@@ -43,7 +43,6 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+
+ static struct ctrl sd_ctrls[] = {
+-#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+@@ -52,7 +51,8 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+- .default_value = 127,
++#define BRIGHTNESS_DEF 127
++ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+@@ -64,12 +64,12 @@ static const struct v4l2_pix_format vga_mode[] = {
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+- .priv = 5},
++ .priv = 4},
+ {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+- .priv = 4},
++ .priv = 3},
+ {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 2,
+@@ -93,6 +93,7 @@ static const struct v4l2_pix_format vga_mode[] = {
+
+ #define SPCA50X_USB_CTRL 0x00 /* spca505 */
+ #define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */
++
+ #define SPCA50X_REG_GLOBAL 0x03 /* spca505 */
+ #define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */
+ #define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */
+@@ -101,230 +102,230 @@ static const struct v4l2_pix_format vga_mode[] = {
+ #define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */
+ #define SPCA50X_GMISC3_SAA7113RST 0x20 /* Not sure about this one spca505 */
+
++/* Image format and compression control */
++#define SPCA50X_REG_COMPRESS 0x04
++
+ /*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+-static const __u16 spca505_init_data[][3] = {
+- /* line bmRequest,value,index */
+- /* 1819 */
++static const u8 spca505_init_data[][3] = {
++ /* bmRequest,value,index */
+ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
+ /* Sensor reset */
+- /* 1822 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
+- /* 1825 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
++ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
++ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
+ /* Block USB reset */
+- /* 1828 */ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL,
+- SPCA50X_GLOBAL_MISC0},
++ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL, SPCA50X_GLOBAL_MISC0},
+
+- /* 1831 */ {0x5, 0x01, 0x10},
++ {0x05, 0x01, 0x10},
+ /* Maybe power down some stuff */
+- /* 1834 */ {0x5, 0x0f, 0x11},
++ {0x05, 0x0f, 0x11},
+
+ /* Setup internal CCD ? */
+- /* 1837 */ {0x6, 0x10, 0x08},
+- /* 1840 */ {0x6, 0x00, 0x09},
+- /* 1843 */ {0x6, 0x00, 0x0a},
+- /* 1846 */ {0x6, 0x00, 0x0b},
+- /* 1849 */ {0x6, 0x10, 0x0c},
+- /* 1852 */ {0x6, 0x00, 0x0d},
+- /* 1855 */ {0x6, 0x00, 0x0e},
+- /* 1858 */ {0x6, 0x00, 0x0f},
+- /* 1861 */ {0x6, 0x10, 0x10},
+- /* 1864 */ {0x6, 0x02, 0x11},
+- /* 1867 */ {0x6, 0x00, 0x12},
+- /* 1870 */ {0x6, 0x04, 0x13},
+- /* 1873 */ {0x6, 0x02, 0x14},
+- /* 1876 */ {0x6, 0x8a, 0x51},
+- /* 1879 */ {0x6, 0x40, 0x52},
+- /* 1882 */ {0x6, 0xb6, 0x53},
+- /* 1885 */ {0x6, 0x3d, 0x54},
++ {0x06, 0x10, 0x08},
++ {0x06, 0x00, 0x09},
++ {0x06, 0x00, 0x0a},
++ {0x06, 0x00, 0x0b},
++ {0x06, 0x10, 0x0c},
++ {0x06, 0x00, 0x0d},
++ {0x06, 0x00, 0x0e},
++ {0x06, 0x00, 0x0f},
++ {0x06, 0x10, 0x10},
++ {0x06, 0x02, 0x11},
++ {0x06, 0x00, 0x12},
++ {0x06, 0x04, 0x13},
++ {0x06, 0x02, 0x14},
++ {0x06, 0x8a, 0x51},
++ {0x06, 0x40, 0x52},
++ {0x06, 0xb6, 0x53},
++ {0x06, 0x3d, 0x54},
+ {}
+ };
+
+ /*
+ * Data to initialize the camera using the internal CCD
+ */
+-static const __u16 spca505_open_data_ccd[][3] = {
+- /* line bmRequest,value,index */
++static const u8 spca505_open_data_ccd[][3] = {
++ /* bmRequest,value,index */
+ /* Internal CCD data set */
+- /* 1891 */ {0x3, 0x04, 0x01},
++ {0x03, 0x04, 0x01},
+ /* This could be a reset */
+- /* 1894 */ {0x3, 0x00, 0x01},
++ {0x03, 0x00, 0x01},
+
+ /* Setup compression and image registers. 0x6 and 0x7 seem to be
+ related to H&V hold, and are resolution mode specific */
+- /* 1897 */ {0x4, 0x10, 0x01},
++ {0x04, 0x10, 0x01},
+ /* DIFF(0x50), was (0x10) */
+- /* 1900 */ {0x4, 0x00, 0x04},
+- /* 1903 */ {0x4, 0x00, 0x05},
+- /* 1906 */ {0x4, 0x20, 0x06},
+- /* 1909 */ {0x4, 0x20, 0x07},
++ {0x04, 0x00, 0x04},
++ {0x04, 0x00, 0x05},
++ {0x04, 0x20, 0x06},
++ {0x04, 0x20, 0x07},
+
+- /* 1912 */ {0x8, 0x0a, 0x00},
++ {0x08, 0x0a, 0x00},
+ /* DIFF (0x4a), was (0xa) */
+
+- /* 1915 */ {0x5, 0x00, 0x10},
+- /* 1918 */ {0x5, 0x00, 0x11},
+- /* 1921 */ {0x5, 0x00, 0x00},
++ {0x05, 0x00, 0x10},
++ {0x05, 0x00, 0x11},
++ {0x05, 0x00, 0x00},
+ /* DIFF not written */
+- /* 1924 */ {0x5, 0x00, 0x01},
++ {0x05, 0x00, 0x01},
+ /* DIFF not written */
+- /* 1927 */ {0x5, 0x00, 0x02},
++ {0x05, 0x00, 0x02},
+ /* DIFF not written */
+- /* 1930 */ {0x5, 0x00, 0x03},
++ {0x05, 0x00, 0x03},
+ /* DIFF not written */
+- /* 1933 */ {0x5, 0x00, 0x04},
++ {0x05, 0x00, 0x04},
+ /* DIFF not written */
+- /* 1936 */ {0x5, 0x80, 0x05},
++ {0x05, 0x80, 0x05},
+ /* DIFF not written */
+- /* 1939 */ {0x5, 0xe0, 0x06},
++ {0x05, 0xe0, 0x06},
+ /* DIFF not written */
+- /* 1942 */ {0x5, 0x20, 0x07},
++ {0x05, 0x20, 0x07},
+ /* DIFF not written */
+- /* 1945 */ {0x5, 0xa0, 0x08},
++ {0x05, 0xa0, 0x08},
+ /* DIFF not written */
+- /* 1948 */ {0x5, 0x0, 0x12},
++ {0x05, 0x0, 0x12},
+ /* DIFF not written */
+- /* 1951 */ {0x5, 0x02, 0x0f},
++ {0x05, 0x02, 0x0f},
+ /* DIFF not written */
+- /* 1954 */ {0x5, 0x10, 0x46},
++ {0x05, 0x10, 0x46},
+ /* DIFF not written */
+- /* 1957 */ {0x5, 0x8, 0x4a},
++ {0x05, 0x8, 0x4a},
+ /* DIFF not written */
+
+- /* 1960 */ {0x3, 0x08, 0x03},
++ {0x03, 0x08, 0x03},
+ /* DIFF (0x3,0x28,0x3) */
+- /* 1963 */ {0x3, 0x08, 0x01},
+- /* 1966 */ {0x3, 0x0c, 0x03},
++ {0x03, 0x08, 0x01},
++ {0x03, 0x0c, 0x03},
+ /* DIFF not written */
+- /* 1969 */ {0x3, 0x21, 0x00},
++ {0x03, 0x21, 0x00},
+ /* DIFF (0x39) */
+
+ /* Extra block copied from init to hopefully ensure CCD is in a sane state */
+- /* 1837 */ {0x6, 0x10, 0x08},
+- /* 1840 */ {0x6, 0x00, 0x09},
+- /* 1843 */ {0x6, 0x00, 0x0a},
+- /* 1846 */ {0x6, 0x00, 0x0b},
+- /* 1849 */ {0x6, 0x10, 0x0c},
+- /* 1852 */ {0x6, 0x00, 0x0d},
+- /* 1855 */ {0x6, 0x00, 0x0e},
+- /* 1858 */ {0x6, 0x00, 0x0f},
+- /* 1861 */ {0x6, 0x10, 0x10},
+- /* 1864 */ {0x6, 0x02, 0x11},
+- /* 1867 */ {0x6, 0x00, 0x12},
+- /* 1870 */ {0x6, 0x04, 0x13},
+- /* 1873 */ {0x6, 0x02, 0x14},
+- /* 1876 */ {0x6, 0x8a, 0x51},
+- /* 1879 */ {0x6, 0x40, 0x52},
+- /* 1882 */ {0x6, 0xb6, 0x53},
+- /* 1885 */ {0x6, 0x3d, 0x54},
++ {0x06, 0x10, 0x08},
++ {0x06, 0x00, 0x09},
++ {0x06, 0x00, 0x0a},
++ {0x06, 0x00, 0x0b},
++ {0x06, 0x10, 0x0c},
++ {0x06, 0x00, 0x0d},
++ {0x06, 0x00, 0x0e},
++ {0x06, 0x00, 0x0f},
++ {0x06, 0x10, 0x10},
++ {0x06, 0x02, 0x11},
++ {0x06, 0x00, 0x12},
++ {0x06, 0x04, 0x13},
++ {0x06, 0x02, 0x14},
++ {0x06, 0x8a, 0x51},
++ {0x06, 0x40, 0x52},
++ {0x06, 0xb6, 0x53},
++ {0x06, 0x3d, 0x54},
+ /* End of extra block */
+
+- /* 1972 */ {0x6, 0x3f, 0x1},
++ {0x06, 0x3f, 0x1},
+ /* Block skipped */
+- /* 1975 */ {0x6, 0x10, 0x02},
+- /* 1978 */ {0x6, 0x64, 0x07},
+- /* 1981 */ {0x6, 0x10, 0x08},
+- /* 1984 */ {0x6, 0x00, 0x09},
+- /* 1987 */ {0x6, 0x00, 0x0a},
+- /* 1990 */ {0x6, 0x00, 0x0b},
+- /* 1993 */ {0x6, 0x10, 0x0c},
+- /* 1996 */ {0x6, 0x00, 0x0d},
+- /* 1999 */ {0x6, 0x00, 0x0e},
+- /* 2002 */ {0x6, 0x00, 0x0f},
+- /* 2005 */ {0x6, 0x10, 0x10},
+- /* 2008 */ {0x6, 0x02, 0x11},
+- /* 2011 */ {0x6, 0x00, 0x12},
+- /* 2014 */ {0x6, 0x04, 0x13},
+- /* 2017 */ {0x6, 0x02, 0x14},
+- /* 2020 */ {0x6, 0x8a, 0x51},
+- /* 2023 */ {0x6, 0x40, 0x52},
+- /* 2026 */ {0x6, 0xb6, 0x53},
+- /* 2029 */ {0x6, 0x3d, 0x54},
+- /* 2032 */ {0x6, 0x60, 0x57},
+- /* 2035 */ {0x6, 0x20, 0x58},
+- /* 2038 */ {0x6, 0x15, 0x59},
+- /* 2041 */ {0x6, 0x05, 0x5a},
+-
+- /* 2044 */ {0x5, 0x01, 0xc0},
+- /* 2047 */ {0x5, 0x10, 0xcb},
+- /* 2050 */ {0x5, 0x80, 0xc1},
++ {0x06, 0x10, 0x02},
++ {0x06, 0x64, 0x07},
++ {0x06, 0x10, 0x08},
++ {0x06, 0x00, 0x09},
++ {0x06, 0x00, 0x0a},
++ {0x06, 0x00, 0x0b},
++ {0x06, 0x10, 0x0c},
++ {0x06, 0x00, 0x0d},
++ {0x06, 0x00, 0x0e},
++ {0x06, 0x00, 0x0f},
++ {0x06, 0x10, 0x10},
++ {0x06, 0x02, 0x11},
++ {0x06, 0x00, 0x12},
++ {0x06, 0x04, 0x13},
++ {0x06, 0x02, 0x14},
++ {0x06, 0x8a, 0x51},
++ {0x06, 0x40, 0x52},
++ {0x06, 0xb6, 0x53},
++ {0x06, 0x3d, 0x54},
++ {0x06, 0x60, 0x57},
++ {0x06, 0x20, 0x58},
++ {0x06, 0x15, 0x59},
++ {0x06, 0x05, 0x5a},
++
++ {0x05, 0x01, 0xc0},
++ {0x05, 0x10, 0xcb},
++ {0x05, 0x80, 0xc1},
+ /* */
+- /* 2053 */ {0x5, 0x0, 0xc2},
++ {0x05, 0x0, 0xc2},
+ /* 4 was 0 */
+- /* 2056 */ {0x5, 0x00, 0xca},
+- /* 2059 */ {0x5, 0x80, 0xc1},
++ {0x05, 0x00, 0xca},
++ {0x05, 0x80, 0xc1},
+ /* */
+- /* 2062 */ {0x5, 0x04, 0xc2},
+- /* 2065 */ {0x5, 0x00, 0xca},
+- /* 2068 */ {0x5, 0x0, 0xc1},
++ {0x05, 0x04, 0xc2},
++ {0x05, 0x00, 0xca},
++ {0x05, 0x0, 0xc1},
+ /* */
+- /* 2071 */ {0x5, 0x00, 0xc2},
+- /* 2074 */ {0x5, 0x00, 0xca},
+- /* 2077 */ {0x5, 0x40, 0xc1},
++ {0x05, 0x00, 0xc2},
++ {0x05, 0x00, 0xca},
++ {0x05, 0x40, 0xc1},
+ /* */
+- /* 2080 */ {0x5, 0x17, 0xc2},
+- /* 2083 */ {0x5, 0x00, 0xca},
+- /* 2086 */ {0x5, 0x80, 0xc1},
++ {0x05, 0x17, 0xc2},
++ {0x05, 0x00, 0xca},
++ {0x05, 0x80, 0xc1},
+ /* */
+- /* 2089 */ {0x5, 0x06, 0xc2},
+- /* 2092 */ {0x5, 0x00, 0xca},
+- /* 2095 */ {0x5, 0x80, 0xc1},
++ {0x05, 0x06, 0xc2},
++ {0x05, 0x00, 0xca},
++ {0x05, 0x80, 0xc1},
+ /* */
+- /* 2098 */ {0x5, 0x04, 0xc2},
+- /* 2101 */ {0x5, 0x00, 0xca},
++ {0x05, 0x04, 0xc2},
++ {0x05, 0x00, 0xca},
+
+- /* 2104 */ {0x3, 0x4c, 0x3},
+- /* 2107 */ {0x3, 0x18, 0x1},
++ {0x03, 0x4c, 0x3},
++ {0x03, 0x18, 0x1},
+
+- /* 2110 */ {0x6, 0x70, 0x51},
+- /* 2113 */ {0x6, 0xbe, 0x53},
+- /* 2116 */ {0x6, 0x71, 0x57},
+- /* 2119 */ {0x6, 0x20, 0x58},
+- /* 2122 */ {0x6, 0x05, 0x59},
+- /* 2125 */ {0x6, 0x15, 0x5a},
++ {0x06, 0x70, 0x51},
++ {0x06, 0xbe, 0x53},
++ {0x06, 0x71, 0x57},
++ {0x06, 0x20, 0x58},
++ {0x06, 0x05, 0x59},
++ {0x06, 0x15, 0x5a},
+
+- /* 2128 */ {0x4, 0x00, 0x08},
++ {0x04, 0x00, 0x08},
+ /* Compress = OFF (0x1 to turn on) */
+- /* 2131 */ {0x4, 0x12, 0x09},
+- /* 2134 */ {0x4, 0x21, 0x0a},
+- /* 2137 */ {0x4, 0x10, 0x0b},
+- /* 2140 */ {0x4, 0x21, 0x0c},
+- /* 2143 */ {0x4, 0x05, 0x00},
++ {0x04, 0x12, 0x09},
++ {0x04, 0x21, 0x0a},
++ {0x04, 0x10, 0x0b},
++ {0x04, 0x21, 0x0c},
++ {0x04, 0x05, 0x00},
+ /* was 5 (Image Type ? ) */
+- /* 2146 */ {0x4, 0x00, 0x01},
+-
+- /* 2149 */ {0x6, 0x3f, 0x01},
+-
+- /* 2152 */ {0x4, 0x00, 0x04},
+- /* 2155 */ {0x4, 0x00, 0x05},
+- /* 2158 */ {0x4, 0x40, 0x06},
+- /* 2161 */ {0x4, 0x40, 0x07},
+-
+- /* 2164 */ {0x6, 0x1c, 0x17},
+- /* 2167 */ {0x6, 0xe2, 0x19},
+- /* 2170 */ {0x6, 0x1c, 0x1b},
+- /* 2173 */ {0x6, 0xe2, 0x1d},
+- /* 2176 */ {0x6, 0xaa, 0x1f},
+- /* 2179 */ {0x6, 0x70, 0x20},
+-
+- /* 2182 */ {0x5, 0x01, 0x10},
+- /* 2185 */ {0x5, 0x00, 0x11},
+- /* 2188 */ {0x5, 0x01, 0x00},
+- /* 2191 */ {0x5, 0x05, 0x01},
+- /* 2194 */ {0x5, 0x00, 0xc1},
++ {0x04, 0x00, 0x01},
++
++ {0x06, 0x3f, 0x01},
++
++ {0x04, 0x00, 0x04},
++ {0x04, 0x00, 0x05},
++ {0x04, 0x40, 0x06},
++ {0x04, 0x40, 0x07},
++
++ {0x06, 0x1c, 0x17},
++ {0x06, 0xe2, 0x19},
++ {0x06, 0x1c, 0x1b},
++ {0x06, 0xe2, 0x1d},
++ {0x06, 0xaa, 0x1f},
++ {0x06, 0x70, 0x20},
++
++ {0x05, 0x01, 0x10},
++ {0x05, 0x00, 0x11},
++ {0x05, 0x01, 0x00},
++ {0x05, 0x05, 0x01},
++ {0x05, 0x00, 0xc1},
+ /* */
+- /* 2197 */ {0x5, 0x00, 0xc2},
+- /* 2200 */ {0x5, 0x00, 0xca},
++ {0x05, 0x00, 0xc2},
++ {0x05, 0x00, 0xca},
+
+- /* 2203 */ {0x6, 0x70, 0x51},
+- /* 2206 */ {0x6, 0xbe, 0x53},
++ {0x06, 0x70, 0x51},
++ {0x06, 0xbe, 0x53},
+ {}
+ };
+
+ /*
+- Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
++ * Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
+ * SPCA505b chip based cameras initialization data
+- *
+ */
+ /* jfm */
+ #define initial_brightness 0x7f /* 0x0(white)-0xff(black) */
+@@ -332,7 +333,7 @@ static const __u16 spca505_open_data_ccd[][3] = {
+ /*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+-static const __u16 spca505b_init_data[][3] = {
++static const u8 spca505b_init_data[][3] = {
+ /* start */
+ {0x02, 0x00, 0x00}, /* init */
+ {0x02, 0x00, 0x01},
+@@ -396,7 +397,7 @@ static const __u16 spca505b_init_data[][3] = {
+ /*
+ * Data to initialize the camera using the internal CCD
+ */
+-static const __u16 spca505b_open_data_ccd[][3] = {
++static const u8 spca505b_open_data_ccd[][3] = {
+
+ /* {0x02,0x00,0x00}, */
+ {0x03, 0x04, 0x01}, /* rst */
+@@ -426,7 +427,7 @@ static const __u16 spca505b_open_data_ccd[][3] = {
+ {0x05, 0x00, 0x12},
+ {0x05, 0x6f, 0x00},
+ {0x05, initial_brightness >> 6, 0x00},
+- {0x05, initial_brightness << 2, 0x01},
++ {0x05, (initial_brightness << 2) & 0xff, 0x01},
+ {0x05, 0x00, 0x02},
+ {0x05, 0x01, 0x03},
+ {0x05, 0x00, 0x04},
+@@ -436,7 +437,7 @@ static const __u16 spca505b_open_data_ccd[][3] = {
+ {0x05, 0xa0, 0x08},
+ {0x05, 0x00, 0x12},
+ {0x05, 0x02, 0x0f},
+- {0x05, 128, 0x14}, /* max exposure off (0=on) */
++ {0x05, 0x80, 0x14}, /* max exposure off (0=on) */
+ {0x05, 0x01, 0xb0},
+ {0x05, 0x01, 0xbf},
+ {0x03, 0x02, 0x06},
+@@ -560,26 +561,26 @@ static const __u16 spca505b_open_data_ccd[][3] = {
+ {0x06, 0x32, 0x20},
+
+ {0x05, initial_brightness >> 6, 0x00},
+- {0x05, initial_brightness << 2, 0x01},
++ {0x05, (initial_brightness << 2) & 0xff, 0x01},
+ {0x05, 0x06, 0xc1},
+ {0x05, 0x58, 0xc2},
+- {0x05, 0x0, 0xca},
+- {0x05, 0x0, 0x11},
++ {0x05, 0x00, 0xca},
++ {0x05, 0x00, 0x11},
+ {}
+ };
+
+ static int reg_write(struct usb_device *dev,
+- __u16 reg, __u16 index, __u16 value)
++ u16 req, u16 index, u16 value)
+ {
+ int ret;
+
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+- reg,
++ req,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+- PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
+- reg, index, value, ret);
++ PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
++ req, index, value, ret);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+ return ret;
+@@ -587,42 +588,34 @@ static int reg_write(struct usb_device *dev,
+
+ /* returns: negative is error, pos or zero is data */
+ static int reg_read(struct gspca_dev *gspca_dev,
+- __u16 reg, /* bRequest */
+- __u16 index, /* wIndex */
+- __u16 length) /* wLength (1 or 2 only) */
++ u16 req, /* bRequest */
++ u16 index) /* wIndex */
+ {
+ int ret;
+
+- gspca_dev->usb_buf[1] = 0;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+- reg,
++ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+- (__u16) 0, /* value */
+- (__u16) index,
+- gspca_dev->usb_buf, length,
++ 0, /* value */
++ index,
++ gspca_dev->usb_buf, 2,
+ 500); /* timeout */
+- if (ret < 0) {
+- PDEBUG(D_ERR, "reg_read err %d", ret);
+- return -1;
+- }
++ if (ret < 0)
++ return ret;
+ return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+ }
+
+ static int write_vector(struct gspca_dev *gspca_dev,
+- const __u16 data[][3])
++ const u8 data[][3])
+ {
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+- while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
++ while (data[i][0] != 0) {
+ ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+- if (ret < 0) {
+- PDEBUG(D_ERR,
+- "Register write failed for 0x%x,0x%x,0x%x",
+- data[i][0], data[i][1], data[i][2]);
++ if (ret < 0)
+ return ret;
+- }
+ i++;
+ }
+ return 0;
+@@ -636,14 +629,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ sd->subtype = id->driver_info;
+ if (sd->subtype != IntelPCCameraPro)
+- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
++ cam->nmodes = ARRAY_SIZE(vga_mode);
+ else /* no 640x480 for IntelPCCameraPro */
+- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0] - 1;
+- sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
++ cam->nmodes = ARRAY_SIZE(vga_mode) - 1;
++ sd->brightness = BRIGHTNESS_DEF;
+
+ if (sd->subtype == Nxultra) {
+ if (write_vector(gspca_dev, spca505b_init_data))
+@@ -658,81 +650,71 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ /* this function is called at probe and resume time */
+ static int sd_init(struct gspca_dev *gspca_dev)
+ {
++ return 0;
++}
++
++static void setbrightness(struct gspca_dev *gspca_dev)
++{
+ struct sd *sd = (struct sd *) gspca_dev;
+- int ret;
++ u8 brightness = sd->brightness;
++
++ reg_write(gspca_dev->dev, 0x05, 0x00, (255 - brightness) >> 6);
++ reg_write(gspca_dev->dev, 0x05, 0x01, (255 - brightness) << 2);
++}
++
++static int sd_start(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++ struct usb_device *dev = gspca_dev->dev;
++ int ret, mode;
++ static u8 mode_tb[][3] = {
++ /* r00 r06 r07 */
++ {0x00, 0x10, 0x10}, /* 640x480 */
++ {0x01, 0x1a, 0x1a}, /* 352x288 */
++ {0x02, 0x1c, 0x1d}, /* 320x240 */
++ {0x04, 0x34, 0x34}, /* 176x144 */
++ {0x05, 0x40, 0x40} /* 160x120 */
++ };
+
+- PDEBUG(D_STREAM, "Initializing SPCA505");
+ if (sd->subtype == Nxultra)
+ write_vector(gspca_dev, spca505b_open_data_ccd);
+ else
+ write_vector(gspca_dev, spca505_open_data_ccd);
+- ret = reg_read(gspca_dev, 6, 0x16, 2);
++ ret = reg_read(gspca_dev, 0x06, 0x16);
+
+ if (ret < 0) {
+- PDEBUG(D_ERR|D_STREAM,
+- "register read failed for after vector read err = %d",
++ PDEBUG(D_ERR|D_CONF,
++ "register read failed err: %d",
+ ret);
+- return -EIO;
++ return ret;
+ }
+- PDEBUG(D_STREAM,
+- "After vector read returns : 0x%x should be 0x0101",
+- ret & 0xffff);
+-
+- ret = reg_write(gspca_dev->dev, 6, 0x16, 0x0a);
+- if (ret < 0) {
+- PDEBUG(D_ERR, "register write failed for (6,0xa,0x16) err=%d",
+- ret);
+- return -EIO;
++ if (ret != 0x0101) {
++ PDEBUG(D_ERR|D_CONF,
++ "After vector read returns 0x%04x should be 0x0101",
++ ret);
+ }
+- reg_write(gspca_dev->dev, 5, 0xc2, 18);
+- return 0;
+-}
+
+-static int sd_start(struct gspca_dev *gspca_dev)
+-{
+- struct usb_device *dev = gspca_dev->dev;
+- int ret;
++ ret = reg_write(gspca_dev->dev, 0x06, 0x16, 0x0a);
++ if (ret < 0)
++ return ret;
++ reg_write(gspca_dev->dev, 0x05, 0xc2, 0x12);
+
+ /* necessary because without it we can see stream
+ * only once after loading module */
+ /* stopping usb registers Tomasz change */
+- reg_write(dev, 0x02, 0x0, 0x0);
+- switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+- case 0:
+- reg_write(dev, 0x04, 0x00, 0x00);
+- reg_write(dev, 0x04, 0x06, 0x10);
+- reg_write(dev, 0x04, 0x07, 0x10);
+- break;
+- case 1:
+- reg_write(dev, 0x04, 0x00, 0x01);
+- reg_write(dev, 0x04, 0x06, 0x1a);
+- reg_write(dev, 0x04, 0x07, 0x1a);
+- break;
+- case 2:
+- reg_write(dev, 0x04, 0x00, 0x02);
+- reg_write(dev, 0x04, 0x06, 0x1c);
+- reg_write(dev, 0x04, 0x07, 0x1d);
+- break;
+- case 4:
+- reg_write(dev, 0x04, 0x00, 0x04);
+- reg_write(dev, 0x04, 0x06, 0x34);
+- reg_write(dev, 0x04, 0x07, 0x34);
+- break;
+- default:
+-/* case 5: */
+- reg_write(dev, 0x04, 0x00, 0x05);
+- reg_write(dev, 0x04, 0x06, 0x40);
+- reg_write(dev, 0x04, 0x07, 0x40);
+- break;
+- }
+-/* Enable ISO packet machine - should we do this here or in ISOC init ? */
++ reg_write(dev, 0x02, 0x00, 0x00);
++
++ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
++ reg_write(dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]);
++ reg_write(dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]);
++ reg_write(dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]);
++
+ ret = reg_write(dev, SPCA50X_REG_USB,
+ SPCA50X_USB_CTRL,
+ SPCA50X_CUSB_ENABLE);
+
+-/* reg_write(dev, 0x5, 0x0, 0x0); */
+-/* reg_write(dev, 0x5, 0x0, 0x1); */
+-/* reg_write(dev, 0x5, 0x11, 0x2); */
++ setbrightness(gspca_dev);
++
+ return ret;
+ }
+
+@@ -750,15 +732,15 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
+
+ /* This maybe reset or power control */
+ reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
+- reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
+- reg_write(gspca_dev->dev, 0x03, 0x00, 0x1);
+- reg_write(gspca_dev->dev, 0x05, 0x10, 0x1);
+- reg_write(gspca_dev->dev, 0x05, 0x11, 0xf);
++ reg_write(gspca_dev->dev, 0x03, 0x01, 0x00);
++ reg_write(gspca_dev->dev, 0x03, 0x00, 0x01);
++ reg_write(gspca_dev->dev, 0x05, 0x10, 0x01);
++ reg_write(gspca_dev->dev, 0x05, 0x11, 0x0f);
+ }
+
+ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+- __u8 *data, /* isoc packet */
++ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+ {
+ switch (data[0]) {
+@@ -771,7 +753,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ data, len);
+ break;
+ case 0xff: /* drop */
+-/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ break;
+ default:
+ data += 1;
+@@ -782,24 +763,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ }
+ }
+
+-static void setbrightness(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- __u8 brightness = sd->brightness;
+- reg_write(gspca_dev->dev, 5, 0x00, (255 - brightness) >> 6);
+- reg_write(gspca_dev->dev, 5, 0x01, (255 - brightness) << 2);
+-
+-}
+-static void getbrightness(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- sd->brightness = 255
+- - ((reg_read(gspca_dev, 5, 0x01, 1) >> 2)
+- + (reg_read(gspca_dev, 5, 0x0, 1) << 6));
+-}
+-
+ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -814,7 +777,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+ }
+@@ -863,8 +825,11 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
+index 96e2512..3a0c893 100644
+--- a/drivers/media/video/gspca/spca506.c
++++ b/drivers/media/video/gspca/spca506.c
+@@ -193,24 +193,6 @@ static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur,
+ }
+ }
+
+-static int spca506_ReadI2c(struct gspca_dev *gspca_dev, __u16 reg)
+-{
+- int retry = 60;
+-
+- reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+- reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+- reg_w(gspca_dev->dev, 0x07, 0x01, 0x0002);
+- while (--retry) {
+- reg_r(gspca_dev, 0x07, 0x0003, 2);
+- if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00)
+- break;
+- }
+- if (retry == 0)
+- return -1;
+- reg_r(gspca_dev, 0x07, 0x0000, 1);
+- return gspca_dev->usb_buf[0];
+-}
+-
+ static void spca506_SetNormeInput(struct gspca_dev *gspca_dev,
+ __u16 norme,
+ __u16 channel)
+@@ -303,7 +285,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+@@ -596,13 +577,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+ }
+
+-static void getbrightness(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- sd->brightness = spca506_ReadI2c(gspca_dev, SAA7113_bright);
+-}
+-
+ static void setcontrast(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -612,13 +586,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+ }
+
+-static void getcontrast(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- sd->contrast = spca506_ReadI2c(gspca_dev, SAA7113_contrast);
+-}
+-
+ static void setcolors(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -628,13 +595,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+ }
+
+-static void getcolors(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- sd->colors = spca506_ReadI2c(gspca_dev, SAA7113_saturation);
+-}
+-
+ static void sethue(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -644,13 +604,6 @@ static void sethue(struct gspca_dev *gspca_dev)
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+ }
+
+-static void gethue(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- sd->hue = spca506_ReadI2c(gspca_dev, SAA7113_hue);
+-}
+-
+ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -665,7 +618,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+ }
+@@ -684,7 +636,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+ }
+@@ -703,7 +654,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+ }
+@@ -722,7 +672,6 @@ static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- gethue(gspca_dev);
+ *val = sd->hue;
+ return 0;
+ }
+@@ -772,8 +721,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
+index be5d740..adacf84 100644
+--- a/drivers/media/video/gspca/spca508.c
++++ b/drivers/media/video/gspca/spca508.c
+@@ -101,8 +101,7 @@ static const struct v4l2_pix_format sif_mode[] = {
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+-static const __u16 spca508_init_data[][3] =
+-#define IGN(x) /* nothing */
++static const u16 spca508_init_data[][2] =
+ {
+ /* line URB value, index */
+ /* 44274 1804 */ {0x0000, 0x870b},
+@@ -589,11 +588,10 @@ static const __u16 spca508_init_data[][3] =
+ {}
+ };
+
+-
+ /*
+ * Initialization data for Intel EasyPC Camera CS110
+ */
+-static const __u16 spca508cs110_init_data[][3] = {
++static const u16 spca508cs110_init_data[][2] = {
+ {0x0000, 0x870b}, /* Reset CTL3 */
+ {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+ {0x0000, 0x8111}, /* Normal operation on reset */
+@@ -677,7 +675,7 @@ static const __u16 spca508cs110_init_data[][3] = {
+ {}
+ };
+
+-static const __u16 spca508_sightcam_init_data[][3] = {
++static const u16 spca508_sightcam_init_data[][2] = {
+ /* This line seems to setup the frame/canvas */
+ /*368 */ {0x000f, 0x8402},
+
+@@ -760,7 +758,7 @@ static const __u16 spca508_sightcam_init_data[][3] = {
+ {}
+ };
+
+-static const __u16 spca508_sightcam2_init_data[][3] = {
++static const u16 spca508_sightcam2_init_data[][2] = {
+ /* 35 */ {0x0020, 0x8112},
+
+ /* 36 */ {0x000f, 0x8402},
+@@ -1107,7 +1105,7 @@ static const __u16 spca508_sightcam2_init_data[][3] = {
+ /*
+ * Initialization data for Creative Webcam Vista
+ */
+-static const __u16 spca508_vista_init_data[][3] = {
++static const u16 spca508_vista_init_data[][2] = {
+ {0x0008, 0x8200}, /* Clear register */
+ {0x0000, 0x870b}, /* Reset CTL3 */
+ {0x0020, 0x8112}, /* Video Drop packet enable */
+@@ -1309,18 +1307,18 @@ static const __u16 spca508_vista_init_data[][3] = {
+
+ {0x0050, 0x8703},
+ {0x0002, 0x8704}, /* External input CKIx1 */
+- {0x0001, 0x870C}, /* Select CKOx2 output */
+- {0x009A, 0x8600}, /* Line memory Read Counter (L) */
++ {0x0001, 0x870c}, /* Select CKOx2 output */
++ {0x009a, 0x8600}, /* Line memory Read Counter (L) */
+ {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+ {0x0023, 0x8601},
+ {0x0010, 0x8602},
+- {0x000A, 0x8603},
++ {0x000a, 0x8603},
+ {0x009A, 0x8600},
+- {0x0001, 0x865B}, /* 1 Horizontal Offset for Valid Pixel(L) */
+- {0x0003, 0x865C}, /* Vertical offset for valid lines (L) */
+- {0x0058, 0x865D}, /* Horizontal valid pixels window (L) */
+- {0x0048, 0x865E}, /* Vertical valid lines window (L) */
+- {0x0000, 0x865F},
++ {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
++ {0x0003, 0x865c}, /* Vertical offset for valid lines (L) */
++ {0x0058, 0x865d}, /* Horizontal valid pixels window (L) */
++ {0x0048, 0x865e}, /* Vertical valid lines window (L) */
++ {0x0000, 0x865f},
+
+ {0x0006, 0x8660},
+ /* Enable nibble data input, select nibble input order */
+@@ -1328,63 +1326,63 @@ static const __u16 spca508_vista_init_data[][3] = {
+ {0x0013, 0x8608}, /* A11 Coeficients for color correction */
+ {0x0028, 0x8609},
+ /* Note: these values are confirmed at the end of array */
+- {0x0005, 0x860A}, /* ... */
+- {0x0025, 0x860B},
+- {0x00E1, 0x860C},
+- {0x00FA, 0x860D},
+- {0x00F4, 0x860E},
+- {0x00E8, 0x860F},
++ {0x0005, 0x860a}, /* ... */
++ {0x0025, 0x860b},
++ {0x00e1, 0x860c},
++ {0x00fa, 0x860D},
++ {0x00f4, 0x860e},
++ {0x00e8, 0x860f},
+ {0x0025, 0x8610}, /* A33 Coef. */
+- {0x00FC, 0x8611}, /* White balance offset: R */
++ {0x00fc, 0x8611}, /* White balance offset: R */
+ {0x0001, 0x8612}, /* White balance offset: Gr */
+- {0x00FE, 0x8613}, /* White balance offset: B */
++ {0x00fe, 0x8613}, /* White balance offset: B */
+ {0x0000, 0x8614}, /* White balance offset: Gb */
+
+ {0x0064, 0x8651}, /* R gain for white balance (L) */
+ {0x0040, 0x8652}, /* Gr gain for white balance (L) */
+ {0x0066, 0x8653}, /* B gain for white balance (L) */
+ {0x0040, 0x8654}, /* Gb gain for white balance (L) */
+- {0x0001, 0x863F}, /* Enable fixed gamma correction */
++ {0x0001, 0x863f}, /* Enable fixed gamma correction */
+
+- {0x00A1, 0x8656}, /* Size - Window1: 256x256, Window2: 128x128 */
++ {0x00a1, 0x8656}, /* Size - Window1: 256x256, Window2: 128x128 */
+ /* UV division: UV no change, Enable New edge enhancement */
+ {0x0018, 0x8657}, /* Edge gain high threshold */
+ {0x0020, 0x8658}, /* Edge gain low threshold */
+ {0x000A, 0x8659}, /* Edge bandwidth high threshold */
+- {0x0005, 0x865A}, /* Edge bandwidth low threshold */
++ {0x0005, 0x865a}, /* Edge bandwidth low threshold */
+ {0x0064, 0x8607}, /* UV filter enable */
+
+ {0x0016, 0x8660},
+- {0x0000, 0x86B0}, /* Bad pixels compensation address */
+- {0x00DC, 0x86B1}, /* X coord for bad pixels compensation (L) */
+- {0x0000, 0x86B2},
+- {0x0009, 0x86B3}, /* Y coord for bad pixels compensation (L) */
+- {0x0000, 0x86B4},
+-
+- {0x0001, 0x86B0},
+- {0x00F5, 0x86B1},
+- {0x0000, 0x86B2},
+- {0x00C6, 0x86B3},
+- {0x0000, 0x86B4},
+-
+- {0x0002, 0x86B0},
+- {0x001C, 0x86B1},
+- {0x0001, 0x86B2},
+- {0x00D7, 0x86B3},
+- {0x0000, 0x86B4},
+-
+- {0x0003, 0x86B0},
+- {0x001C, 0x86B1},
+- {0x0001, 0x86B2},
+- {0x00D8, 0x86B3},
+- {0x0000, 0x86B4},
+-
+- {0x0004, 0x86B0},
+- {0x001D, 0x86B1},
+- {0x0001, 0x86B2},
+- {0x00D8, 0x86B3},
+- {0x0000, 0x86B4},
+- {0x001E, 0x8660},
++ {0x0000, 0x86b0}, /* Bad pixels compensation address */
++ {0x00dc, 0x86b1}, /* X coord for bad pixels compensation (L) */
++ {0x0000, 0x86b2},
++ {0x0009, 0x86b3}, /* Y coord for bad pixels compensation (L) */
++ {0x0000, 0x86b4},
++
++ {0x0001, 0x86b0},
++ {0x00f5, 0x86b1},
++ {0x0000, 0x86b2},
++ {0x00c6, 0x86b3},
++ {0x0000, 0x86b4},
++
++ {0x0002, 0x86b0},
++ {0x001c, 0x86b1},
++ {0x0001, 0x86b2},
++ {0x00d7, 0x86b3},
++ {0x0000, 0x86b4},
++
++ {0x0003, 0x86b0},
++ {0x001c, 0x86b1},
++ {0x0001, 0x86b2},
++ {0x00d8, 0x86b3},
++ {0x0000, 0x86b4},
++
++ {0x0004, 0x86b0},
++ {0x001d, 0x86b1},
++ {0x0001, 0x86b2},
++ {0x00d8, 0x86b3},
++ {0x0000, 0x86b4},
++ {0x001e, 0x8660},
+
+ /* READ { 0, 0x0000, 0x8608 } ->
+ 0000: 13 */
+@@ -1449,7 +1447,7 @@ static int reg_read(struct gspca_dev *gspca_dev,
+ }
+
+ static int write_vector(struct gspca_dev *gspca_dev,
+- const __u16 data[][3])
++ const u16 data[][2])
+ {
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+@@ -1487,7 +1485,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1);
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+
+@@ -1593,13 +1590,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ reg_write(gspca_dev->dev, 0x8654, brightness);
+ }
+
+-static void getbrightness(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- sd->brightness = reg_read(gspca_dev, 0x8651);
+-}
+-
+ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -1614,7 +1604,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+ }
+@@ -1666,8 +1655,11 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
+index 3c92880..c99c5e3 100644
+--- a/drivers/media/video/gspca/spca561.c
++++ b/drivers/media/video/gspca/spca561.c
+@@ -141,38 +141,38 @@ static const struct v4l2_pix_format sif_072a_mode[] = {
+ #define SPCA561_OFFSET_WIN1GBAVE 14
+ #define SPCA561_OFFSET_FREQ 15
+ #define SPCA561_OFFSET_VSYNC 16
+-#define SPCA561_OFFSET_DATA 1
+ #define SPCA561_INDEX_I2C_BASE 0x8800
+ #define SPCA561_SNAPBIT 0x20
+ #define SPCA561_SNAPCTRL 0x40
+
+-static const __u16 rev72a_init_data1[][2] = {
++static const u16 rev72a_reset[][2] = {
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0001, 0x8114}, /* Software GPIO output data */
+ {0x0000, 0x8112}, /* Some kind of reset */
++ {}
++};
++static const __u16 rev72a_init_data1[][2] = {
+ {0x0003, 0x8701}, /* PCLK clock delay adjustment */
+ {0x0001, 0x8703}, /* HSYNC from cmos inverted */
+ {0x0011, 0x8118}, /* Enable and conf sensor */
+ {0x0001, 0x8118}, /* Conf sensor */
+ {0x0092, 0x8804}, /* I know nothing about these */
+ {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
+- {0x000d, 0x8805}, /* sensor default setting */
+ {}
+ };
+-static const __u16 rev72a_init_sensor1[][2] = {
+- /* ms-win values */
+- {0x0001, 0x0018}, /* 0x01 <- 0x0d */
+- {0x0002, 0x0065}, /* 0x02 <- 0x18 */
+- {0x0004, 0x0121}, /* 0x04 <- 0x0165 */
+- {0x0005, 0x00aa}, /* 0x05 <- 0x21 */
+- {0x0007, 0x0004}, /* 0x07 <- 0xaa */
+- {0x0020, 0x1502}, /* 0x20 <- 0x1504 */
+- {0x0039, 0x0010}, /* 0x39 <- 0x02 */
+- {0x0035, 0x0049}, /* 0x35 <- 0x10 */
+- {0x0009, 0x100b}, /* 0x09 <- 0x1049 */
+- {0x0028, 0x000f}, /* 0x28 <- 0x0b */
+- {0x003b, 0x003c}, /* 0x3b <- 0x0f */
+- {0x003c, 0x0000}, /* 0x3c <- 0x00 */
++static const u16 rev72a_init_sensor1[][2] = {
++ {0x0001, 0x000d},
++ {0x0002, 0x0018},
++ {0x0004, 0x0165},
++ {0x0005, 0x0021},
++ {0x0007, 0x00aa},
++ {0x0020, 0x1504},
++ {0x0039, 0x0002},
++ {0x0035, 0x0010},
++ {0x0009, 0x1049},
++ {0x0028, 0x000b},
++ {0x003b, 0x000f},
++ {0x003c, 0x0000},
+ {}
+ };
+ static const __u16 rev72a_init_data2[][2] = {
+@@ -190,15 +190,10 @@ static const __u16 rev72a_init_data2[][2] = {
+ {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
+ {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
+ {0x0001, 0x8200}, /* OprMode to be executed by hardware */
+- {0x0007, 0x8201}, /* Output address for r/w serial EEPROM */
+- {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
+- {0x0001, 0x8200}, /* OprMode to be executed by hardware */
+- {0x0010, 0x8660}, /* Compensation memory stuff */
+- {0x0018, 0x8660}, /* Compensation memory stuff */
+-
+- {0x0004, 0x8611}, /* R offset for white balance */
+- {0x0004, 0x8612}, /* Gr offset for white balance */
+- {0x0007, 0x8613}, /* B offset for white balance */
++/* from ms-win */
++ {0x0000, 0x8611}, /* R offset for white balance */
++ {0x00fd, 0x8612}, /* Gr offset for white balance */
++ {0x0003, 0x8613}, /* B offset for white balance */
+ {0x0000, 0x8614}, /* Gb offset for white balance */
+ /* from ms-win */
+ {0x0035, 0x8651}, /* R gain for white balance */
+@@ -206,8 +201,8 @@ static const __u16 rev72a_init_data2[][2] = {
+ {0x005f, 0x8653}, /* B gain for white balance */
+ {0x0040, 0x8654}, /* Gb gain for white balance */
+ {0x0002, 0x8502}, /* Maximum average bit rate stuff */
+-
+ {0x0011, 0x8802},
++
+ {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
+ {0x0081, 0x8702}, /* Master clock output enable */
+
+@@ -218,104 +213,15 @@ static const __u16 rev72a_init_data2[][2] = {
+ {0x0003, 0x865c}, /* Vertical offset for valid lines */
+ {}
+ };
+-static const __u16 rev72a_init_sensor2[][2] = {
+- /* ms-win values */
+- {0x0003, 0x0121}, /* 0x03 <- 0x01 0x21 //289 */
+- {0x0004, 0x0165}, /* 0x04 <- 0x01 0x65 //357 */
+- {0x0005, 0x002f}, /* 0x05 <- 0x2f */
+- {0x0006, 0x0000}, /* 0x06 <- 0 */
+- {0x000a, 0x0002}, /* 0x0a <- 2 */
+- {0x0009, 0x1061}, /* 0x09 <- 0x1061 */
+- {0x0035, 0x0014}, /* 0x35 <- 0x14 */
+- {}
+-};
+-static const __u16 rev72a_init_data3[][2] = {
+- {0x0030, 0x8112}, /* ISO and drop packet enable */
+-/*fixme: should stop here*/
+- {0x0000, 0x8112}, /* Some kind of reset ???? */
+- {0x0009, 0x8118}, /* Enable sensor and set standby */
+- {0x0000, 0x8114}, /* Software GPIO output data */
+- {0x0000, 0x8114}, /* Software GPIO output data */
+- {0x0001, 0x8114}, /* Software GPIO output data */
+- {0x0000, 0x8112}, /* Some kind of reset ??? */
+- {0x0003, 0x8701},
+- {0x0001, 0x8703},
+- {0x0011, 0x8118},
+- {0x0001, 0x8118},
+- /***************/
+- {0x0092, 0x8804},
+- {0x0010, 0x8802},
+- {0x000d, 0x8805},
+- {0x0001, 0x8801},
+- {0x0000, 0x8800},
+- {0x0018, 0x8805},
+- {0x0002, 0x8801},
+- {0x0000, 0x8800},
+- {0x0065, 0x8805},
+- {0x0004, 0x8801},
+- {0x0001, 0x8800},
+- {0x0021, 0x8805},
+- {0x0005, 0x8801},
+- {0x0000, 0x8800},
+- {0x00aa, 0x8805},
+- {0x0007, 0x8801}, /* mode 0xaa */
+- {0x0000, 0x8800},
+- {0x0004, 0x8805},
+- {0x0020, 0x8801},
+- {0x0015, 0x8800}, /* mode 0x0415 */
+- {0x0002, 0x8805},
+- {0x0039, 0x8801},
+- {0x0000, 0x8800},
+- {0x0010, 0x8805},
+- {0x0035, 0x8801},
+- {0x0000, 0x8800},
+- {0x0049, 0x8805},
+- {0x0009, 0x8801},
+- {0x0010, 0x8800},
+- {0x000b, 0x8805},
+- {0x0028, 0x8801},
+- {0x0000, 0x8800},
+- {0x000f, 0x8805},
+- {0x003b, 0x8801},
+- {0x0000, 0x8800},
+- {0x0000, 0x8805},
+- {0x003c, 0x8801},
+- {0x0000, 0x8800},
+- {0x0002, 0x8502},
+- {0x0039, 0x8801},
+- {0x0000, 0x8805},
+- {0x0000, 0x8800},
+-
+- {0x0087, 0x8700}, /* overwrite by start */
+- {0x0081, 0x8702},
+- {0x0000, 0x8500},
+-/* {0x0010, 0x8500}, -- Previous line was this */
+- {0x0002, 0x865b},
+- {0x0003, 0x865c},
+- /***************/
+- {0x0003, 0x8801}, /* 0x121-> 289 */
+- {0x0021, 0x8805},
+- {0x0001, 0x8800},
+- {0x0004, 0x8801}, /* 0x165 -> 357 */
+- {0x0065, 0x8805},
+- {0x0001, 0x8800},
+- {0x0005, 0x8801}, /* 0x2f //blanking control colonne */
+- {0x002f, 0x8805},
+- {0x0000, 0x8800},
+- {0x0006, 0x8801}, /* 0x00 //blanking mode row */
+- {0x0000, 0x8805},
+- {0x0000, 0x8800},
+- {0x000a, 0x8801}, /* 0x01 //0x02 */
+- {0x0001, 0x8805},
+- {0x0000, 0x8800},
+- {0x0009, 0x8801}, /* 0x1061 - setexposure times && pixel clock
++static const u16 rev72a_init_sensor2[][2] = {
++ {0x0003, 0x0121},
++ {0x0004, 0x0165},
++ {0x0005, 0x002f}, /* blanking control column */
++ {0x0006, 0x0000}, /* blanking mode row*/
++ {0x000a, 0x0002},
++ {0x0009, 0x1061}, /* setexposure times && pixel clock
+ * 0001 0 | 000 0110 0001 */
+- {0x0061, 0x8805}, /* 61 31 */
+- {0x0008, 0x8800}, /* 08 */
+- {0x0035, 0x8801}, /* 0x14 - set gain general */
+- {0x001f, 0x8805}, /* 0x14 */
+- {0x0000, 0x8800},
+- {0x000e, 0x8112}, /* white balance - was 30 */
++ {0x0035, 0x0014},
+ {}
+ };
+
+@@ -460,6 +366,7 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
+ reg_r(gspca_dev, 0x8803, 1);
+ if (!gspca_dev->usb_buf[0])
+ return;
++ msleep(10);
+ } while (--retry);
+ }
+
+@@ -479,6 +386,7 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
+ reg_r(gspca_dev, 0x8805, 1);
+ return ((int) value << 8) | gspca_dev->usb_buf[0];
+ }
++ msleep(10);
+ } while (--retry);
+ return -1;
+ }
+@@ -541,7 +449,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ }
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
+
+ sd->chip_revision = id->driver_info;
+@@ -572,11 +479,13 @@ static int sd_init_12a(struct gspca_dev *gspca_dev)
+ static int sd_init_72a(struct gspca_dev *gspca_dev)
+ {
+ PDEBUG(D_STREAM, "Chip revision: 072a");
++ write_vector(gspca_dev, rev72a_reset);
++ msleep(200);
+ write_vector(gspca_dev, rev72a_init_data1);
+ write_sensor_72a(gspca_dev, rev72a_init_sensor1);
+ write_vector(gspca_dev, rev72a_init_data2);
+ write_sensor_72a(gspca_dev, rev72a_init_sensor2);
+- write_vector(gspca_dev, rev72a_init_data3);
++ reg_w_val(gspca_dev->dev, 0x8112, 0x30);
+ return 0;
+ }
+
+@@ -731,11 +640,18 @@ static int sd_start_72a(struct gspca_dev *gspca_dev)
+ int Clck;
+ int mode;
+
++ write_vector(gspca_dev, rev72a_reset);
++ msleep(200);
++ write_vector(gspca_dev, rev72a_init_data1);
++ write_sensor_72a(gspca_dev, rev72a_init_sensor1);
++
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (mode) {
+ default:
+-/* case 0:
+- case 1: */
++ case 0:
++ Clck = 0x27; /* ms-win 0x87 */
++ break;
++ case 1:
+ Clck = 0x25;
+ break;
+ case 2:
+@@ -745,13 +661,14 @@ static int sd_start_72a(struct gspca_dev *gspca_dev)
+ Clck = 0x21;
+ break;
+ }
+- reg_w_val(dev, 0x8500, mode); /* mode */
+ reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
+- reg_w_val(dev, 0x8112, 0x10 | 0x20);
++ reg_w_val(dev, 0x8702, 0x81);
++ reg_w_val(dev, 0x8500, mode); /* mode */
++ write_sensor_72a(gspca_dev, rev72a_init_sensor2);
+ setcontrast(gspca_dev);
+ /* setbrightness(gspca_dev); * fixme: bad values */
+- setwhite(gspca_dev);
+ setautogain(gspca_dev);
++ reg_w_val(dev, 0x8112, 0x10 | 0x20);
+ return 0;
+ }
+
+@@ -867,12 +784,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- switch (data[0]) { /* sequence number */
++ len--;
++ switch (*data++) { /* sequence number */
+ case 0: /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+- data += SPCA561_OFFSET_DATA;
+- len -= SPCA561_OFFSET_DATA;
+ if (data[1] & 0x10) {
+ /* compressed bayer */
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+@@ -893,8 +809,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ case 0xff: /* drop (empty mpackets) */
+ return;
+ }
+- data++;
+- len--;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ }
+
+@@ -1197,8 +1111,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c
+new file mode 100644
+index 0000000..04e3ae5
+--- /dev/null
++++ b/drivers/media/video/gspca/sq905.c
+@@ -0,0 +1,456 @@
++/*
++ * SQ905 subdriver
++ *
++ * Copyright (C) 2008, 2009 Adam Baker and Theodore Kilgore
++ *
++ * 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
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/*
++ * History and Acknowledgments
++ *
++ * The original Linux driver for SQ905 based cameras was written by
++ * Marcell Lengyel and furter developed by many other contributers
++ * and is available from http://sourceforge.net/projects/sqcam/
++ *
++ * This driver takes advantage of the reverse engineering work done for
++ * that driver and for libgphoto2 but shares no code with them.
++ *
++ * This driver has used as a base the finepix driver and other gspca
++ * based drivers and may still contain code fragments taken from those
++ * drivers.
++ */
++
++#define MODULE_NAME "sq905"
++
++#include <linux/workqueue.h>
++#include "gspca.h"
++
++MODULE_AUTHOR("Adam Baker <linux@baker-net.org.uk>, "
++ "Theodore Kilgore <kilgota@auburn.edu>");
++MODULE_DESCRIPTION("GSPCA/SQ905 USB Camera Driver");
++MODULE_LICENSE("GPL");
++
++/* Default timeouts, in ms */
++#define SQ905_CMD_TIMEOUT 500
++#define SQ905_DATA_TIMEOUT 1000
++
++/* Maximum transfer size to use. */
++#define SQ905_MAX_TRANSFER 0x8000
++#define FRAME_HEADER_LEN 64
++
++/* The known modes, or registers. These go in the "value" slot. */
++
++/* 00 is "none" obviously */
++
++#define SQ905_BULK_READ 0x03 /* precedes any bulk read */
++#define SQ905_COMMAND 0x06 /* precedes the command codes below */
++#define SQ905_PING 0x07 /* when reading an "idling" command */
++#define SQ905_READ_DONE 0xc0 /* ack bulk read completed */
++
++/* Any non-zero value in the bottom 2 bits of the 2nd byte of
++ * the ID appears to indicate the camera can do 640*480. If the
++ * LSB of that byte is set the image is just upside down, otherwise
++ * it is rotated 180 degrees. */
++#define SQ905_HIRES_MASK 0x00000300
++#define SQ905_ORIENTATION_MASK 0x00000100
++
++/* Some command codes. These go in the "index" slot. */
++
++#define SQ905_ID 0xf0 /* asks for model string */
++#define SQ905_CONFIG 0x20 /* gets photo alloc. table, not used here */
++#define SQ905_DATA 0x30 /* accesses photo data, not used here */
++#define SQ905_CLEAR 0xa0 /* clear everything */
++#define SQ905_CAPTURE_LOW 0x60 /* Starts capture at 160x120 */
++#define SQ905_CAPTURE_MED 0x61 /* Starts capture at 320x240 */
++#define SQ905_CAPTURE_HIGH 0x62 /* Starts capture at 640x480 (some cams only) */
++/* note that the capture command also controls the output dimensions */
++
++/* Structure to hold all of our device specific stuff */
++struct sd {
++ struct gspca_dev gspca_dev; /* !! must be the first item */
++
++ /*
++ * Driver stuff
++ */
++ struct work_struct work_struct;
++ struct workqueue_struct *work_thread;
++};
++
++static struct v4l2_pix_format sq905_mode[] = {
++ { 160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
++ .bytesperline = 160,
++ .sizeimage = 160 * 120,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 0},
++ { 320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
++ .bytesperline = 320,
++ .sizeimage = 320 * 240,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 0},
++ { 640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
++ .bytesperline = 640,
++ .sizeimage = 640 * 480,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 0}
++};
++
++/*
++ * Send a command to the camera.
++ */
++static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
++{
++ int ret;
++
++ gspca_dev->usb_buf[0] = '\0';
++ ret = usb_control_msg(gspca_dev->dev,
++ usb_sndctrlpipe(gspca_dev->dev, 0),
++ USB_REQ_SYNCH_FRAME, /* request */
++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ SQ905_COMMAND, index, gspca_dev->usb_buf, 1,
++ SQ905_CMD_TIMEOUT);
++ if (ret < 0) {
++ PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
++ __func__, ret);
++ return ret;
++ }
++
++ ret = usb_control_msg(gspca_dev->dev,
++ usb_sndctrlpipe(gspca_dev->dev, 0),
++ USB_REQ_SYNCH_FRAME, /* request */
++ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ SQ905_PING, 0, gspca_dev->usb_buf, 1,
++ SQ905_CMD_TIMEOUT);
++ if (ret < 0) {
++ PDEBUG(D_ERR, "%s: usb_control_msg failed 2 (%d)",
++ __func__, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++/*
++ * Acknowledge the end of a frame - see warning on sq905_command.
++ */
++static int sq905_ack_frame(struct gspca_dev *gspca_dev)
++{
++ int ret;
++
++ gspca_dev->usb_buf[0] = '\0';
++ ret = usb_control_msg(gspca_dev->dev,
++ usb_sndctrlpipe(gspca_dev->dev, 0),
++ USB_REQ_SYNCH_FRAME, /* request */
++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ SQ905_READ_DONE, 0, gspca_dev->usb_buf, 1,
++ SQ905_CMD_TIMEOUT);
++ if (ret < 0) {
++ PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++/*
++ * request and read a block of data - see warning on sq905_command.
++ */
++static int
++sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size)
++{
++ int ret;
++ int act_len;
++
++ gspca_dev->usb_buf[0] = '\0';
++ ret = usb_control_msg(gspca_dev->dev,
++ usb_sndctrlpipe(gspca_dev->dev, 0),
++ USB_REQ_SYNCH_FRAME, /* request */
++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ SQ905_BULK_READ, size, gspca_dev->usb_buf,
++ 1, SQ905_CMD_TIMEOUT);
++ if (ret < 0) {
++ PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret);
++ return ret;
++ }
++ ret = usb_bulk_msg(gspca_dev->dev,
++ usb_rcvbulkpipe(gspca_dev->dev, 0x81),
++ data, size, &act_len, SQ905_DATA_TIMEOUT);
++
++ /* successful, it returns 0, otherwise negative */
++ if (ret < 0 || act_len != size) {
++ PDEBUG(D_ERR, "bulk read fail (%d) len %d/%d",
++ ret, act_len, size);
++ return -EIO;
++ }
++ return 0;
++}
++
++/* This function is called as a workqueue function and runs whenever the camera
++ * is streaming data. Because it is a workqueue function it is allowed to sleep
++ * so we can use synchronous USB calls. To avoid possible collisions with other
++ * threads attempting to use the camera's USB interface we take the gspca
++ * usb_lock when performing USB operations. In practice the only thing we need
++ * to protect against is the usb_set_interface call that gspca makes during
++ * stream_off as the camera doesn't provide any controls that the user could try
++ * to change.
++ */
++static void sq905_dostream(struct work_struct *work)
++{
++ struct sd *dev = container_of(work, struct sd, work_struct);
++ struct gspca_dev *gspca_dev = &dev->gspca_dev;
++ struct gspca_frame *frame;
++ int bytes_left; /* bytes remaining in current frame. */
++ int data_len; /* size to use for the next read. */
++ int header_read; /* true if we have already read the frame header. */
++ int discarding; /* true if we failed to get space for frame. */
++ int packet_type;
++ int frame_sz;
++ int ret;
++ u8 *data;
++ u8 *buffer;
++
++ buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
++ mutex_lock(&gspca_dev->usb_lock);
++ if (!buffer) {
++ PDEBUG(D_ERR, "Couldn't allocate USB buffer");
++ goto quit_stream;
++ }
++
++ frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage
++ + FRAME_HEADER_LEN;
++
++ while (gspca_dev->present && gspca_dev->streaming) {
++ /* Need a short delay to ensure streaming flag was set by
++ * gspca and to make sure gspca can grab the mutex. */
++ mutex_unlock(&gspca_dev->usb_lock);
++ msleep(1);
++
++ /* request some data and then read it until we have
++ * a complete frame. */
++ bytes_left = frame_sz;
++ header_read = 0;
++ discarding = 0;
++
++ while (bytes_left > 0) {
++ data_len = bytes_left > SQ905_MAX_TRANSFER ?
++ SQ905_MAX_TRANSFER : bytes_left;
++ mutex_lock(&gspca_dev->usb_lock);
++ if (!gspca_dev->present)
++ goto quit_stream;
++ ret = sq905_read_data(gspca_dev, buffer, data_len);
++ if (ret < 0)
++ goto quit_stream;
++ mutex_unlock(&gspca_dev->usb_lock);
++ PDEBUG(D_STREAM,
++ "Got %d bytes out of %d for frame",
++ data_len, bytes_left);
++ bytes_left -= data_len;
++ data = buffer;
++ if (!header_read) {
++ packet_type = FIRST_PACKET;
++ /* The first 64 bytes of each frame are
++ * a header full of FF 00 bytes */
++ data += FRAME_HEADER_LEN;
++ data_len -= FRAME_HEADER_LEN;
++ header_read = 1;
++ } else if (bytes_left == 0) {
++ packet_type = LAST_PACKET;
++ } else {
++ packet_type = INTER_PACKET;
++ }
++ frame = gspca_get_i_frame(gspca_dev);
++ if (frame && !discarding) {
++ frame = gspca_frame_add(gspca_dev, packet_type,
++ frame, data, data_len);
++ /* If entire frame fits in one packet we still
++ need to add a LAST_PACKET */
++ if (packet_type == FIRST_PACKET &&
++ bytes_left == 0)
++ frame = gspca_frame_add(gspca_dev,
++ LAST_PACKET,
++ frame, data, 0);
++ } else {
++ discarding = 1;
++ }
++ }
++ /* acknowledge the frame */
++ mutex_lock(&gspca_dev->usb_lock);
++ if (!gspca_dev->present)
++ goto quit_stream;
++ ret = sq905_ack_frame(gspca_dev);
++ if (ret < 0)
++ goto quit_stream;
++ }
++quit_stream:
++ /* the usb_lock is already acquired */
++ if (gspca_dev->present)
++ sq905_command(gspca_dev, SQ905_CLEAR);
++ mutex_unlock(&gspca_dev->usb_lock);
++ kfree(buffer);
++}
++
++/* This function is called at probe time just before sd_init */
++static int sd_config(struct gspca_dev *gspca_dev,
++ const struct usb_device_id *id)
++{
++ struct cam *cam = &gspca_dev->cam;
++ struct sd *dev = (struct sd *) gspca_dev;
++
++ /* We don't use the buffer gspca allocates so make it small. */
++ cam->bulk_size = 64;
++
++ INIT_WORK(&dev->work_struct, sq905_dostream);
++
++ return 0;
++}
++
++/* called on streamoff with alt==0 and on disconnect */
++/* the usb_lock is held at entry - restore on exit */
++static void sd_stop0(struct gspca_dev *gspca_dev)
++{
++ struct sd *dev = (struct sd *) gspca_dev;
++
++ /* wait for the work queue to terminate */
++ mutex_unlock(&gspca_dev->usb_lock);
++ /* This waits for sq905_dostream to finish */
++ destroy_workqueue(dev->work_thread);
++ dev->work_thread = NULL;
++ mutex_lock(&gspca_dev->usb_lock);
++}
++
++/* this function is called at probe and resume time */
++static int sd_init(struct gspca_dev *gspca_dev)
++{
++ u32 ident;
++ int ret;
++
++ /* connect to the camera and read
++ * the model ID and process that and put it away.
++ */
++ ret = sq905_command(gspca_dev, SQ905_CLEAR);
++ if (ret < 0)
++ return ret;
++ ret = sq905_command(gspca_dev, SQ905_ID);
++ if (ret < 0)
++ return ret;
++ ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4);
++ if (ret < 0)
++ return ret;
++ /* usb_buf is allocated with kmalloc so is aligned.
++ * Camera model number is the right way round if we assume this
++ * reverse engineered ID is supposed to be big endian. */
++ ident = be32_to_cpup((__be32 *)gspca_dev->usb_buf);
++ ret = sq905_command(gspca_dev, SQ905_CLEAR);
++ if (ret < 0)
++ return ret;
++ PDEBUG(D_CONF, "SQ905 camera ID %08x detected", ident);
++ gspca_dev->cam.cam_mode = sq905_mode;
++ gspca_dev->cam.nmodes = ARRAY_SIZE(sq905_mode);
++ if (!(ident & SQ905_HIRES_MASK))
++ gspca_dev->cam.nmodes--;
++ return 0;
++}
++
++/* Set up for getting frames. */
++static int sd_start(struct gspca_dev *gspca_dev)
++{
++ struct sd *dev = (struct sd *) gspca_dev;
++ int ret;
++
++ /* "Open the shutter" and set size, to start capture */
++ switch (gspca_dev->curr_mode) {
++ default:
++/* case 2: */
++ PDEBUG(D_STREAM, "Start streaming at high resolution");
++ ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_HIGH);
++ break;
++ case 1:
++ PDEBUG(D_STREAM, "Start streaming at medium resolution");
++ ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_MED);
++ break;
++ case 0:
++ PDEBUG(D_STREAM, "Start streaming at low resolution");
++ ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_LOW);
++ }
++
++ if (ret < 0) {
++ PDEBUG(D_ERR, "Start streaming command failed");
++ return ret;
++ }
++ /* Start the workqueue function to do the streaming */
++ dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
++ queue_work(dev->work_thread, &dev->work_struct);
++
++ return 0;
++}
++
++/* Table of supported USB devices */
++static const __devinitdata struct usb_device_id device_table[] = {
++ {USB_DEVICE(0x2770, 0x9120)},
++ {}
++};
++
++MODULE_DEVICE_TABLE(usb, device_table);
++
++/* sub-driver description */
++static const struct sd_desc sd_desc = {
++ .name = MODULE_NAME,
++ .config = sd_config,
++ .init = sd_init,
++ .start = sd_start,
++ .stop0 = sd_stop0,
++};
++
++/* -- device connect -- */
++static int sd_probe(struct usb_interface *intf,
++ const struct usb_device_id *id)
++{
++ return gspca_dev_probe(intf, id,
++ &sd_desc,
++ sizeof(struct sd),
++ THIS_MODULE);
++}
++
++static struct usb_driver sd_driver = {
++ .name = MODULE_NAME,
++ .id_table = device_table,
++ .probe = sd_probe,
++ .disconnect = gspca_disconnect,
++#ifdef CONFIG_PM
++ .suspend = gspca_suspend,
++ .resume = gspca_resume,
++#endif
++};
++
++/* -- module insert / remove -- */
++static int __init sd_mod_init(void)
++{
++ int ret;
++
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
++ PDEBUG(D_PROBE, "registered");
++ return 0;
++}
++
++static void __exit sd_mod_exit(void)
++{
++ usb_deregister(&sd_driver);
++ PDEBUG(D_PROBE, "deregistered");
++}
++
++module_init(sd_mod_init);
++module_exit(sd_mod_exit);
+diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
+new file mode 100644
+index 0000000..0bcb74a
+--- /dev/null
++++ b/drivers/media/video/gspca/sq905c.c
+@@ -0,0 +1,328 @@
++/*
++ * SQ905C subdriver
++ *
++ * Copyright (C) 2009 Theodore Kilgore
++ *
++ * 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
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/*
++ *
++ * This driver uses work done in
++ * libgphoto2/camlibs/digigr8, Copyright (C) Theodore Kilgore.
++ *
++ * This driver has also used as a base the sq905c driver
++ * and may contain code fragments from it.
++ */
++
++#define MODULE_NAME "sq905c"
++
++#include <linux/workqueue.h>
++#include "gspca.h"
++
++MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
++MODULE_DESCRIPTION("GSPCA/SQ905C USB Camera Driver");
++MODULE_LICENSE("GPL");
++
++/* Default timeouts, in ms */
++#define SQ905C_CMD_TIMEOUT 500
++#define SQ905C_DATA_TIMEOUT 1000
++
++/* Maximum transfer size to use. */
++#define SQ905C_MAX_TRANSFER 0x8000
++
++#define FRAME_HEADER_LEN 0x50
++
++/* Commands. These go in the "value" slot. */
++#define SQ905C_CLEAR 0xa0 /* clear everything */
++#define SQ905C_CAPTURE_LOW 0xa040 /* Starts capture at 160x120 */
++#define SQ905C_CAPTURE_MED 0x1440 /* Starts capture at 320x240 */
++#define SQ905C_CAPTURE_HI 0x2840 /* Starts capture at 320x240 */
++
++/* For capture, this must go in the "index" slot. */
++#define SQ905C_CAPTURE_INDEX 0x110f
++
++/* Structure to hold all of our device specific stuff */
++struct sd {
++ struct gspca_dev gspca_dev; /* !! must be the first item */
++ const struct v4l2_pix_format *cap_mode;
++ /* Driver stuff */
++ struct work_struct work_struct;
++ struct workqueue_struct *work_thread;
++};
++
++/*
++ * Most of these cameras will do 640x480 and 320x240. 160x120 works
++ * in theory but gives very poor output. Therefore, not supported.
++ * The 0x2770:0x9050 cameras have max resolution of 320x240.
++ */
++static struct v4l2_pix_format sq905c_mode[] = {
++ { 320, 240, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
++ .bytesperline = 320,
++ .sizeimage = 320 * 240,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 0},
++ { 640, 480, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
++ .bytesperline = 640,
++ .sizeimage = 640 * 480,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 0}
++};
++
++/* Send a command to the camera. */
++static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
++{
++ int ret;
++
++ ret = usb_control_msg(gspca_dev->dev,
++ usb_sndctrlpipe(gspca_dev->dev, 0),
++ USB_REQ_SYNCH_FRAME, /* request */
++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ command, index, NULL, 0,
++ SQ905C_CMD_TIMEOUT);
++ if (ret < 0) {
++ PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
++ __func__, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++/* This function is called as a workqueue function and runs whenever the camera
++ * is streaming data. Because it is a workqueue function it is allowed to sleep
++ * so we can use synchronous USB calls. To avoid possible collisions with other
++ * threads attempting to use the camera's USB interface the gspca usb_lock is
++ * used when performing the one USB control operation inside the workqueue,
++ * which tells the camera to close the stream. In practice the only thing
++ * which needs to be protected against is the usb_set_interface call that
++ * gspca makes during stream_off. Otherwise the camera doesn't provide any
++ * controls that the user could try to change.
++ */
++static void sq905c_dostream(struct work_struct *work)
++{
++ struct sd *dev = container_of(work, struct sd, work_struct);
++ struct gspca_dev *gspca_dev = &dev->gspca_dev;
++ struct gspca_frame *frame;
++ int bytes_left; /* bytes remaining in current frame. */
++ int data_len; /* size to use for the next read. */
++ int act_len;
++ int discarding = 0; /* true if we failed to get space for frame. */
++ int packet_type;
++ int ret;
++ u8 *buffer;
++
++ buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
++ if (!buffer) {
++ PDEBUG(D_ERR, "Couldn't allocate USB buffer");
++ goto quit_stream;
++ }
++
++ while (gspca_dev->present && gspca_dev->streaming) {
++ if (!gspca_dev->present)
++ goto quit_stream;
++ /* Request the header, which tells the size to download */
++ ret = usb_bulk_msg(gspca_dev->dev,
++ usb_rcvbulkpipe(gspca_dev->dev, 0x81),
++ buffer, FRAME_HEADER_LEN, &act_len,
++ SQ905C_DATA_TIMEOUT);
++ PDEBUG(D_STREAM,
++ "Got %d bytes out of %d for header",
++ act_len, FRAME_HEADER_LEN);
++ if (ret < 0 || act_len < FRAME_HEADER_LEN)
++ goto quit_stream;
++ /* size is read from 4 bytes starting 0x40, little endian */
++ bytes_left = buffer[0x40]|(buffer[0x41]<<8)|(buffer[0x42]<<16)
++ |(buffer[0x43]<<24);
++ PDEBUG(D_STREAM, "bytes_left = 0x%x", bytes_left);
++ /* We keep the header. It has other information, too. */
++ packet_type = FIRST_PACKET;
++ frame = gspca_get_i_frame(gspca_dev);
++ if (frame && !discarding) {
++ gspca_frame_add(gspca_dev, packet_type,
++ frame, buffer, FRAME_HEADER_LEN);
++ } else
++ discarding = 1;
++ while (bytes_left > 0) {
++ data_len = bytes_left > SQ905C_MAX_TRANSFER ?
++ SQ905C_MAX_TRANSFER : bytes_left;
++ if (!gspca_dev->present)
++ goto quit_stream;
++ ret = usb_bulk_msg(gspca_dev->dev,
++ usb_rcvbulkpipe(gspca_dev->dev, 0x81),
++ buffer, data_len, &act_len,
++ SQ905C_DATA_TIMEOUT);
++ if (ret < 0 || act_len < data_len)
++ goto quit_stream;
++ PDEBUG(D_STREAM,
++ "Got %d bytes out of %d for frame",
++ data_len, bytes_left);
++ bytes_left -= data_len;
++ if (bytes_left == 0)
++ packet_type = LAST_PACKET;
++ else
++ packet_type = INTER_PACKET;
++ frame = gspca_get_i_frame(gspca_dev);
++ if (frame && !discarding)
++ gspca_frame_add(gspca_dev, packet_type,
++ frame, buffer, data_len);
++ else
++ discarding = 1;
++ }
++ }
++quit_stream:
++ mutex_lock(&gspca_dev->usb_lock);
++ if (gspca_dev->present)
++ sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
++ mutex_unlock(&gspca_dev->usb_lock);
++ kfree(buffer);
++}
++
++/* This function is called at probe time just before sd_init */
++static int sd_config(struct gspca_dev *gspca_dev,
++ const struct usb_device_id *id)
++{
++ struct cam *cam = &gspca_dev->cam;
++ struct sd *dev = (struct sd *) gspca_dev;
++
++ PDEBUG(D_PROBE,
++ "SQ9050 camera detected"
++ " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
++ cam->cam_mode = sq905c_mode;
++ cam->nmodes = 2;
++ if (id->idProduct == 0x9050)
++ cam->nmodes = 1;
++ /* We don't use the buffer gspca allocates so make it small. */
++ cam->bulk_size = 32;
++ INIT_WORK(&dev->work_struct, sq905c_dostream);
++ return 0;
++}
++
++/* called on streamoff with alt==0 and on disconnect */
++/* the usb_lock is held at entry - restore on exit */
++static void sd_stop0(struct gspca_dev *gspca_dev)
++{
++ struct sd *dev = (struct sd *) gspca_dev;
++
++ /* wait for the work queue to terminate */
++ mutex_unlock(&gspca_dev->usb_lock);
++ /* This waits for sq905c_dostream to finish */
++ destroy_workqueue(dev->work_thread);
++ dev->work_thread = NULL;
++ mutex_lock(&gspca_dev->usb_lock);
++}
++
++/* this function is called at probe and resume time */
++static int sd_init(struct gspca_dev *gspca_dev)
++{
++ int ret;
++
++ /* connect to the camera and reset it. */
++ ret = sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
++ return ret;
++}
++
++/* Set up for getting frames. */
++static int sd_start(struct gspca_dev *gspca_dev)
++{
++ struct sd *dev = (struct sd *) gspca_dev;
++ int ret;
++
++ dev->cap_mode = gspca_dev->cam.cam_mode;
++ /* "Open the shutter" and set size, to start capture */
++ switch (gspca_dev->width) {
++ case 640:
++ PDEBUG(D_STREAM, "Start streaming at high resolution");
++ dev->cap_mode++;
++ ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_HI,
++ SQ905C_CAPTURE_INDEX);
++ break;
++ default: /* 320 */
++ PDEBUG(D_STREAM, "Start streaming at medium resolution");
++ ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_MED,
++ SQ905C_CAPTURE_INDEX);
++ }
++
++ if (ret < 0) {
++ PDEBUG(D_ERR, "Start streaming command failed");
++ return ret;
++ }
++ /* Start the workqueue function to do the streaming */
++ dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
++ queue_work(dev->work_thread, &dev->work_struct);
++
++ return 0;
++}
++
++/* Table of supported USB devices */
++static const __devinitdata struct usb_device_id device_table[] = {
++ {USB_DEVICE(0x2770, 0x905c)},
++ {USB_DEVICE(0x2770, 0x9050)},
++ {USB_DEVICE(0x2770, 0x913d)},
++ {}
++};
++
++MODULE_DEVICE_TABLE(usb, device_table);
++
++/* sub-driver description */
++static const struct sd_desc sd_desc = {
++ .name = MODULE_NAME,
++ .config = sd_config,
++ .init = sd_init,
++ .start = sd_start,
++ .stop0 = sd_stop0,
++};
++
++/* -- device connect -- */
++static int sd_probe(struct usb_interface *intf,
++ const struct usb_device_id *id)
++{
++ return gspca_dev_probe(intf, id,
++ &sd_desc,
++ sizeof(struct sd),
++ THIS_MODULE);
++}
++
++static struct usb_driver sd_driver = {
++ .name = MODULE_NAME,
++ .id_table = device_table,
++ .probe = sd_probe,
++ .disconnect = gspca_disconnect,
++#ifdef CONFIG_PM
++ .suspend = gspca_suspend,
++ .resume = gspca_resume,
++#endif
++};
++
++/* -- module insert / remove -- */
++static int __init sd_mod_init(void)
++{
++ int ret;
++
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
++ PDEBUG(D_PROBE, "registered");
++ return 0;
++}
++
++static void __exit sd_mod_exit(void)
++{
++ usb_deregister(&sd_driver);
++ PDEBUG(D_PROBE, "deregistered");
++}
++
++module_init(sd_mod_init);
++module_exit(sd_mod_exit);
+diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
+index 60de9af..f25be20 100644
+--- a/drivers/media/video/gspca/stk014.c
++++ b/drivers/media/video/gspca/stk014.c
+@@ -35,10 +35,13 @@ struct sd {
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char lightfreq;
+-};
++ u8 quality;
++#define QUALITY_MIN 60
++#define QUALITY_MAX 95
++#define QUALITY_DEF 80
+
+-/* global parameters */
+-static int sd_quant = 7; /* <= 4 KO - 7: good (enough!) */
++ u8 *jpeg_hdr;
++};
+
+ /* V4L2 controls supported by the driver */
+ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+@@ -180,7 +183,7 @@ static int rcv_val(struct gspca_dev *gspca_dev,
+ reg_w(gspca_dev, 0x63b, 0);
+ reg_w(gspca_dev, 0x630, 5);
+ ret = usb_bulk_msg(dev,
+- usb_rcvbulkpipe(dev, 5),
++ usb_rcvbulkpipe(dev, 0x05),
+ gspca_dev->usb_buf,
+ 4, /* length */
+ &alen,
+@@ -294,15 +297,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- struct cam *cam = &gspca_dev->cam;
+
+- cam->epaddr = 0x02;
+ gspca_dev->cam.cam_mode = vga_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->lightfreq = FREQ_DEF;
++ sd->quality = QUALITY_DEF;
+ return 0;
+ }
+
+@@ -326,8 +328,15 @@ static int sd_init(struct gspca_dev *gspca_dev)
+ /* -- start the camera -- */
+ static int sd_start(struct gspca_dev *gspca_dev)
+ {
++ struct sd *sd = (struct sd *) gspca_dev;
+ int ret, value;
+
++ /* create the JPEG header */
++ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
++ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
++ 0x22); /* JPEG 411 */
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++
+ /* work on alternate 1 */
+ usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+
+@@ -399,11 +408,19 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
+ PDEBUG(D_STREAM, "camera stopped");
+ }
+
++static void sd_stop0(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ kfree(sd->jpeg_hdr);
++}
++
+ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+ {
++ struct sd *sd = (struct sd *) gspca_dev;
+ static unsigned char ffd9[] = {0xff, 0xd9};
+
+ /* a frame starts with:
+@@ -420,7 +437,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ ffd9, 2);
+
+ /* put the JPEG 411 header */
+- jpeg_put_header(gspca_dev, frame, sd_quant, 0x22);
++ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
++ sd->jpeg_hdr, JPEG_HDR_SZ);
+
+ /* beginning of the frame */
+ #define STKHDRSZ 12
+@@ -520,6 +538,34 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
+ return -EINVAL;
+ }
+
++static int sd_set_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ if (jcomp->quality < QUALITY_MIN)
++ sd->quality = QUALITY_MIN;
++ else if (jcomp->quality > QUALITY_MAX)
++ sd->quality = QUALITY_MAX;
++ else
++ sd->quality = jcomp->quality;
++ if (gspca_dev->streaming)
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++ return 0;
++}
++
++static int sd_get_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ memset(jcomp, 0, sizeof *jcomp);
++ jcomp->quality = sd->quality;
++ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
++ | V4L2_JPEG_MARKER_DQT;
++ return 0;
++}
++
+ /* sub-driver description */
+ static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+@@ -529,8 +575,11 @@ static const struct sd_desc sd_desc = {
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
++ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
++ .get_jcomp = sd_get_jcomp,
++ .set_jcomp = sd_set_jcomp,
+ };
+
+ /* -- module initialisation -- */
+@@ -562,8 +611,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ info("registered");
+ return 0;
+ }
+@@ -575,6 +626,3 @@ static void __exit sd_mod_exit(void)
+
+ module_init(sd_mod_init);
+ module_exit(sd_mod_exit);
+-
+-module_param_named(quant, sd_quant, int, 0644);
+-MODULE_PARM_DESC(quant, "Quantization index (0..8)");
+diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
+index 13a021e..9dff2e6 100644
+--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
++++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
+@@ -429,7 +429,6 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
+ PDEBUG(D_PROBE, "Configuring camera");
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = STV_ISOC_ENDPOINT_ADDR;
+ sd->desc = sd_desc;
+ gspca_dev->sd_desc = &sd->desc;
+
+@@ -501,8 +500,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+index 14335a9..b169038 100644
+--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
++++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+@@ -30,6 +30,66 @@
+
+ #include "stv06xx_hdcs.h"
+
++static const struct ctrl hdcs1x00_ctrl[] = {
++ {
++ {
++ .id = V4L2_CID_EXPOSURE,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "exposure",
++ .minimum = 0x00,
++ .maximum = 0xffff,
++ .step = 0x1,
++ .default_value = HDCS_DEFAULT_EXPOSURE,
++ .flags = V4L2_CTRL_FLAG_SLIDER
++ },
++ .set = hdcs_set_exposure,
++ .get = hdcs_get_exposure
++ }, {
++ {
++ .id = V4L2_CID_GAIN,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "gain",
++ .minimum = 0x00,
++ .maximum = 0xff,
++ .step = 0x1,
++ .default_value = HDCS_DEFAULT_GAIN,
++ .flags = V4L2_CTRL_FLAG_SLIDER
++ },
++ .set = hdcs_set_gain,
++ .get = hdcs_get_gain
++ }
++};
++
++static struct v4l2_pix_format hdcs1x00_mode[] = {
++ {
++ HDCS_1X00_DEF_WIDTH,
++ HDCS_1X00_DEF_HEIGHT,
++ V4L2_PIX_FMT_SBGGR8,
++ V4L2_FIELD_NONE,
++ .sizeimage =
++ HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
++ .bytesperline = HDCS_1X00_DEF_WIDTH,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 1
++ }
++};
++
++static const struct ctrl hdcs1020_ctrl[] = {};
++
++static struct v4l2_pix_format hdcs1020_mode[] = {
++ {
++ HDCS_1020_DEF_WIDTH,
++ HDCS_1020_DEF_HEIGHT,
++ V4L2_PIX_FMT_SBGGR8,
++ V4L2_FIELD_NONE,
++ .sizeimage =
++ HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
++ .bytesperline = HDCS_1020_DEF_WIDTH,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 1
++ }
++};
++
+ enum hdcs_power_state {
+ HDCS_STATE_SLEEP,
+ HDCS_STATE_IDLE,
+@@ -353,10 +413,10 @@ static int hdcs_probe_1x00(struct sd *sd)
+
+ info("HDCS-1000/1100 sensor detected");
+
+- sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1x00.modes;
+- sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1x00.nmodes;
+- sd->desc.ctrls = stv06xx_sensor_hdcs1x00.ctrls;
+- sd->desc.nctrls = stv06xx_sensor_hdcs1x00.nctrls;
++ sd->gspca_dev.cam.cam_mode = hdcs1x00_mode;
++ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode);
++ sd->desc.ctrls = hdcs1x00_ctrl;
++ sd->desc.nctrls = ARRAY_SIZE(hdcs1x00_ctrl);
+
+ hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
+ if (!hdcs)
+@@ -412,10 +472,10 @@ static int hdcs_probe_1020(struct sd *sd)
+
+ info("HDCS-1020 sensor detected");
+
+- sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1020.modes;
+- sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1020.nmodes;
+- sd->desc.ctrls = stv06xx_sensor_hdcs1020.ctrls;
+- sd->desc.nctrls = stv06xx_sensor_hdcs1020.nctrls;
++ sd->gspca_dev.cam.cam_mode = hdcs1020_mode;
++ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode);
++ sd->desc.ctrls = hdcs1020_ctrl;
++ sd->desc.nctrls = ARRAY_SIZE(hdcs1020_ctrl);
+
+ hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
+ if (!hdcs)
+diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
+index 9c7279a..412f06c 100644
+--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
++++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
+@@ -152,53 +152,6 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
+ .stop = hdcs_stop,
+ .disconnect = hdcs_disconnect,
+ .dump = hdcs_dump,
+-
+- .nctrls = 2,
+- .ctrls = {
+- {
+- {
+- .id = V4L2_CID_EXPOSURE,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "exposure",
+- .minimum = 0x00,
+- .maximum = 0xffff,
+- .step = 0x1,
+- .default_value = HDCS_DEFAULT_EXPOSURE,
+- .flags = V4L2_CTRL_FLAG_SLIDER
+- },
+- .set = hdcs_set_exposure,
+- .get = hdcs_get_exposure
+- },
+- {
+- {
+- .id = V4L2_CID_GAIN,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "gain",
+- .minimum = 0x00,
+- .maximum = 0xff,
+- .step = 0x1,
+- .default_value = HDCS_DEFAULT_GAIN,
+- .flags = V4L2_CTRL_FLAG_SLIDER
+- },
+- .set = hdcs_set_gain,
+- .get = hdcs_get_gain
+- }
+- },
+-
+- .nmodes = 1,
+- .modes = {
+- {
+- HDCS_1X00_DEF_WIDTH,
+- HDCS_1X00_DEF_HEIGHT,
+- V4L2_PIX_FMT_SBGGR8,
+- V4L2_FIELD_NONE,
+- .sizeimage =
+- HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
+- .bytesperline = HDCS_1X00_DEF_WIDTH,
+- .colorspace = V4L2_COLORSPACE_SRGB,
+- .priv = 1
+- }
+- }
+ };
+
+ const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
+@@ -207,29 +160,11 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
+ .i2c_addr = (0x55 << 1),
+ .i2c_len = 1,
+
+- .nctrls = 0,
+- .ctrls = {},
+-
+ .init = hdcs_init,
+ .probe = hdcs_probe_1020,
+ .start = hdcs_start,
+ .stop = hdcs_stop,
+ .dump = hdcs_dump,
+-
+- .nmodes = 1,
+- .modes = {
+- {
+- HDCS_1020_DEF_WIDTH,
+- HDCS_1020_DEF_HEIGHT,
+- V4L2_PIX_FMT_SBGGR8,
+- V4L2_FIELD_NONE,
+- .sizeimage =
+- HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
+- .bytesperline = HDCS_1020_DEF_WIDTH,
+- .colorspace = V4L2_COLORSPACE_SRGB,
+- .priv = 1
+- }
+- }
+ };
+
+ static const u16 stv_bridge_init[][2] = {
+diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+index d0a0f85..285221e 100644
+--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
++++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+@@ -46,6 +46,132 @@
+
+ #include "stv06xx_pb0100.h"
+
++static const struct ctrl pb0100_ctrl[] = {
++#define GAIN_IDX 0
++ {
++ {
++ .id = V4L2_CID_GAIN,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Gain",
++ .minimum = 0,
++ .maximum = 255,
++ .step = 1,
++ .default_value = 128
++ },
++ .set = pb0100_set_gain,
++ .get = pb0100_get_gain
++ },
++#define RED_BALANCE_IDX 1
++ {
++ {
++ .id = V4L2_CID_RED_BALANCE,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Red Balance",
++ .minimum = -255,
++ .maximum = 255,
++ .step = 1,
++ .default_value = 0
++ },
++ .set = pb0100_set_red_balance,
++ .get = pb0100_get_red_balance
++ },
++#define BLUE_BALANCE_IDX 2
++ {
++ {
++ .id = V4L2_CID_BLUE_BALANCE,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Blue Balance",
++ .minimum = -255,
++ .maximum = 255,
++ .step = 1,
++ .default_value = 0
++ },
++ .set = pb0100_set_blue_balance,
++ .get = pb0100_get_blue_balance
++ },
++#define EXPOSURE_IDX 3
++ {
++ {
++ .id = V4L2_CID_EXPOSURE,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Exposure",
++ .minimum = 0,
++ .maximum = 511,
++ .step = 1,
++ .default_value = 12
++ },
++ .set = pb0100_set_exposure,
++ .get = pb0100_get_exposure
++ },
++#define AUTOGAIN_IDX 4
++ {
++ {
++ .id = V4L2_CID_AUTOGAIN,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .name = "Automatic Gain and Exposure",
++ .minimum = 0,
++ .maximum = 1,
++ .step = 1,
++ .default_value = 1
++ },
++ .set = pb0100_set_autogain,
++ .get = pb0100_get_autogain
++ },
++#define AUTOGAIN_TARGET_IDX 5
++ {
++ {
++ .id = V4L2_CTRL_CLASS_USER + 0x1000,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "Automatic Gain Target",
++ .minimum = 0,
++ .maximum = 255,
++ .step = 1,
++ .default_value = 128
++ },
++ .set = pb0100_set_autogain_target,
++ .get = pb0100_get_autogain_target
++ },
++#define NATURAL_IDX 6
++ {
++ {
++ .id = V4L2_CTRL_CLASS_USER + 0x1001,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .name = "Natural Light Source",
++ .minimum = 0,
++ .maximum = 1,
++ .step = 1,
++ .default_value = 1
++ },
++ .set = pb0100_set_natural,
++ .get = pb0100_get_natural
++ }
++};
++
++static struct v4l2_pix_format pb0100_mode[] = {
++/* low res / subsample modes disabled as they are only half res horizontal,
++ halving the vertical resolution does not seem to work */
++ {
++ 320,
++ 240,
++ V4L2_PIX_FMT_SGRBG8,
++ V4L2_FIELD_NONE,
++ .sizeimage = 320 * 240,
++ .bytesperline = 320,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = PB0100_CROP_TO_VGA
++ },
++ {
++ 352,
++ 288,
++ V4L2_PIX_FMT_SGRBG8,
++ V4L2_FIELD_NONE,
++ .sizeimage = 352 * 288,
++ .bytesperline = 352,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 0
++ }
++};
++
+ static int pb0100_probe(struct sd *sd)
+ {
+ u16 sensor;
+@@ -59,20 +185,19 @@ static int pb0100_probe(struct sd *sd)
+
+ if ((sensor >> 8) == 0x64) {
+ sensor_settings = kmalloc(
+- stv06xx_sensor_pb0100.nctrls * sizeof(s32),
++ ARRAY_SIZE(pb0100_ctrl) * sizeof(s32),
+ GFP_KERNEL);
+ if (!sensor_settings)
+ return -ENOMEM;
+
+ info("Photobit pb0100 sensor detected");
+
+- sd->gspca_dev.cam.cam_mode = stv06xx_sensor_pb0100.modes;
+- sd->gspca_dev.cam.nmodes = stv06xx_sensor_pb0100.nmodes;
+- sd->desc.ctrls = stv06xx_sensor_pb0100.ctrls;
+- sd->desc.nctrls = stv06xx_sensor_pb0100.nctrls;
+- for (i = 0; i < stv06xx_sensor_pb0100.nctrls; i++)
+- sensor_settings[i] = stv06xx_sensor_pb0100.
+- ctrls[i].qctrl.default_value;
++ sd->gspca_dev.cam.cam_mode = pb0100_mode;
++ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
++ sd->desc.ctrls = pb0100_ctrl;
++ sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl);
++ for (i = 0; i < sd->desc.nctrls; i++)
++ sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value;
+ sd->sensor_priv = sensor_settings;
+
+ return 0;
+@@ -143,6 +268,12 @@ out:
+ return (err < 0) ? err : 0;
+ }
+
++static void pb0100_disconnect(struct sd *sd)
++{
++ sd->sensor = NULL;
++ kfree(sd->sensor_priv);
++}
++
+ /* FIXME: Sort the init commands out and put them into tables,
+ this is only for getting the camera to work */
+ /* FIXME: No error handling for now,
+diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
+index 5ea21a1..4de4fa5 100644
+--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
++++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
+@@ -114,6 +114,7 @@ static int pb0100_start(struct sd *sd);
+ static int pb0100_init(struct sd *sd);
+ static int pb0100_stop(struct sd *sd);
+ static int pb0100_dump(struct sd *sd);
++static void pb0100_disconnect(struct sd *sd);
+
+ /* V4L2 controls supported by the driver */
+ static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+@@ -137,139 +138,12 @@ const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
+ .i2c_addr = 0xba,
+ .i2c_len = 2,
+
+- .nctrls = 7,
+- .ctrls = {
+-#define GAIN_IDX 0
+- {
+- {
+- .id = V4L2_CID_GAIN,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "Gain",
+- .minimum = 0,
+- .maximum = 255,
+- .step = 1,
+- .default_value = 128
+- },
+- .set = pb0100_set_gain,
+- .get = pb0100_get_gain
+- },
+-#define RED_BALANCE_IDX 1
+- {
+- {
+- .id = V4L2_CID_RED_BALANCE,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "Red Balance",
+- .minimum = -255,
+- .maximum = 255,
+- .step = 1,
+- .default_value = 0
+- },
+- .set = pb0100_set_red_balance,
+- .get = pb0100_get_red_balance
+- },
+-#define BLUE_BALANCE_IDX 2
+- {
+- {
+- .id = V4L2_CID_BLUE_BALANCE,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "Blue Balance",
+- .minimum = -255,
+- .maximum = 255,
+- .step = 1,
+- .default_value = 0
+- },
+- .set = pb0100_set_blue_balance,
+- .get = pb0100_get_blue_balance
+- },
+-#define EXPOSURE_IDX 3
+- {
+- {
+- .id = V4L2_CID_EXPOSURE,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "Exposure",
+- .minimum = 0,
+- .maximum = 511,
+- .step = 1,
+- .default_value = 12
+- },
+- .set = pb0100_set_exposure,
+- .get = pb0100_get_exposure
+- },
+-#define AUTOGAIN_IDX 4
+- {
+- {
+- .id = V4L2_CID_AUTOGAIN,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- .name = "Automatic Gain and Exposure",
+- .minimum = 0,
+- .maximum = 1,
+- .step = 1,
+- .default_value = 1
+- },
+- .set = pb0100_set_autogain,
+- .get = pb0100_get_autogain
+- },
+-#define AUTOGAIN_TARGET_IDX 5
+- {
+- {
+- .id = V4L2_CTRL_CLASS_USER + 0x1000,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "Automatic Gain Target",
+- .minimum = 0,
+- .maximum = 255,
+- .step = 1,
+- .default_value = 128
+- },
+- .set = pb0100_set_autogain_target,
+- .get = pb0100_get_autogain_target
+- },
+-#define NATURAL_IDX 6
+- {
+- {
+- .id = V4L2_CTRL_CLASS_USER + 0x1001,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- .name = "Natural Light Source",
+- .minimum = 0,
+- .maximum = 1,
+- .step = 1,
+- .default_value = 1
+- },
+- .set = pb0100_set_natural,
+- .get = pb0100_get_natural
+- },
+- },
+-
+ .init = pb0100_init,
+ .probe = pb0100_probe,
+ .start = pb0100_start,
+ .stop = pb0100_stop,
+ .dump = pb0100_dump,
+-
+- .nmodes = 2,
+- .modes = {
+-/* low res / subsample modes disabled as they are only half res horizontal,
+- halving the vertical resolution does not seem to work */
+- {
+- 320,
+- 240,
+- V4L2_PIX_FMT_SGRBG8,
+- V4L2_FIELD_NONE,
+- .sizeimage = 320 * 240,
+- .bytesperline = 320,
+- .colorspace = V4L2_COLORSPACE_SRGB,
+- .priv = PB0100_CROP_TO_VGA
+- },
+- {
+- 352,
+- 288,
+- V4L2_PIX_FMT_SGRBG8,
+- V4L2_FIELD_NONE,
+- .sizeimage = 352 * 288,
+- .bytesperline = 352,
+- .colorspace = V4L2_COLORSPACE_SRGB,
+- .priv = 0
+- },
+- }
++ .disconnect = pb0100_disconnect,
+ };
+
+ #endif
+diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
+index c726dac..e88c42f 100644
+--- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
++++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
+@@ -41,8 +41,6 @@ extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00;
+ extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020;
+ extern const struct stv06xx_sensor stv06xx_sensor_pb0100;
+
+-#define STV06XX_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
+-
+ struct stv06xx_sensor {
+ /* Defines the name of a sensor */
+ char name[32];
+@@ -81,12 +79,6 @@ struct stv06xx_sensor {
+
+ /* Instructs the sensor to dump all its contents */
+ int (*dump)(struct sd *sd);
+-
+- int nctrls;
+- struct ctrl ctrls[STV06XX_MAX_CTRLS];
+-
+- char nmodes;
+- struct v4l2_pix_format modes[];
+ };
+
+ #endif
+diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
+index 1ca91f2..69c77c9 100644
+--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
++++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
+@@ -29,26 +29,92 @@
+
+ #include "stv06xx_vv6410.h"
+
++static struct v4l2_pix_format vv6410_mode[] = {
++ {
++ 356,
++ 292,
++ V4L2_PIX_FMT_SGRBG8,
++ V4L2_FIELD_NONE,
++ .sizeimage = 356 * 292,
++ .bytesperline = 356,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 0
++ }
++};
++
++static const struct ctrl vv6410_ctrl[] = {
++#define HFLIP_IDX 0
++ {
++ {
++ .id = V4L2_CID_HFLIP,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .name = "horizontal flip",
++ .minimum = 0,
++ .maximum = 1,
++ .step = 1,
++ .default_value = 0
++ },
++ .set = vv6410_set_hflip,
++ .get = vv6410_get_hflip
++ },
++#define VFLIP_IDX 1
++ {
++ {
++ .id = V4L2_CID_VFLIP,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .name = "vertical flip",
++ .minimum = 0,
++ .maximum = 1,
++ .step = 1,
++ .default_value = 0
++ },
++ .set = vv6410_set_vflip,
++ .get = vv6410_get_vflip
++ },
++#define GAIN_IDX 2
++ {
++ {
++ .id = V4L2_CID_GAIN,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .name = "analog gain",
++ .minimum = 0,
++ .maximum = 15,
++ .step = 1,
++ .default_value = 0
++ },
++ .set = vv6410_set_analog_gain,
++ .get = vv6410_get_analog_gain
++ }
++};
++
+ static int vv6410_probe(struct sd *sd)
+ {
+ u16 data;
+- int err;
++ int err, i;
++ s32 *sensor_settings;
+
+ err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
+-
+ if (err < 0)
+ return -ENODEV;
+
+ if (data == 0x19) {
+ info("vv6410 sensor detected");
+
+- sd->gspca_dev.cam.cam_mode = stv06xx_sensor_vv6410.modes;
+- sd->gspca_dev.cam.nmodes = stv06xx_sensor_vv6410.nmodes;
+- sd->desc.ctrls = stv06xx_sensor_vv6410.ctrls;
+- sd->desc.nctrls = stv06xx_sensor_vv6410.nctrls;
++ sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32),
++ GFP_KERNEL);
++ if (!sensor_settings)
++ return -ENOMEM;
++
++ sd->gspca_dev.cam.cam_mode = vv6410_mode;
++ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode);
++ sd->desc.ctrls = vv6410_ctrl;
++ sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl);
++
++ for (i = 0; i < sd->desc.nctrls; i++)
++ sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value;
++ sd->sensor_priv = sensor_settings;
+ return 0;
+ }
+-
+ return -ENODEV;
+ }
+
+@@ -80,6 +146,12 @@ static int vv6410_init(struct sd *sd)
+ return (err < 0) ? err : 0;
+ }
+
++static void vv6410_disconnect(struct sd *sd)
++{
++ sd->sensor = NULL;
++ kfree(sd->sensor_priv);
++}
++
+ static int vv6410_start(struct sd *sd)
+ {
+ int err;
+@@ -156,17 +228,13 @@ static int vv6410_dump(struct sd *sd)
+
+ static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+- int err;
+- u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
++ s32 *sensor_settings = sd->sensor_priv;
+
+- err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+-
+- *val = (i2c_data & VV6410_HFLIP) ? 1 : 0;
+-
++ *val = sensor_settings[HFLIP_IDX];
+ PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
+
+- return (err < 0) ? err : 0;
++ return 0;
+ }
+
+ static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+@@ -174,6 +242,9 @@ static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+ int err;
+ u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
++ s32 *sensor_settings = sd->sensor_priv;
++
++ sensor_settings[HFLIP_IDX] = val;
+ err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+ if (err < 0)
+ return err;
+@@ -191,17 +262,13 @@ static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+
+ static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+- int err;
+- u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
++ s32 *sensor_settings = sd->sensor_priv;
+
+- err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+-
+- *val = (i2c_data & VV6410_VFLIP) ? 1 : 0;
+-
++ *val = sensor_settings[VFLIP_IDX];
+ PDEBUG(D_V4L2, "Read vertical flip %d", *val);
+
+- return (err < 0) ? err : 0;
++ return 0;
+ }
+
+ static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+@@ -209,6 +276,9 @@ static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+ int err;
+ u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
++ s32 *sensor_settings = sd->sensor_priv;
++
++ sensor_settings[VFLIP_IDX] = val;
+ err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+ if (err < 0)
+ return err;
+@@ -226,24 +296,23 @@ static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+
+ static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+- int err;
+- u16 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
++ s32 *sensor_settings = sd->sensor_priv;
+
+- err = stv06xx_read_sensor(sd, VV6410_ANALOGGAIN, &i2c_data);
+-
+- *val = i2c_data & 0xf;
++ *val = sensor_settings[GAIN_IDX];
+
+ PDEBUG(D_V4L2, "Read analog gain %d", *val);
+
+- return (err < 0) ? err : 0;
++ return 0;
+ }
+
+ static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
+ {
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
++ s32 *sensor_settings = sd->sensor_priv;
+
++ sensor_settings[GAIN_IDX] = val;
+ PDEBUG(D_V4L2, "Set analog gain to %d", val);
+ err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
+
+diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+index 3ff8c4e..95ac558 100644
+--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
++++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+@@ -178,6 +178,7 @@ static int vv6410_start(struct sd *sd);
+ static int vv6410_init(struct sd *sd);
+ static int vv6410_stop(struct sd *sd);
+ static int vv6410_dump(struct sd *sd);
++static void vv6410_disconnect(struct sd *sd);
+
+ /* V4L2 controls supported by the driver */
+ static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+@@ -197,62 +198,7 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
+ .start = vv6410_start,
+ .stop = vv6410_stop,
+ .dump = vv6410_dump,
+-
+- .nctrls = 3,
+- .ctrls = {
+- {
+- {
+- .id = V4L2_CID_HFLIP,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- .name = "horizontal flip",
+- .minimum = 0,
+- .maximum = 1,
+- .step = 1,
+- .default_value = 0
+- },
+- .set = vv6410_set_hflip,
+- .get = vv6410_get_hflip
+- }, {
+- {
+- .id = V4L2_CID_VFLIP,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- .name = "vertical flip",
+- .minimum = 0,
+- .maximum = 1,
+- .step = 1,
+- .default_value = 0
+- },
+- .set = vv6410_set_vflip,
+- .get = vv6410_get_vflip
+- }, {
+- {
+- .id = V4L2_CID_GAIN,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "analog gain",
+- .minimum = 0,
+- .maximum = 15,
+- .step = 1,
+- .default_value = 0
+- },
+- .set = vv6410_set_analog_gain,
+- .get = vv6410_get_analog_gain
+- }
+- },
+-
+- .nmodes = 1,
+- .modes = {
+- {
+- 356,
+- 292,
+- V4L2_PIX_FMT_SGRBG8,
+- V4L2_FIELD_NONE,
+- .sizeimage =
+- 356 * 292,
+- .bytesperline = 356,
+- .colorspace = V4L2_COLORSPACE_SRGB,
+- .priv = 0
+- }
+- }
++ .disconnect = vv6410_disconnect,
+ };
+
+ /* If NULL, only single value to write, stored in len */
+diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
+index 6d904d5..c2b8c10 100644
+--- a/drivers/media/video/gspca/sunplus.c
++++ b/drivers/media/video/gspca/sunplus.c
+@@ -39,8 +39,11 @@ struct sd {
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
++ u8 quality;
++#define QUALITY_MIN 70
++#define QUALITY_MAX 95
++#define QUALITY_DEF 85
+
+- char qindex;
+ char bridge;
+ #define BRIDGE_SPCA504 0
+ #define BRIDGE_SPCA504B 1
+@@ -52,6 +55,8 @@ struct sd {
+ #define LogitechClickSmart420 2
+ #define LogitechClickSmart820 3
+ #define MegapixV4 4
++
++ u8 *jpeg_hdr;
+ };
+
+ /* V4L2 controls supported by the driver */
+@@ -812,7 +817,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+
+ sd->bridge = id->driver_info >> 8;
+ sd->subtype = id->driver_info;
+@@ -850,10 +854,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
+ break;
+ }
+- sd->qindex = 5; /* set the quantization table */
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
++ sd->quality = QUALITY_DEF;
+ return 0;
+ }
+
+@@ -970,6 +974,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ __u8 i;
+ __u8 info[6];
+
++ /* create the JPEG header */
++ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
++ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
++ 0x22); /* JPEG 411 */
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++
+ if (sd->bridge == BRIDGE_SPCA504B)
+ spca504B_setQtable(gspca_dev);
+ spca504B_SetSizeType(gspca_dev);
+@@ -1079,6 +1089,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
+ }
+ }
+
++static void sd_stop0(struct gspca_dev *gspca_dev)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ kfree(sd->jpeg_hdr);
++}
++
+ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+@@ -1155,9 +1172,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ ffd9, 2);
+
+ /* put the JPEG header in the new frame */
+- jpeg_put_header(gspca_dev, frame,
+- ((struct sd *) gspca_dev)->qindex,
+- 0x22);
++ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
++ sd->jpeg_hdr, JPEG_HDR_SZ);
+ }
+
+ /* add 0x00 after 0xff */
+@@ -1198,26 +1214,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ }
+ }
+
+-static void getbrightness(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+- __u16 brightness = 0;
+-
+- switch (sd->bridge) {
+- default:
+-/* case BRIDGE_SPCA533: */
+-/* case BRIDGE_SPCA504B: */
+-/* case BRIDGE_SPCA504: */
+-/* case BRIDGE_SPCA504C: */
+- brightness = reg_r_12(gspca_dev, 0x00, 0x21a7, 2);
+- break;
+- case BRIDGE_SPCA536:
+- brightness = reg_r_12(gspca_dev, 0x00, 0x20f0, 2);
+- break;
+- }
+- sd->brightness = ((brightness & 0xff) - 128) % 255;
+-}
+-
+ static void setcontrast(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -1237,24 +1233,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
+ }
+ }
+
+-static void getcontrast(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- switch (sd->bridge) {
+- default:
+-/* case BRIDGE_SPCA533: */
+-/* case BRIDGE_SPCA504B: */
+-/* case BRIDGE_SPCA504: */
+-/* case BRIDGE_SPCA504C: */
+- sd->contrast = reg_r_12(gspca_dev, 0x00, 0x21a8, 2);
+- break;
+- case BRIDGE_SPCA536:
+- sd->contrast = reg_r_12(gspca_dev, 0x00, 0x20f1, 2);
+- break;
+- }
+-}
+-
+ static void setcolors(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -1274,24 +1252,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
+ }
+ }
+
+-static void getcolors(struct gspca_dev *gspca_dev)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- switch (sd->bridge) {
+- default:
+-/* case BRIDGE_SPCA533: */
+-/* case BRIDGE_SPCA504B: */
+-/* case BRIDGE_SPCA504: */
+-/* case BRIDGE_SPCA504C: */
+- sd->colors = reg_r_12(gspca_dev, 0x00, 0x21ae, 2) >> 1;
+- break;
+- case BRIDGE_SPCA536:
+- sd->colors = reg_r_12(gspca_dev, 0x00, 0x20f6, 2) >> 1;
+- break;
+- }
+-}
+-
+ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -1306,7 +1266,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+ }
+@@ -1325,7 +1284,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+ }
+@@ -1344,7 +1302,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+ }
+@@ -1365,6 +1322,34 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+ return 0;
+ }
+
++static int sd_set_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ if (jcomp->quality < QUALITY_MIN)
++ sd->quality = QUALITY_MIN;
++ else if (jcomp->quality > QUALITY_MAX)
++ sd->quality = QUALITY_MAX;
++ else
++ sd->quality = jcomp->quality;
++ if (gspca_dev->streaming)
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++ return 0;
++}
++
++static int sd_get_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ memset(jcomp, 0, sizeof *jcomp);
++ jcomp->quality = sd->quality;
++ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
++ | V4L2_JPEG_MARKER_DQT;
++ return 0;
++}
++
+ /* sub-driver description */
+ static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+@@ -1374,7 +1359,10 @@ static const struct sd_desc sd_desc = {
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
++ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
++ .get_jcomp = sd_get_jcomp,
++ .set_jcomp = sd_set_jcomp,
+ };
+
+ /* -- module initialisation -- */
+@@ -1465,8 +1453,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
+index 6ee111a..f63e37e 100644
+--- a/drivers/media/video/gspca/t613.c
++++ b/drivers/media/video/gspca/t613.c
+@@ -37,20 +37,21 @@ MODULE_LICENSE("GPL");
+ struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+- unsigned char brightness;
+- unsigned char contrast;
+- unsigned char colors;
+- unsigned char autogain;
+- unsigned char gamma;
+- unsigned char sharpness;
+- unsigned char freq;
+- unsigned char whitebalance;
+- unsigned char mirror;
+- unsigned char effect;
+-
+- __u8 sensor;
+-#define SENSOR_TAS5130A 0
+-#define SENSOR_OM6802 1
++ u8 brightness;
++ u8 contrast;
++ u8 colors;
++ u8 autogain;
++ u8 gamma;
++ u8 sharpness;
++ u8 freq;
++ u8 whitebalance;
++ u8 mirror;
++ u8 effect;
++
++ u8 sensor;
++#define SENSOR_OM6802 0
++#define SENSOR_OTHER 1
++#define SENSOR_TAS5130A 2
+ };
+
+ /* V4L2 controls supported by the driver */
+@@ -78,7 +79,6 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu);
+
+ static struct ctrl sd_ctrls[] = {
+-#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+@@ -87,12 +87,12 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 14,
+ .step = 1,
+- .default_value = 8,
++#define BRIGHTNESS_DEF 8
++ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+-#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+@@ -101,12 +101,12 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 0x0d,
+ .step = 1,
+- .default_value = 0x07,
++#define CONTRAST_DEF 0x07
++ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+-#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+@@ -115,7 +115,8 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 0x0f,
+ .step = 1,
+- .default_value = 0x05,
++#define COLORS_DEF 0x05
++ .default_value = COLORS_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+@@ -135,7 +136,6 @@ static struct ctrl sd_ctrls[] = {
+ .set = sd_setgamma,
+ .get = sd_getgamma,
+ },
+-#define SD_AUTOGAIN 4
+ {
+ {
+ .id = V4L2_CID_GAIN, /* here, i activate only the lowlight,
+@@ -146,12 +146,12 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+- .default_value = 0x01,
++#define AUTOGAIN_DEF 0x01
++ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setlowlight,
+ .get = sd_getlowlight,
+ },
+-#define SD_MIRROR 5
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+@@ -160,12 +160,12 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+- .default_value = 0,
++#define MIRROR_DEF 0
++ .default_value = MIRROR_DEF,
+ },
+ .set = sd_setflip,
+ .get = sd_getflip
+ },
+-#define SD_LIGHTFREQ 6
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+@@ -174,12 +174,12 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 1, /* 1 -> 0x50, 2->0x60 */
+ .maximum = 2,
+ .step = 1,
+- .default_value = 1,
++#define FREQ_DEF 1
++ .default_value = FREQ_DEF,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq},
+
+-#define SD_WHITE_BALANCE 7
+ {
+ {
+ .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+@@ -188,12 +188,12 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+- .default_value = 0,
++#define WHITE_BALANCE_DEF 0
++ .default_value = WHITE_BALANCE_DEF,
+ },
+ .set = sd_setwhitebalance,
+ .get = sd_getwhitebalance
+ },
+-#define SD_SHARPNESS 8 /* (aka definition on win) */
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+@@ -202,12 +202,12 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 15,
+ .step = 1,
+- .default_value = 0x06,
++#define SHARPNESS_DEF 0x06
++ .default_value = SHARPNESS_DEF,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+-#define SD_EFFECTS 9
+ {
+ {
+ .id = V4L2_CID_EFFECTS,
+@@ -216,7 +216,8 @@ static struct ctrl sd_ctrls[] = {
+ .minimum = 0,
+ .maximum = 4,
+ .step = 1,
+- .default_value = 0,
++#define EFFECTS_DEF 0
++ .default_value = EFFECTS_DEF,
+ },
+ .set = sd_seteffect,
+ .get = sd_geteffect
+@@ -263,28 +264,50 @@ static const struct v4l2_pix_format vga_mode_t16[] = {
+
+ /* sensor specific data */
+ struct additional_sensor_data {
+- const __u8 data1[20];
+- const __u8 data2[18];
+- const __u8 data3[18];
+- const __u8 data4[4];
+- const __u8 data5[6];
+- const __u8 stream[4];
++ const u8 data1[10];
++ const u8 data2[9];
++ const u8 data3[9];
++ const u8 data4[4];
++ const u8 data5[6];
++ const u8 stream[4];
+ };
+
+-const static struct additional_sensor_data sensor_data[] = {
++static const struct additional_sensor_data sensor_data[] = {
++ { /* OM6802 */
++ .data1 =
++ {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
++ 0xb3, 0xfc},
++ .data2 =
++ {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
++ 0xff},
++ .data4 = /*Freq (50/60Hz). Splitted for test purpose */
++ {0x66, 0xca, 0xa8, 0xf0},
++ .data5 = /* this could be removed later */
++ {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
++ .stream =
++ {0x0b, 0x04, 0x0a, 0x78},
++ },
++ { /* OTHER */
++ .data1 =
++ {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
++ 0xe8, 0xfc},
++ .data2 =
++ {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
++ 0xd9},
++ .data4 =
++ {0x66, 0x00, 0xa8, 0xa8},
++ .data5 =
++ {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
++ .stream =
++ {0x0b, 0x04, 0x0a, 0x00},
++ },
+ { /* TAS5130A */
+ .data1 =
+- {0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10,
+- 0xd4, 0xbb, 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
+- 0xd8, 0xc8, 0xd9, 0xfc},
++ {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
++ 0xc8, 0xfc},
+ .data2 =
+- {0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60,
+- 0xe4, 0xa8, 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
+- 0xe8, 0xe0},
+- .data3 =
+- {0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60,
+- 0xcb, 0xa8, 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
+- 0xcf, 0xe0},
++ {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
++ 0xe0},
+ .data4 = /* Freq (50/60Hz). Splitted for test purpose */
+ {0x66, 0x00, 0xa8, 0xe8},
+ .data5 =
+@@ -292,32 +315,12 @@ const static struct additional_sensor_data sensor_data[] = {
+ .stream =
+ {0x0b, 0x04, 0x0a, 0x40},
+ },
+- { /* OM6802 */
+- .data1 =
+- {0xd0, 0xc2, 0xd1, 0x28, 0xd2, 0x0f, 0xd3, 0x22,
+- 0xd4, 0xcd, 0xd5, 0x27, 0xd6, 0x2c, 0xd7, 0x06,
+- 0xd8, 0xb3, 0xd9, 0xfc},
+- .data2 =
+- {0xe0, 0x80, 0xe1, 0xff, 0xe2, 0xff, 0xe3, 0x80,
+- 0xe4, 0xff, 0xe5, 0xff, 0xe6, 0x80, 0xe7, 0xff,
+- 0xe8, 0xff},
+- .data3 =
+- {0xc7, 0x80, 0xc8, 0xff, 0xc9, 0xff, 0xca, 0x80,
+- 0xcb, 0xff, 0xcc, 0xff, 0xcd, 0x80, 0xce, 0xff,
+- 0xcf, 0xff},
+- .data4 = /*Freq (50/60Hz). Splitted for test purpose */
+- {0x66, 0xca, 0xa8, 0xf0 },
+- .data5 = /* this could be removed later */
+- {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
+- .stream =
+- {0x0b, 0x04, 0x0a, 0x78},
+- }
+ };
+
+ #define MAX_EFFECTS 7
+ /* easily done by soft, this table could be removed,
+ * i keep it here just in case */
+-static const __u8 effects_table[MAX_EFFECTS][6] = {
++static const u8 effects_table[MAX_EFFECTS][6] = {
+ {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
+ {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
+ {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
+@@ -327,90 +330,58 @@ static const __u8 effects_table[MAX_EFFECTS][6] = {
+ {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
+ };
+
+-static const __u8 gamma_table[GAMMA_MAX][34] = {
+- {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85, /* 0 */
+- 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
+- 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
+- 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x33, 0x92, 0x5a, 0x93, 0x75, /* 1 */
+- 0x94, 0x85, 0x95, 0x93, 0x96, 0xa1, 0x97, 0xad,
+- 0x98, 0xb7, 0x99, 0xc2, 0x9a, 0xcb, 0x9b, 0xd4,
+- 0x9c, 0xde, 0x9D, 0xe7, 0x9e, 0xf0, 0x9f, 0xf7,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x2f, 0x92, 0x51, 0x93, 0x6b, /* 2 */
+- 0x94, 0x7c, 0x95, 0x8a, 0x96, 0x99, 0x97, 0xa6,
+- 0x98, 0xb1, 0x99, 0xbc, 0x9a, 0xc6, 0x9b, 0xd0,
+- 0x9c, 0xdb, 0x9d, 0xe4, 0x9e, 0xed, 0x9f, 0xf6,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60, /* 3 */
+- 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9e,
+- 0x98, 0xaa, 0x99, 0xb5, 0x9a, 0xbf, 0x9b, 0xcb,
+- 0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x23, 0x92, 0x3f, 0x93, 0x55, /* 4 */
+- 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
+- 0x98, 0xa2, 0x99, 0xad, 0x9a, 0xb9, 0x9b, 0xc6,
+- 0x9c, 0xd2, 0x9d, 0xde, 0x9e, 0xe9, 0x9f, 0xf4,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x1b, 0x92, 0x33, 0x93, 0x48, /* 5 */
+- 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
+- 0x98, 0x96, 0x99, 0xa3, 0x9a, 0xb1, 0x9b, 0xbe,
+- 0x9c, 0xcc, 0x9d, 0xda, 0x9e, 0xe7, 0x9f, 0xf3,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20, /* 6 */
+- 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
+- 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
+- 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26, /* 7 */
+- 0x94, 0x38, 0x95, 0x4a, 0x96, 0x60, 0x97, 0x70,
+- 0x98, 0x80, 0x99, 0x90, 0x9a, 0xa0, 0x9b, 0xb0,
+- 0x9c, 0xc0, 0x9D, 0xd0, 0x9e, 0xe0, 0x9f, 0xf0,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35, /* 8 */
+- 0x94, 0x47, 0x95, 0x5a, 0x96, 0x69, 0x97, 0x79,
+- 0x98, 0x88, 0x99, 0x97, 0x9a, 0xa7, 0x9b, 0xb6,
+- 0x9c, 0xc4, 0x9d, 0xd3, 0x9e, 0xe0, 0x9f, 0xf0,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40, /* 9 */
+- 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+- 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
+- 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x18, 0x92, 0x2b, 0x93, 0x44, /* 10 */
+- 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8e,
+- 0x98, 0x9c, 0x99, 0xaa, 0x9a, 0xb7, 0x9b, 0xc4,
+- 0x9c, 0xd0, 0x9d, 0xd8, 0x9e, 0xe2, 0x9f, 0xf0,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x1a, 0x92, 0x34, 0x93, 0x52, /* 11 */
+- 0x94, 0x66, 0x95, 0x7e, 0x96, 0x8D, 0x97, 0x9B,
+- 0x98, 0xa8, 0x99, 0xb4, 0x9a, 0xc0, 0x9b, 0xcb,
+- 0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x3f, 0x92, 0x5a, 0x93, 0x6e, /* 12 */
+- 0x94, 0x7f, 0x95, 0x8e, 0x96, 0x9c, 0x97, 0xa8,
+- 0x98, 0xb4, 0x99, 0xbf, 0x9a, 0xc9, 0x9b, 0xd3,
+- 0x9c, 0xdc, 0x9d, 0xe5, 0x9e, 0xee, 0x9f, 0xf6,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x54, 0x92, 0x6f, 0x93, 0x83, /* 13 */
+- 0x94, 0x93, 0x95, 0xa0, 0x96, 0xad, 0x97, 0xb7,
+- 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdc,
+- 0x9c, 0xe4, 0x9d, 0xeb, 0x9e, 0xf2, 0x9f, 0xf9,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x6e, 0x92, 0x88, 0x93, 0x9a, /* 14 */
+- 0x94, 0xa8, 0x95, 0xb3, 0x96, 0xbd, 0x97, 0xc6,
+- 0x98, 0xcf, 0x99, 0xd6, 0x9a, 0xdd, 0x9b, 0xe3,
+- 0x9c, 0xe9, 0x9d, 0xef, 0x9e, 0xf4, 0x9f, 0xfa,
+- 0xa0, 0xff},
+- {0x90, 0x00, 0x91, 0x93, 0x92, 0xa8, 0x93, 0xb7, /* 15 */
+- 0x94, 0xc1, 0x95, 0xca, 0x96, 0xd2, 0x97, 0xd8,
+- 0x98, 0xde, 0x99, 0xe3, 0x9a, 0xe8, 0x9b, 0xed,
+- 0x9c, 0xf1, 0x9d, 0xf5, 0x9e, 0xf8, 0x9f, 0xfc,
+- 0xa0, 0xff}
++static const u8 gamma_table[GAMMA_MAX][17] = {
++ {0x00, 0x3e, 0x69, 0x85, 0x95, 0xa1, 0xae, 0xb9, /* 0 */
++ 0xc2, 0xcb, 0xd4, 0xdb, 0xe3, 0xea, 0xf1, 0xf8,
++ 0xff},
++ {0x00, 0x33, 0x5a, 0x75, 0x85, 0x93, 0xa1, 0xad, /* 1 */
++ 0xb7, 0xc2, 0xcb, 0xd4, 0xde, 0xe7, 0xf0, 0xf7,
++ 0xff},
++ {0x00, 0x2f, 0x51, 0x6b, 0x7c, 0x8a, 0x99, 0xa6, /* 2 */
++ 0xb1, 0xbc, 0xc6, 0xd0, 0xdb, 0xe4, 0xed, 0xf6,
++ 0xff},
++ {0x00, 0x29, 0x48, 0x60, 0x72, 0x81, 0x90, 0x9e, /* 3 */
++ 0xaa, 0xb5, 0xbf, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
++ 0xff},
++ {0x00, 0x23, 0x3f, 0x55, 0x68, 0x77, 0x86, 0x95, /* 4 */
++ 0xa2, 0xad, 0xb9, 0xc6, 0xd2, 0xde, 0xe9, 0xf4,
++ 0xff},
++ {0x00, 0x1b, 0x33, 0x48, 0x59, 0x69, 0x79, 0x87, /* 5 */
++ 0x96, 0xa3, 0xb1, 0xbe, 0xcc, 0xda, 0xe7, 0xf3,
++ 0xff},
++ {0x00, 0x02, 0x10, 0x20, 0x32, 0x40, 0x57, 0x67, /* 6 */
++ 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
++ 0xff},
++ {0x00, 0x02, 0x14, 0x26, 0x38, 0x4a, 0x60, 0x70, /* 7 */
++ 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
++ 0xff},
++ {0x00, 0x10, 0x22, 0x35, 0x47, 0x5a, 0x69, 0x79, /* 8 */
++ 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe0, 0xf0,
++ 0xff},
++ {0x00, 0x10, 0x26, 0x40, 0x54, 0x65, 0x75, 0x84, /* 9 */
++ 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd6, 0xe0, 0xf0,
++ 0xff},
++ {0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e, /* 10 */
++ 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0,
++ 0xff},
++ {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8D, 0x9B, /* 11 */
++ 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
++ 0xff},
++ {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
++ 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
++ 0xff},
++ {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
++ 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
++ 0xff},
++ {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
++ 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
++ 0xff},
++ {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
++ 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
++ 0xff}
+ };
+
+-static const __u8 tas5130a_sensor_init[][8] = {
++static const u8 tas5130a_sensor_init[][8] = {
+ {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
+ {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
+ {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+@@ -418,11 +389,11 @@ static const __u8 tas5130a_sensor_init[][8] = {
+ {},
+ };
+
+-static __u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
++static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
+
+ /* read 1 byte */
+-static int reg_r(struct gspca_dev *gspca_dev,
+- __u16 index)
++static u8 reg_r(struct gspca_dev *gspca_dev,
++ u16 index)
+ {
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+@@ -435,7 +406,7 @@ static int reg_r(struct gspca_dev *gspca_dev,
+ }
+
+ static void reg_w(struct gspca_dev *gspca_dev,
+- __u16 index)
++ u16 index)
+ {
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+@@ -446,7 +417,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
+ }
+
+ static void reg_w_buf(struct gspca_dev *gspca_dev,
+- const __u8 *buffer, __u16 len)
++ const u8 *buffer, u16 len)
+ {
+ if (len <= USB_BUF_SZ) {
+ memcpy(gspca_dev->usb_buf, buffer, len);
+@@ -457,7 +428,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
+ 0x01, 0,
+ gspca_dev->usb_buf, len, 500);
+ } else {
+- __u8 *tmpbuf;
++ u8 *tmpbuf;
+
+ tmpbuf = kmalloc(len, GFP_KERNEL);
+ memcpy(tmpbuf, buffer, len);
+@@ -471,14 +442,41 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
+ }
+ }
+
++/* write values to consecutive registers */
++static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
++ u8 reg,
++ const u8 *buffer, u16 len)
++{
++ int i;
++ u8 *p, *tmpbuf;
++
++ if (len * 2 <= USB_BUF_SZ)
++ p = tmpbuf = gspca_dev->usb_buf;
++ else
++ p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
++ i = len;
++ while (--i >= 0) {
++ *p++ = reg++;
++ *p++ = *buffer++;
++ }
++ usb_control_msg(gspca_dev->dev,
++ usb_sndctrlpipe(gspca_dev->dev, 0),
++ 0,
++ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++ 0x01, 0,
++ tmpbuf, len * 2, 500);
++ if (len * 2 > USB_BUF_SZ)
++ kfree(tmpbuf);
++}
++
+ /* Reported as OM6802*/
+ static void om6802_sensor_init(struct gspca_dev *gspca_dev)
+ {
+ int i;
+- const __u8 *p;
+- __u8 byte;
+- __u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
+- static const __u8 sensor_init[] = {
++ const u8 *p;
++ u8 byte;
++ u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
++ static const u8 sensor_init[] = {
+ 0xdf, 0x6d,
+ 0xdd, 0x18,
+ 0x5a, 0xe0,
+@@ -497,7 +495,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev)
+ };
+
+ reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
+- msleep(5);
++ msleep(100);
+ i = 4;
+ while (--i > 0) {
+ byte = reg_r(gspca_dev, 0x0060);
+@@ -538,20 +536,20 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+
+ cam->cam_mode = vga_mode_t16;
+ cam->nmodes = ARRAY_SIZE(vga_mode_t16);
+
+- sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+- sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+- sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
++ sd->brightness = BRIGHTNESS_DEF;
++ sd->contrast = CONTRAST_DEF;
++ sd->colors = COLORS_DEF;
+ sd->gamma = GAMMA_DEF;
+- sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
+- sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
+- sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
+- sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+- sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value;
++ sd->autogain = AUTOGAIN_DEF;
++ sd->mirror = MIRROR_DEF;
++ sd->freq = FREQ_DEF;
++ sd->whitebalance = WHITE_BALANCE_DEF;
++ sd->sharpness = SHARPNESS_DEF;
++ sd->effect = EFFECTS_DEF;
+ return 0;
+ }
+
+@@ -559,7 +557,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned int brightness;
+- __u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
++ u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
+
+ brightness = sd->brightness;
+ if (brightness < 7) {
+@@ -576,7 +574,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned int contrast = sd->contrast;
+- __u16 reg_to_write;
++ u16 reg_to_write;
+
+ if (contrast < 7)
+ reg_to_write = 0x8ea9 - contrast * 0x200;
+@@ -589,7 +587,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
+ static void setcolors(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- __u16 reg_to_write;
++ u16 reg_to_write;
+
+ reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */
+ reg_w(gspca_dev, reg_to_write);
+@@ -600,14 +598,15 @@ static void setgamma(struct gspca_dev *gspca_dev)
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
+- reg_w_buf(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
++ reg_w_ixbuf(gspca_dev, 0x90,
++ gamma_table[sd->gamma], sizeof gamma_table[0]);
+ }
+
+ static void setwhitebalance(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- __u8 white_balance[8] =
++ u8 white_balance[8] =
+ {0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38};
+
+ if (sd->whitebalance)
+@@ -619,7 +618,7 @@ static void setwhitebalance(struct gspca_dev *gspca_dev)
+ static void setsharpness(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- __u16 reg_to_write;
++ u16 reg_to_write;
+
+ reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
+
+@@ -635,18 +634,22 @@ static int sd_init(struct gspca_dev *gspca_dev)
+ * to see the initial parameters.*/
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+- __u8 byte, test_byte;
+-
+- static const __u8 read_indexs[] =
+- { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
+- 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
+- static const __u8 n1[] =
++ u16 sensor_id;
++ u8 test_byte = 0;
++ u16 reg80, reg8e;
++
++ static const u8 read_indexs[] =
++ { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
++ 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
++ static const u8 n1[] =
+ {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
+- static const __u8 n2[] =
++ static const u8 n2[] =
+ {0x08, 0x00};
+- static const __u8 n3[] =
++ static const u8 n3[6] =
+ {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
+- static const __u8 n4[] =
++ static const u8 n3_other[6] =
++ {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00};
++ static const u8 n4[] =
+ {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
+ 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
+ 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
+@@ -656,40 +659,61 @@ static int sd_init(struct gspca_dev *gspca_dev)
+ 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
+ 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
+ 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
+- static const __u8 nset9[4] =
+- { 0x0b, 0x04, 0x0a, 0x78 };
+- static const __u8 nset8[6] =
++ static const u8 n4_other[] =
++ {0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
++ 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
++ 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
++ 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
++ 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
++ 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
++ 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
++ 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00};
++ static const u8 nset8[6] =
+ { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
+-
+- byte = reg_r(gspca_dev, 0x06);
+- test_byte = reg_r(gspca_dev, 0x07);
+- if (byte == 0x08 && test_byte == 0x07) {
+- PDEBUG(D_CONF, "sensor om6802");
+- sd->sensor = SENSOR_OM6802;
+- } else if (byte == 0x08 && test_byte == 0x01) {
+- PDEBUG(D_CONF, "sensor tas5130a");
+- sd->sensor = SENSOR_TAS5130A;
+- } else {
+- PDEBUG(D_CONF, "unknown sensor %02x %02x", byte, test_byte);
++ static const u8 nset8_other[6] =
++ { 0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00 };
++ static const u8 nset9[4] =
++ { 0x0b, 0x04, 0x0a, 0x78 };
++ static const u8 nset9_other[4] =
++ { 0x0b, 0x04, 0x0a, 0x00 };
++
++ sensor_id = (reg_r(gspca_dev, 0x06) << 8)
++ | reg_r(gspca_dev, 0x07);
++ switch (sensor_id & 0xff0f) {
++ case 0x0801:
++ PDEBUG(D_PROBE, "sensor tas5130a");
+ sd->sensor = SENSOR_TAS5130A;
++ break;
++ case 0x0803:
++ PDEBUG(D_PROBE, "sensor 'other'");
++ sd->sensor = SENSOR_OTHER;
++ break;
++ case 0x0807:
++ PDEBUG(D_PROBE, "sensor om6802");
++ sd->sensor = SENSOR_OM6802;
++ break;
++ default:
++ PDEBUG(D_ERR|D_PROBE, "unknown sensor %04x", sensor_id);
++ return -EINVAL;
+ }
+
+- reg_w_buf(gspca_dev, n1, sizeof n1);
+- test_byte = 0;
+- i = 5;
+- while (--i >= 0) {
+- reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
+- test_byte = reg_r(gspca_dev, 0x0063);
+- msleep(100);
+- if (test_byte == 0x17)
+- break; /* OK */
+- }
+- if (i < 0) {
+- err("Bad sensor reset %02x", test_byte);
+-/* return -EIO; */
++ if (sd->sensor != SENSOR_OTHER) {
++ reg_w_buf(gspca_dev, n1, sizeof n1);
++ i = 5;
++ while (--i >= 0) {
++ reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
++ test_byte = reg_r(gspca_dev, 0x0063);
++ msleep(100);
++ if (test_byte == 0x17)
++ break; /* OK */
++ }
++ if (i < 0) {
++ err("Bad sensor reset %02x", test_byte);
++/* return -EIO; */
+ /*fixme: test - continue */
++ }
++ reg_w_buf(gspca_dev, n2, sizeof n2);
+ }
+- reg_w_buf(gspca_dev, n2, sizeof n2);
+
+ i = 0;
+ while (read_indexs[i] != 0x00) {
+@@ -699,21 +723,31 @@ static int sd_init(struct gspca_dev *gspca_dev)
+ i++;
+ }
+
+- reg_w_buf(gspca_dev, n3, sizeof n3);
+- reg_w_buf(gspca_dev, n4, sizeof n4);
+- reg_r(gspca_dev, 0x0080);
+- reg_w(gspca_dev, 0x2c80);
++ if (sd->sensor != SENSOR_OTHER) {
++ reg_w_buf(gspca_dev, n3, sizeof n3);
++ reg_w_buf(gspca_dev, n4, sizeof n4);
++ reg_r(gspca_dev, 0x0080);
++ reg_w(gspca_dev, 0x2c80);
++ reg80 = 0x3880;
++ reg8e = 0x338e;
++ } else {
++ reg_w_buf(gspca_dev, n3_other, sizeof n3_other);
++ reg_w_buf(gspca_dev, n4_other, sizeof n4_other);
++ sd->gamma = 5;
++ reg80 = 0xac80;
++ reg8e = 0xb88e;
++ }
+
+- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data1,
++ reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
+ sizeof sensor_data[sd->sensor].data1);
+- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
+- sizeof sensor_data[sd->sensor].data3);
+- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
++ reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
++ sizeof sensor_data[sd->sensor].data2);
++ reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
+ sizeof sensor_data[sd->sensor].data2);
+
+- reg_w(gspca_dev, 0x3880);
+- reg_w(gspca_dev, 0x3880);
+- reg_w(gspca_dev, 0x338e);
++ reg_w(gspca_dev, reg80);
++ reg_w(gspca_dev, reg80);
++ reg_w(gspca_dev, reg8e);
+
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+@@ -730,16 +764,20 @@ static int sd_init(struct gspca_dev *gspca_dev)
+ sizeof sensor_data[sd->sensor].data4);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data5,
+ sizeof sensor_data[sd->sensor].data5);
+- reg_w_buf(gspca_dev, nset8, sizeof nset8);
+- reg_w_buf(gspca_dev, nset9, sizeof nset9);
+-
+- reg_w(gspca_dev, 0x2880);
++ if (sd->sensor != SENSOR_OTHER) {
++ reg_w_buf(gspca_dev, nset8, sizeof nset8);
++ reg_w_buf(gspca_dev, nset9, sizeof nset9);
++ reg_w(gspca_dev, 0x2880);
++ } else {
++ reg_w_buf(gspca_dev, nset8_other, sizeof nset8_other);
++ reg_w_buf(gspca_dev, nset9_other, sizeof nset9_other);
++ }
+
+- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data1,
++ reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
+ sizeof sensor_data[sd->sensor].data1);
+- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
+- sizeof sensor_data[sd->sensor].data3);
+- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
++ reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
++ sizeof sensor_data[sd->sensor].data2);
++ reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
+ sizeof sensor_data[sd->sensor].data2);
+
+ return 0;
+@@ -748,7 +786,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
+ static void setflip(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- __u8 flipcmd[8] =
++ u8 flipcmd[8] =
+ {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
+
+ if (sd->mirror)
+@@ -778,7 +816,7 @@ static void seteffect(struct gspca_dev *gspca_dev)
+ static void setlightfreq(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- __u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
++ u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
+
+ if (sd->freq == 2) /* 60hz */
+ freq[1] = 0x00;
+@@ -791,22 +829,22 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
+ static void poll_sensor(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- static const __u8 poll1[] =
++ static const u8 poll1[] =
+ {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
+ 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
+ 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
+ 0x60, 0x14};
+- static const __u8 poll2[] =
++ static const u8 poll2[] =
+ {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
+ 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
+- static const __u8 poll3[] =
++ static const u8 poll3[] =
+ {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
+- static const __u8 poll4[] =
++ static const u8 poll4[] =
+ {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
+ 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
+ 0xc2, 0x80, 0xc3, 0x10};
+
+- if (sd->sensor != SENSOR_TAS5130A) {
++ if (sd->sensor == SENSOR_OM6802) {
+ PDEBUG(D_STREAM, "[Sensor requires polling]");
+ reg_w_buf(gspca_dev, poll1, sizeof poll1);
+ reg_w_buf(gspca_dev, poll2, sizeof poll2);
+@@ -819,13 +857,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, mode;
+- __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
+- static const __u8 t3[] =
+- { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
+- 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
++ u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
++ static const u8 t3[] =
++ { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+ switch (mode) {
++ case 0: /* 640x480 (0x00) */
++ break;
+ case 1: /* 352x288 */
+ t2[1] = 0x40;
+ break;
+@@ -835,14 +874,20 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ case 3: /* 176x144 */
+ t2[1] = 0x50;
+ break;
+- case 4: /* 160x120 */
++ default:
++/* case 4: * 160x120 */
+ t2[1] = 0x20;
+ break;
+- default: /* 640x480 (0x00) */
+- break;
+ }
+
+- if (sd->sensor == SENSOR_TAS5130A) {
++ switch (sd->sensor) {
++ case SENSOR_OM6802:
++ om6802_sensor_init(gspca_dev);
++ break;
++ case SENSOR_OTHER:
++ break;
++ default:
++/* case SENSOR_TAS5130A: */
+ i = 0;
+ while (tas5130a_sensor_init[i][0] != 0) {
+ reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
+@@ -854,14 +899,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ reg_w_buf(gspca_dev, tas5130a_sensor_init[3],
+ sizeof tas5130a_sensor_init[0]);
+ reg_w(gspca_dev, 0x3c80);
+- } else {
+- om6802_sensor_init(gspca_dev);
++ break;
+ }
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
+ sizeof sensor_data[sd->sensor].data4);
+ reg_r(gspca_dev, 0x0012);
+ reg_w_buf(gspca_dev, t2, sizeof t2);
+- reg_w_buf(gspca_dev, t3, sizeof t3);
++ reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
+ reg_w(gspca_dev, 0x0013);
+ msleep(15);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
+@@ -885,16 +929,18 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
+ msleep(20);
+ reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
+ sizeof sensor_data[sd->sensor].stream);
+- msleep(20);
+- reg_w(gspca_dev, 0x0309);
++ if (sd->sensor != SENSOR_OTHER) {
++ msleep(20);
++ reg_w(gspca_dev, 0x0309);
++ }
+ }
+
+ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+- __u8 *data, /* isoc packet */
++ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+ {
+- static __u8 ffd9[] = { 0xff, 0xd9 };
++ static u8 ffd9[] = { 0xff, 0xd9 };
+
+ if (data[0] == 0x5a) {
+ /* Control Packet, after this came the header again,
+@@ -1172,8 +1218,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
+index 94163cc..9f243d7 100644
+--- a/drivers/media/video/gspca/tv8532.c
++++ b/drivers/media/video/gspca/tv8532.c
+@@ -31,7 +31,6 @@ struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ __u16 brightness;
+- __u16 contrast;
+
+ __u8 packet;
+ };
+@@ -39,38 +38,22 @@ struct sd {
+ /* V4L2 controls supported by the driver */
+ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+ static struct ctrl sd_ctrls[] = {
+-#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 1,
+- .maximum = 0x2ff,
++ .maximum = 0x15f, /* = 352 - 1 */
+ .step = 1,
+- .default_value = 0x18f,
++#define BRIGHTNESS_DEF 0x14c
++ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+-#define SD_CONTRAST 1
+- {
+- {
+- .id = V4L2_CID_CONTRAST,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "Contrast",
+- .minimum = 0,
+- .maximum = 0xffff,
+- .step = 1,
+- .default_value = 0x7fff,
+- },
+- .set = sd_setcontrast,
+- .get = sd_getcontrast,
+- },
+ };
+
+ static const struct v4l2_pix_format sif_mode[] = {
+@@ -86,78 +69,64 @@ static const struct v4l2_pix_format sif_mode[] = {
+ .priv = 0},
+ };
+
+-/*
+- * Initialization data: this is the first set-up data written to the
+- * device (before the open data).
+- */
+-#define TESTCLK 0x10 /* reg 0x2c -> 0x12 //10 */
+-#define TESTCOMP 0x90 /* reg 0x28 -> 0x80 */
+-#define TESTLINE 0x81 /* reg 0x29 -> 0x81 */
+-#define QCIFLINE 0x41 /* reg 0x29 -> 0x81 */
+-#define TESTPTL 0x14 /* reg 0x2D -> 0x14 */
+-#define TESTPTH 0x01 /* reg 0x2E -> 0x01 */
+-#define TESTPTBL 0x12 /* reg 0x2F -> 0x0a */
+-#define TESTPTBH 0x01 /* reg 0x30 -> 0x01 */
+-#define ADWIDTHL 0xe8 /* reg 0x0c -> 0xe8 */
+-#define ADWIDTHH 0x03 /* reg 0x0d -> 0x03 */
+-#define ADHEIGHL 0x90 /* reg 0x0e -> 0x91 //93 */
+-#define ADHEIGHH 0x01 /* reg 0x0f -> 0x01 */
+-#define EXPOL 0x8f /* reg 0x1c -> 0x8f */
+-#define EXPOH 0x01 /* reg 0x1d -> 0x01 */
+-#define ADCBEGINL 0x44 /* reg 0x10 -> 0x46 //47 */
+-#define ADCBEGINH 0x00 /* reg 0x11 -> 0x00 */
+-#define ADRBEGINL 0x0a /* reg 0x14 -> 0x0b //0x0c */
+-#define ADRBEGINH 0x00 /* reg 0x15 -> 0x00 */
+-#define TV8532_CMD_UPDATE 0x84
+-
+-#define TV8532_EEprom_Add 0x03
+-#define TV8532_EEprom_DataL 0x04
+-#define TV8532_EEprom_DataM 0x05
+-#define TV8532_EEprom_DataH 0x06
+-#define TV8532_EEprom_TableLength 0x07
+-#define TV8532_EEprom_Write 0x08
+-#define TV8532_PART_CTRL 0x00
+-#define TV8532_CTRL 0x01
+-#define TV8532_CMD_EEprom_Open 0x30
+-#define TV8532_CMD_EEprom_Close 0x29
+-#define TV8532_UDP_UPDATE 0x31
+-#define TV8532_GPIO 0x39
+-#define TV8532_GPIO_OE 0x3B
+-#define TV8532_REQ_RegWrite 0x02
+-#define TV8532_REQ_RegRead 0x03
+-
+-#define TV8532_ADWIDTH_L 0x0C
+-#define TV8532_ADWIDTH_H 0x0D
+-#define TV8532_ADHEIGHT_L 0x0E
+-#define TV8532_ADHEIGHT_H 0x0F
+-#define TV8532_EXPOSURE 0x1C
+-#define TV8532_QUANT_COMP 0x28
+-#define TV8532_MODE_PACKET 0x29
+-#define TV8532_SETCLK 0x2C
+-#define TV8532_POINT_L 0x2D
+-#define TV8532_POINT_H 0x2E
+-#define TV8532_POINTB_L 0x2F
+-#define TV8532_POINTB_H 0x30
+-#define TV8532_BUDGET_L 0x2A
+-#define TV8532_BUDGET_H 0x2B
+-#define TV8532_VID_L 0x34
+-#define TV8532_VID_H 0x35
+-#define TV8532_PID_L 0x36
+-#define TV8532_PID_H 0x37
+-#define TV8532_DeviceID 0x83
+-#define TV8532_AD_SLOPE 0x91
+-#define TV8532_AD_BITCTRL 0x94
+-#define TV8532_AD_COLBEGIN_L 0x10
+-#define TV8532_AD_COLBEGIN_H 0x11
+-#define TV8532_AD_ROWBEGIN_L 0x14
+-#define TV8532_AD_ROWBEGIN_H 0x15
+-
+-static const __u32 tv_8532_eeprom_data[] = {
+-/* add dataL dataM dataH */
+- 0x00010001, 0x01018011, 0x02050014, 0x0305001c,
+- 0x040d001e, 0x0505001f, 0x06050519, 0x0705011b,
+- 0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9,
+- 0x0c0509f1, 0
++/* TV-8532A (ICM532A) registers (LE) */
++#define R00_PART_CONTROL 0x00
++#define LATENT_CHANGE 0x80
++#define EXPO_CHANGE 0x04
++#define R01_TIMING_CONTROL_LOW 0x01
++#define CMD_EEprom_Open 0x30
++#define CMD_EEprom_Close 0x29
++#define R03_TABLE_ADDR 0x03
++#define R04_WTRAM_DATA_L 0x04
++#define R05_WTRAM_DATA_M 0x05
++#define R06_WTRAM_DATA_H 0x06
++#define R07_TABLE_LEN 0x07
++#define R08_RAM_WRITE_ACTION 0x08
++#define R0C_AD_WIDTHL 0x0c
++#define R0D_AD_WIDTHH 0x0d
++#define R0E_AD_HEIGHTL 0x0e
++#define R0F_AD_HEIGHTH 0x0f
++#define R10_AD_COL_BEGINL 0x10
++#define R11_AD_COL_BEGINH 0x11
++#define MIRROR 0x04 /* [10] */
++#define R14_AD_ROW_BEGINL 0x14
++#define R15_AD_ROWBEGINH 0x15
++#define R1C_AD_EXPOSE_TIMEL 0x1c
++#define R28_QUANT 0x28
++#define R29_LINE 0x29
++#define R2C_POLARITY 0x2c
++#define R2D_POINT 0x2d
++#define R2E_POINTH 0x2e
++#define R2F_POINTB 0x2f
++#define R30_POINTBH 0x30
++#define R31_UPD 0x31
++#define R2A_HIGH_BUDGET 0x2a
++#define R2B_LOW_BUDGET 0x2b
++#define R34_VID 0x34
++#define R35_VIDH 0x35
++#define R36_PID 0x36
++#define R37_PIDH 0x37
++#define R39_Test1 0x39 /* GPIO */
++#define R3B_Test3 0x3B /* GPIO */
++#define R83_AD_IDH 0x83
++#define R91_AD_SLOPEREG 0x91
++#define R94_AD_BITCONTROL 0x94
++
++static const u8 eeprom_data[][3] = {
++/* dataH dataM dataL */
++ {0x01, 0x00, 0x01},
++ {0x01, 0x80, 0x11},
++ {0x05, 0x00, 0x14},
++ {0x05, 0x00, 0x1c},
++ {0x0d, 0x00, 0x1e},
++ {0x05, 0x00, 0x1f},
++ {0x05, 0x05, 0x19},
++ {0x05, 0x01, 0x1b},
++ {0x05, 0x09, 0x1e},
++ {0x0d, 0x89, 0x2e},
++ {0x05, 0x89, 0x2f},
++ {0x05, 0x0d, 0xd9},
++ {0x05, 0x09, 0xf1},
+ };
+
+ static int reg_r(struct gspca_dev *gspca_dev,
+@@ -165,7 +134,7 @@ static int reg_r(struct gspca_dev *gspca_dev,
+ {
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+- TV8532_REQ_RegRead,
++ 0x03,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, 1,
+@@ -174,27 +143,27 @@ static int reg_r(struct gspca_dev *gspca_dev,
+ }
+
+ /* write 1 byte */
+-static void reg_w_1(struct gspca_dev *gspca_dev,
++static void reg_w1(struct gspca_dev *gspca_dev,
+ __u16 index, __u8 value)
+ {
+ gspca_dev->usb_buf[0] = value;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+- TV8532_REQ_RegWrite,
++ 0x02,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, 1, 500);
+ }
+
+ /* write 2 bytes */
+-static void reg_w_2(struct gspca_dev *gspca_dev,
+- __u16 index, __u8 val1, __u8 val2)
++static void reg_w2(struct gspca_dev *gspca_dev,
++ u16 index, u16 value)
+ {
+- gspca_dev->usb_buf[0] = val1;
+- gspca_dev->usb_buf[1] = val2;
++ gspca_dev->usb_buf[0] = value;
++ gspca_dev->usb_buf[1] = value >> 8;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+- TV8532_REQ_RegWrite,
++ 0x02,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, gspca_dev->usb_buf, 2, 500);
+@@ -202,32 +171,18 @@ static void reg_w_2(struct gspca_dev *gspca_dev,
+
+ static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
+ {
+- int i = 0;
+- __u8 reg, data0, data1, data2;
+-
+- reg_w_1(gspca_dev, TV8532_GPIO, 0xb0);
+- reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Open);
+-/* msleep(1); */
+- while (tv_8532_eeprom_data[i]) {
+- reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24;
+- reg_w_1(gspca_dev, TV8532_EEprom_Add, reg);
+- /* msleep(1); */
+- data0 = (tv_8532_eeprom_data[i] & 0x000000ff);
+- reg_w_1(gspca_dev, TV8532_EEprom_DataL, data0);
+- /* msleep(1); */
+- data1 = (tv_8532_eeprom_data[i] & 0x0000ff00) >> 8;
+- reg_w_1(gspca_dev, TV8532_EEprom_DataM, data1);
+- /* msleep(1); */
+- data2 = (tv_8532_eeprom_data[i] & 0x00ff0000) >> 16;
+- reg_w_1(gspca_dev, TV8532_EEprom_DataH, data2);
+- /* msleep(1); */
+- reg_w_1(gspca_dev, TV8532_EEprom_Write, 0);
+- /* msleep(10); */
+- i++;
++ int i;
++
++ reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Open);
++ for (i = 0; i < ARRAY_SIZE(eeprom_data); i++) {
++ reg_w1(gspca_dev, R03_TABLE_ADDR, i);
++ reg_w1(gspca_dev, R04_WTRAM_DATA_L, eeprom_data[i][2]);
++ reg_w1(gspca_dev, R05_WTRAM_DATA_M, eeprom_data[i][1]);
++ reg_w1(gspca_dev, R06_WTRAM_DATA_H, eeprom_data[i][0]);
++ reg_w1(gspca_dev, R08_RAM_WRITE_ACTION, 0);
+ }
+- reg_w_1(gspca_dev, TV8532_EEprom_TableLength, i);
+-/* msleep(1); */
+- reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Close);
++ reg_w1(gspca_dev, R07_TABLE_LEN, i);
++ reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
+ msleep(10);
+ }
+
+@@ -238,79 +193,76 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+- tv_8532WriteEEprom(gspca_dev);
+-
+ cam = &gspca_dev->cam;
+- cam->epaddr = 1;
+ cam->cam_mode = sif_mode;
+- cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
++ cam->nmodes = ARRAY_SIZE(sif_mode);
+
+- sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+- sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
++ sd->brightness = BRIGHTNESS_DEF;
+ return 0;
+ }
+
+ static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
+ {
+- __u8 data;
+-
+- data = reg_r(gspca_dev, 0x0001);
+- PDEBUG(D_USBI, "register 0x01-> %x", data);
+- data = reg_r(gspca_dev, 0x0002);
+- PDEBUG(D_USBI, "register 0x02-> %x", data);
+- reg_r(gspca_dev, TV8532_ADWIDTH_L);
+- reg_r(gspca_dev, TV8532_ADWIDTH_H);
+- reg_r(gspca_dev, TV8532_QUANT_COMP);
+- reg_r(gspca_dev, TV8532_MODE_PACKET);
+- reg_r(gspca_dev, TV8532_SETCLK);
+- reg_r(gspca_dev, TV8532_POINT_L);
+- reg_r(gspca_dev, TV8532_POINT_H);
+- reg_r(gspca_dev, TV8532_POINTB_L);
+- reg_r(gspca_dev, TV8532_POINTB_H);
+- reg_r(gspca_dev, TV8532_BUDGET_L);
+- reg_r(gspca_dev, TV8532_BUDGET_H);
+- reg_r(gspca_dev, TV8532_VID_L);
+- reg_r(gspca_dev, TV8532_VID_H);
+- reg_r(gspca_dev, TV8532_PID_L);
+- reg_r(gspca_dev, TV8532_PID_H);
+- reg_r(gspca_dev, TV8532_DeviceID);
+- reg_r(gspca_dev, TV8532_AD_COLBEGIN_L);
+- reg_r(gspca_dev, TV8532_AD_COLBEGIN_H);
+- reg_r(gspca_dev, TV8532_AD_ROWBEGIN_L);
+- reg_r(gspca_dev, TV8532_AD_ROWBEGIN_H);
++ int i;
++ static u8 reg_tb[] = {
++ R0C_AD_WIDTHL,
++ R0D_AD_WIDTHH,
++ R28_QUANT,
++ R29_LINE,
++ R2C_POLARITY,
++ R2D_POINT,
++ R2E_POINTH,
++ R2F_POINTB,
++ R30_POINTBH,
++ R2A_HIGH_BUDGET,
++ R2B_LOW_BUDGET,
++ R34_VID,
++ R35_VIDH,
++ R36_PID,
++ R37_PIDH,
++ R83_AD_IDH,
++ R10_AD_COL_BEGINL,
++ R11_AD_COL_BEGINH,
++ R14_AD_ROW_BEGINL,
++ R15_AD_ROWBEGINH,
++ 0
++ };
++
++ i = 0;
++ do {
++ reg_r(gspca_dev, reg_tb[i]);
++ i++;
++ } while (reg_tb[i] != 0);
+ }
+
+ static void tv_8532_setReg(struct gspca_dev *gspca_dev)
+ {
+- reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L,
+- ADCBEGINL); /* 0x10 */
+- reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H,
+- ADCBEGINH); /* also digital gain */
+- reg_w_1(gspca_dev, TV8532_PART_CTRL,
+- TV8532_CMD_UPDATE); /* 0x00<-0x84 */
+-
+- reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0a);
++ reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
++ /* begin active line */
++ reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
++ /* mirror and digital gain */
++ reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
++ /* = 0x84 */
++
++ reg_w1(gspca_dev, R3B_Test3, 0x0a); /* Test0Sel = 10 */
+ /******************************************************/
+- reg_w_1(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL); /* 0e */
+- reg_w_1(gspca_dev, TV8532_ADHEIGHT_H, ADHEIGHH); /* 0f */
+- reg_w_2(gspca_dev, TV8532_EXPOSURE,
+- EXPOL, EXPOH); /* 350d 0x014c; 1c */
+- reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L,
+- ADCBEGINL); /* 0x10 */
+- reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H,
+- ADCBEGINH); /* also digital gain */
+- reg_w_1(gspca_dev, TV8532_AD_ROWBEGIN_L,
+- ADRBEGINL); /* 0x14 */
+-
+- reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00); /* 0x91 */
+- reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x02); /* 0x94 */
+-
+- reg_w_1(gspca_dev, TV8532_CTRL,
+- TV8532_CMD_EEprom_Close); /* 0x01 */
+-
+- reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00); /* 0x91 */
+- reg_w_1(gspca_dev, TV8532_PART_CTRL,
+- TV8532_CMD_UPDATE); /* 0x00<-0x84 */
++ reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90);
++ reg_w1(gspca_dev, R0F_AD_HEIGHTH, 0x01);
++ reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
++ reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
++ /* begin active line */
++ reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
++ /* mirror and digital gain */
++ reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a);
++
++ reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
++ reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02);
++
++ reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
++
++ reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
++ reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
++ /* = 0x84 */
+ }
+
+ static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
+@@ -319,54 +271,55 @@ static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
+
+ /* strange polling from tgc */
+ for (i = 0; i < 10; i++) {
+- reg_w_1(gspca_dev, TV8532_SETCLK,
+- TESTCLK); /* 0x48; //0x08; 0x2c */
+- reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+- reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */
++ reg_w1(gspca_dev, R2C_POLARITY, 0x10);
++ reg_w1(gspca_dev, R00_PART_CONTROL,
++ LATENT_CHANGE | EXPO_CHANGE);
++ reg_w1(gspca_dev, R31_UPD, 0x01);
+ }
+ }
+
+ /* this function is called at probe and resume time */
+ static int sd_init(struct gspca_dev *gspca_dev)
+ {
+- reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
+- reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
++ tv_8532WriteEEprom(gspca_dev);
++
++ reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V,
++ * slope rate 2 */
++ reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
+ tv_8532ReadRegisters(gspca_dev);
+- reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+- reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL,
+- ADHEIGHH); /* 401d 0x0169; 0e */
+- reg_w_2(gspca_dev, TV8532_EXPOSURE, EXPOL,
+- EXPOH); /* 350d 0x014c; 1c */
+- reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */
+- reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */
++ reg_w1(gspca_dev, R3B_Test3, 0x0b);
++ reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
++ reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
++ reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);
++ reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
+
+ /*******************************************************************/
+- reg_w_1(gspca_dev, TV8532_QUANT_COMP,
+- TESTCOMP); /* 0x72 compressed mode 0x28 */
+- reg_w_1(gspca_dev, TV8532_MODE_PACKET,
+- TESTLINE); /* 0x84; // CIF | 4 packet 0x29 */
++ reg_w1(gspca_dev, R28_QUANT, 0x90);
++ /* no compress - fixed Q - quant 0 */
++ reg_w1(gspca_dev, R29_LINE, 0x81);
++ /* 0x84; // CIF | 4 packet 0x29 */
+
+ /************************************************/
+- reg_w_1(gspca_dev, TV8532_SETCLK,
+- TESTCLK); /* 0x48; //0x08; 0x2c */
+- reg_w_1(gspca_dev, TV8532_POINT_L,
+- TESTPTL); /* 0x38; 0x2d */
+- reg_w_1(gspca_dev, TV8532_POINT_H,
+- TESTPTH); /* 0x04; 0x2e */
+- reg_w_1(gspca_dev, TV8532_POINTB_L,
+- TESTPTBL); /* 0x04; 0x2f */
+- reg_w_1(gspca_dev, TV8532_POINTB_H,
+- TESTPTBH); /* 0x04; 0x30 */
+- reg_w_1(gspca_dev, TV8532_PART_CTRL,
+- TV8532_CMD_UPDATE); /* 0x00<-0x84 */
++ reg_w1(gspca_dev, R2C_POLARITY, 0x10);
++ /* 0x48; //0x08; 0x2c */
++ reg_w1(gspca_dev, R2D_POINT, 0x14);
++ /* 0x38; 0x2d */
++ reg_w1(gspca_dev, R2E_POINTH, 0x01);
++ /* 0x04; 0x2e */
++ reg_w1(gspca_dev, R2F_POINTB, 0x12);
++ /* 0x04; 0x2f */
++ reg_w1(gspca_dev, R30_POINTBH, 0x01);
++ /* 0x04; 0x30 */
++ reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
++ /* 0x00<-0x84 */
+ /*************************************************/
+- reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */
++ reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */
+ msleep(200);
+- reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */
++ reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
+ /*************************************************/
+ tv_8532_setReg(gspca_dev);
+ /*************************************************/
+- reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
++ reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */
+ /*************************************************/
+ tv_8532_setReg(gspca_dev);
+ /*************************************************/
+@@ -377,11 +330,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
+ static void setbrightness(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- int brightness = sd->brightness;
+
+- reg_w_2(gspca_dev, TV8532_EXPOSURE,
+- brightness >> 8, brightness); /* 1c */
+- reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
++ reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->brightness);
++ reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
++ /* 0x84 */
+ }
+
+ /* -- start the camera -- */
+@@ -389,57 +341,50 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
+- reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
+- reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
++ reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V,
++ * slope rate 2 */
++ reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
+ tv_8532ReadRegisters(gspca_dev);
+- reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+- reg_w_2(gspca_dev, TV8532_ADHEIGHT_L,
+- ADHEIGHL, ADHEIGHH); /* 401d 0x0169; 0e */
+-/* reg_w_2(gspca_dev, TV8532_EXPOSURE,
+- EXPOL, EXPOH); * 350d 0x014c; 1c */
++ reg_w1(gspca_dev, R3B_Test3, 0x0b);
++
++ reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
+ setbrightness(gspca_dev);
+
+- reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */
+- reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */
++ reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); /* 0x20; 0x0c */
++ reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
+
+ /************************************************/
+- reg_w_1(gspca_dev, TV8532_QUANT_COMP,
+- TESTCOMP); /* 0x72 compressed mode 0x28 */
++ reg_w1(gspca_dev, R28_QUANT, 0x90);
++ /* 0x72 compressed mode 0x28 */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ /* 176x144 */
+- reg_w_1(gspca_dev, TV8532_MODE_PACKET,
+- QCIFLINE); /* 0x84; // CIF | 4 packet 0x29 */
++ reg_w1(gspca_dev, R29_LINE, 0x41);
++ /* CIF - 2 lines/packet */
+ } else {
+ /* 352x288 */
+- reg_w_1(gspca_dev, TV8532_MODE_PACKET,
+- TESTLINE); /* 0x84; // CIF | 4 packet 0x29 */
++ reg_w1(gspca_dev, R29_LINE, 0x81);
++ /* CIF - 2 lines/packet */
+ }
+ /************************************************/
+- reg_w_1(gspca_dev, TV8532_SETCLK,
+- TESTCLK); /* 0x48; //0x08; 0x2c */
+- reg_w_1(gspca_dev, TV8532_POINT_L,
+- TESTPTL); /* 0x38; 0x2d */
+- reg_w_1(gspca_dev, TV8532_POINT_H,
+- TESTPTH); /* 0x04; 0x2e */
+- reg_w_1(gspca_dev, TV8532_POINTB_L,
+- TESTPTBL); /* 0x04; 0x2f */
+- reg_w_1(gspca_dev, TV8532_POINTB_H,
+- TESTPTBH); /* 0x04; 0x30 */
+- reg_w_1(gspca_dev, TV8532_PART_CTRL,
+- TV8532_CMD_UPDATE); /* 0x00<-0x84 */
++ reg_w1(gspca_dev, R2C_POLARITY, 0x10); /* slow clock */
++ reg_w1(gspca_dev, R2D_POINT, 0x14);
++ reg_w1(gspca_dev, R2E_POINTH, 0x01);
++ reg_w1(gspca_dev, R2F_POINTB, 0x12);
++ reg_w1(gspca_dev, R30_POINTBH, 0x01);
++ reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
+ /************************************************/
+- reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */
++ reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */
+ msleep(200);
+- reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */
++ reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
+ /************************************************/
+ tv_8532_setReg(gspca_dev);
+ /************************************************/
+- reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
++ reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */
+ /************************************************/
+ tv_8532_setReg(gspca_dev);
+ /************************************************/
+ tv_8532_PollReg(gspca_dev);
+- reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */
++ reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
+
+ gspca_dev->empty_packet = 0; /* check the empty packets */
+ sd->packet = 0; /* ignore the first packets */
+@@ -449,7 +394,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
+
+ static void sd_stopN(struct gspca_dev *gspca_dev)
+ {
+- reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
++ reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */
+ }
+
+ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+@@ -473,9 +418,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+
+ /* each packet contains:
+ * - header 2 bytes
+- * - RG line
++ * - RGRG line
+ * - 4 bytes
+- * - GB line
++ * - GBGB line
+ * - 4 bytes
+ */
+ gspca_frame_add(gspca_dev, packet_type0,
+@@ -484,10 +429,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ frame, data + gspca_dev->width + 6, gspca_dev->width);
+ }
+
+-static void setcontrast(struct gspca_dev *gspca_dev)
+-{
+-}
+-
+ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+@@ -506,24 +447,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+ return 0;
+ }
+
+-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- sd->contrast = val;
+- if (gspca_dev->streaming)
+- setcontrast(gspca_dev);
+- return 0;
+-}
+-
+-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+-{
+- struct sd *sd = (struct sd *) gspca_dev;
+-
+- *val = sd->contrast;
+- return 0;
+-}
+-
+ /* sub-driver description */
+ static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+@@ -570,8 +493,10 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
+index 0525ea5..4c802fb 100644
+--- a/drivers/media/video/gspca/vc032x.c
++++ b/drivers/media/video/gspca/vc032x.c
+@@ -37,18 +37,21 @@ struct sd {
+ __u8 lightfreq;
+ __u8 sharpness;
+
++ u8 image_offset;
++
+ char bridge;
+ #define BRIDGE_VC0321 0
+ #define BRIDGE_VC0323 1
+ char sensor;
+ #define SENSOR_HV7131R 0
+ #define SENSOR_MI0360 1
+-#define SENSOR_MI1320 2
+-#define SENSOR_MI1310_SOC 3
+-#define SENSOR_OV7660 4
+-#define SENSOR_OV7670 5
+-#define SENSOR_PO1200 6
+-#define SENSOR_PO3130NC 7
++#define SENSOR_MI1310_SOC 2
++#define SENSOR_MI1320 3
++#define SENSOR_MI1320_SOC 4
++#define SENSOR_OV7660 5
++#define SENSOR_OV7670 6
++#define SENSOR_PO1200 7
++#define SENSOR_PO3130NC 8
+ };
+
+ /* V4L2 controls supported by the driver */
+@@ -149,8 +152,50 @@ static const struct v4l2_pix_format vc0323_mode[] = {
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
++ {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi13x0_soc only */
++ .bytesperline = 1280,
++ .sizeimage = 1280 * 1024 * 1 / 4 + 590,
++ .colorspace = V4L2_COLORSPACE_JPEG,
++ .priv = 2},
++};
++static const struct v4l2_pix_format bi_mode[] = {
++/*fixme: jeg does not work
++ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
++ .bytesperline = 320,
++ .sizeimage = 320 * 240 * 3 / 8 + 590,
++ .colorspace = V4L2_COLORSPACE_JPEG,
++ .priv = 5},
++*/
++ {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
++ .bytesperline = 320,
++ .sizeimage = 320 * 240 * 2,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 4},
++/*
++ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
++ .bytesperline = 640,
++ .sizeimage = 640 * 480 * 3 / 8 + 590,
++ .colorspace = V4L2_COLORSPACE_JPEG,
++ .priv = 3},
++*/
++ {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
++ .bytesperline = 640,
++ .sizeimage = 640 * 480 * 2,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 2},
++/*
++ {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
++ .bytesperline = 1280,
++ .sizeimage = 1280 * 1024 * 1 / 4 + 590,
++ .colorspace = V4L2_COLORSPACE_JPEG,
++ .priv = 1},
++*/
++ {1280, 1024, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
++ .bytesperline = 1280,
++ .sizeimage = 1280 * 1024 * 2,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .priv = 0},
+ };
+-
+ static const struct v4l2_pix_format svga_mode[] = {
+ {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 800,
+@@ -400,92 +445,208 @@ static const __u8 mi0360_initQVGA_JPG[][4] = {
+ static const __u8 mi1310_socinitVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+- {0xb3, 0x00, 0x64, 0xcc},
+- {0xb3, 0x00, 0x65, 0xcc},
+- {0xb3, 0x05, 0x00, 0xcc},
+- {0xb3, 0x06, 0x00, 0xcc},
++ {0xb3, 0x00, 0x24, 0xcc},
++ {0xb3, 0x00, 0x25, 0xcc},
++ {0xb3, 0x05, 0x01, 0xcc},
++ {0xb3, 0x06, 0x03, 0xcc},
++ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc},
+- {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+- {0xb3, 0x04, 0x05, 0xcc},
++ {0xb3, 0x04, 0x0d, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+- {0xb3, 0x22, 0x03, 0xcc},
+- {0xb3, 0x23, 0xc0, 0xcc},
++ {0xb3, 0x22, 0x01, 0xcc},
++ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+- {0xb3, 0x16, 0x04, 0xcc},
+- {0xb3, 0x17, 0xff, 0xcc},
+- {0xb3, 0x00, 0x65, 0xcc},
+- {0xb8, 0x00, 0x00, 0xcc},
+- {0xbc, 0x00, 0xd0, 0xcc},
+- {0xbc, 0x01, 0x01, 0xcc},
+- {0xf0, 0x00, 0x02, 0xbb},
+- {0xc8, 0x9f, 0x0b, 0xbb},
+- {0x5b, 0x00, 0x01, 0xbb},
+- {0x2f, 0xde, 0x20, 0xbb},
++ {0xb3, 0x16, 0x02, 0xcc},
++ {0xb3, 0x17, 0x7f, 0xcc},
++ {0xb8, 0x01, 0x7d, 0xcc},
++ {0xb8, 0x81, 0x09, 0xcc},
++ {0xb8, 0x27, 0x20, 0xcc},
++ {0xb8, 0x26, 0x80, 0xcc},
++ {0xb3, 0x00, 0x25, 0xcc},
++ {0xb8, 0x00, 0x13, 0xcc},
++ {0xbc, 0x00, 0x71, 0xcc},
++ {0xb8, 0x81, 0x01, 0xcc},
++ {0xb8, 0x2c, 0x5a, 0xcc},
++ {0xb8, 0x2d, 0xff, 0xcc},
++ {0xb8, 0x2e, 0xee, 0xcc},
++ {0xb8, 0x2f, 0xfb, 0xcc},
++ {0xb8, 0x30, 0x52, 0xcc},
++ {0xb8, 0x31, 0xf8, 0xcc},
++ {0xb8, 0x32, 0xf1, 0xcc},
++ {0xb8, 0x33, 0xff, 0xcc},
++ {0xb8, 0x34, 0x54, 0xcc},
++ {0xb8, 0x35, 0x00, 0xcc},
++ {0xb8, 0x36, 0x00, 0xcc},
++ {0xb8, 0x37, 0x00, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+- {0x20, 0x03, 0x02, 0xbb},
++ {0x00, 0x01, 0x00, 0xdd},
++ {0x0d, 0x00, 0x09, 0xbb},
++ {0x0d, 0x00, 0x08, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+- {0x05, 0x00, 0x07, 0xbb},
+- {0x34, 0x00, 0x00, 0xbb},
+- {0x35, 0xff, 0x00, 0xbb},
+- {0xdc, 0x07, 0x02, 0xbb},
+- {0xdd, 0x3c, 0x18, 0xbb},
+- {0xde, 0x92, 0x6d, 0xbb},
+- {0xdf, 0xcd, 0xb1, 0xbb},
+- {0xe0, 0xff, 0xe7, 0xbb},
+- {0x06, 0xf0, 0x0d, 0xbb},
+- {0x06, 0x70, 0x0e, 0xbb},
+- {0x4c, 0x00, 0x01, 0xbb},
+- {0x4d, 0x00, 0x01, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb},
+- {0x2e, 0x0c, 0x55, 0xbb},
+- {0x21, 0xb6, 0x6e, 0xbb},
+- {0x36, 0x30, 0x10, 0xbb},
+- {0x37, 0x00, 0xc1, 0xbb},
++ {0x00, 0x01, 0x00, 0xdd},
++ {0x06, 0x00, 0x14, 0xbb},
++ {0x3a, 0x10, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0x9b, 0x10, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+- {0x07, 0x00, 0x84, 0xbb},
+- {0x08, 0x02, 0x4a, 0xbb},
+- {0x05, 0x01, 0x10, 0xbb},
+- {0x06, 0x00, 0x39, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb},
+- {0x58, 0x02, 0x67, 0xbb},
+- {0x57, 0x02, 0x00, 0xbb},
+- {0x5a, 0x02, 0x67, 0xbb},
+- {0x59, 0x02, 0x00, 0xbb},
+- {0x5c, 0x12, 0x0d, 0xbb},
+- {0x5d, 0x16, 0x11, 0xbb},
+- {0x39, 0x06, 0x18, 0xbb},
+- {0x3a, 0x06, 0x18, 0xbb},
+- {0x3b, 0x06, 0x18, 0xbb},
+- {0x3c, 0x06, 0x18, 0xbb},
+- {0x64, 0x7b, 0x5b, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb},
+- {0x36, 0x30, 0x10, 0xbb},
+- {0x37, 0x00, 0xc0, 0xbb},
+- {0xbc, 0x0e, 0x00, 0xcc},
+- {0xbc, 0x0f, 0x05, 0xcc},
+- {0xbc, 0x10, 0xc0, 0xcc},
+- {0xbc, 0x11, 0x03, 0xcc},
++ {0x00, 0x01, 0x00, 0xdd},
++ {0x2b, 0x00, 0x28, 0xbb},
++ {0x2c, 0x00, 0x30, 0xbb},
++ {0x2d, 0x00, 0x30, 0xbb},
++ {0x2e, 0x00, 0x28, 0xbb},
++ {0x41, 0x00, 0xd7, 0xbb},
++ {0x09, 0x02, 0x3a, 0xbb},
++ {0x0c, 0x00, 0x00, 0xbb},
++ {0x20, 0x00, 0x00, 0xbb},
++ {0x05, 0x00, 0x8c, 0xbb},
++ {0x06, 0x00, 0x32, 0xbb},
++ {0x07, 0x00, 0xc6, 0xbb},
++ {0x08, 0x00, 0x19, 0xbb},
++ {0x24, 0x80, 0x6f, 0xbb},
++ {0xc8, 0x00, 0x0f, 0xbb},
++ {0x20, 0x00, 0x0f, 0xbb},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+- {0xb6, 0x12, 0xf8, 0xcc},
+- {0xb6, 0x13, 0x25, 0xcc},
++ {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
++ {0xb3, 0x02, 0x02, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+- {0xbf, 0xcc, 0x00, 0xcc},
++ {0xbf, 0xcc, 0x10, 0xcc},
++ {0xb9, 0x12, 0x00, 0xcc},
++ {0xb9, 0x13, 0x0a, 0xcc},
++ {0xb9, 0x14, 0x0a, 0xcc},
++ {0xb9, 0x15, 0x0a, 0xcc},
++ {0xb9, 0x16, 0x0a, 0xcc},
++ {0xb9, 0x18, 0x00, 0xcc},
++ {0xb9, 0x19, 0x0f, 0xcc},
++ {0xb9, 0x1a, 0x0f, 0xcc},
++ {0xb9, 0x1b, 0x0f, 0xcc},
++ {0xb9, 0x1c, 0x0f, 0xcc},
++ {0xb8, 0x8e, 0x00, 0xcc},
++ {0xb8, 0x8f, 0xff, 0xcc},
++ {0xb3, 0x01, 0x41, 0xcc},
++ {0x03, 0x03, 0xc0, 0xbb},
++ {0x06, 0x00, 0x10, 0xbb},
++ {0xb6, 0x12, 0xf8, 0xcc},
++ {0xb8, 0x0c, 0x20, 0xcc},
++ {0xb8, 0x0d, 0x70, 0xcc},
++ {0xb6, 0x13, 0x13, 0xcc},
++ {0x2f, 0x00, 0xC0, 0xbb},
++ {0xb8, 0xa0, 0x12, 0xcc},
++ {},
++};
++static const __u8 mi1310_socinitQVGA_JPG[][4] = {
++ {0xb0, 0x03, 0x19, 0xcc},
++ {0xb0, 0x04, 0x02, 0xcc},
++ {0xb3, 0x00, 0x24, 0xcc},
++ {0xb3, 0x00, 0x25, 0xcc},
++ {0xb3, 0x05, 0x01, 0xcc},
++ {0xb3, 0x06, 0x03, 0xcc},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xb3, 0x08, 0x01, 0xcc},
++ {0xb3, 0x09, 0x0c, 0xcc},
++ {0xb3, 0x34, 0x02, 0xcc},
++ {0xb3, 0x35, 0xdd, 0xcc},
++ {0xb3, 0x03, 0x0a, 0xcc},
++ {0xb3, 0x04, 0x0d, 0xcc},
++ {0xb3, 0x20, 0x00, 0xcc},
++ {0xb3, 0x21, 0x00, 0xcc},
++ {0xb3, 0x22, 0x01, 0xcc},
++ {0xb3, 0x23, 0xe0, 0xcc},
++ {0xb3, 0x14, 0x00, 0xcc},
++ {0xb3, 0x15, 0x00, 0xcc},
++ {0xb3, 0x16, 0x02, 0xcc},
++ {0xb3, 0x17, 0x7f, 0xcc},
++ {0xb8, 0x01, 0x7d, 0xcc},
++ {0xb8, 0x81, 0x09, 0xcc},
++ {0xb8, 0x27, 0x20, 0xcc},
++ {0xb8, 0x26, 0x80, 0xcc},
++ {0xb3, 0x00, 0x25, 0xcc},
++ {0xb8, 0x00, 0x13, 0xcc},
++ {0xbc, 0x00, 0xd1, 0xcc},
++ {0xb8, 0x81, 0x01, 0xcc},
++ {0xb8, 0x2c, 0x5a, 0xcc},
++ {0xb8, 0x2d, 0xff, 0xcc},
++ {0xb8, 0x2e, 0xee, 0xcc},
++ {0xb8, 0x2f, 0xfb, 0xcc},
++ {0xb8, 0x30, 0x52, 0xcc},
++ {0xb8, 0x31, 0xf8, 0xcc},
++ {0xb8, 0x32, 0xf1, 0xcc},
++ {0xb8, 0x33, 0xff, 0xcc},
++ {0xb8, 0x34, 0x54, 0xcc},
++ {0xb8, 0x35, 0x00, 0xcc},
++ {0xb8, 0x36, 0x00, 0xcc},
++ {0xb8, 0x37, 0x00, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x01, 0x00, 0xdd},
++ {0x0d, 0x00, 0x09, 0xbb},
++ {0x0d, 0x00, 0x08, 0xbb},
++ {0xf0, 0x00, 0x01, 0xbb},
++ {0x00, 0x01, 0x00, 0xdd},
++ {0x06, 0x00, 0x14, 0xbb},
++ {0x3a, 0x10, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0x9b, 0x10, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x01, 0x00, 0xdd},
++ {0x2b, 0x00, 0x28, 0xbb},
++ {0x2c, 0x00, 0x30, 0xbb},
++ {0x2d, 0x00, 0x30, 0xbb},
++ {0x2e, 0x00, 0x28, 0xbb},
++ {0x41, 0x00, 0xd7, 0xbb},
++ {0x09, 0x02, 0x3a, 0xbb},
++ {0x0c, 0x00, 0x00, 0xbb},
++ {0x20, 0x00, 0x00, 0xbb},
++ {0x05, 0x00, 0x8c, 0xbb},
++ {0x06, 0x00, 0x32, 0xbb},
++ {0x07, 0x00, 0xc6, 0xbb},
++ {0x08, 0x00, 0x19, 0xbb},
++ {0x24, 0x80, 0x6f, 0xbb},
++ {0xc8, 0x00, 0x0f, 0xbb},
++ {0x20, 0x00, 0x0f, 0xbb},
++ {0xb6, 0x00, 0x00, 0xcc},
++ {0xb6, 0x03, 0x01, 0xcc},
++ {0xb6, 0x02, 0x40, 0xcc},
++ {0xb6, 0x05, 0x00, 0xcc},
++ {0xb6, 0x04, 0xf0, 0xcc},
++ {0xb6, 0x12, 0x78, 0xcc},
++ {0xb6, 0x18, 0x00, 0xcc},
++ {0xb6, 0x17, 0x96, 0xcc},
++ {0xb6, 0x16, 0x00, 0xcc},
++ {0xb6, 0x22, 0x12, 0xcc},
++ {0xb6, 0x23, 0x0b, 0xcc},
++ {0xb3, 0x02, 0x02, 0xcc},
++ {0xbf, 0xc0, 0x39, 0xcc},
++ {0xbf, 0xc1, 0x04, 0xcc},
++ {0xbf, 0xcc, 0x10, 0xcc},
++ {0xb9, 0x12, 0x00, 0xcc},
++ {0xb9, 0x13, 0x0a, 0xcc},
++ {0xb9, 0x14, 0x0a, 0xcc},
++ {0xb9, 0x15, 0x0a, 0xcc},
++ {0xb9, 0x16, 0x0a, 0xcc},
++ {0xb9, 0x18, 0x00, 0xcc},
++ {0xb9, 0x19, 0x0f, 0xcc},
++ {0xb9, 0x1a, 0x0f, 0xcc},
++ {0xb9, 0x1b, 0x0f, 0xcc},
++ {0xb9, 0x1c, 0x0f, 0xcc},
++ {0xb8, 0x8e, 0x00, 0xcc},
++ {0xb8, 0x8f, 0xff, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+@@ -496,131 +657,123 @@ static const __u8 mi1310_socinitVGA_JPG[][4] = {
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+- {0xb3, 0x5c, 0x01, 0xcc},
+- {0xf0, 0x00, 0x01, 0xbb},
+- {0x80, 0x00, 0x03, 0xbb},
+- {0x81, 0xc7, 0x14, 0xbb},
+- {0x82, 0xeb, 0xe8, 0xbb},
+- {0x83, 0xfe, 0xf4, 0xbb},
+- {0x84, 0xcd, 0x10, 0xbb},
+- {0x85, 0xf3, 0xee, 0xbb},
+- {0x86, 0xff, 0xf1, 0xbb},
+- {0x87, 0xcd, 0x10, 0xbb},
+- {0x88, 0xf3, 0xee, 0xbb},
+- {0x89, 0x01, 0xf1, 0xbb},
+- {0x8a, 0xe5, 0x17, 0xbb},
+- {0x8b, 0xe8, 0xe2, 0xbb},
+- {0x8c, 0xf7, 0xed, 0xbb},
+- {0x8d, 0x00, 0xff, 0xbb},
+- {0x8e, 0xec, 0x10, 0xbb},
+- {0x8f, 0xf0, 0xed, 0xbb},
+- {0x90, 0xf9, 0xf2, 0xbb},
+- {0x91, 0x00, 0x00, 0xbb},
+- {0x92, 0xe9, 0x0d, 0xbb},
+- {0x93, 0xf4, 0xf2, 0xbb},
+- {0x94, 0xfb, 0xf5, 0xbb},
+- {0x95, 0x00, 0xff, 0xbb},
+- {0xb6, 0x0f, 0x08, 0xbb},
+- {0xb7, 0x3d, 0x16, 0xbb},
+- {0xb8, 0x0c, 0x04, 0xbb},
+- {0xb9, 0x1c, 0x07, 0xbb},
+- {0xba, 0x0a, 0x03, 0xbb},
+- {0xbb, 0x1b, 0x09, 0xbb},
+- {0xbc, 0x17, 0x0d, 0xbb},
+- {0xbd, 0x23, 0x1d, 0xbb},
+- {0xbe, 0x00, 0x28, 0xbb},
+- {0xbf, 0x11, 0x09, 0xbb},
+- {0xc0, 0x16, 0x15, 0xbb},
+- {0xc1, 0x00, 0x1b, 0xbb},
+- {0xc2, 0x0e, 0x07, 0xbb},
+- {0xc3, 0x14, 0x10, 0xbb},
+- {0xc4, 0x00, 0x17, 0xbb},
+- {0x06, 0x74, 0x8e, 0xbb},
+- {0xf0, 0x00, 0x01, 0xbb},
+- {0x06, 0xf4, 0x8e, 0xbb},
+- {0x00, 0x00, 0x50, 0xdd},
+- {0x06, 0x74, 0x8e, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb},
+- {0x24, 0x50, 0x20, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb},
+- {0x34, 0x0c, 0x50, 0xbb},
+ {0xb3, 0x01, 0x41, 0xcc},
+- {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
++ {0x06, 0x00, 0x10, 0xbb},
++ {0xb6, 0x12, 0xf8, 0xcc},
++ {0xb8, 0x0c, 0x20, 0xcc},
++ {0xb8, 0x0d, 0x70, 0xcc},
++ {0xb6, 0x13, 0x13, 0xcc},
++ {0x2f, 0x00, 0xC0, 0xbb},
++ {0xb8, 0xa0, 0x12, 0xcc},
+ {},
+ };
+-static const __u8 mi1310_socinitQVGA_JPG[][4] = {
+- {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc},
+- {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+- {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc},
+- {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+- {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc},
+- {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc},
+- {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+- {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc},
+- {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
+- {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc},
+- {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+- {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc},
+- {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb},
+- {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
+- {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+- {0x20, 0x03, 0x02, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+- {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb},
+- {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb},
+- {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb},
+- {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb},
+- {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb},
+- {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb},
+- {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+- {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+- {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb},
+- {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb},
+- {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb},
+- {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
+- {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb},
+- {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb},
+- {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+- {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
+- {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
+- {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
+- {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc},
+- {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
+- {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc},
+- {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
+- {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+- {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+- {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+- {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb},
+- {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb},
+- {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb},
+- {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb},
+- {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb},
+- {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb},
+- {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb},
+- {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb},
+- {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb},
+- {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
+- {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb},
+- {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb},
+- {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb},
+- {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb},
+- {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb},
+- {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb},
+- {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb},
+- {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb},
+- {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb},
+- {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb},
+- {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb},
+- {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb},
+- {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb},
+- {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
+- {0x03, 0x03, 0xc0, 0xbb},
+- {},
++static const u8 mi1310_soc_InitSXGA_JPG[][4] = {
++ {0xb0, 0x03, 0x19, 0xcc},
++ {0xb0, 0x04, 0x02, 0xcc},
++ {0xb3, 0x00, 0x24, 0xcc},
++ {0xb3, 0x00, 0x25, 0xcc},
++ {0xb3, 0x05, 0x00, 0xcc},
++ {0xb3, 0x06, 0x01, 0xcc},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xb3, 0x08, 0x01, 0xcc},
++ {0xb3, 0x09, 0x0c, 0xcc},
++ {0xb3, 0x34, 0x02, 0xcc},
++ {0xb3, 0x35, 0xdd, 0xcc},
++ {0xb3, 0x03, 0x0a, 0xcc},
++ {0xb3, 0x04, 0x0d, 0xcc},
++ {0xb3, 0x20, 0x00, 0xcc},
++ {0xb3, 0x21, 0x00, 0xcc},
++ {0xb3, 0x22, 0x04, 0xcc},
++ {0xb3, 0x23, 0x00, 0xcc},
++ {0xb3, 0x14, 0x00, 0xcc},
++ {0xb3, 0x15, 0x00, 0xcc},
++ {0xb3, 0x16, 0x04, 0xcc},
++ {0xb3, 0x17, 0xff, 0xcc},
++ {0xb8, 0x01, 0x7d, 0xcc},
++ {0xb8, 0x81, 0x09, 0xcc},
++ {0xb8, 0x27, 0x20, 0xcc},
++ {0xb8, 0x26, 0x80, 0xcc},
++ {0xb8, 0x06, 0x00, 0xcc},
++ {0xb8, 0x07, 0x05, 0xcc},
++ {0xb8, 0x08, 0x00, 0xcc},
++ {0xb8, 0x09, 0x04, 0xcc},
++ {0xb3, 0x00, 0x25, 0xcc},
++ {0xb8, 0x00, 0x11, 0xcc},
++ {0xbc, 0x00, 0x71, 0xcc},
++ {0xb8, 0x81, 0x01, 0xcc},
++ {0xb8, 0x2c, 0x5a, 0xcc},
++ {0xb8, 0x2d, 0xff, 0xcc},
++ {0xb8, 0x2e, 0xee, 0xcc},
++ {0xb8, 0x2f, 0xfb, 0xcc},
++ {0xb8, 0x30, 0x52, 0xcc},
++ {0xb8, 0x31, 0xf8, 0xcc},
++ {0xb8, 0x32, 0xf1, 0xcc},
++ {0xb8, 0x33, 0xff, 0xcc},
++ {0xb8, 0x34, 0x54, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x01, 0x00, 0xdd},
++ {0x0d, 0x00, 0x09, 0xbb},
++ {0x0d, 0x00, 0x08, 0xbb},
++ {0xf0, 0x00, 0x01, 0xbb},
++ {0x00, 0x01, 0x00, 0xdd},
++ {0x06, 0x00, 0x14, 0xbb},
++ {0x3a, 0x10, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0x9b, 0x10, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x01, 0x00, 0xdd},
++ {0x2b, 0x00, 0x28, 0xbb},
++ {0x2c, 0x00, 0x30, 0xbb},
++ {0x2d, 0x00, 0x30, 0xbb},
++ {0x2e, 0x00, 0x28, 0xbb},
++ {0x41, 0x00, 0xd7, 0xbb},
++ {0x09, 0x02, 0x3a, 0xbb},
++ {0x0c, 0x00, 0x00, 0xbb},
++ {0x20, 0x00, 0x00, 0xbb},
++ {0x05, 0x00, 0x8c, 0xbb},
++ {0x06, 0x00, 0x32, 0xbb},
++ {0x07, 0x00, 0xc6, 0xbb},
++ {0x08, 0x00, 0x19, 0xbb},
++ {0x24, 0x80, 0x6f, 0xbb},
++ {0xc8, 0x00, 0x0f, 0xbb},
++ {0x20, 0x00, 0x03, 0xbb},
++ {0xb6, 0x00, 0x00, 0xcc},
++ {0xb6, 0x03, 0x05, 0xcc},
++ {0xb6, 0x02, 0x00, 0xcc},
++ {0xb6, 0x05, 0x04, 0xcc},
++ {0xb6, 0x04, 0x00, 0xcc},
++ {0xb6, 0x12, 0xf8, 0xcc},
++ {0xb6, 0x18, 0x0a, 0xcc},
++ {0xb6, 0x17, 0x00, 0xcc},
++ {0xb6, 0x16, 0x00, 0xcc},
++ {0xb6, 0x22, 0x12, 0xcc},
++ {0xb6, 0x23, 0x0b, 0xcc},
++ {0xb3, 0x02, 0x02, 0xcc},
++ {0xbf, 0xc0, 0x39, 0xcc},
++ {0xbf, 0xc1, 0x04, 0xcc},
++ {0xbf, 0xcc, 0x10, 0xcc},
++ {0xb9, 0x12, 0x00, 0xcc},
++ {0xb9, 0x13, 0x14, 0xcc},
++ {0xb9, 0x14, 0x14, 0xcc},
++ {0xb9, 0x15, 0x14, 0xcc},
++ {0xb9, 0x16, 0x14, 0xcc},
++ {0xb9, 0x18, 0x00, 0xcc},
++ {0xb9, 0x19, 0x1e, 0xcc},
++ {0xb9, 0x1a, 0x1e, 0xcc},
++ {0xb9, 0x1b, 0x1e, 0xcc},
++ {0xb9, 0x1c, 0x1e, 0xcc},
++ {0xb3, 0x01, 0x41, 0xcc},
++ {0xb8, 0x8e, 0x00, 0xcc},
++ {0xb8, 0x8f, 0xff, 0xcc},
++ {0xb6, 0x12, 0xf8, 0xcc},
++ {0xb8, 0x0c, 0x20, 0xcc},
++ {0xb8, 0x0d, 0x70, 0xcc},
++ {0xb6, 0x13, 0x13, 0xcc},
++ {0x2f, 0x00, 0xC0, 0xbb},
++ {0xb8, 0xa0, 0x12, 0xcc},
++ {}
+ };
+
+ static const __u8 mi1320_gamma[17] = {
+@@ -778,6 +931,722 @@ static const __u8 mi1320_initQVGA_data[][4] = {
+ {}
+ };
+
++static const u8 mi1320_soc_InitVGA[][4] = {
++ {0xb3, 0x01, 0x01, 0xcc},
++ {0xb0, 0x03, 0x19, 0xcc},
++ {0xb0, 0x04, 0x02, 0xcc},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xb3, 0x00, 0x64, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb3, 0x05, 0x01, 0xcc},
++ {0xb3, 0x06, 0x01, 0xcc},
++ {0xb3, 0x08, 0x01, 0xcc},
++ {0xb3, 0x09, 0x0c, 0xcc},
++ {0xb3, 0x34, 0x02, 0xcc},
++ {0xb3, 0x35, 0xc8, 0xcc},
++ {0xb3, 0x02, 0x00, 0xcc},
++ {0xb3, 0x03, 0x0a, 0xcc},
++ {0xb3, 0x04, 0x05, 0xcc},
++ {0xb3, 0x20, 0x00, 0xcc},
++ {0xb3, 0x21, 0x00, 0xcc},
++ {0xb3, 0x22, 0x01, 0xcc},
++ {0xb3, 0x23, 0xe0, 0xcc},
++ {0xb3, 0x14, 0x00, 0xcc},
++ {0xb3, 0x15, 0x00, 0xcc},
++ {0xb3, 0x16, 0x02, 0xcc},
++ {0xb3, 0x17, 0x7f, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb8, 0x00, 0x00, 0xcc},
++ {0xbc, 0x00, 0x71, 0xcc},
++ {0xbc, 0x01, 0x01, 0xcc},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0xc8, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0x07, 0x00, 0xe0, 0xbb},
++ {0x08, 0x00, 0x0b, 0xbb},
++ {0x21, 0x00, 0x0c, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0xbf, 0xc0, 0x26, 0xcc},
++ {0xbf, 0xc1, 0x02, 0xcc},
++ {0xbf, 0xcc, 0x04, 0xcc},
++ {0xb3, 0x01, 0x41, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x05, 0x01, 0x78, 0xbb},
++ {0x06, 0x00, 0x11, 0xbb},
++ {0x07, 0x01, 0x42, 0xbb},
++ {0x08, 0x00, 0x11, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x21, 0x80, 0x00, 0xbb},
++ {0x22, 0x0d, 0x0f, 0xbb},
++ {0x24, 0x80, 0x00, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x39, 0x03, 0xca, 0xbb},
++ {0x3a, 0x06, 0x80, 0xbb},
++ {0x3b, 0x01, 0x52, 0xbb},
++ {0x3c, 0x05, 0x40, 0xbb},
++ {0x57, 0x01, 0x9c, 0xbb},
++ {0x58, 0x01, 0xee, 0xbb},
++ {0x59, 0x00, 0xf0, 0xbb},
++ {0x5a, 0x01, 0x20, 0xbb},
++ {0x5c, 0x1d, 0x17, 0xbb},
++ {0x5d, 0x22, 0x1c, 0xbb},
++ {0x64, 0x1e, 0x1c, 0xbb},
++ {0x5b, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x22, 0xa0, 0x78, 0xbb},
++ {0x23, 0xa0, 0x78, 0xbb},
++ {0x24, 0x7f, 0x00, 0xbb},
++ {0x28, 0xea, 0x02, 0xbb},
++ {0x29, 0x86, 0x7a, 0xbb},
++ {0x5e, 0x52, 0x4c, 0xbb},
++ {0x5f, 0x20, 0x24, 0xbb},
++ {0x60, 0x00, 0x02, 0xbb},
++ {0x02, 0x00, 0xee, 0xbb},
++ {0x03, 0x39, 0x23, 0xbb},
++ {0x04, 0x07, 0x24, 0xbb},
++ {0x09, 0x00, 0xc0, 0xbb},
++ {0x0a, 0x00, 0x79, 0xbb},
++ {0x0b, 0x00, 0x04, 0xbb},
++ {0x0c, 0x00, 0x5c, 0xbb},
++ {0x0d, 0x00, 0xd9, 0xbb},
++ {0x0e, 0x00, 0x53, 0xbb},
++ {0x0f, 0x00, 0x21, 0xbb},
++ {0x10, 0x00, 0xa4, 0xbb},
++ {0x11, 0x00, 0xe5, 0xbb},
++ {0x15, 0x00, 0x00, 0xbb},
++ {0x16, 0x00, 0x00, 0xbb},
++ {0x17, 0x00, 0x00, 0xbb},
++ {0x18, 0x00, 0x00, 0xbb},
++ {0x19, 0x00, 0x00, 0xbb},
++ {0x1a, 0x00, 0x00, 0xbb},
++ {0x1b, 0x00, 0x00, 0xbb},
++ {0x1c, 0x00, 0x00, 0xbb},
++ {0x1d, 0x00, 0x00, 0xbb},
++ {0x1e, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x01, 0xbb},
++ {0x06, 0xe0, 0x0e, 0xbb},
++ {0x06, 0x60, 0x0e, 0xbb},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {}
++};
++static const u8 mi1320_soc_InitVGA_JPG[][4] = {
++ {0xb3, 0x01, 0x01, 0xcc},
++ {0xb0, 0x03, 0x19, 0xcc},
++ {0xb0, 0x04, 0x02, 0xcc},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xb3, 0x00, 0x64, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb3, 0x05, 0x01, 0xcc},
++ {0xb3, 0x06, 0x01, 0xcc},
++ {0xb3, 0x08, 0x01, 0xcc},
++ {0xb3, 0x09, 0x0c, 0xcc},
++ {0xb3, 0x34, 0x02, 0xcc},
++ {0xb3, 0x35, 0xc8, 0xcc},
++ {0xb3, 0x02, 0x00, 0xcc},
++ {0xb3, 0x03, 0x0a, 0xcc},
++ {0xb3, 0x04, 0x05, 0xcc},
++ {0xb3, 0x20, 0x00, 0xcc},
++ {0xb3, 0x21, 0x00, 0xcc},
++ {0xb3, 0x22, 0x01, 0xcc},
++ {0xb3, 0x23, 0xe0, 0xcc},
++ {0xb3, 0x14, 0x00, 0xcc},
++ {0xb3, 0x15, 0x00, 0xcc},
++ {0xb3, 0x16, 0x02, 0xcc},
++ {0xb3, 0x17, 0x7f, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb8, 0x00, 0x00, 0xcc},
++ {0xbc, 0x00, 0x71, 0xcc},
++ {0xbc, 0x01, 0x01, 0xcc},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0xc8, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0x07, 0x00, 0xe0, 0xbb},
++ {0x08, 0x00, 0x0b, 0xbb},
++ {0x21, 0x00, 0x0c, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0xb6, 0x00, 0x00, 0xcc},
++ {0xb6, 0x03, 0x02, 0xcc},
++ {0xb6, 0x02, 0x80, 0xcc},
++ {0xb6, 0x05, 0x01, 0xcc},
++ {0xb6, 0x04, 0xe0, 0xcc},
++ {0xb6, 0x12, 0xf8, 0xcc},
++ {0xb6, 0x13, 0x05, 0xcc},
++ {0xb6, 0x18, 0x02, 0xcc},
++ {0xb6, 0x17, 0x58, 0xcc},
++ {0xb6, 0x16, 0x00, 0xcc},
++ {0xb6, 0x22, 0x12, 0xcc},
++ {0xb6, 0x23, 0x0b, 0xcc},
++ {0xbf, 0xc0, 0x39, 0xcc},
++ {0xbf, 0xc1, 0x04, 0xcc},
++ {0xbf, 0xcc, 0x00, 0xcc},
++ {0xb3, 0x01, 0x41, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x05, 0x01, 0x78, 0xbb},
++ {0x06, 0x00, 0x11, 0xbb},
++ {0x07, 0x01, 0x42, 0xbb},
++ {0x08, 0x00, 0x11, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x21, 0x80, 0x00, 0xbb},
++ {0x22, 0x0d, 0x0f, 0xbb},
++ {0x24, 0x80, 0x00, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x39, 0x03, 0xca, 0xbb},
++ {0x3a, 0x06, 0x80, 0xbb},
++ {0x3b, 0x01, 0x52, 0xbb},
++ {0x3c, 0x05, 0x40, 0xbb},
++ {0x57, 0x01, 0x9c, 0xbb},
++ {0x58, 0x01, 0xee, 0xbb},
++ {0x59, 0x00, 0xf0, 0xbb},
++ {0x5a, 0x01, 0x20, 0xbb},
++ {0x5c, 0x1d, 0x17, 0xbb},
++ {0x5d, 0x22, 0x1c, 0xbb},
++ {0x64, 0x1e, 0x1c, 0xbb},
++ {0x5b, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x22, 0xa0, 0x78, 0xbb},
++ {0x23, 0xa0, 0x78, 0xbb},
++ {0x24, 0x7f, 0x00, 0xbb},
++ {0x28, 0xea, 0x02, 0xbb},
++ {0x29, 0x86, 0x7a, 0xbb},
++ {0x5e, 0x52, 0x4c, 0xbb},
++ {0x5f, 0x20, 0x24, 0xbb},
++ {0x60, 0x00, 0x02, 0xbb},
++ {0x02, 0x00, 0xee, 0xbb},
++ {0x03, 0x39, 0x23, 0xbb},
++ {0x04, 0x07, 0x24, 0xbb},
++ {0x09, 0x00, 0xc0, 0xbb},
++ {0x0a, 0x00, 0x79, 0xbb},
++ {0x0b, 0x00, 0x04, 0xbb},
++ {0x0c, 0x00, 0x5c, 0xbb},
++ {0x0d, 0x00, 0xd9, 0xbb},
++ {0x0e, 0x00, 0x53, 0xbb},
++ {0x0f, 0x00, 0x21, 0xbb},
++ {0x10, 0x00, 0xa4, 0xbb},
++ {0x11, 0x00, 0xe5, 0xbb},
++ {0x15, 0x00, 0x00, 0xbb},
++ {0x16, 0x00, 0x00, 0xbb},
++ {0x17, 0x00, 0x00, 0xbb},
++ {0x18, 0x00, 0x00, 0xbb},
++ {0x19, 0x00, 0x00, 0xbb},
++ {0x1a, 0x00, 0x00, 0xbb},
++ {0x1b, 0x00, 0x00, 0xbb},
++ {0x1c, 0x00, 0x00, 0xbb},
++ {0x1d, 0x00, 0x00, 0xbb},
++ {0x1e, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x01, 0xbb},
++ {0x06, 0xe0, 0x0e, 0xbb},
++ {0x06, 0x60, 0x0e, 0xbb},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {}
++};
++static const u8 mi1320_soc_InitQVGA[][4] = {
++ {0xb3, 0x01, 0x01, 0xcc},
++ {0xb0, 0x03, 0x19, 0xcc},
++ {0xb0, 0x04, 0x02, 0xcc},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xb3, 0x00, 0x64, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb3, 0x05, 0x01, 0xcc},
++ {0xb3, 0x06, 0x01, 0xcc},
++ {0xb3, 0x08, 0x01, 0xcc},
++ {0xb3, 0x09, 0x0c, 0xcc},
++ {0xb3, 0x34, 0x02, 0xcc},
++ {0xb3, 0x35, 0xc8, 0xcc},
++ {0xb3, 0x02, 0x00, 0xcc},
++ {0xb3, 0x03, 0x0a, 0xcc},
++ {0xb3, 0x04, 0x05, 0xcc},
++ {0xb3, 0x20, 0x00, 0xcc},
++ {0xb3, 0x21, 0x00, 0xcc},
++ {0xb3, 0x22, 0x01, 0xcc},
++ {0xb3, 0x23, 0xe0, 0xcc},
++ {0xb3, 0x14, 0x00, 0xcc},
++ {0xb3, 0x15, 0x00, 0xcc},
++ {0xb3, 0x16, 0x02, 0xcc},
++ {0xb3, 0x17, 0x7f, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb8, 0x00, 0x00, 0xcc},
++ {0xbc, 0x00, 0xd1, 0xcc},
++ {0xbc, 0x01, 0x01, 0xcc},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0xc8, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0x07, 0x00, 0xe0, 0xbb},
++ {0x08, 0x00, 0x0b, 0xbb},
++ {0x21, 0x00, 0x0c, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0xbf, 0xc0, 0x26, 0xcc},
++ {0xbf, 0xc1, 0x02, 0xcc},
++ {0xbf, 0xcc, 0x04, 0xcc},
++ {0xbc, 0x02, 0x18, 0xcc},
++ {0xbc, 0x03, 0x50, 0xcc},
++ {0xbc, 0x04, 0x18, 0xcc},
++ {0xbc, 0x05, 0x00, 0xcc},
++ {0xbc, 0x06, 0x00, 0xcc},
++ {0xbc, 0x08, 0x30, 0xcc},
++ {0xbc, 0x09, 0x40, 0xcc},
++ {0xbc, 0x0a, 0x10, 0xcc},
++ {0xbc, 0x0b, 0x00, 0xcc},
++ {0xbc, 0x0c, 0x00, 0xcc},
++ {0xb3, 0x01, 0x41, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x05, 0x01, 0x78, 0xbb},
++ {0x06, 0x00, 0x11, 0xbb},
++ {0x07, 0x01, 0x42, 0xbb},
++ {0x08, 0x00, 0x11, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x21, 0x80, 0x00, 0xbb},
++ {0x22, 0x0d, 0x0f, 0xbb},
++ {0x24, 0x80, 0x00, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x39, 0x03, 0xca, 0xbb},
++ {0x3a, 0x06, 0x80, 0xbb},
++ {0x3b, 0x01, 0x52, 0xbb},
++ {0x3c, 0x05, 0x40, 0xbb},
++ {0x57, 0x01, 0x9c, 0xbb},
++ {0x58, 0x01, 0xee, 0xbb},
++ {0x59, 0x00, 0xf0, 0xbb},
++ {0x5a, 0x01, 0x20, 0xbb},
++ {0x5c, 0x1d, 0x17, 0xbb},
++ {0x5d, 0x22, 0x1c, 0xbb},
++ {0x64, 0x1e, 0x1c, 0xbb},
++ {0x5b, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x22, 0xa0, 0x78, 0xbb},
++ {0x23, 0xa0, 0x78, 0xbb},
++ {0x24, 0x7f, 0x00, 0xbb},
++ {0x28, 0xea, 0x02, 0xbb},
++ {0x29, 0x86, 0x7a, 0xbb},
++ {0x5e, 0x52, 0x4c, 0xbb},
++ {0x5f, 0x20, 0x24, 0xbb},
++ {0x60, 0x00, 0x02, 0xbb},
++ {0x02, 0x00, 0xee, 0xbb},
++ {0x03, 0x39, 0x23, 0xbb},
++ {0x04, 0x07, 0x24, 0xbb},
++ {0x09, 0x00, 0xc0, 0xbb},
++ {0x0a, 0x00, 0x79, 0xbb},
++ {0x0b, 0x00, 0x04, 0xbb},
++ {0x0c, 0x00, 0x5c, 0xbb},
++ {0x0d, 0x00, 0xd9, 0xbb},
++ {0x0e, 0x00, 0x53, 0xbb},
++ {0x0f, 0x00, 0x21, 0xbb},
++ {0x10, 0x00, 0xa4, 0xbb},
++ {0x11, 0x00, 0xe5, 0xbb},
++ {0x15, 0x00, 0x00, 0xbb},
++ {0x16, 0x00, 0x00, 0xbb},
++ {0x17, 0x00, 0x00, 0xbb},
++ {0x18, 0x00, 0x00, 0xbb},
++ {0x19, 0x00, 0x00, 0xbb},
++ {0x1a, 0x00, 0x00, 0xbb},
++ {0x1b, 0x00, 0x00, 0xbb},
++ {0x1c, 0x00, 0x00, 0xbb},
++ {0x1d, 0x00, 0x00, 0xbb},
++ {0x1e, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x01, 0xbb},
++ {0x06, 0xe0, 0x0e, 0xbb},
++ {0x06, 0x60, 0x0e, 0xbb},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {}
++};
++static const u8 mi1320_soc_InitQVGA_JPG[][4] = {
++ {0xb3, 0x01, 0x01, 0xcc},
++ {0xb0, 0x03, 0x19, 0xcc},
++ {0xb0, 0x04, 0x02, 0xcc},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xb3, 0x00, 0x64, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb3, 0x05, 0x01, 0xcc},
++ {0xb3, 0x06, 0x01, 0xcc},
++ {0xb3, 0x08, 0x01, 0xcc},
++ {0xb3, 0x09, 0x0c, 0xcc},
++ {0xb3, 0x34, 0x02, 0xcc},
++ {0xb3, 0x35, 0xc8, 0xcc},
++ {0xb3, 0x02, 0x00, 0xcc},
++ {0xb3, 0x03, 0x0a, 0xcc},
++ {0xb3, 0x04, 0x05, 0xcc},
++ {0xb3, 0x20, 0x00, 0xcc},
++ {0xb3, 0x21, 0x00, 0xcc},
++ {0xb3, 0x22, 0x01, 0xcc},
++ {0xb3, 0x23, 0xe0, 0xcc},
++ {0xb3, 0x14, 0x00, 0xcc},
++ {0xb3, 0x15, 0x00, 0xcc},
++ {0xb3, 0x16, 0x02, 0xcc},
++ {0xb3, 0x17, 0x7f, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb8, 0x00, 0x00, 0xcc},
++ {0xbc, 0x00, 0xd1, 0xcc},
++ {0xbc, 0x01, 0x01, 0xcc},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0xc8, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x10, 0xdd},
++ {0x07, 0x00, 0xe0, 0xbb},
++ {0x08, 0x00, 0x0b, 0xbb},
++ {0x21, 0x00, 0x0c, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0xb6, 0x00, 0x00, 0xcc},
++ {0xb6, 0x03, 0x01, 0xcc},
++ {0xb6, 0x02, 0x40, 0xcc},
++ {0xb6, 0x05, 0x00, 0xcc},
++ {0xb6, 0x04, 0xf0, 0xcc},
++ {0xb6, 0x12, 0xf8, 0xcc},
++ {0xb6, 0x13, 0x05, 0xcc},
++ {0xb6, 0x18, 0x00, 0xcc},
++ {0xb6, 0x17, 0x96, 0xcc},
++ {0xb6, 0x16, 0x00, 0xcc},
++ {0xb6, 0x22, 0x12, 0xcc},
++ {0xb6, 0x23, 0x0b, 0xcc},
++ {0xbf, 0xc0, 0x39, 0xcc},
++ {0xbf, 0xc1, 0x04, 0xcc},
++ {0xbf, 0xcc, 0x00, 0xcc},
++ {0xbc, 0x02, 0x18, 0xcc},
++ {0xbc, 0x03, 0x50, 0xcc},
++ {0xbc, 0x04, 0x18, 0xcc},
++ {0xbc, 0x05, 0x00, 0xcc},
++ {0xbc, 0x06, 0x00, 0xcc},
++ {0xbc, 0x08, 0x30, 0xcc},
++ {0xbc, 0x09, 0x40, 0xcc},
++ {0xbc, 0x0a, 0x10, 0xcc},
++ {0xbc, 0x0b, 0x00, 0xcc},
++ {0xbc, 0x0c, 0x00, 0xcc},
++ {0xb3, 0x01, 0x41, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x05, 0x01, 0x78, 0xbb},
++ {0x06, 0x00, 0x11, 0xbb},
++ {0x07, 0x01, 0x42, 0xbb},
++ {0x08, 0x00, 0x11, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x21, 0x80, 0x00, 0xbb},
++ {0x22, 0x0d, 0x0f, 0xbb},
++ {0x24, 0x80, 0x00, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x39, 0x03, 0xca, 0xbb},
++ {0x3a, 0x06, 0x80, 0xbb},
++ {0x3b, 0x01, 0x52, 0xbb},
++ {0x3c, 0x05, 0x40, 0xbb},
++ {0x57, 0x01, 0x9c, 0xbb},
++ {0x58, 0x01, 0xee, 0xbb},
++ {0x59, 0x00, 0xf0, 0xbb},
++ {0x5a, 0x01, 0x20, 0xbb},
++ {0x5c, 0x1d, 0x17, 0xbb},
++ {0x5d, 0x22, 0x1c, 0xbb},
++ {0x64, 0x1e, 0x1c, 0xbb},
++ {0x5b, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x22, 0xa0, 0x78, 0xbb},
++ {0x23, 0xa0, 0x78, 0xbb},
++ {0x24, 0x7f, 0x00, 0xbb},
++ {0x28, 0xea, 0x02, 0xbb},
++ {0x29, 0x86, 0x7a, 0xbb},
++ {0x5e, 0x52, 0x4c, 0xbb},
++ {0x5f, 0x20, 0x24, 0xbb},
++ {0x60, 0x00, 0x02, 0xbb},
++ {0x02, 0x00, 0xee, 0xbb},
++ {0x03, 0x39, 0x23, 0xbb},
++ {0x04, 0x07, 0x24, 0xbb},
++ {0x09, 0x00, 0xc0, 0xbb},
++ {0x0a, 0x00, 0x79, 0xbb},
++ {0x0b, 0x00, 0x04, 0xbb},
++ {0x0c, 0x00, 0x5c, 0xbb},
++ {0x0d, 0x00, 0xd9, 0xbb},
++ {0x0e, 0x00, 0x53, 0xbb},
++ {0x0f, 0x00, 0x21, 0xbb},
++ {0x10, 0x00, 0xa4, 0xbb},
++ {0x11, 0x00, 0xe5, 0xbb},
++ {0x15, 0x00, 0x00, 0xbb},
++ {0x16, 0x00, 0x00, 0xbb},
++ {0x17, 0x00, 0x00, 0xbb},
++ {0x18, 0x00, 0x00, 0xbb},
++ {0x19, 0x00, 0x00, 0xbb},
++ {0x1a, 0x00, 0x00, 0xbb},
++ {0x1b, 0x00, 0x00, 0xbb},
++ {0x1c, 0x00, 0x00, 0xbb},
++ {0x1d, 0x00, 0x00, 0xbb},
++ {0x1e, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x01, 0xbb},
++ {0x06, 0xe0, 0x0e, 0xbb},
++ {0x06, 0x60, 0x0e, 0xbb},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {}
++};
++static const u8 mi1320_soc_InitSXGA_JPG[][4] = {
++ {0xb3, 0x01, 0x01, 0xcc},
++ {0xb0, 0x03, 0x19, 0xcc},
++ {0xb0, 0x04, 0x02, 0xcc},
++ {0x00, 0x00, 0x33, 0xdd},
++ {0xb3, 0x00, 0x64, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb3, 0x05, 0x00, 0xcc},
++ {0xb3, 0x06, 0x00, 0xcc},
++ {0xb3, 0x08, 0x01, 0xcc},
++ {0xb3, 0x09, 0x0c, 0xcc},
++ {0xb3, 0x34, 0x02, 0xcc},
++ {0xb3, 0x35, 0xc8, 0xcc},
++ {0xb3, 0x02, 0x00, 0xcc},
++ {0xb3, 0x03, 0x0a, 0xcc},
++ {0xb3, 0x04, 0x05, 0xcc},
++ {0xb3, 0x20, 0x00, 0xcc},
++ {0xb3, 0x21, 0x00, 0xcc},
++ {0xb3, 0x22, 0x04, 0xcc},
++ {0xb3, 0x23, 0x00, 0xcc},
++ {0xb3, 0x14, 0x00, 0xcc},
++ {0xb3, 0x15, 0x00, 0xcc},
++ {0xb3, 0x16, 0x04, 0xcc},
++ {0xb3, 0x17, 0xff, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xbc, 0x00, 0x71, 0xcc},
++ {0xbc, 0x01, 0x01, 0xcc},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xc8, 0x9f, 0x0b, 0xbb},
++ {0x00, 0x00, 0x20, 0xdd},
++ {0x5b, 0x00, 0x01, 0xbb},
++ {0x00, 0x00, 0x20, 0xdd},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x00, 0x00, 0x20, 0xdd},
++ {0xb6, 0x00, 0x00, 0xcc},
++ {0xb6, 0x03, 0x05, 0xcc},
++ {0xb6, 0x02, 0x00, 0xcc},
++ {0xb6, 0x05, 0x04, 0xcc},
++ {0xb6, 0x04, 0x00, 0xcc},
++ {0xb6, 0x12, 0xf8, 0xcc},
++ {0xb6, 0x13, 0x29, 0xcc},
++ {0xb6, 0x18, 0x0a, 0xcc},
++ {0xb6, 0x17, 0x00, 0xcc},
++ {0xb6, 0x16, 0x00, 0xcc},
++ {0xb6, 0x22, 0x12, 0xcc},
++ {0xb6, 0x23, 0x0b, 0xcc},
++ {0xbf, 0xc0, 0x39, 0xcc},
++ {0xbf, 0xc1, 0x04, 0xcc},
++ {0xbf, 0xcc, 0x00, 0xcc},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xb3, 0x01, 0x41, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x05, 0x01, 0x78, 0xbb},
++ {0x06, 0x00, 0x11, 0xbb},
++ {0x07, 0x01, 0x42, 0xbb},
++ {0x08, 0x00, 0x11, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x21, 0x80, 0x00, 0xbb},
++ {0x22, 0x0d, 0x0f, 0xbb},
++ {0x24, 0x80, 0x00, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x39, 0x03, 0xca, 0xbb},
++ {0x3a, 0x06, 0x80, 0xbb},
++ {0x3b, 0x01, 0x52, 0xbb},
++ {0x3c, 0x05, 0x40, 0xbb},
++ {0x57, 0x01, 0x9c, 0xbb},
++ {0x58, 0x01, 0xee, 0xbb},
++ {0x59, 0x00, 0xf0, 0xbb},
++ {0x5a, 0x01, 0x20, 0xbb},
++ {0x5c, 0x1d, 0x17, 0xbb},
++ {0x5d, 0x22, 0x1c, 0xbb},
++ {0x64, 0x1e, 0x1c, 0xbb},
++ {0x5b, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x22, 0xa0, 0x78, 0xbb},
++ {0x23, 0xa0, 0x78, 0xbb},
++ {0x24, 0x7f, 0x00, 0xbb},
++ {0x28, 0xea, 0x02, 0xbb},
++ {0x29, 0x86, 0x7a, 0xbb},
++ {0x5e, 0x52, 0x4c, 0xbb},
++ {0x5f, 0x20, 0x24, 0xbb},
++ {0x60, 0x00, 0x02, 0xbb},
++ {0x02, 0x00, 0xee, 0xbb},
++ {0x03, 0x39, 0x23, 0xbb},
++ {0x04, 0x07, 0x24, 0xbb},
++ {0x09, 0x00, 0xc0, 0xbb},
++ {0x0a, 0x00, 0x79, 0xbb},
++ {0x0b, 0x00, 0x04, 0xbb},
++ {0x0c, 0x00, 0x5c, 0xbb},
++ {0x0d, 0x00, 0xd9, 0xbb},
++ {0x0e, 0x00, 0x53, 0xbb},
++ {0x0f, 0x00, 0x21, 0xbb},
++ {0x10, 0x00, 0xa4, 0xbb},
++ {0x11, 0x00, 0xe5, 0xbb},
++ {0x15, 0x00, 0x00, 0xbb},
++ {0x16, 0x00, 0x00, 0xbb},
++ {0x17, 0x00, 0x00, 0xbb},
++ {0x18, 0x00, 0x00, 0xbb},
++ {0x19, 0x00, 0x00, 0xbb},
++ {0x1a, 0x00, 0x00, 0xbb},
++ {0x1b, 0x00, 0x00, 0xbb},
++ {0x1c, 0x00, 0x00, 0xbb},
++ {0x1d, 0x00, 0x00, 0xbb},
++ {0x1e, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x01, 0xbb},
++ {0x06, 0xe0, 0x0e, 0xbb},
++ {0x06, 0x60, 0x0e, 0xbb},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x05, 0x01, 0x13, 0xbb},
++ {0x06, 0x00, 0x11, 0xbb},
++ {0x07, 0x00, 0x85, 0xbb},
++ {0x08, 0x00, 0x27, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x21, 0x80, 0x00, 0xbb},
++ {0x22, 0x0d, 0x0f, 0xbb},
++ {0x24, 0x80, 0x00, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x39, 0x03, 0x0d, 0xbb},
++ {0x3a, 0x06, 0x1b, 0xbb},
++ {0x3b, 0x00, 0x95, 0xbb},
++ {0x3c, 0x04, 0xdb, 0xbb},
++ {0x57, 0x02, 0x00, 0xbb},
++ {0x58, 0x02, 0x66, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0x5a, 0x01, 0x33, 0xbb},
++ {0x5c, 0x12, 0x0d, 0xbb},
++ {0x5d, 0x16, 0x11, 0xbb},
++ {0x64, 0x5e, 0x1c, 0xbb},
++ {0x2f, 0x90, 0x00, 0xbb},
++ {}
++};
++static const u8 mi1320_soc_InitSXGA[][4] = {
++ {0xb3, 0x01, 0x01, 0xcc},
++ {0xb0, 0x03, 0x19, 0xcc},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xb3, 0x00, 0x64, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xb3, 0x05, 0x01, 0xcc},
++ {0xb3, 0x06, 0x01, 0xcc},
++ {0xb3, 0x08, 0x01, 0xcc},
++ {0xb3, 0x09, 0x0c, 0xcc},
++ {0xb3, 0x34, 0x02, 0xcc},
++ {0xb3, 0x35, 0xc8, 0xcc},
++ {0xb3, 0x02, 0x00, 0xcc},
++ {0xb3, 0x03, 0x0a, 0xcc},
++ {0xb3, 0x04, 0x05, 0xcc},
++ {0xb3, 0x20, 0x00, 0xcc},
++ {0xb3, 0x21, 0x00, 0xcc},
++ {0xb3, 0x22, 0x04, 0xcc},
++ {0xb3, 0x23, 0x00, 0xcc},
++ {0xb3, 0x14, 0x00, 0xcc},
++ {0xb3, 0x15, 0x00, 0xcc},
++ {0xb3, 0x16, 0x04, 0xcc},
++ {0xb3, 0x17, 0xff, 0xcc},
++ {0xb3, 0x00, 0x67, 0xcc},
++ {0xbc, 0x00, 0x71, 0xcc},
++ {0xbc, 0x01, 0x01, 0xcc},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0xc8, 0x9f, 0x0b, 0xbb},
++ {0x00, 0x00, 0x20, 0xdd},
++ {0x5b, 0x00, 0x01, 0xbb},
++ {0x00, 0x00, 0x20, 0xdd},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x00, 0x00, 0x30, 0xdd},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x00, 0x00, 0x20, 0xdd},
++ {0xbf, 0xc0, 0x26, 0xcc},
++ {0xbf, 0xc1, 0x02, 0xcc},
++ {0xbf, 0xcc, 0x04, 0xcc},
++ {0xb3, 0x01, 0x41, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x05, 0x01, 0x78, 0xbb},
++ {0x06, 0x00, 0x11, 0xbb},
++ {0x07, 0x01, 0x42, 0xbb},
++ {0x08, 0x00, 0x11, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x21, 0x80, 0x00, 0xbb},
++ {0x22, 0x0d, 0x0f, 0xbb},
++ {0x24, 0x80, 0x00, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x39, 0x03, 0xca, 0xbb},
++ {0x3a, 0x06, 0x80, 0xbb},
++ {0x3b, 0x01, 0x52, 0xbb},
++ {0x3c, 0x05, 0x40, 0xbb},
++ {0x57, 0x01, 0x9c, 0xbb},
++ {0x58, 0x01, 0xee, 0xbb},
++ {0x59, 0x00, 0xf0, 0xbb},
++ {0x5a, 0x01, 0x20, 0xbb},
++ {0x5c, 0x1d, 0x17, 0xbb},
++ {0x5d, 0x22, 0x1c, 0xbb},
++ {0x64, 0x1e, 0x1c, 0xbb},
++ {0x5b, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x22, 0xa0, 0x78, 0xbb},
++ {0x23, 0xa0, 0x78, 0xbb},
++ {0x24, 0x7f, 0x00, 0xbb},
++ {0x28, 0xea, 0x02, 0xbb},
++ {0x29, 0x86, 0x7a, 0xbb},
++ {0x5e, 0x52, 0x4c, 0xbb},
++ {0x5f, 0x20, 0x24, 0xbb},
++ {0x60, 0x00, 0x02, 0xbb},
++ {0x02, 0x00, 0xee, 0xbb},
++ {0x03, 0x39, 0x23, 0xbb},
++ {0x04, 0x07, 0x24, 0xbb},
++ {0x09, 0x00, 0xc0, 0xbb},
++ {0x0a, 0x00, 0x79, 0xbb},
++ {0x0b, 0x00, 0x04, 0xbb},
++ {0x0c, 0x00, 0x5c, 0xbb},
++ {0x0d, 0x00, 0xd9, 0xbb},
++ {0x0e, 0x00, 0x53, 0xbb},
++ {0x0f, 0x00, 0x21, 0xbb},
++ {0x10, 0x00, 0xa4, 0xbb},
++ {0x11, 0x00, 0xe5, 0xbb},
++ {0x15, 0x00, 0x00, 0xbb},
++ {0x16, 0x00, 0x00, 0xbb},
++ {0x17, 0x00, 0x00, 0xbb},
++ {0x18, 0x00, 0x00, 0xbb},
++ {0x19, 0x00, 0x00, 0xbb},
++ {0x1a, 0x00, 0x00, 0xbb},
++ {0x1b, 0x00, 0x00, 0xbb},
++ {0x1c, 0x00, 0x00, 0xbb},
++ {0x1d, 0x00, 0x00, 0xbb},
++ {0x1e, 0x00, 0x00, 0xbb},
++ {0xf0, 0x00, 0x01, 0xbb},
++ {0x06, 0xe0, 0x0e, 0xbb},
++ {0x06, 0x60, 0x0e, 0xbb},
++ {0xb3, 0x5c, 0x01, 0xcc},
++ {0xf0, 0x00, 0x00, 0xbb},
++ {0x05, 0x01, 0x13, 0xbb},
++ {0x06, 0x00, 0x11, 0xbb},
++ {0x07, 0x00, 0x85, 0xbb},
++ {0x08, 0x00, 0x27, 0xbb},
++ {0x20, 0x01, 0x03, 0xbb},
++ {0x21, 0x80, 0x00, 0xbb},
++ {0x22, 0x0d, 0x0f, 0xbb},
++ {0x24, 0x80, 0x00, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0xf0, 0x00, 0x02, 0xbb},
++ {0x39, 0x03, 0x0d, 0xbb},
++ {0x3a, 0x06, 0x1b, 0xbb},
++ {0x3b, 0x00, 0x95, 0xbb},
++ {0x3c, 0x04, 0xdb, 0xbb},
++ {0x57, 0x02, 0x00, 0xbb},
++ {0x58, 0x02, 0x66, 0xbb},
++ {0x59, 0x00, 0xff, 0xbb},
++ {0x5a, 0x01, 0x33, 0xbb},
++ {0x5c, 0x12, 0x0d, 0xbb},
++ {0x5d, 0x16, 0x11, 0xbb},
++ {0x64, 0x5e, 0x1c, 0xbb},
++ {}
++};
+ static const __u8 po3130_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+@@ -1764,26 +2633,43 @@ static const __u8 po1200_initVGA_data[][4] = {
+ };
+
+ struct sensor_info {
+- int sensorId;
+- __u8 I2cAdd;
+- __u8 IdAdd;
+- __u16 VpId;
+- __u8 m1;
+- __u8 m2;
+- __u8 op;
+- };
++ s8 sensorId;
++ u8 I2cAdd;
++ u8 IdAdd;
++ u16 VpId;
++ u8 m1;
++ u8 m2;
++ u8 op;
++};
+
+ static const struct sensor_info sensor_info_data[] = {
+ /* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+- {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+- {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
++ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
++ {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
++/* (tested in vc032x_probe_sensor) */
++/* {-1, 0x80 | 0x20, 0x83, 0x0000, 0x24, 0x25, 0x01}, */
+ {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
+- {SENSOR_MI1320, 0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
+- {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+ {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+ /* (tested in vc032x_probe_sensor) */
+ /* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
++ {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
++ {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
++ {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
++ {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
++/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
++ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
++/* {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
++/* {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, */
++ {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
+ {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
++ {-1, 0x80 | 0x2d, 0x00, 0x0000, 0x65, 0x67, 0x01},
++ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
++ {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
++ {SENSOR_MI1320_SOC, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x67, 0x01},
++/*fixme: previously detected?*/
++ {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01},
++/*fixme: not in the ms-win probe - may be found before?*/
++ {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+ };
+
+ /* read 'len' bytes in gspca_dev->usb_buf */
+@@ -1814,51 +2700,49 @@ static void reg_w(struct usb_device *dev,
+ 500);
+ }
+
+-static void read_sensor_register(struct gspca_dev *gspca_dev,
+- __u16 address, __u16 *value)
++static u16 read_sensor_register(struct gspca_dev *gspca_dev,
++ u16 address)
+ {
+ struct usb_device *dev = gspca_dev->dev;
+- __u8 ldata, mdata, hdata;
++ u8 ldata, mdata, hdata;
+ int retry = 50;
+
+- *value = 0;
+-
+ reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+- /*PDEBUG(D_PROBE, " I2c Bus Busy Wait 0x%02X ", tmpvalue); */
+ if (!(gspca_dev->usb_buf[0] & 0x02)) {
+- PDEBUG(D_ERR, "I2c Bus Busy Wait %d",
+- gspca_dev->usb_buf[0] & 0x02);
+- return;
++ PDEBUG(D_ERR, "I2c Bus Busy Wait %02x",
++ gspca_dev->usb_buf[0]);
++ return 0;
+ }
+ reg_w(dev, 0xa0, address, 0xb33a);
+ reg_w(dev, 0xa0, 0x02, 0xb339);
+
+- reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+- while (retry-- && gspca_dev->usb_buf[0]) {
++ do {
+ reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+-/* PDEBUG(D_PROBE, "Read again 0xb33b %d", tmpvalue); */
+- msleep(1);
+- }
++ if (gspca_dev->usb_buf[0] == 0x00)
++ break;
++ msleep(40);
++ } while (--retry >= 0);
++
+ reg_r(gspca_dev, 0xa1, 0xb33e, 1);
+ ldata = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0xa1, 0xb33d, 1);
+ mdata = gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0xa1, 0xb33c, 1);
+ hdata = gspca_dev->usb_buf[0];
+- PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x",
+- hdata, mdata, ldata);
++ if (hdata != 0 && mdata != 0 && ldata != 0)
++ PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x",
++ hdata, mdata, ldata);
+ reg_r(gspca_dev, 0xa1, 0xb334, 1);
+ if (gspca_dev->usb_buf[0] == 0x02)
+- *value = (hdata << 8) + mdata;
+- else
+- *value = hdata;
++ return (hdata << 8) + mdata;
++ return hdata;
+ }
+
+ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
+ {
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
+- __u16 value;
++ u16 value;
+ const struct sensor_info *ptsensor_info;
+
+ reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
+@@ -1872,48 +2756,51 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
+ reg_w(dev, 0xa0, 0x0c, 0xb309);
+ reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+ reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+- read_sensor_register(gspca_dev, ptsensor_info->IdAdd, &value);
+- if (value == ptsensor_info->VpId)
+- return ptsensor_info->sensorId;
+-
+- /* special case for MI0360 */
+- if (ptsensor_info->sensorId == SENSOR_MI1310_SOC
+- && value == 0x8243)
+- return SENSOR_MI0360;
++ value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
++ if (value == 0 && ptsensor_info->IdAdd == 0x82)
++ value = read_sensor_register(gspca_dev, 0x83);
++ if (value != 0) {
++ PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)",
++ value, i);
++ if (value == ptsensor_info->VpId)
++ return ptsensor_info->sensorId;
++
++ switch (value) {
++ case 0x7673:
++ return SENSOR_OV7670;
++ case 0x8243:
++ return SENSOR_MI0360;
++ }
++/*fixme: should return here*/
++ }
+ }
+ return -1;
+ }
+
+-static __u8 i2c_write(struct gspca_dev *gspca_dev,
+- __u8 reg, const __u8 *val, __u8 size)
++static void i2c_write(struct gspca_dev *gspca_dev,
++ u8 reg, const u8 *val,
++ u8 size) /* 1 or 2 */
+ {
+ struct usb_device *dev = gspca_dev->dev;
++ int retry;
+
+- if (size > 3 || size < 1)
+- return -EINVAL;
+ reg_r(gspca_dev, 0xa1, 0xb33f, 1);
++/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
+ reg_w(dev, 0xa0, size, 0xb334);
+ reg_w(dev, 0xa0, reg, 0xb33a);
+- switch (size) {
+- case 1:
+- reg_w(dev, 0xa0, val[0], 0xb336);
+- break;
+- case 2:
+- reg_w(dev, 0xa0, val[0], 0xb336);
++ reg_w(dev, 0xa0, val[0], 0xb336);
++ if (size > 1)
+ reg_w(dev, 0xa0, val[1], 0xb337);
+- break;
+- case 3:
+- reg_w(dev, 0xa0, val[0], 0xb336);
+- reg_w(dev, 0xa0, val[1], 0xb337);
+- reg_w(dev, 0xa0, val[2], 0xb338);
+- break;
+- default:
+- reg_w(dev, 0xa0, 0x01, 0xb334);
+- return -EINVAL;
+- }
+ reg_w(dev, 0xa0, 0x01, 0xb339);
+- reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+- return gspca_dev->usb_buf[0] == 0;
++ retry = 4;
++ do {
++ reg_r(gspca_dev, 0xa1, 0xb33b, 1);
++ if (gspca_dev->usb_buf[0] == 0)
++ break;
++ msleep(20);
++ } while (--retry > 0);
++ if (retry <= 0)
++ PDEBUG(D_ERR, "i2c_write failed");
+ }
+
+ static void put_tab_to_reg(struct gspca_dev *gspca_dev,
+@@ -1938,7 +2825,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
+ return;
+ case 0xcc: /* normal write */
+ reg_w(dev, 0xa0, data[i][2],
+- ((data[i][0])<<8) | data[i][1]);
++ (data[i][0]) << 8 | data[i][1]);
+ break;
+ case 0xaa: /* i2c op */
+ i2c_write(gspca_dev, data[i][1], &data[i][2], 1);
+@@ -1955,19 +2842,6 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
+ /*not reached*/
+ }
+
+-/*
+- "GammaT"=hex:04,17,31,4f,6a,83,99,ad,bf,ce,da,e5,ee,f5,fb,ff,ff
+- "MatrixT"=hex:60,f9,e5,e7,50,05,f3,e6,66
+- */
+-
+-static void vc0321_reset(struct gspca_dev *gspca_dev)
+-{
+- reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb04d);
+- reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb301);
+- msleep(100);
+- reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb003);
+- msleep(100);
+-}
+
+ /* this function is called at probe time */
+ static int sd_config(struct gspca_dev *gspca_dev,
+@@ -1979,10 +2853,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ int sensor;
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x02;
+ sd->bridge = id->driver_info;
+-
+- vc0321_reset(gspca_dev);
+ sensor = vc032x_probe_sensor(gspca_dev);
+ switch (sensor) {
+ case -1:
+@@ -2001,6 +2872,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ case SENSOR_MI1320:
+ PDEBUG(D_PROBE, "Find Sensor MI1320");
+ break;
++ case SENSOR_MI1320_SOC:
++ PDEBUG(D_PROBE, "Find Sensor MI1320_SOC");
++ break;
+ case SENSOR_OV7660:
+ PDEBUG(D_PROBE, "Find Sensor OV7660");
+ break;
+@@ -2020,12 +2894,23 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ cam->cam_mode = vc0321_mode;
+ cam->nmodes = ARRAY_SIZE(vc0321_mode);
+ } else {
+- if (sensor != SENSOR_PO1200) {
+- cam->cam_mode = vc0323_mode;
+- cam->nmodes = ARRAY_SIZE(vc0323_mode);
+- } else {
++ switch (sensor) {
++ case SENSOR_PO1200:
+ cam->cam_mode = svga_mode;
+ cam->nmodes = ARRAY_SIZE(svga_mode);
++ break;
++ case SENSOR_MI1310_SOC:
++ cam->cam_mode = vc0323_mode;
++ cam->nmodes = ARRAY_SIZE(vc0323_mode);
++ break;
++ case SENSOR_MI1320_SOC:
++ cam->cam_mode = bi_mode;
++ cam->nmodes = ARRAY_SIZE(bi_mode);
++ break;
++ default:
++ cam->cam_mode = vc0323_mode;
++ cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1;
++ break;
+ }
+ }
+
+@@ -2061,7 +2946,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ return 0;
+ }
+
+-/* this function is called at probe and time */
++/* this function is called at probe and resume time */
+ static int sd_init(struct gspca_dev *gspca_dev)
+ {
+ return 0;
+@@ -2124,9 +3009,18 @@ static void setsharpness(struct gspca_dev *gspca_dev)
+ static int sd_start(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
++ const __u8 (*init)[4];
+ const __u8 *GammaT = NULL;
+ const __u8 *MatrixT = NULL;
+ int mode;
++ static const u8 (*mi1320_soc_init[])[4] = {
++ mi1320_soc_InitSXGA,
++ mi1320_soc_InitSXGA_JPG,
++ mi1320_soc_InitVGA,
++ mi1320_soc_InitVGA_JPG,
++ mi1320_soc_InitQVGA,
++ mi1320_soc_InitQVGA_JPG
++ };
+
+ /* Assume start use the good resolution from gspca_dev->mode */
+ if (sd->bridge == BRIDGE_VC0321) {
+@@ -2134,6 +3028,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
++ sd->image_offset = 46;
++ } else {
++ if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
++ == V4L2_PIX_FMT_JPEG)
++ sd->image_offset = 0;
++ else
++ sd->image_offset = 32;
+ }
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+@@ -2141,115 +3042,87 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ case SENSOR_HV7131R:
+ GammaT = hv7131r_gamma;
+ MatrixT = hv7131r_matrix;
+- if (mode) {
+- /* 320x240 */
+- usb_exchange(gspca_dev, hv7131r_initQVGA_data);
+- } else {
+- /* 640x480 */
+- usb_exchange(gspca_dev, hv7131r_initVGA_data);
+- }
++ if (mode)
++ init = hv7131r_initQVGA_data; /* 320x240 */
++ else
++ init = hv7131r_initVGA_data; /* 640x480 */
+ break;
+ case SENSOR_OV7660:
+ GammaT = ov7660_gamma;
+ MatrixT = ov7660_matrix;
+- if (mode) {
+- /* 320x240 */
+- usb_exchange(gspca_dev, ov7660_initQVGA_data);
+- } else {
+- /* 640x480 */
+- usb_exchange(gspca_dev, ov7660_initVGA_data);
+- }
++ if (mode)
++ init = ov7660_initQVGA_data; /* 320x240 */
++ else
++ init = ov7660_initVGA_data; /* 640x480 */
+ break;
+ case SENSOR_OV7670:
+ /*GammaT = ov7660_gamma; */
+ /*MatrixT = ov7660_matrix; */
+- if (mode) {
+- /* 320x240 */
+- usb_exchange(gspca_dev, ov7670_initQVGA_JPG);
+- } else {
+- /* 640x480 */
+- usb_exchange(gspca_dev, ov7670_initVGA_JPG);
+- }
++ if (mode)
++ init = ov7670_initQVGA_JPG; /* 320x240 */
++ else
++ init = ov7670_initVGA_JPG; /* 640x480 */
+ break;
+ case SENSOR_MI0360:
+ GammaT = mi1320_gamma;
+ MatrixT = mi0360_matrix;
+- if (mode) {
+- /* 320x240 */
+- usb_exchange(gspca_dev, mi0360_initQVGA_JPG);
+- } else {
+- /* 640x480 */
+- usb_exchange(gspca_dev, mi0360_initVGA_JPG);
+- }
++ if (mode)
++ init = mi0360_initQVGA_JPG; /* 320x240 */
++ else
++ init = mi0360_initVGA_JPG; /* 640x480 */
+ break;
+ case SENSOR_MI1310_SOC:
+- if (mode) {
+- /* 320x240 */
+- usb_exchange(gspca_dev, mi1310_socinitQVGA_JPG);
+- } else {
+- /* 640x480 */
+- usb_exchange(gspca_dev, mi1310_socinitVGA_JPG);
++ GammaT = mi1320_gamma;
++ MatrixT = mi1320_matrix;
++ switch (mode) {
++ case 1:
++ init = mi1310_socinitQVGA_JPG; /* 320x240 */
++ break;
++ case 0:
++ init = mi1310_socinitVGA_JPG; /* 640x480 */
++ break;
++ default:
++ init = mi1310_soc_InitSXGA_JPG; /* 1280x1024 */
++ break;
+ }
+ break;
+ case SENSOR_MI1320:
+ GammaT = mi1320_gamma;
+ MatrixT = mi1320_matrix;
+- if (mode) {
+- /* 320x240 */
+- usb_exchange(gspca_dev, mi1320_initQVGA_data);
+- } else {
+- /* 640x480 */
+- usb_exchange(gspca_dev, mi1320_initVGA_data);
+- }
++ if (mode)
++ init = mi1320_initQVGA_data; /* 320x240 */
++ else
++ init = mi1320_initVGA_data; /* 640x480 */
++ break;
++ case SENSOR_MI1320_SOC:
++ GammaT = mi1320_gamma;
++ MatrixT = mi1320_matrix;
++ init = mi1320_soc_init[mode];
+ break;
+ case SENSOR_PO3130NC:
+ GammaT = po3130_gamma;
+ MatrixT = po3130_matrix;
+- if (mode) {
+- /* 320x240 */
+- usb_exchange(gspca_dev, po3130_initQVGA_data);
+- } else {
+- /* 640x480 */
+- usb_exchange(gspca_dev, po3130_initVGA_data);
+- }
+- usb_exchange(gspca_dev, po3130_rundata);
++ if (mode)
++ init = po3130_initQVGA_data; /* 320x240 */
++ else
++ init = po3130_initVGA_data; /* 640x480 */
++ usb_exchange(gspca_dev, init);
++ init = po3130_rundata;
+ break;
+- case SENSOR_PO1200:
++ default:
++/* case SENSOR_PO1200: */
+ GammaT = po1200_gamma;
+ MatrixT = po1200_matrix;
+- usb_exchange(gspca_dev, po1200_initVGA_data);
++ init = po1200_initVGA_data;
+ break;
+- default:
+- PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
+- return -EMEDIUMTYPE;
+ }
++ usb_exchange(gspca_dev, init);
+ if (GammaT && MatrixT) {
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b);
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
+ put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
+
+- /* Seem SHARPNESS */
+- /*
+- reg_w(gspca_dev->dev, 0xa0, 0x80, 0xb80a);
+- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80b);
+- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80e);
+- */
+- /* all 0x40 ??? do nothing
+- reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb822);
+- reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb823);
+- reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb824);
+- */
+- /* Only works for HV7131R ??
+- reg_r (gspca_dev, 0xa1, 0xb881, 1);
+- reg_w(gspca_dev->dev, 0xa0, 0xfe01, 0xb881);
+- reg_w(gspca_dev->dev, 0xa0, 0x79, 0xb801);
+- */
+- /* only hv7131r et ov7660
+- reg_w(gspca_dev->dev, 0xa0, 0x20, 0xb827);
+- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb826); * ISP_GAIN 80
+- reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
+- */
+ /* set the led on 0x0892 0x0896 */
+ if (sd->sensor != SENSOR_PO1200) {
+ reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+@@ -2296,12 +3169,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ "vc032x header packet found len %d", len);
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+- if (sd->bridge == BRIDGE_VC0321) {
+-#define VCHDRSZ 46
+- data += VCHDRSZ;
+- len -= VCHDRSZ;
+-#undef VCHDRSZ
+- }
++ data += sd->image_offset;
++ len -= sd->image_offset;
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, len);
+ return;
+@@ -2399,7 +3268,8 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
++ default:
++/* case 2: * V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+@@ -2424,6 +3294,7 @@ static const struct sd_desc sd_desc = {
+
+ /* -- module initialisation -- */
+ static const __devinitdata struct usb_device_id device_table[] = {
++ {USB_DEVICE(0x041e, 0x405b), .driver_info = BRIDGE_VC0323},
+ {USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321},
+ {USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321},
+ {USB_DEVICE(0x046d, 0x0897), .driver_info = BRIDGE_VC0321},
+@@ -2432,6 +3303,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321},
+ {USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321},
+ {USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321},
++ {USB_DEVICE(0x15b8, 0x6001), .driver_info = BRIDGE_VC0323},
+ {USB_DEVICE(0x15b8, 0x6002), .driver_info = BRIDGE_VC0323},
+ {USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323},
+ {}
+@@ -2460,8 +3332,11 @@ static struct usb_driver sd_driver = {
+ /* -- module insert / remove -- */
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
+index ec2a53d..4fe01d8 100644
+--- a/drivers/media/video/gspca/zc3xx.c
++++ b/drivers/media/video/gspca/zc3xx.c
+@@ -23,6 +23,7 @@
+ #define MODULE_NAME "zc3xx"
+
+ #include "gspca.h"
++#include "jpeg.h"
+
+ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
+ "Serge A. Suchkov <Serge.A.S@tochka.ru>");
+@@ -31,7 +32,7 @@ MODULE_LICENSE("GPL");
+
+ static int force_sensor = -1;
+
+-#include "jpeg.h"
++#define QUANT_VAL 1 /* quantization table */
+ #include "zc3xx-reg.h"
+
+ /* specific webcam descriptor */
+@@ -44,30 +45,36 @@ struct sd {
+ __u8 autogain;
+ __u8 lightfreq;
+ __u8 sharpness;
++ u8 quality; /* image quality */
++#define QUALITY_MIN 40
++#define QUALITY_MAX 60
++#define QUALITY_DEF 50
+
+- char qindex;
+ signed char sensor; /* Type of image sensor chip */
+ /* !! values used in different tables */
+-#define SENSOR_CS2102 0
+-#define SENSOR_CS2102K 1
+-#define SENSOR_GC0305 2
+-#define SENSOR_HDCS2020b 3
+-#define SENSOR_HV7131B 4
+-#define SENSOR_HV7131C 5
+-#define SENSOR_ICM105A 6
+-#define SENSOR_MC501CB 7
+-#define SENSOR_OV7620 8
+-/*#define SENSOR_OV7648 8 - same values */
+-#define SENSOR_OV7630C 9
+-#define SENSOR_PAS106 10
+-#define SENSOR_PAS202B 11
+-#define SENSOR_PB0330 12
+-#define SENSOR_PO2030 13
+-#define SENSOR_TAS5130CK 14
+-#define SENSOR_TAS5130CXX 15
+-#define SENSOR_TAS5130C_VF0250 16
+-#define SENSOR_MAX 17
++#define SENSOR_ADCM2700 0
++#define SENSOR_CS2102 1
++#define SENSOR_CS2102K 2
++#define SENSOR_GC0305 3
++#define SENSOR_HDCS2020b 4
++#define SENSOR_HV7131B 5
++#define SENSOR_HV7131C 6
++#define SENSOR_ICM105A 7
++#define SENSOR_MC501CB 8
++#define SENSOR_OV7620 9
++/*#define SENSOR_OV7648 9 - same values */
++#define SENSOR_OV7630C 10
++#define SENSOR_PAS106 11
++#define SENSOR_PAS202B 12
++#define SENSOR_PB0330 13
++#define SENSOR_PO2030 14
++#define SENSOR_TAS5130CK 15
++#define SENSOR_TAS5130CXX 16
++#define SENSOR_TAS5130C_VF0250 17
++#define SENSOR_MAX 18
+ unsigned short chip_revision;
++
++ u8 *jpeg_hdr;
+ };
+
+ /* V4L2 controls supported by the driver */
+@@ -206,6 +213,213 @@ struct usb_action {
+ __u16 idx;
+ };
+
++static const struct usb_action adcm2700_Initial[] = {
++ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
++ {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */
++ {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */
++ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
++ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
++ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
++ {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */
++ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
++ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
++ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
++ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
++ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
++ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
++ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
++ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
++ {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */
++ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */
++ {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */
++ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */
++ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
++ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
++ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
++ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
++ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
++ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
++ {0xa0, 0x58, ZC3XX_R116_RGAIN}, /* 01,16,58,cc */
++ {0xa0, 0x5a, ZC3XX_R118_BGAIN}, /* 01,18,5a,cc */
++ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
++ {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */
++ {0xbb, 0x00, 0x0408}, /* 04,00,08,bb */
++ {0xdd, 0x00, 0x0200}, /* 00,02,00,dd */
++ {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */
++ {0xbb, 0xe0, 0x0c2e}, /* 0c,e0,2e,bb */
++ {0xbb, 0x01, 0x2000}, /* 20,01,00,bb */
++ {0xbb, 0x96, 0x2400}, /* 24,96,00,bb */
++ {0xbb, 0x06, 0x1006}, /* 10,06,06,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xbb, 0x5f, 0x2090}, /* 20,5f,90,bb */
++ {0xbb, 0x01, 0x8000}, /* 80,01,00,bb */
++ {0xbb, 0x09, 0x8400}, /* 84,09,00,bb */
++ {0xbb, 0x86, 0x0002}, /* 00,86,02,bb */
++ {0xbb, 0xe6, 0x0401}, /* 04,e6,01,bb */
++ {0xbb, 0x86, 0x0802}, /* 08,86,02,bb */
++ {0xbb, 0xe6, 0x0c01}, /* 0c,e6,01,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0020}, /* 00,fe,20,aa */
++/*mswin+*/
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},
++ {0xaa, 0xfe, 0x0002},
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
++ {0xaa, 0xb4, 0xcd37},
++ {0xaa, 0xa4, 0x0004},
++ {0xaa, 0xa8, 0x0007},
++ {0xaa, 0xac, 0x0004},
++/*mswin-*/
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xbb, 0x04, 0x0400}, /* 04,04,00,bb */
++ {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
++ {0xbb, 0x01, 0x0400}, /* 04,01,00,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xbb, 0x41, 0x2803}, /* 28,41,03,bb */
++ {0xbb, 0x40, 0x2c03}, /* 2c,40,03,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */
++ {}
++};
++static const struct usb_action adcm2700_InitialScale[] = {
++ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
++ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
++ {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */
++ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
++ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
++ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
++ {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */
++ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
++ {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
++ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
++ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
++ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
++ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
++ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
++ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
++ {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */
++ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */
++ {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */
++ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */
++ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
++ {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
++ {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
++ {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
++ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
++ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
++ {0xa0, 0x58, ZC3XX_R116_RGAIN}, /* 01,16,58,cc */
++ {0xa0, 0x5a, ZC3XX_R118_BGAIN}, /* 01,18,5a,cc */
++ {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
++ {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */
++ {0xbb, 0x00, 0x0408}, /* 04,00,08,bb */
++ {0xdd, 0x00, 0x0200}, /* 00,02,00,dd */
++ {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */
++ {0xdd, 0x00, 0x0050}, /* 00,00,50,dd */
++ {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */
++ {0xbb, 0xe0, 0x0c2e}, /* 0c,e0,2e,bb */
++ {0xbb, 0x01, 0x2000}, /* 20,01,00,bb */
++ {0xbb, 0x96, 0x2400}, /* 24,96,00,bb */
++ {0xbb, 0x06, 0x1006}, /* 10,06,06,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xbb, 0x5f, 0x2090}, /* 20,5f,90,bb */
++ {0xbb, 0x01, 0x8000}, /* 80,01,00,bb */
++ {0xbb, 0x09, 0x8400}, /* 84,09,00,bb */
++ {0xbb, 0x86, 0x0002}, /* 00,88,02,bb */
++ {0xbb, 0xe6, 0x0401}, /* 04,e6,01,bb */
++ {0xbb, 0x86, 0x0802}, /* 08,88,02,bb */
++ {0xbb, 0xe6, 0x0c01}, /* 0c,e6,01,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0020}, /* 00,fe,20,aa */
++ /*******/
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */
++ {0xbb, 0x04, 0x0400}, /* 04,04,00,bb */
++ {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
++ {0xbb, 0x01, 0x0400}, /* 04,01,00,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xbb, 0x41, 0x2803}, /* 28,41,03,bb */
++ {0xbb, 0x40, 0x2c03}, /* 2c,40,03,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */
++ {}
++};
++static const struct usb_action adcm2700_50HZ[] = {
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xbb, 0x05, 0x8400}, /* 84,05,00,bb */
++ {0xbb, 0xd0, 0xb007}, /* b0,d0,07,bb */
++ {0xbb, 0xa0, 0xb80f}, /* b8,a0,0f,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */
++ {0xaa, 0x26, 0x00d0}, /* 00,26,d0,aa */
++ {0xaa, 0x28, 0x0002}, /* 00,28,02,aa */
++ {}
++};
++static const struct usb_action adcm2700_60HZ[] = {
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xbb, 0x07, 0x8400}, /* 84,07,00,bb */
++ {0xbb, 0x82, 0xb006}, /* b0,82,06,bb */
++ {0xbb, 0x04, 0xb80d}, /* b8,04,0d,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */
++ {0xaa, 0x26, 0x0057}, /* 00,26,57,aa */
++ {0xaa, 0x28, 0x0002}, /* 00,28,02,aa */
++ {}
++};
++static const struct usb_action adcm2700_NoFliker[] = {
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */
++ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */
++ {0xbb, 0x07, 0x8400}, /* 84,07,00,bb */
++ {0xbb, 0x05, 0xb000}, /* b0,05,00,bb */
++ {0xbb, 0xa0, 0xb801}, /* b8,a0,01,bb */
++ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
++ {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */
++ {}
++};
+ static const struct usb_action cs2102_Initial[] = {
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0008},
+@@ -877,7 +1091,7 @@ static const struct usb_action cs2102K_Initial[] = {
+ };
+
+ static const struct usb_action cs2102K_InitialScale[] = {
+- {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
++ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+@@ -894,6 +1108,7 @@ static const struct usb_action cs2102K_InitialScale[] = {
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
++/*fixme: next sequence = i2c exchanges*/
+ {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+@@ -1077,207 +1292,6 @@ static const struct usb_action cs2102K_InitialScale[] = {
+ {0xa0, 0x60, ZC3XX_R116_RGAIN},
+ {0xa0, 0x40, ZC3XX_R117_GGAIN},
+ {0xa0, 0x4c, ZC3XX_R118_BGAIN},
+- {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+- {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+- {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+- {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+- {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+- {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+- {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+- {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+- {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+- {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+- {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+- {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+- {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+- {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+- {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+- {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+- {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+- {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
+- {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x0A, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x0B, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x0C, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x0D, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0xA3, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x0E, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x0C, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
+- {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+- {0xa0, 0x78, ZC3XX_R18D_YTARGET},
+- {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+- {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+- {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+- {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+- {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+- {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+- {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+- {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+- {0xa0, 0x00, 0x01ad},
+- {0xa0, 0x01, 0x01b1},
+- {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+- {0xa0, 0x60, ZC3XX_R116_RGAIN},
+- {0xa0, 0x40, ZC3XX_R117_GGAIN},
+- {0xa0, 0x4c, ZC3XX_R118_BGAIN},
+- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
+- {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
+- {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
+- {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */
+- {0xa0, 0x38, ZC3XX_R121_GAMMA01},
+- {0xa0, 0x59, ZC3XX_R122_GAMMA02},
+- {0xa0, 0x79, ZC3XX_R123_GAMMA03},
+- {0xa0, 0x92, ZC3XX_R124_GAMMA04},
+- {0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+- {0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+- {0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+- {0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+- {0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+- {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+- {0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+- {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+- {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+- {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+- {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+- {0xa0, 0x26, ZC3XX_R130_GAMMA10},
+- {0xa0, 0x22, ZC3XX_R131_GAMMA11},
+- {0xa0, 0x20, ZC3XX_R132_GAMMA12},
+- {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+- {0xa0, 0x16, ZC3XX_R134_GAMMA14},
+- {0xa0, 0x13, ZC3XX_R135_GAMMA15},
+- {0xa0, 0x10, ZC3XX_R136_GAMMA16},
+- {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+- {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+- {0xa0, 0x09, ZC3XX_R139_GAMMA19},
+- {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+- {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+- {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+- {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+- {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+- {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+- {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */
+- {0xa0, 0xf4, ZC3XX_R10B_RGB01},
+- {0xa0, 0xf4, ZC3XX_R10C_RGB02},
+- {0xa0, 0xf4, ZC3XX_R10D_RGB10},
+- {0xa0, 0x58, ZC3XX_R10E_RGB11},
+- {0xa0, 0xf4, ZC3XX_R10F_RGB12},
+- {0xa0, 0xf4, ZC3XX_R110_RGB20},
+- {0xa0, 0xf4, ZC3XX_R111_RGB21},
+- {0xa0, 0x58, ZC3XX_R112_RGB22},
+- {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+- {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+- {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+- {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+- {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+- {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW},
+- {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+- {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+- {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW},
+- {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+- {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+- {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW},
+- {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+- {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+- {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
+- {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+- {0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+- {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1},
+- {0xa0, 0x19, ZC3XX_R01F_HSYNC_2},
+- {0xa0, 0x1f, ZC3XX_R020_HSYNC_3},
+- {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+- {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+- {0xa0, 0x60, ZC3XX_R116_RGAIN},
+- {0xa0, 0x40, ZC3XX_R117_GGAIN},
+- {0xa0, 0x4c, ZC3XX_R118_BGAIN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+ {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+@@ -1334,6 +1348,7 @@ static const struct usb_action cs2102K_InitialScale[] = {
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
++/*fixme:what does the next sequence?*/
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+ {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+@@ -6237,7 +6252,7 @@ static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
+ {}
+ };
+
+-static int reg_r_i(struct gspca_dev *gspca_dev,
++static u8 reg_r_i(struct gspca_dev *gspca_dev,
+ __u16 index)
+ {
+ usb_control_msg(gspca_dev->dev,
+@@ -6250,10 +6265,10 @@ static int reg_r_i(struct gspca_dev *gspca_dev,
+ return gspca_dev->usb_buf[0];
+ }
+
+-static int reg_r(struct gspca_dev *gspca_dev,
++static u8 reg_r(struct gspca_dev *gspca_dev,
+ __u16 index)
+ {
+- int ret;
++ u8 ret;
+
+ ret = reg_r_i(gspca_dev, index);
+ PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret);
+@@ -6286,8 +6301,8 @@ static __u16 i2c_read(struct gspca_dev *gspca_dev,
+ __u8 retbyte;
+ __u16 retval;
+
+- reg_w_i(gspca_dev->dev, reg, 0x92);
+- reg_w_i(gspca_dev->dev, 0x02, 0x90); /* <- read command */
++ reg_w_i(gspca_dev->dev, reg, 0x0092);
++ reg_w_i(gspca_dev->dev, 0x02, 0x0090); /* <- read command */
+ msleep(25);
+ retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
+ retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */
+@@ -6332,6 +6347,12 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
+ action->idx & 0xff, /* valL */
+ action->idx >> 8); /* valH */
+ break;
++ case 0xbb:
++ i2c_write(gspca_dev,
++ action->idx >> 8, /* reg */
++ action->idx & 0xff, /* valL */
++ action->val); /* valH */
++ break;
+ default:
+ /* case 0xdd: * delay */
+ msleep(action->val / 64 + 10);
+@@ -6347,6 +6368,10 @@ static void setmatrix(struct gspca_dev *gspca_dev)
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ const __u8 *matrix;
++ static const u8 adcm2700_matrix[9] =
++/* {0x66, 0xed, 0xed, 0xed, 0x66, 0xed, 0xed, 0xed, 0x66}; */
++/*ms-win*/
++ {0x74, 0xed, 0xed, 0xed, 0x74, 0xed, 0xed, 0xed, 0x74};
+ static const __u8 gc0305_matrix[9] =
+ {0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50};
+ static const __u8 ov7620_matrix[9] =
+@@ -6358,23 +6383,24 @@ static void setmatrix(struct gspca_dev *gspca_dev)
+ static const __u8 vf0250_matrix[9] =
+ {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
+ static const __u8 *matrix_tb[SENSOR_MAX] = {
+- NULL, /* SENSOR_CS2102 0 */
+- NULL, /* SENSOR_CS2102K 1 */
+- gc0305_matrix, /* SENSOR_GC0305 2 */
+- NULL, /* SENSOR_HDCS2020b 3 */
+- NULL, /* SENSOR_HV7131B 4 */
+- NULL, /* SENSOR_HV7131C 5 */
+- NULL, /* SENSOR_ICM105A 6 */
+- NULL, /* SENSOR_MC501CB 7 */
+- ov7620_matrix, /* SENSOR_OV7620 8 */
+- NULL, /* SENSOR_OV7630C 9 */
+- NULL, /* SENSOR_PAS106 10 */
+- pas202b_matrix, /* SENSOR_PAS202B 11 */
+- NULL, /* SENSOR_PB0330 12 */
+- po2030_matrix, /* SENSOR_PO2030 13 */
+- NULL, /* SENSOR_TAS5130CK 14 */
+- NULL, /* SENSOR_TAS5130CXX 15 */
+- vf0250_matrix, /* SENSOR_TAS5130C_VF0250 16 */
++ adcm2700_matrix, /* SENSOR_ADCM2700 0 */
++ NULL, /* SENSOR_CS2102 1 */
++ NULL, /* SENSOR_CS2102K 2 */
++ gc0305_matrix, /* SENSOR_GC0305 3 */
++ NULL, /* SENSOR_HDCS2020b 4 */
++ NULL, /* SENSOR_HV7131B 5 */
++ NULL, /* SENSOR_HV7131C 6 */
++ NULL, /* SENSOR_ICM105A 7 */
++ NULL, /* SENSOR_MC501CB 8 */
++ ov7620_matrix, /* SENSOR_OV7620 9 */
++ NULL, /* SENSOR_OV7630C 10 */
++ NULL, /* SENSOR_PAS106 11 */
++ pas202b_matrix, /* SENSOR_PAS202B 12 */
++ NULL, /* SENSOR_PB0330 13 */
++ po2030_matrix, /* SENSOR_PO2030 14 */
++ NULL, /* SENSOR_TAS5130CK 15 */
++ NULL, /* SENSOR_TAS5130CXX 16 */
++ vf0250_matrix, /* SENSOR_TAS5130C_VF0250 17 */
+ };
+
+ matrix = matrix_tb[sd->sensor];
+@@ -6398,8 +6424,11 @@ static void setbrightness(struct gspca_dev *gspca_dev)
+ /*fixme: is it really write to 011d and 018d for all other sensors? */
+ brightness = sd->brightness;
+ reg_w(gspca_dev->dev, brightness, 0x011d);
+- if (sd->sensor == SENSOR_HV7131B)
++ switch (sd->sensor) {
++ case SENSOR_ADCM2700:
++ case SENSOR_HV7131B:
+ return;
++ }
+ if (brightness < 0x70)
+ brightness += 0x10;
+ else
+@@ -6536,10 +6565,10 @@ static void setquality(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+- __u8 quality;
+ __u8 frxt;
+
+ switch (sd->sensor) {
++ case SENSOR_ADCM2700:
+ case SENSOR_GC0305:
+ case SENSOR_HV7131B:
+ case SENSOR_OV7620:
+@@ -6547,26 +6576,18 @@ static void setquality(struct gspca_dev *gspca_dev)
+ return;
+ }
+ /*fixme: is it really 0008 0007 0018 for all other sensors? */
+- quality = sd->qindex;
+- reg_w(dev, quality, 0x0008);
++ reg_w(dev, QUANT_VAL, 0x0008);
+ frxt = 0x30;
+ reg_w(dev, frxt, 0x0007);
+- switch (quality) {
+- case 0:
+- case 1:
+- case 2:
+- frxt = 0xff;
+- break;
+- case 3:
+- frxt = 0xf0;
+- break;
+- case 4:
+- frxt = 0xe0;
+- break;
+- case 5:
+- frxt = 0x20;
+- break;
+- }
++#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2
++ frxt = 0xff;
++#elif QUANT_VAL == 3
++ frxt = 0xf0;
++#elif QUANT_VAL == 4
++ frxt = 0xe0;
++#else
++ frxt = 0x20;
++#endif
+ reg_w(dev, frxt, 0x0018);
+ }
+
+@@ -6583,71 +6604,75 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
+ int i, mode;
+ const struct usb_action *zc3_freq;
+ static const struct usb_action *freq_tb[SENSOR_MAX][6] = {
+-/* SENSOR_CS2102 0 */
++/* SENSOR_ADCM2700 0 */
++ {adcm2700_NoFliker, adcm2700_NoFliker,
++ adcm2700_50HZ, adcm2700_50HZ,
++ adcm2700_60HZ, adcm2700_60HZ},
++/* SENSOR_CS2102 1 */
+ {cs2102_NoFliker, cs2102_NoFlikerScale,
+ cs2102_50HZ, cs2102_50HZScale,
+ cs2102_60HZ, cs2102_60HZScale},
+-/* SENSOR_CS2102K 1 */
++/* SENSOR_CS2102K 2 */
+ {cs2102_NoFliker, cs2102_NoFlikerScale,
+ NULL, NULL, /* currently disabled */
+ NULL, NULL},
+-/* SENSOR_GC0305 2 */
++/* SENSOR_GC0305 3 */
+ {gc0305_NoFliker, gc0305_NoFliker,
+ gc0305_50HZ, gc0305_50HZ,
+ gc0305_60HZ, gc0305_60HZ},
+-/* SENSOR_HDCS2020b 3 */
++/* SENSOR_HDCS2020b 4 */
+ {hdcs2020b_NoFliker, hdcs2020b_NoFliker,
+ hdcs2020b_50HZ, hdcs2020b_50HZ,
+ hdcs2020b_60HZ, hdcs2020b_60HZ},
+-/* SENSOR_HV7131B 4 */
++/* SENSOR_HV7131B 5 */
+ {hv7131b_NoFlikerScale, hv7131b_NoFliker,
+ hv7131b_50HZScale, hv7131b_50HZ,
+ hv7131b_60HZScale, hv7131b_60HZ},
+-/* SENSOR_HV7131C 5 */
++/* SENSOR_HV7131C 6 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+-/* SENSOR_ICM105A 6 */
++/* SENSOR_ICM105A 7 */
+ {icm105a_NoFliker, icm105a_NoFlikerScale,
+ icm105a_50HZ, icm105a_50HZScale,
+ icm105a_60HZ, icm105a_60HZScale},
+-/* SENSOR_MC501CB 7 */
++/* SENSOR_MC501CB 8 */
+ {MC501CB_NoFliker, MC501CB_NoFlikerScale,
+ MC501CB_50HZ, MC501CB_50HZScale,
+ MC501CB_60HZ, MC501CB_60HZScale},
+-/* SENSOR_OV7620 8 */
++/* SENSOR_OV7620 9 */
+ {OV7620_NoFliker, OV7620_NoFliker,
+ OV7620_50HZ, OV7620_50HZ,
+ OV7620_60HZ, OV7620_60HZ},
+-/* SENSOR_OV7630C 9 */
++/* SENSOR_OV7630C 10 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+-/* SENSOR_PAS106 10 */
++/* SENSOR_PAS106 11 */
+ {pas106b_NoFliker, pas106b_NoFliker,
+ pas106b_50HZ, pas106b_50HZ,
+ pas106b_60HZ, pas106b_60HZ},
+-/* SENSOR_PAS202B 11 */
++/* SENSOR_PAS202B 12 */
+ {pas202b_NoFlikerScale, pas202b_NoFliker,
+ pas202b_50HZScale, pas202b_50HZ,
+ pas202b_60HZScale, pas202b_60HZ},
+-/* SENSOR_PB0330 12 */
++/* SENSOR_PB0330 13 */
+ {pb0330_NoFliker, pb0330_NoFlikerScale,
+ pb0330_50HZ, pb0330_50HZScale,
+ pb0330_60HZ, pb0330_60HZScale},
+-/* SENSOR_PO2030 13 */
++/* SENSOR_PO2030 14 */
+ {PO2030_NoFliker, PO2030_NoFliker,
+ PO2030_50HZ, PO2030_50HZ,
+ PO2030_60HZ, PO2030_60HZ},
+-/* SENSOR_TAS5130CK 14 */
++/* SENSOR_TAS5130CK 15 */
+ {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+ tas5130cxx_50HZ, tas5130cxx_50HZScale,
+ tas5130cxx_60HZ, tas5130cxx_60HZScale},
+-/* SENSOR_TAS5130CXX 15 */
++/* SENSOR_TAS5130CXX 16 */
+ {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+ tas5130cxx_50HZ, tas5130cxx_50HZScale,
+ tas5130cxx_60HZ, tas5130cxx_60HZScale},
+-/* SENSOR_TAS5130C_VF0250 16 */
++/* SENSOR_TAS5130C_VF0250 17 */
+ {tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
+ tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
+ tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
+@@ -6701,6 +6726,7 @@ static void send_unknown(struct usb_device *dev, int sensor)
+ reg_w(dev, 0x0c, 0x003b);
+ reg_w(dev, 0x08, 0x0038);
+ break;
++ case SENSOR_ADCM2700:
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PB0330:
+@@ -6743,26 +6769,25 @@ static int sif_probe(struct gspca_dev *gspca_dev)
+ static int vga_2wr_probe(struct gspca_dev *gspca_dev)
+ {
+ struct usb_device *dev = gspca_dev->dev;
+- __u8 retbyte;
+- __u16 checkword;
++ u16 retword;
+
+ start_2wr_probe(dev, 0x00); /* HV7131B */
+ i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
+- retbyte = i2c_read(gspca_dev, 0x01);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x01);
++ if (retword != 0)
+ return 0x00; /* HV7131B */
+
+ start_2wr_probe(dev, 0x04); /* CS2102 */
+ i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
+- retbyte = i2c_read(gspca_dev, 0x01);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x01);
++ if (retword != 0)
+ return 0x04; /* CS2102 */
+
+ start_2wr_probe(dev, 0x06); /* OmniVision */
+ reg_w(dev, 0x08, 0x008d);
+ i2c_write(gspca_dev, 0x11, 0xaa, 0x00);
+- retbyte = i2c_read(gspca_dev, 0x11);
+- if (retbyte != 0) {
++ retword = i2c_read(gspca_dev, 0x11);
++ if (retword != 0) {
+ /* (should have returned 0xaa) --> Omnivision? */
+ /* reg_r 0x10 -> 0x06 --> */
+ goto ov_check;
+@@ -6770,40 +6795,40 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev)
+
+ start_2wr_probe(dev, 0x08); /* HDCS2020 */
+ i2c_write(gspca_dev, 0x15, 0xaa, 0x00);
+- retbyte = i2c_read(gspca_dev, 0x15);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x15);
++ if (retword != 0)
+ return 0x08; /* HDCS2020 */
+
+ start_2wr_probe(dev, 0x0a); /* PB0330 */
+ i2c_write(gspca_dev, 0x07, 0xaa, 0xaa);
+- retbyte = i2c_read(gspca_dev, 0x07);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x07);
++ if (retword != 0)
+ return 0x0a; /* PB0330 */
+- retbyte = i2c_read(gspca_dev, 0x03);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x03);
++ if (retword != 0)
+ return 0x0a; /* PB0330 ?? */
+- retbyte = i2c_read(gspca_dev, 0x04);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x04);
++ if (retword != 0)
+ return 0x0a; /* PB0330 ?? */
+
+ start_2wr_probe(dev, 0x0c); /* ICM105A */
+ i2c_write(gspca_dev, 0x01, 0x11, 0x00);
+- retbyte = i2c_read(gspca_dev, 0x01);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x01);
++ if (retword != 0)
+ return 0x0c; /* ICM105A */
+
+ start_2wr_probe(dev, 0x0e); /* PAS202BCB */
+ reg_w(dev, 0x08, 0x008d);
+ i2c_write(gspca_dev, 0x03, 0xaa, 0x00);
+ msleep(500);
+- retbyte = i2c_read(gspca_dev, 0x03);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x03);
++ if (retword != 0)
+ return 0x0e; /* PAS202BCB */
+
+ start_2wr_probe(dev, 0x02); /* ?? */
+ i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
+- retbyte = i2c_read(gspca_dev, 0x01);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x01);
++ if (retword != 0)
+ return 0x02; /* ?? */
+ ov_check:
+ reg_r(gspca_dev, 0x0010); /* ?? */
+@@ -6817,12 +6842,10 @@ ov_check:
+ msleep(500);
+ reg_w(dev, 0x01, 0x0012);
+ i2c_write(gspca_dev, 0x12, 0x80, 0x00); /* sensor reset */
+- retbyte = i2c_read(gspca_dev, 0x0a);
+- checkword = retbyte << 8;
+- retbyte = i2c_read(gspca_dev, 0x0b);
+- checkword |= retbyte;
+- PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", checkword);
+- switch (checkword) {
++ retword = i2c_read(gspca_dev, 0x0a) << 8;
++ retword |= i2c_read(gspca_dev, 0x0b);
++ PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", retword);
++ switch (retword) {
+ case 0x7631: /* OV7630C */
+ reg_w(dev, 0x06, 0x0010);
+ break;
+@@ -6832,7 +6855,7 @@ ov_check:
+ default:
+ return -1; /* not OmniVision */
+ }
+- return checkword;
++ return retword;
+ }
+
+ struct sensor_by_chipset_revision {
+@@ -6845,6 +6868,7 @@ static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
+ {0x8001, 0x13},
+ {0x8000, 0x14}, /* CS2102K */
+ {0x8400, 0x15}, /* TAS5130K */
++ {0x4001, 0x16}, /* ADCM2700 */
+ };
+
+ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+@@ -6853,7 +6877,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
+ __u8 retbyte;
+- __u16 checkword;
++ u16 retword;
+
+ /*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
+ reg_w(dev, 0x02, 0x0010);
+@@ -6865,27 +6889,25 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+ reg_w(dev, 0x03, 0x0012);
+ reg_w(dev, 0x01, 0x0012);
+ reg_w(dev, 0x05, 0x0012);
+- retbyte = i2c_read(gspca_dev, 0x14);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x14);
++ if (retword != 0)
+ return 0x11; /* HV7131R */
+- retbyte = i2c_read(gspca_dev, 0x15);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x15);
++ if (retword != 0)
+ return 0x11; /* HV7131R */
+- retbyte = i2c_read(gspca_dev, 0x16);
+- if (retbyte != 0)
++ retword = i2c_read(gspca_dev, 0x16);
++ if (retword != 0)
+ return 0x11; /* HV7131R */
+
+ reg_w(dev, 0x02, 0x0010);
+- retbyte = reg_r(gspca_dev, 0x000b);
+- checkword = retbyte << 8;
+- retbyte = reg_r(gspca_dev, 0x000a);
+- checkword |= retbyte;
+- PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", checkword);
++ retword = reg_r(gspca_dev, 0x000b) << 8;
++ retword |= reg_r(gspca_dev, 0x000a);
++ PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", retword);
+ reg_r(gspca_dev, 0x0010);
+ /* this is tested only once anyway */
+ for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
+- if (chipset_revision_sensor[i].revision == checkword) {
+- sd->chip_revision = checkword;
++ if (chipset_revision_sensor[i].revision == retword) {
++ sd->chip_revision = retword;
+ send_unknown(dev, SENSOR_PB0330);
+ return chipset_revision_sensor[i].internal_sensor_id;
+ }
+@@ -6897,8 +6919,8 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+ reg_w(dev, 0x0a, 0x0010);
+ reg_w(dev, 0x03, 0x0012);
+ reg_w(dev, 0x01, 0x0012);
+- retbyte = i2c_read(gspca_dev, 0x00);
+- if (retbyte != 0) {
++ retword = i2c_read(gspca_dev, 0x00);
++ if (retword != 0) {
+ PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
+ return 0x0a; /* ?? */
+ }
+@@ -6910,14 +6932,14 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+ reg_w(dev, 0x03, 0x0012);
+ msleep(2);
+ reg_w(dev, 0x01, 0x0012);
+- retbyte = i2c_read(gspca_dev, 0x00);
+- if (retbyte != 0) {
+- PDEBUG(D_PROBE, "probe 3wr vga type %02x", retbyte);
+- if (retbyte == 0x11) /* VF0250 */
++ retword = i2c_read(gspca_dev, 0x00);
++ if (retword != 0) {
++ PDEBUG(D_PROBE, "probe 3wr vga type %02x", retword);
++ if (retword == 0x0011) /* VF0250 */
+ return 0x0250;
+- if (retbyte == 0x29) /* gc0305 */
++ if (retword == 0x0029) /* gc0305 */
+ send_unknown(dev, SENSOR_GC0305);
+- return retbyte;
++ return retword;
+ }
+
+ reg_w(dev, 0x01, 0x0000); /* check OmniVision */
+@@ -6927,8 +6949,8 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+ reg_w(dev, 0x06, 0x0010);
+ reg_w(dev, 0x01, 0x0012);
+ reg_w(dev, 0x05, 0x0012);
+- if (i2c_read(gspca_dev, 0x1c) == 0x7f /* OV7610 - manufacturer ID */
+- && i2c_read(gspca_dev, 0x1d) == 0xa2) {
++ if (i2c_read(gspca_dev, 0x1c) == 0x007f /* OV7610 - manufacturer ID */
++ && i2c_read(gspca_dev, 0x1d) == 0x00a2) {
+ send_unknown(dev, SENSOR_OV7620);
+ return 0x06; /* OmniVision confirm ? */
+ }
+@@ -6942,16 +6964,14 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+ /* msleep(150); */
+ reg_w(dev, 0x01, 0x0012);
+ reg_w(dev, 0x05, 0x0012);
+- retbyte = i2c_read(gspca_dev, 0x0000); /* ID 0 */
+- checkword = retbyte << 8;
+- retbyte = i2c_read(gspca_dev, 0x0001); /* ID 1 */
+- checkword |= retbyte;
+- PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", checkword);
+- if (checkword == 0x2030) {
++ retword = i2c_read(gspca_dev, 0x00) << 8; /* ID 0 */
++ retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */
++ PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword);
++ if (retword == 0x2030) {
+ retbyte = i2c_read(gspca_dev, 0x02); /* revision number */
+ PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
+ send_unknown(dev, SENSOR_PO2030);
+- return checkword;
++ return retword;
+ }
+
+ reg_w(dev, 0x01, 0x0000);
+@@ -6962,10 +6982,10 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+ reg_w(dev, 0x01, 0x0012);
+ reg_w(dev, 0x05, 0x0001);
+ reg_w(dev, 0xd3, 0x008b);
+- retbyte = i2c_read(gspca_dev, 0x01);
+- if (retbyte != 0) {
+- PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
+- return 0x0a; /* ?? */
++ retword = i2c_read(gspca_dev, 0x01);
++ if (retword != 0) {
++ PDEBUG(D_PROBE, "probe 3wr vga type 0a ? ret: %04x", retword);
++ return retword;
+ }
+ return -1;
+ }
+@@ -6973,7 +6993,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+- int sensor, sensor2;
++ int sensor;
+
+ switch (sd->sensor) {
+ case SENSOR_MC501CB:
+@@ -6988,16 +7008,9 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
+ break;
+ }
+ sensor = vga_2wr_probe(gspca_dev);
+- if (sensor >= 0) {
+- if (sensor < 0x7600)
+- return sensor;
+- /* next probe is needed for OmniVision ? */
+- }
+- sensor2 = vga_3wr_probe(gspca_dev);
+- if (sensor2 >= 0
+- && sensor >= 0)
++ if (sensor >= 0)
+ return sensor;
+- return sensor2;
++ return vga_3wr_probe(gspca_dev);
+ }
+
+ /* this function is called at probe time */
+@@ -7009,23 +7022,24 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ int sensor;
+ int vga = 1; /* 1: vga, 0: sif */
+ static const __u8 gamma[SENSOR_MAX] = {
+- 5, /* SENSOR_CS2102 0 */
+- 5, /* SENSOR_CS2102K 1 */
+- 4, /* SENSOR_GC0305 2 */
+- 4, /* SENSOR_HDCS2020b 3 */
+- 4, /* SENSOR_HV7131B 4 */
+- 4, /* SENSOR_HV7131C 5 */
+- 4, /* SENSOR_ICM105A 6 */
+- 4, /* SENSOR_MC501CB 7 */
+- 3, /* SENSOR_OV7620 8 */
+- 4, /* SENSOR_OV7630C 9 */
+- 4, /* SENSOR_PAS106 10 */
+- 4, /* SENSOR_PAS202B 11 */
+- 4, /* SENSOR_PB0330 12 */
+- 4, /* SENSOR_PO2030 13 */
+- 4, /* SENSOR_TAS5130CK 14 */
+- 4, /* SENSOR_TAS5130CXX 15 */
+- 3, /* SENSOR_TAS5130C_VF0250 16 */
++ 4, /* SENSOR_ADCM2700 0 */
++ 5, /* SENSOR_CS2102 1 */
++ 5, /* SENSOR_CS2102K 2 */
++ 4, /* SENSOR_GC0305 3 */
++ 4, /* SENSOR_HDCS2020b 4 */
++ 4, /* SENSOR_HV7131B 5 */
++ 4, /* SENSOR_HV7131C 6 */
++ 4, /* SENSOR_ICM105A 7 */
++ 4, /* SENSOR_MC501CB 8 */
++ 3, /* SENSOR_OV7620 9 */
++ 4, /* SENSOR_OV7630C 10 */
++ 4, /* SENSOR_PAS106 11 */
++ 4, /* SENSOR_PAS202B 12 */
++ 4, /* SENSOR_PB0330 13 */
++ 4, /* SENSOR_PO2030 14 */
++ 4, /* SENSOR_TAS5130CK 15 */
++ 4, /* SENSOR_TAS5130CXX 16 */
++ 3, /* SENSOR_TAS5130C_VF0250 17 */
+ };
+
+ /* define some sensors from the vendor/product */
+@@ -7033,7 +7047,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ sd->sensor = id->driver_info;
+ sensor = zcxx_probeSensor(gspca_dev);
+ if (sensor >= 0)
+- PDEBUG(D_PROBE, "probe sensor -> %02x", sensor);
++ PDEBUG(D_PROBE, "probe sensor -> %04x", sensor);
+ if ((unsigned) force_sensor < SENSOR_MAX) {
+ sd->sensor = force_sensor;
+ PDEBUG(D_PROBE, "sensor forced to %d", force_sensor);
+@@ -7112,6 +7126,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ sd->chip_revision);
+ sd->sensor = SENSOR_TAS5130CK;
+ break;
++ case 0x16:
++ PDEBUG(D_PROBE, "Find Sensor ADCM2700");
++ sd->sensor = SENSOR_ADCM2700;
++ break;
+ case 0x29:
+ PDEBUG(D_PROBE, "Find Sensor GC0305");
+ sd->sensor = SENSOR_GC0305;
+@@ -7129,12 +7147,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ PDEBUG(D_PROBE, "Find Sensor OV7620");
+ sd->sensor = SENSOR_OV7620;
+ break;
++ case 0x7631:
++ PDEBUG(D_PROBE, "Find Sensor OV7630C");
++ sd->sensor = SENSOR_OV7630C;
++ break;
+ case 0x7648:
+ PDEBUG(D_PROBE, "Find Sensor OV7648");
+ sd->sensor = SENSOR_OV7620; /* same sensor (?) */
+ break;
+ default:
+- PDEBUG(D_ERR|D_PROBE, "Unknown sensor %02x", sensor);
++ PDEBUG(D_ERR|D_PROBE, "Unknown sensor %04x", sensor);
+ return -EINVAL;
+ }
+ }
+@@ -7147,7 +7169,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ }
+
+ cam = &gspca_dev->cam;
+- cam->epaddr = 0x01;
+ /*fixme:test*/
+ gspca_dev->nbalt--;
+ if (vga) {
+@@ -7157,12 +7178,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ }
+- sd->qindex = 1;
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->gamma = gamma[(int) sd->sensor];
+ sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+ sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
++ sd->quality = QUALITY_DEF;
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+@@ -7196,27 +7217,34 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ const struct usb_action *zc3_init;
+ int mode;
+ static const struct usb_action *init_tb[SENSOR_MAX][2] = {
+- {cs2102_InitialScale, cs2102_Initial}, /* 0 */
+- {cs2102K_InitialScale, cs2102K_Initial}, /* 1 */
+- {gc0305_Initial, gc0305_InitialScale}, /* 2 */
+- {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 3 */
+- {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 4 */
+- {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 5 */
+- {icm105axx_InitialScale, icm105axx_Initial}, /* 6 */
+- {MC501CB_InitialScale, MC501CB_Initial}, /* 7 */
+- {OV7620_mode0, OV7620_mode1}, /* 8 */
+- {ov7630c_InitialScale, ov7630c_Initial}, /* 9 */
+- {pas106b_InitialScale, pas106b_Initial}, /* 10 */
+- {pas202b_Initial, pas202b_InitialScale}, /* 11 */
+- {pb0330xx_InitialScale, pb0330xx_Initial}, /* 12 */
++ {adcm2700_Initial, adcm2700_InitialScale}, /* 0 */
++ {cs2102_InitialScale, cs2102_Initial}, /* 1 */
++ {cs2102K_InitialScale, cs2102K_Initial}, /* 2 */
++ {gc0305_Initial, gc0305_InitialScale}, /* 3 */
++ {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 4 */
++ {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 5 */
++ {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 6 */
++ {icm105axx_InitialScale, icm105axx_Initial}, /* 7 */
++ {MC501CB_InitialScale, MC501CB_Initial}, /* 8 */
++ {OV7620_mode0, OV7620_mode1}, /* 9 */
++ {ov7630c_InitialScale, ov7630c_Initial}, /* 10 */
++ {pas106b_InitialScale, pas106b_Initial}, /* 11 */
++ {pas202b_Initial, pas202b_InitialScale}, /* 12 */
++ {pb0330xx_InitialScale, pb0330xx_Initial}, /* 13 */
+ /* or {pb03303x_InitialScale, pb03303x_Initial}, */
+- {PO2030_mode0, PO2030_mode1}, /* 13 */
+- {tas5130CK_InitialScale, tas5130CK_Initial}, /* 14 */
+- {tas5130cxx_InitialScale, tas5130cxx_Initial}, /* 15 */
++ {PO2030_mode0, PO2030_mode1}, /* 14 */
++ {tas5130CK_InitialScale, tas5130CK_Initial}, /* 15 */
++ {tas5130cxx_InitialScale, tas5130cxx_Initial}, /* 16 */
+ {tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial},
+- /* 16 */
++ /* 17 */
+ };
+
++ /* create the JPEG header */
++ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
++ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
++ 0x21); /* JPEG 422 */
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ zc3_init = init_tb[(int) sd->sensor][mode];
+ switch (sd->sensor) {
+@@ -7243,11 +7271,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ usb_exchange(gspca_dev, zc3_init);
+
+ switch (sd->sensor) {
++ case SENSOR_ADCM2700:
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PO2030:
+ case SENSOR_TAS5130C_VF0250:
+- msleep(100); /* ?? */
++/* msleep(100); * ?? */
+ reg_r(gspca_dev, 0x0002); /* --> 0x40 */
+ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(dev, 0x15, 0x01ae);
+@@ -7260,6 +7289,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ setmatrix(gspca_dev);
+ setbrightness(gspca_dev);
+ switch (sd->sensor) {
++ case SENSOR_ADCM2700:
+ case SENSOR_OV7620:
+ reg_r(gspca_dev, 0x0008);
+ reg_w(dev, 0x00, 0x0008);
+@@ -7301,6 +7331,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
+ setlightfreq(gspca_dev);
+
+ switch (sd->sensor) {
++ case SENSOR_ADCM2700:
++ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
++ reg_w(dev, 0x15, 0x01ae);
++ reg_w(dev, 0x02, 0x0180);
++ /* ms-win + */
++ reg_w(dev, 0x40, 0x0117);
++ break;
+ case SENSOR_GC0305:
+ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(dev, 0x15, 0x01ae);
+@@ -7323,19 +7360,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
+
+ setautogain(gspca_dev);
+ switch (sd->sensor) {
+- case SENSOR_PAS202B:
+- reg_w(dev, 0x00, 0x0007); /* (from win traces) */
+- break;
+ case SENSOR_PO2030:
+ msleep(500);
+ reg_r(gspca_dev, 0x0008);
+ reg_r(gspca_dev, 0x0007);
++ /*fall thru*/
++ case SENSOR_PAS202B:
+ reg_w(dev, 0x00, 0x0007); /* (from win traces) */
+- reg_w(dev, 0x02, 0x0008);
++ reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
+ break;
+ }
+- if (sd->sensor == SENSOR_PAS202B)
+- reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
+ return 0;
+ }
+
+@@ -7344,6 +7378,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
+ {
+ struct sd *sd = (struct sd *) gspca_dev;
+
++ kfree(sd->jpeg_hdr);
+ if (!gspca_dev->present)
+ return;
+ send_unknown(gspca_dev->dev, sd->sensor);
+@@ -7354,14 +7389,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ __u8 *data,
+ int len)
+ {
++ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (data[0] == 0xff && data[1] == 0xd8) { /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ /* put the JPEG header in the new frame */
+- jpeg_put_header(gspca_dev, frame,
+- ((struct sd *) gspca_dev)->qindex,
+- 0x21);
++ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
++ sd->jpeg_hdr, JPEG_HDR_SZ);
++
+ /* remove the webcam's header:
+ * ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp
+ * - 'ss ss' is the frame sequence number (BE)
+@@ -7503,6 +7539,34 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
+ return -EINVAL;
+ }
+
++static int sd_set_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ if (jcomp->quality < QUALITY_MIN)
++ sd->quality = QUALITY_MIN;
++ else if (jcomp->quality > QUALITY_MAX)
++ sd->quality = QUALITY_MAX;
++ else
++ sd->quality = jcomp->quality;
++ if (gspca_dev->streaming)
++ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
++ return 0;
++}
++
++static int sd_get_jcomp(struct gspca_dev *gspca_dev,
++ struct v4l2_jpegcompression *jcomp)
++{
++ struct sd *sd = (struct sd *) gspca_dev;
++
++ memset(jcomp, 0, sizeof *jcomp);
++ jcomp->quality = sd->quality;
++ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
++ | V4L2_JPEG_MARKER_DQT;
++ return 0;
++}
++
+ static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+@@ -7513,6 +7577,8 @@ static const struct sd_desc sd_desc = {
+ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
++ .get_jcomp = sd_get_jcomp,
++ .set_jcomp = sd_set_jcomp,
+ };
+
+ static const __devinitdata struct usb_device_id device_table[] = {
+@@ -7563,11 +7629,9 @@ static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x055f, 0xd004)},
+ {USB_DEVICE(0x0698, 0x2003)},
+ {USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106},
+- {USB_DEVICE(0x0ac8, 0x0302)},
++ {USB_DEVICE(0x0ac8, 0x0302), .driver_info = SENSOR_PAS106},
+ {USB_DEVICE(0x0ac8, 0x301b)},
+-#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
+ {USB_DEVICE(0x0ac8, 0x303b)},
+-#endif
+ {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250},
+ {USB_DEVICE(0x0ac8, 0x307b)},
+ {USB_DEVICE(0x10fd, 0x0128)},
+@@ -7600,8 +7664,10 @@ static struct usb_driver sd_driver = {
+
+ static int __init sd_mod_init(void)
+ {
+- if (usb_register(&sd_driver) < 0)
+- return -1;
++ int ret;
++ ret = usb_register(&sd_driver);
++ if (ret < 0)
++ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+ }
+diff --git a/drivers/media/video/hdpvr/Kconfig b/drivers/media/video/hdpvr/Kconfig
+new file mode 100644
+index 0000000..de247f3
+--- /dev/null
++++ b/drivers/media/video/hdpvr/Kconfig
+@@ -0,0 +1,10 @@
++
++config VIDEO_HDPVR
++ tristate "Hauppauge HD PVR support"
++ depends on VIDEO_DEV
++ ---help---
++ This is a video4linux driver for Hauppauge's HD PVR USB device.
++
++ To compile this driver as a module, choose M here: the
++ module will be called hdpvr
++
+diff --git a/drivers/media/video/hdpvr/Makefile b/drivers/media/video/hdpvr/Makefile
+new file mode 100644
+index 0000000..e0230fc
+--- /dev/null
++++ b/drivers/media/video/hdpvr/Makefile
+@@ -0,0 +1,9 @@
++hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o
++
++hdpvr-$(CONFIG_I2C) += hdpvr-i2c.o
++
++obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
++
++EXTRA_CFLAGS += -Idrivers/media/video
++
++EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+diff --git a/drivers/media/video/hdpvr/hdpvr-control.c b/drivers/media/video/hdpvr/hdpvr-control.c
+new file mode 100644
+index 0000000..0679174
+--- /dev/null
++++ b/drivers/media/video/hdpvr/hdpvr-control.c
+@@ -0,0 +1,201 @@
++/*
++ * Hauppauge HD PVR USB driver - video 4 linux 2 interface
++ *
++ * Copyright (C) 2008 Janne Grunau (j@jannau.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, version 2.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/usb.h>
++#include <linux/mutex.h>
++
++#include <linux/videodev2.h>
++
++#include <media/v4l2-common.h>
++
++#include "hdpvr.h"
++
++
++int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf)
++{
++ int ret;
++ char request_type = 0x38, snd_request = 0x01;
++
++ msleep(10);
++
++ mutex_lock(&dev->usbc_mutex);
++ dev->usbc_buf[0] = valbuf;
++ ret = usb_control_msg(dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ snd_request, 0x00 | request_type,
++ value, CTRL_DEFAULT_INDEX,
++ dev->usbc_buf, 1, 10000);
++
++ mutex_unlock(&dev->usbc_mutex);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "config call request for value 0x%x returned %d\n", value,
++ ret);
++
++ return ret < 0 ? ret : 0;
++}
++
++struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
++{
++ struct hdpvr_video_info *vidinf = NULL;
++#ifdef HDPVR_DEBUG
++ char print_buf[15];
++#endif
++ int ret;
++
++ vidinf = kzalloc(sizeof(struct hdpvr_video_info), GFP_KERNEL);
++ if (!vidinf) {
++ v4l2_err(&dev->v4l2_dev, "out of memory\n");
++ goto err;
++ }
++
++ mutex_lock(&dev->usbc_mutex);
++ ret = usb_control_msg(dev->udev,
++ usb_rcvctrlpipe(dev->udev, 0),
++ 0x81, 0x80 | 0x38,
++ 0x1400, 0x0003,
++ dev->usbc_buf, 5,
++ 1000);
++ if (ret == 5) {
++ vidinf->width = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
++ vidinf->height = dev->usbc_buf[3] << 8 | dev->usbc_buf[2];
++ vidinf->fps = dev->usbc_buf[4];
++ }
++
++#ifdef HDPVR_DEBUG
++ if (hdpvr_debug & MSG_INFO) {
++ hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf,
++ sizeof(print_buf), 0);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "get video info returned: %d, %s\n", ret, print_buf);
++ }
++#endif
++ mutex_unlock(&dev->usbc_mutex);
++
++ if (!vidinf->width || !vidinf->height || !vidinf->fps) {
++ kfree(vidinf);
++ vidinf = NULL;
++ }
++err:
++ return vidinf;
++}
++
++int get_input_lines_info(struct hdpvr_device *dev)
++{
++#ifdef HDPVR_DEBUG
++ char print_buf[9];
++#endif
++ int ret, lines;
++
++ mutex_lock(&dev->usbc_mutex);
++ ret = usb_control_msg(dev->udev,
++ usb_rcvctrlpipe(dev->udev, 0),
++ 0x81, 0x80 | 0x38,
++ 0x1800, 0x0003,
++ dev->usbc_buf, 3,
++ 1000);
++
++#ifdef HDPVR_DEBUG
++ if (hdpvr_debug & MSG_INFO) {
++ hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf,
++ sizeof(print_buf), 0);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "get input lines info returned: %d, %s\n", ret,
++ print_buf);
++ }
++#endif
++ lines = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
++ mutex_unlock(&dev->usbc_mutex);
++ return lines;
++}
++
++
++int hdpvr_set_bitrate(struct hdpvr_device *dev)
++{
++ int ret;
++
++ mutex_lock(&dev->usbc_mutex);
++ memset(dev->usbc_buf, 0, 4);
++ dev->usbc_buf[0] = dev->options.bitrate;
++ dev->usbc_buf[2] = dev->options.peak_bitrate;
++
++ ret = usb_control_msg(dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ 0x01, 0x38, CTRL_BITRATE_VALUE,
++ CTRL_DEFAULT_INDEX, dev->usbc_buf, 4, 1000);
++ mutex_unlock(&dev->usbc_mutex);
++
++ return ret;
++}
++
++int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
++ enum v4l2_mpeg_audio_encoding codec)
++{
++ int ret = 0;
++
++ if (dev->flags & HDPVR_FLAG_AC3_CAP) {
++ mutex_lock(&dev->usbc_mutex);
++ memset(dev->usbc_buf, 0, 2);
++ dev->usbc_buf[0] = input;
++ if (codec == V4L2_MPEG_AUDIO_ENCODING_AAC)
++ dev->usbc_buf[1] = 0;
++ else if (codec == V4L2_MPEG_AUDIO_ENCODING_AC3)
++ dev->usbc_buf[1] = 1;
++ else {
++ mutex_unlock(&dev->usbc_mutex);
++ v4l2_err(&dev->v4l2_dev, "invalid audio codec %d\n",
++ codec);
++ ret = -EINVAL;
++ goto error;
++ }
++
++ ret = usb_control_msg(dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ 0x01, 0x38, CTRL_AUDIO_INPUT_VALUE,
++ CTRL_DEFAULT_INDEX, dev->usbc_buf, 2,
++ 1000);
++ mutex_unlock(&dev->usbc_mutex);
++ if (ret == 2)
++ ret = 0;
++ } else
++ ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE,
++ dev->options.audio_input+1);
++error:
++ return ret;
++}
++
++int hdpvr_set_options(struct hdpvr_device *dev)
++{
++ hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std);
++
++ hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE,
++ dev->options.video_input+1);
++
++ hdpvr_set_audio(dev, dev->options.audio_input+1,
++ dev->options.audio_codec);
++
++ hdpvr_set_bitrate(dev);
++ hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
++ dev->options.bitrate_mode);
++ hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode);
++
++ hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness);
++ hdpvr_config_call(dev, CTRL_CONTRAST, dev->options.contrast);
++ hdpvr_config_call(dev, CTRL_HUE, dev->options.hue);
++ hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation);
++ hdpvr_config_call(dev, CTRL_SHARPNESS, dev->options.sharpness);
++
++ return 0;
++}
+diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
+new file mode 100644
+index 0000000..188bd5a
+--- /dev/null
++++ b/drivers/media/video/hdpvr/hdpvr-core.c
+@@ -0,0 +1,466 @@
++/*
++ * Hauppauge HD PVR USB driver
++ *
++ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
++ * Copyright (C) 2008 Janne Grunau (j@jannau.net)
++ * Copyright (C) 2008 John Poet
++ *
++ * 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, version 2.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/uaccess.h>
++#include <asm/atomic.h>
++#include <linux/usb.h>
++#include <linux/mutex.h>
++#include <linux/i2c.h>
++
++#include <linux/videodev2.h>
++#include <media/v4l2-dev.h>
++#include <media/v4l2-common.h>
++
++#include "hdpvr.h"
++
++static int video_nr[HDPVR_MAX] = {[0 ... (HDPVR_MAX - 1)] = UNSET};
++module_param_array(video_nr, int, NULL, 0);
++MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)");
++
++/* holds the number of currently registered devices */
++static atomic_t dev_nr = ATOMIC_INIT(-1);
++
++int hdpvr_debug;
++module_param(hdpvr_debug, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(hdpvr_debug, "enable debugging output");
++
++uint default_video_input = HDPVR_VIDEO_INPUTS;
++module_param(default_video_input, uint, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / "
++ "1=S-Video / 2=Composite");
++
++uint default_audio_input = HDPVR_AUDIO_INPUTS;
++module_param(default_audio_input, uint, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / "
++ "1=RCA front / 2=S/PDIF");
++
++static int boost_audio;
++module_param(boost_audio, bool, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(boost_audio, "boost the audio signal");
++
++
++/* table of devices that work with this driver */
++static struct usb_device_id hdpvr_table[] = {
++ { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID) },
++ { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) },
++ { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) },
++ { } /* Terminating entry */
++};
++MODULE_DEVICE_TABLE(usb, hdpvr_table);
++
++
++void hdpvr_delete(struct hdpvr_device *dev)
++{
++ hdpvr_free_buffers(dev);
++
++ if (dev->video_dev)
++ video_device_release(dev->video_dev);
++
++ usb_put_dev(dev->udev);
++}
++
++static void challenge(u8 *bytes)
++{
++ u64 *i64P, tmp64;
++ uint i, idx;
++
++ for (idx = 0; idx < 32; ++idx) {
++
++ if (idx & 0x3)
++ bytes[(idx >> 3) + 3] = bytes[(idx >> 2) & 0x3];
++
++ switch (idx & 0x3) {
++ case 0x3:
++ bytes[2] += bytes[3] * 4 + bytes[4] + bytes[5];
++ bytes[4] += bytes[(idx & 0x1) * 2] * 9 + 9;
++ break;
++ case 0x1:
++ bytes[0] *= 8;
++ bytes[0] += 7*idx + 4;
++ bytes[6] += bytes[3] * 3;
++ break;
++ case 0x0:
++ bytes[3 - (idx >> 3)] = bytes[idx >> 2];
++ bytes[5] += bytes[6] * 3;
++ for (i = 0; i < 3; i++)
++ bytes[3] *= bytes[3] + 1;
++ break;
++ case 0x2:
++ for (i = 0; i < 3; i++)
++ bytes[1] *= bytes[6] + 1;
++ for (i = 0; i < 3; i++) {
++ i64P = (u64 *)bytes;
++ tmp64 = le64_to_cpup(i64P);
++ tmp64 <<= bytes[7] & 0x0f;
++ *i64P += cpu_to_le64(tmp64);
++ }
++ break;
++ }
++ }
++}
++
++/* try to init the device like the windows driver */
++static int device_authorization(struct hdpvr_device *dev)
++{
++
++ int ret, retval = -ENOMEM;
++ char request_type = 0x38, rcv_request = 0x81;
++ char *response;
++#ifdef HDPVR_DEBUG
++ size_t buf_size = 46;
++ char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
++ if (!print_buf) {
++ v4l2_err(&dev->v4l2_dev, "Out of memory\n");
++ goto error;
++ }
++#endif
++
++ mutex_lock(&dev->usbc_mutex);
++ ret = usb_control_msg(dev->udev,
++ usb_rcvctrlpipe(dev->udev, 0),
++ rcv_request, 0x80 | request_type,
++ 0x0400, 0x0003,
++ dev->usbc_buf, 46,
++ 10000);
++ if (ret != 46) {
++ v4l2_err(&dev->v4l2_dev,
++ "unexpected answer of status request, len %d\n", ret);
++ goto error;
++ }
++#ifdef HDPVR_DEBUG
++ else {
++ hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf,
++ sizeof(print_buf), 0);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "Status request returned, len %d: %s\n",
++ ret, print_buf);
++ }
++#endif
++ if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION) {
++ dev->flags &= ~HDPVR_FLAG_AC3_CAP;
++ } else if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION_AC3) {
++ dev->flags |= HDPVR_FLAG_AC3_CAP;
++ } else if (dev->usbc_buf[1] > HDPVR_FIRMWARE_VERSION_AC3) {
++ v4l2_info(&dev->v4l2_dev, "untested firmware version 0x%x, "
++ "the driver might not work\n", dev->usbc_buf[1]);
++ dev->flags |= HDPVR_FLAG_AC3_CAP;
++ } else {
++ v4l2_err(&dev->v4l2_dev, "unknown firmware version 0x%x\n",
++ dev->usbc_buf[1]);
++ ret = -EINVAL;
++ goto error;
++ }
++
++ response = dev->usbc_buf+38;
++#ifdef HDPVR_DEBUG
++ hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n",
++ print_buf);
++#endif
++ challenge(response);
++#ifdef HDPVR_DEBUG
++ hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n",
++ print_buf);
++#endif
++
++ msleep(100);
++ ret = usb_control_msg(dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ 0xd1, 0x00 | request_type,
++ 0x0000, 0x0000,
++ response, 8,
++ 10000);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "magic request returned %d\n", ret);
++ mutex_unlock(&dev->usbc_mutex);
++
++ retval = ret != 8;
++error:
++ return retval;
++}
++
++static int hdpvr_device_init(struct hdpvr_device *dev)
++{
++ int ret;
++ u8 *buf;
++ struct hdpvr_video_info *vidinf;
++
++ if (device_authorization(dev))
++ return -EACCES;
++
++ /* default options for init */
++ hdpvr_set_options(dev);
++
++ /* set filter options */
++ mutex_lock(&dev->usbc_mutex);
++ buf = dev->usbc_buf;
++ buf[0] = 0x03; buf[1] = 0x03; buf[2] = 0x00; buf[3] = 0x00;
++ ret = usb_control_msg(dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ 0x01, 0x38,
++ CTRL_LOW_PASS_FILTER_VALUE, CTRL_DEFAULT_INDEX,
++ buf, 4,
++ 1000);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "control request returned %d\n", ret);
++ mutex_unlock(&dev->usbc_mutex);
++
++ vidinf = get_video_info(dev);
++ if (!vidinf)
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "no valid video signal or device init failed\n");
++ else
++ kfree(vidinf);
++
++ /* enable fan and bling leds */
++ mutex_lock(&dev->usbc_mutex);
++ buf[0] = 0x1;
++ ret = usb_control_msg(dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ 0xd4, 0x38, 0, 0, buf, 1,
++ 1000);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "control request returned %d\n", ret);
++
++ /* boost analog audio */
++ buf[0] = boost_audio;
++ ret = usb_control_msg(dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ 0xd5, 0x38, 0, 0, buf, 1,
++ 1000);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "control request returned %d\n", ret);
++ mutex_unlock(&dev->usbc_mutex);
++
++ dev->status = STATUS_IDLE;
++ return 0;
++}
++
++static const struct hdpvr_options hdpvr_default_options = {
++ .video_std = HDPVR_60HZ,
++ .video_input = HDPVR_COMPONENT,
++ .audio_input = HDPVR_RCA_BACK,
++ .bitrate = 65, /* 6 mbps */
++ .peak_bitrate = 90, /* 9 mbps */
++ .bitrate_mode = HDPVR_CONSTANT,
++ .gop_mode = HDPVR_SIMPLE_IDR_GOP,
++ .audio_codec = V4L2_MPEG_AUDIO_ENCODING_AAC,
++ .brightness = 0x86,
++ .contrast = 0x80,
++ .hue = 0x80,
++ .saturation = 0x80,
++ .sharpness = 0x80,
++};
++
++static int hdpvr_probe(struct usb_interface *interface,
++ const struct usb_device_id *id)
++{
++ struct hdpvr_device *dev;
++ struct usb_host_interface *iface_desc;
++ struct usb_endpoint_descriptor *endpoint;
++ size_t buffer_size;
++ int i;
++ int retval = -ENOMEM;
++
++ /* allocate memory for our device state and initialize it */
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (!dev) {
++ err("Out of memory");
++ goto error;
++ }
++
++ /* register v4l2_device early so it can be used for printks */
++ if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
++ err("v4l2_device_register failed");
++ goto error;
++ }
++
++ mutex_init(&dev->io_mutex);
++ mutex_init(&dev->i2c_mutex);
++ mutex_init(&dev->usbc_mutex);
++ dev->usbc_buf = kmalloc(64, GFP_KERNEL);
++ if (!dev->usbc_buf) {
++ v4l2_err(&dev->v4l2_dev, "Out of memory\n");
++ goto error;
++ }
++
++ init_waitqueue_head(&dev->wait_buffer);
++ init_waitqueue_head(&dev->wait_data);
++
++ dev->workqueue = create_singlethread_workqueue("hdpvr_buffer");
++ if (!dev->workqueue)
++ goto error;
++
++ /* init video transfer queues */
++ INIT_LIST_HEAD(&dev->free_buff_list);
++ INIT_LIST_HEAD(&dev->rec_buff_list);
++
++ dev->options = hdpvr_default_options;
++
++ if (default_video_input < HDPVR_VIDEO_INPUTS)
++ dev->options.video_input = default_video_input;
++
++ if (default_audio_input < HDPVR_AUDIO_INPUTS)
++ dev->options.audio_input = default_audio_input;
++
++ dev->udev = usb_get_dev(interface_to_usbdev(interface));
++
++ /* set up the endpoint information */
++ /* use only the first bulk-in and bulk-out endpoints */
++ iface_desc = interface->cur_altsetting;
++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
++ endpoint = &iface_desc->endpoint[i].desc;
++
++ if (!dev->bulk_in_endpointAddr &&
++ usb_endpoint_is_bulk_in(endpoint)) {
++ /* USB interface description is buggy, reported max
++ * packet size is 512 bytes, windows driver uses 8192 */
++ buffer_size = 8192;
++ dev->bulk_in_size = buffer_size;
++ dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
++ }
++
++ }
++ if (!dev->bulk_in_endpointAddr) {
++ v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n");
++ goto error;
++ }
++
++ /* init the device */
++ if (hdpvr_device_init(dev)) {
++ v4l2_err(&dev->v4l2_dev, "device init failed\n");
++ goto error;
++ }
++
++ mutex_lock(&dev->io_mutex);
++ if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) {
++ v4l2_err(&dev->v4l2_dev,
++ "allocating transfer buffers failed\n");
++ goto error;
++ }
++ mutex_unlock(&dev->io_mutex);
++
++ if (hdpvr_register_videodev(dev, &interface->dev,
++ video_nr[atomic_inc_return(&dev_nr)])) {
++ v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
++ goto error;
++ }
++
++#ifdef CONFIG_I2C
++ /* until i2c is working properly */
++ retval = 0; /* hdpvr_register_i2c_adapter(dev); */
++ if (retval < 0) {
++ v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n");
++ goto error;
++ }
++#endif /* CONFIG_I2C */
++
++ /* save our data pointer in this interface device */
++ usb_set_intfdata(interface, dev);
++
++ /* let the user know what node this device is now attached to */
++ v4l2_info(&dev->v4l2_dev, "device now attached to /dev/video%d\n",
++ dev->video_dev->minor);
++ return 0;
++
++error:
++ if (dev) {
++ mutex_unlock(&dev->io_mutex);
++ /* this frees allocated memory */
++ hdpvr_delete(dev);
++ }
++ return retval;
++}
++
++static void hdpvr_disconnect(struct usb_interface *interface)
++{
++ struct hdpvr_device *dev;
++ int minor;
++
++ dev = usb_get_intfdata(interface);
++ usb_set_intfdata(interface, NULL);
++
++ minor = dev->video_dev->minor;
++
++ /* prevent more I/O from starting and stop any ongoing */
++ mutex_lock(&dev->io_mutex);
++ dev->status = STATUS_DISCONNECTED;
++ v4l2_device_disconnect(&dev->v4l2_dev);
++ video_unregister_device(dev->video_dev);
++ wake_up_interruptible(&dev->wait_data);
++ wake_up_interruptible(&dev->wait_buffer);
++ mutex_unlock(&dev->io_mutex);
++ msleep(100);
++ flush_workqueue(dev->workqueue);
++ mutex_lock(&dev->io_mutex);
++ hdpvr_cancel_queue(dev);
++ destroy_workqueue(dev->workqueue);
++ mutex_unlock(&dev->io_mutex);
++
++ /* deregister I2C adapter */
++#ifdef CONFIG_I2C
++ mutex_lock(&dev->i2c_mutex);
++ if (dev->i2c_adapter)
++ i2c_del_adapter(dev->i2c_adapter);
++ kfree(dev->i2c_adapter);
++ dev->i2c_adapter = NULL;
++ mutex_unlock(&dev->i2c_mutex);
++#endif /* CONFIG_I2C */
++
++ atomic_dec(&dev_nr);
++
++ v4l2_info(&dev->v4l2_dev, "device /dev/video%d disconnected\n", minor);
++
++ v4l2_device_unregister(&dev->v4l2_dev);
++ kfree(dev->usbc_buf);
++ kfree(dev);
++}
++
++
++static struct usb_driver hdpvr_usb_driver = {
++ .name = "hdpvr",
++ .probe = hdpvr_probe,
++ .disconnect = hdpvr_disconnect,
++ .id_table = hdpvr_table,
++};
++
++static int __init hdpvr_init(void)
++{
++ int result;
++
++ /* register this driver with the USB subsystem */
++ result = usb_register(&hdpvr_usb_driver);
++ if (result)
++ err("usb_register failed. Error number %d", result);
++
++ return result;
++}
++
++static void __exit hdpvr_exit(void)
++{
++ /* deregister this driver with the USB subsystem */
++ usb_deregister(&hdpvr_usb_driver);
++}
++
++module_init(hdpvr_init);
++module_exit(hdpvr_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Janne Grunau");
++MODULE_DESCRIPTION("Hauppauge HD PVR driver");
+diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c
+new file mode 100644
+index 0000000..c4b5d15
+--- /dev/null
++++ b/drivers/media/video/hdpvr/hdpvr-i2c.c
+@@ -0,0 +1,145 @@
++
++/*
++ * Hauppauge HD PVR USB driver
++ *
++ * Copyright (C) 2008 Janne Grunau (j@jannau.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, version 2.
++ *
++ */
++
++#include <linux/i2c.h>
++
++#include "hdpvr.h"
++
++#define CTRL_READ_REQUEST 0xb8
++#define CTRL_WRITE_REQUEST 0x38
++
++#define REQTYPE_I2C_READ 0xb1
++#define REQTYPE_I2C_WRITE 0xb0
++#define REQTYPE_I2C_WRITE_STATT 0xd0
++
++static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
++ char *data, int len)
++{
++ int ret;
++ char *buf = kmalloc(len, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ ret = usb_control_msg(dev->udev,
++ usb_rcvctrlpipe(dev->udev, 0),
++ REQTYPE_I2C_READ, CTRL_READ_REQUEST,
++ 0x100|addr, 0, buf, len, 1000);
++
++ if (ret == len) {
++ memcpy(data, buf, len);
++ ret = 0;
++ } else if (ret >= 0)
++ ret = -EIO;
++
++ kfree(buf);
++
++ return ret;
++}
++
++static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
++ char *data, int len)
++{
++ int ret;
++ char *buf = kmalloc(len, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ memcpy(buf, data, len);
++ ret = usb_control_msg(dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
++ 0x100|addr, 0, buf, len, 1000);
++
++ if (ret < 0)
++ goto error;
++
++ ret = usb_control_msg(dev->udev,
++ usb_rcvctrlpipe(dev->udev, 0),
++ REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
++ 0, 0, buf, 2, 1000);
++
++ if (ret == 2)
++ ret = 0;
++ else if (ret >= 0)
++ ret = -EIO;
++
++error:
++ kfree(buf);
++ return ret;
++}
++
++static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
++ int num)
++{
++ struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
++ int retval = 0, i, addr;
++
++ if (num <= 0)
++ return 0;
++
++ mutex_lock(&dev->i2c_mutex);
++
++ for (i = 0; i < num && !retval; i++) {
++ addr = msgs[i].addr << 1;
++
++ if (msgs[i].flags & I2C_M_RD)
++ retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
++ msgs[i].len);
++ else
++ retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
++ msgs[i].len);
++ }
++
++ mutex_unlock(&dev->i2c_mutex);
++
++ return retval ? retval : num;
++}
++
++static u32 hdpvr_functionality(struct i2c_adapter *adapter)
++{
++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++static struct i2c_algorithm hdpvr_algo = {
++ .master_xfer = hdpvr_transfer,
++ .functionality = hdpvr_functionality,
++};
++
++int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
++{
++ struct i2c_adapter *i2c_adap;
++ int retval = -ENOMEM;
++
++ i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
++ if (i2c_adap == NULL)
++ goto error;
++
++ strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
++ sizeof(i2c_adap->name));
++ i2c_adap->algo = &hdpvr_algo;
++ i2c_adap->class = I2C_CLASS_TV_ANALOG;
++ i2c_adap->id = I2C_HW_B_HDPVR;
++ i2c_adap->owner = THIS_MODULE;
++ i2c_adap->dev.parent = &dev->udev->dev;
++
++ i2c_set_adapdata(i2c_adap, dev);
++
++ retval = i2c_add_adapter(i2c_adap);
++
++ if (!retval)
++ dev->i2c_adapter = i2c_adap;
++ else
++ kfree(i2c_adap);
++
++error:
++ return retval;
++}
+diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
+new file mode 100644
+index 0000000..3e6ffee
+--- /dev/null
++++ b/drivers/media/video/hdpvr/hdpvr-video.c
+@@ -0,0 +1,1248 @@
++/*
++ * Hauppauge HD PVR USB driver - video 4 linux 2 interface
++ *
++ * Copyright (C) 2008 Janne Grunau (j@jannau.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, version 2.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/uaccess.h>
++#include <linux/usb.h>
++#include <linux/mutex.h>
++#include <linux/version.h>
++#include <linux/workqueue.h>
++
++#include <linux/videodev2.h>
++#include <media/v4l2-dev.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ioctl.h>
++#include "hdpvr.h"
++
++#define BULK_URB_TIMEOUT 1250 /* 1.25 seconds */
++
++#define print_buffer_status() { \
++ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, \
++ "%s:%d buffer stat: %d free, %d proc\n", \
++ __func__, __LINE__, \
++ list_size(&dev->free_buff_list), \
++ list_size(&dev->rec_buff_list)); }
++
++struct hdpvr_fh {
++ struct hdpvr_device *dev;
++};
++
++static uint list_size(struct list_head *list)
++{
++ struct list_head *tmp;
++ uint count = 0;
++
++ list_for_each(tmp, list) {
++ count++;
++ }
++
++ return count;
++}
++
++/*=========================================================================*/
++/* urb callback */
++static void hdpvr_read_bulk_callback(struct urb *urb)
++{
++ struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context;
++ struct hdpvr_device *dev = buf->dev;
++
++ /* marking buffer as received and wake waiting */
++ buf->status = BUFSTAT_READY;
++ wake_up_interruptible(&dev->wait_data);
++}
++
++/*=========================================================================*/
++/* bufffer bits */
++
++/* function expects dev->io_mutex to be hold by caller */
++int hdpvr_cancel_queue(struct hdpvr_device *dev)
++{
++ struct hdpvr_buffer *buf;
++
++ list_for_each_entry(buf, &dev->rec_buff_list, buff_list) {
++ usb_kill_urb(buf->urb);
++ buf->status = BUFSTAT_AVAILABLE;
++ }
++
++ list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev);
++
++ return 0;
++}
++
++static int hdpvr_free_queue(struct list_head *q)
++{
++ struct list_head *tmp;
++ struct list_head *p;
++ struct hdpvr_buffer *buf;
++ struct urb *urb;
++
++ for (p = q->next; p != q;) {
++ buf = list_entry(p, struct hdpvr_buffer, buff_list);
++
++ urb = buf->urb;
++ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
++ urb->transfer_buffer, urb->transfer_dma);
++ usb_free_urb(urb);
++ tmp = p->next;
++ list_del(p);
++ kfree(buf);
++ p = tmp;
++ }
++
++ return 0;
++}
++
++/* function expects dev->io_mutex to be hold by caller */
++int hdpvr_free_buffers(struct hdpvr_device *dev)
++{
++ hdpvr_cancel_queue(dev);
++
++ hdpvr_free_queue(&dev->free_buff_list);
++ hdpvr_free_queue(&dev->rec_buff_list);
++
++ return 0;
++}
++
++/* function expects dev->io_mutex to be hold by caller */
++int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
++{
++ uint i;
++ int retval = -ENOMEM;
++ u8 *mem;
++ struct hdpvr_buffer *buf;
++ struct urb *urb;
++
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "allocating %u buffers\n", count);
++
++ for (i = 0; i < count; i++) {
++
++ buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL);
++ if (!buf) {
++ v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n");
++ goto exit;
++ }
++ buf->dev = dev;
++
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb) {
++ v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n");
++ goto exit;
++ }
++ buf->urb = urb;
++
++ mem = usb_buffer_alloc(dev->udev, dev->bulk_in_size, GFP_KERNEL,
++ &urb->transfer_dma);
++ if (!mem) {
++ v4l2_err(&dev->v4l2_dev,
++ "cannot allocate usb transfer buffer\n");
++ goto exit;
++ }
++
++ usb_fill_bulk_urb(buf->urb, dev->udev,
++ usb_rcvbulkpipe(dev->udev,
++ dev->bulk_in_endpointAddr),
++ mem, dev->bulk_in_size,
++ hdpvr_read_bulk_callback, buf);
++
++ buf->status = BUFSTAT_AVAILABLE;
++ list_add_tail(&buf->buff_list, &dev->free_buff_list);
++ }
++ return 0;
++exit:
++ hdpvr_free_buffers(dev);
++ return retval;
++}
++
++static int hdpvr_submit_buffers(struct hdpvr_device *dev)
++{
++ struct hdpvr_buffer *buf;
++ struct urb *urb;
++ int ret = 0, err_count = 0;
++
++ mutex_lock(&dev->io_mutex);
++
++ while (dev->status == STATUS_STREAMING &&
++ !list_empty(&dev->free_buff_list)) {
++
++ buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer,
++ buff_list);
++ if (buf->status != BUFSTAT_AVAILABLE) {
++ v4l2_err(&dev->v4l2_dev,
++ "buffer not marked as availbale\n");
++ ret = -EFAULT;
++ goto err;
++ }
++
++ urb = buf->urb;
++ urb->status = 0;
++ urb->actual_length = 0;
++ ret = usb_submit_urb(urb, GFP_KERNEL);
++ if (ret) {
++ v4l2_err(&dev->v4l2_dev,
++ "usb_submit_urb in %s returned %d\n",
++ __func__, ret);
++ if (++err_count > 2)
++ break;
++ continue;
++ }
++ buf->status = BUFSTAT_INPROGRESS;
++ list_move_tail(&buf->buff_list, &dev->rec_buff_list);
++ }
++err:
++ print_buffer_status();
++ mutex_unlock(&dev->io_mutex);
++ return ret;
++}
++
++static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev)
++{
++ struct hdpvr_buffer *buf;
++
++ mutex_lock(&dev->io_mutex);
++
++ if (list_empty(&dev->rec_buff_list)) {
++ mutex_unlock(&dev->io_mutex);
++ return NULL;
++ }
++
++ buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer,
++ buff_list);
++ mutex_unlock(&dev->io_mutex);
++
++ return buf;
++}
++
++static void hdpvr_transmit_buffers(struct work_struct *work)
++{
++ struct hdpvr_device *dev = container_of(work, struct hdpvr_device,
++ worker);
++
++ while (dev->status == STATUS_STREAMING) {
++
++ if (hdpvr_submit_buffers(dev)) {
++ v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n");
++ goto error;
++ }
++ if (wait_event_interruptible(dev->wait_buffer,
++ !list_empty(&dev->free_buff_list) ||
++ dev->status != STATUS_STREAMING))
++ goto error;
++ }
++
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "transmit worker exited\n");
++ return;
++error:
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "transmit buffers errored\n");
++ dev->status = STATUS_ERROR;
++}
++
++/* function expects dev->io_mutex to be hold by caller */
++static int hdpvr_start_streaming(struct hdpvr_device *dev)
++{
++ int ret;
++ struct hdpvr_video_info *vidinf;
++
++ if (dev->status == STATUS_STREAMING)
++ return 0;
++ else if (dev->status != STATUS_IDLE)
++ return -EAGAIN;
++
++ vidinf = get_video_info(dev);
++
++ if (vidinf) {
++ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
++ "video signal: %dx%d@%dhz\n", vidinf->width,
++ vidinf->height, vidinf->fps);
++ kfree(vidinf);
++
++ /* start streaming 2 request */
++ ret = usb_control_msg(dev->udev,
++ usb_sndctrlpipe(dev->udev, 0),
++ 0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
++ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
++ "encoder start control request returned %d\n", ret);
++
++ hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
++
++ INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
++ queue_work(dev->workqueue, &dev->worker);
++
++ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
++ "streaming started\n");
++ dev->status = STATUS_STREAMING;
++
++ return 0;
++ }
++ msleep(250);
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "no video signal at input %d\n", dev->options.video_input);
++ return -EAGAIN;
++}
++
++
++/* function expects dev->io_mutex to be hold by caller */
++static int hdpvr_stop_streaming(struct hdpvr_device *dev)
++{
++ uint actual_length, c = 0;
++ u8 *buf;
++
++ if (dev->status == STATUS_IDLE)
++ return 0;
++ else if (dev->status != STATUS_STREAMING)
++ return -EAGAIN;
++
++ buf = kmalloc(dev->bulk_in_size, GFP_KERNEL);
++ if (!buf)
++ v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer "
++ "for emptying the internal device buffer. "
++ "Next capture start will be slow\n");
++
++ dev->status = STATUS_SHUTTING_DOWN;
++ hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00);
++ mutex_unlock(&dev->io_mutex);
++
++ wake_up_interruptible(&dev->wait_buffer);
++ msleep(50);
++
++ flush_workqueue(dev->workqueue);
++
++ mutex_lock(&dev->io_mutex);
++ /* kill the still outstanding urbs */
++ hdpvr_cancel_queue(dev);
++
++ /* emptying the device buffer beforeshutting it down */
++ while (buf && ++c < 500 &&
++ !usb_bulk_msg(dev->udev,
++ usb_rcvbulkpipe(dev->udev,
++ dev->bulk_in_endpointAddr),
++ buf, dev->bulk_in_size, &actual_length,
++ BULK_URB_TIMEOUT)) {
++ /* wait */
++ msleep(5);
++ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
++ "%2d: got %d bytes\n", c, actual_length);
++ }
++ kfree(buf);
++ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
++ "used %d urbs to empty device buffers\n", c-1);
++ msleep(10);
++
++ dev->status = STATUS_IDLE;
++
++ return 0;
++}
++
++
++/*=======================================================================*/
++/*
++ * video 4 linux 2 file operations
++ */
++
++static int hdpvr_open(struct file *file)
++{
++ struct hdpvr_device *dev;
++ struct hdpvr_fh *fh;
++ int retval = -ENOMEM;
++
++ dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
++ if (!dev) {
++ v4l2_err(&dev->v4l2_dev, "open failing with with ENODEV\n");
++ retval = -ENODEV;
++ goto err;
++ }
++
++ fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL);
++ if (!fh) {
++ v4l2_err(&dev->v4l2_dev, "Out of memory\n");
++ goto err;
++ }
++ /* lock the device to allow correctly handling errors
++ * in resumption */
++ mutex_lock(&dev->io_mutex);
++ dev->open_count++;
++
++ fh->dev = dev;
++
++ /* save our object in the file's private structure */
++ file->private_data = fh;
++
++ retval = 0;
++err:
++ mutex_unlock(&dev->io_mutex);
++ return retval;
++}
++
++static int hdpvr_release(struct file *file)
++{
++ struct hdpvr_fh *fh = (struct hdpvr_fh *)file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++
++ if (!dev)
++ return -ENODEV;
++
++ mutex_lock(&dev->io_mutex);
++ if (!(--dev->open_count) && dev->status == STATUS_STREAMING)
++ hdpvr_stop_streaming(dev);
++
++ mutex_unlock(&dev->io_mutex);
++
++ return 0;
++}
++
++/*
++ * hdpvr_v4l2_read()
++ * will allocate buffers when called for the first time
++ */
++static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
++ loff_t *pos)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ struct hdpvr_buffer *buf = NULL;
++ struct urb *urb;
++ unsigned int ret = 0;
++ int rem, cnt;
++
++ if (*pos)
++ return -ESPIPE;
++
++ if (!dev)
++ return -ENODEV;
++
++ mutex_lock(&dev->io_mutex);
++ if (dev->status == STATUS_IDLE) {
++ if (hdpvr_start_streaming(dev)) {
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "start_streaming failed\n");
++ ret = -EIO;
++ msleep(200);
++ dev->status = STATUS_IDLE;
++ mutex_unlock(&dev->io_mutex);
++ goto err;
++ }
++ print_buffer_status();
++ }
++ mutex_unlock(&dev->io_mutex);
++
++ /* wait for the first buffer */
++ if (!(file->f_flags & O_NONBLOCK)) {
++ if (wait_event_interruptible(dev->wait_data,
++ hdpvr_get_next_buffer(dev)))
++ return -ERESTARTSYS;
++ }
++
++ buf = hdpvr_get_next_buffer(dev);
++
++ while (count > 0 && buf) {
++
++ if (buf->status != BUFSTAT_READY &&
++ dev->status != STATUS_DISCONNECTED) {
++ /* return nonblocking */
++ if (file->f_flags & O_NONBLOCK) {
++ if (!ret)
++ ret = -EAGAIN;
++ goto err;
++ }
++
++ if (wait_event_interruptible(dev->wait_data,
++ buf->status == BUFSTAT_READY)) {
++ ret = -ERESTARTSYS;
++ goto err;
++ }
++ }
++
++ if (buf->status != BUFSTAT_READY)
++ break;
++
++ /* set remaining bytes to copy */
++ urb = buf->urb;
++ rem = urb->actual_length - buf->pos;
++ cnt = rem > count ? count : rem;
++
++ if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
++ cnt)) {
++ v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n");
++ if (!ret)
++ ret = -EFAULT;
++ goto err;
++ }
++
++ buf->pos += cnt;
++ count -= cnt;
++ buffer += cnt;
++ ret += cnt;
++
++ /* finished, take next buffer */
++ if (buf->pos == urb->actual_length) {
++ mutex_lock(&dev->io_mutex);
++ buf->pos = 0;
++ buf->status = BUFSTAT_AVAILABLE;
++
++ list_move_tail(&buf->buff_list, &dev->free_buff_list);
++
++ print_buffer_status();
++
++ mutex_unlock(&dev->io_mutex);
++
++ wake_up_interruptible(&dev->wait_buffer);
++
++ buf = hdpvr_get_next_buffer(dev);
++ }
++ }
++err:
++ if (!ret && !buf)
++ ret = -EAGAIN;
++ return ret;
++}
++
++static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
++{
++ struct hdpvr_buffer *buf = NULL;
++ struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ unsigned int mask = 0;
++
++ mutex_lock(&dev->io_mutex);
++
++ if (video_is_unregistered(dev->video_dev))
++ return -EIO;
++
++ if (dev->status == STATUS_IDLE) {
++ if (hdpvr_start_streaming(dev)) {
++ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
++ "start_streaming failed\n");
++ dev->status = STATUS_IDLE;
++ }
++
++ print_buffer_status();
++ }
++ mutex_unlock(&dev->io_mutex);
++
++ buf = hdpvr_get_next_buffer(dev);
++ /* only wait if no data is available */
++ if (!buf || buf->status != BUFSTAT_READY) {
++ poll_wait(filp, &dev->wait_data, wait);
++ buf = hdpvr_get_next_buffer(dev);
++ }
++ if (buf && buf->status == BUFSTAT_READY)
++ mask |= POLLIN | POLLRDNORM;
++
++ return mask;
++}
++
++
++static const struct v4l2_file_operations hdpvr_fops = {
++ .owner = THIS_MODULE,
++ .open = hdpvr_open,
++ .release = hdpvr_release,
++ .read = hdpvr_read,
++ .poll = hdpvr_poll,
++ .unlocked_ioctl = video_ioctl2,
++};
++
++/*=======================================================================*/
++/*
++ * V4L2 ioctl handling
++ */
++
++static int vidioc_querycap(struct file *file, void *priv,
++ struct v4l2_capability *cap)
++{
++ struct hdpvr_device *dev = video_drvdata(file);
++
++ strcpy(cap->driver, "hdpvr");
++ strcpy(cap->card, "Haupauge HD PVR");
++ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
++ cap->version = HDPVR_VERSION;
++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
++ V4L2_CAP_AUDIO |
++ V4L2_CAP_READWRITE;
++ return 0;
++}
++
++static int vidioc_s_std(struct file *file, void *private_data,
++ v4l2_std_id *std)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ u8 std_type = 1;
++
++ if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60))
++ std_type = 0;
++
++ return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
++}
++
++static const char *iname[] = {
++ [HDPVR_COMPONENT] = "Component",
++ [HDPVR_SVIDEO] = "S-Video",
++ [HDPVR_COMPOSITE] = "Composite",
++};
++
++static int vidioc_enum_input(struct file *file, void *priv,
++ struct v4l2_input *i)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ unsigned int n;
++
++ n = i->index;
++ if (n >= HDPVR_VIDEO_INPUTS)
++ return -EINVAL;
++
++ i->type = V4L2_INPUT_TYPE_CAMERA;
++
++ strncpy(i->name, iname[n], sizeof(i->name) - 1);
++ i->name[sizeof(i->name) - 1] = '\0';
++
++ i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
++
++ i->std = dev->video_dev->tvnorms;
++
++ return 0;
++}
++
++static int vidioc_s_input(struct file *file, void *private_data,
++ unsigned int index)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ int retval;
++
++ if (index >= HDPVR_VIDEO_INPUTS)
++ return -EINVAL;
++
++ if (dev->status != STATUS_IDLE)
++ return -EAGAIN;
++
++ retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
++ if (!retval)
++ dev->options.video_input = index;
++
++ return retval;
++}
++
++static int vidioc_g_input(struct file *file, void *private_data,
++ unsigned int *index)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++
++ *index = dev->options.video_input;
++ return 0;
++}
++
++
++static const char *audio_iname[] = {
++ [HDPVR_RCA_FRONT] = "RCA front",
++ [HDPVR_RCA_BACK] = "RCA back",
++ [HDPVR_SPDIF] = "SPDIF",
++};
++
++static int vidioc_enumaudio(struct file *file, void *priv,
++ struct v4l2_audio *audio)
++{
++ unsigned int n;
++
++ n = audio->index;
++ if (n >= HDPVR_AUDIO_INPUTS)
++ return -EINVAL;
++
++ audio->capability = V4L2_AUDCAP_STEREO;
++
++ strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1);
++ audio->name[sizeof(audio->name) - 1] = '\0';
++
++ return 0;
++}
++
++static int vidioc_s_audio(struct file *file, void *private_data,
++ struct v4l2_audio *audio)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ int retval;
++
++ if (audio->index >= HDPVR_AUDIO_INPUTS)
++ return -EINVAL;
++
++ if (dev->status != STATUS_IDLE)
++ return -EAGAIN;
++
++ retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
++ if (!retval)
++ dev->options.audio_input = audio->index;
++
++ return retval;
++}
++
++static int vidioc_g_audio(struct file *file, void *private_data,
++ struct v4l2_audio *audio)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++
++ audio->index = dev->options.audio_input;
++ audio->capability = V4L2_AUDCAP_STEREO;
++ strncpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
++ audio->name[sizeof(audio->name) - 1] = '\0';
++ return 0;
++}
++
++static const s32 supported_v4l2_ctrls[] = {
++ V4L2_CID_BRIGHTNESS,
++ V4L2_CID_CONTRAST,
++ V4L2_CID_SATURATION,
++ V4L2_CID_HUE,
++ V4L2_CID_SHARPNESS,
++ V4L2_CID_MPEG_AUDIO_ENCODING,
++ V4L2_CID_MPEG_VIDEO_ENCODING,
++ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
++ V4L2_CID_MPEG_VIDEO_BITRATE,
++ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
++};
++
++static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc,
++ int ac3)
++{
++ int err;
++
++ switch (qc->id) {
++ case V4L2_CID_BRIGHTNESS:
++ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
++ case V4L2_CID_CONTRAST:
++ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
++ case V4L2_CID_SATURATION:
++ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
++ case V4L2_CID_HUE:
++ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
++ case V4L2_CID_SHARPNESS:
++ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
++ case V4L2_CID_MPEG_AUDIO_ENCODING:
++ return v4l2_ctrl_query_fill(
++ qc, V4L2_MPEG_AUDIO_ENCODING_AAC,
++ ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3
++ : V4L2_MPEG_AUDIO_ENCODING_AAC,
++ 1, V4L2_MPEG_AUDIO_ENCODING_AAC);
++ case V4L2_CID_MPEG_VIDEO_ENCODING:
++ return v4l2_ctrl_query_fill(
++ qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC,
++ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
++ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
++
++/* case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */
++/* return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */
++ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
++ return v4l2_ctrl_query_fill(
++ qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
++
++ case V4L2_CID_MPEG_VIDEO_BITRATE:
++ return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000,
++ 6500000);
++ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
++ err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000,
++ 9000000);
++ if (!err && opt->bitrate_mode == HDPVR_CONSTANT)
++ qc->flags |= V4L2_CTRL_FLAG_INACTIVE;
++ return err;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int vidioc_queryctrl(struct file *file, void *private_data,
++ struct v4l2_queryctrl *qc)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ int i, next;
++ u32 id = qc->id;
++
++ memset(qc, 0, sizeof(*qc));
++
++ next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
++ qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
++
++ for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) {
++ if (next) {
++ if (qc->id < supported_v4l2_ctrls[i])
++ qc->id = supported_v4l2_ctrls[i];
++ else
++ continue;
++ }
++
++ if (qc->id == supported_v4l2_ctrls[i])
++ return fill_queryctrl(&dev->options, qc,
++ dev->flags & HDPVR_FLAG_AC3_CAP);
++
++ if (qc->id < supported_v4l2_ctrls[i])
++ break;
++ }
++
++ return -EINVAL;
++}
++
++static int vidioc_g_ctrl(struct file *file, void *private_data,
++ struct v4l2_control *ctrl)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ ctrl->value = dev->options.brightness;
++ break;
++ case V4L2_CID_CONTRAST:
++ ctrl->value = dev->options.contrast;
++ break;
++ case V4L2_CID_SATURATION:
++ ctrl->value = dev->options.saturation;
++ break;
++ case V4L2_CID_HUE:
++ ctrl->value = dev->options.hue;
++ break;
++ case V4L2_CID_SHARPNESS:
++ ctrl->value = dev->options.sharpness;
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int vidioc_s_ctrl(struct file *file, void *private_data,
++ struct v4l2_control *ctrl)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ int retval;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value);
++ if (!retval)
++ dev->options.brightness = ctrl->value;
++ break;
++ case V4L2_CID_CONTRAST:
++ retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value);
++ if (!retval)
++ dev->options.contrast = ctrl->value;
++ break;
++ case V4L2_CID_SATURATION:
++ retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value);
++ if (!retval)
++ dev->options.saturation = ctrl->value;
++ break;
++ case V4L2_CID_HUE:
++ retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value);
++ if (!retval)
++ dev->options.hue = ctrl->value;
++ break;
++ case V4L2_CID_SHARPNESS:
++ retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value);
++ if (!retval)
++ dev->options.sharpness = ctrl->value;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return retval;
++}
++
++
++static int hdpvr_get_ctrl(struct hdpvr_options *opt,
++ struct v4l2_ext_control *ctrl)
++{
++ switch (ctrl->id) {
++ case V4L2_CID_MPEG_AUDIO_ENCODING:
++ ctrl->value = opt->audio_codec;
++ break;
++ case V4L2_CID_MPEG_VIDEO_ENCODING:
++ ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
++ break;
++/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
++/* ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */
++/* break; */
++ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
++ ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT
++ ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
++ : V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE:
++ ctrl->value = opt->bitrate * 100000;
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
++ ctrl->value = opt->peak_bitrate * 100000;
++ break;
++ case V4L2_CID_MPEG_STREAM_TYPE:
++ ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int vidioc_g_ext_ctrls(struct file *file, void *priv,
++ struct v4l2_ext_controls *ctrls)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ int i, err = 0;
++
++ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
++ for (i = 0; i < ctrls->count; i++) {
++ struct v4l2_ext_control *ctrl = ctrls->controls + i;
++
++ err = hdpvr_get_ctrl(&dev->options, ctrl);
++ if (err) {
++ ctrls->error_idx = i;
++ break;
++ }
++ }
++ return err;
++
++ }
++
++ return -EINVAL;
++}
++
++
++static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
++{
++ int ret = -EINVAL;
++
++ switch (ctrl->id) {
++ case V4L2_CID_MPEG_AUDIO_ENCODING:
++ if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC ||
++ (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3))
++ ret = 0;
++ break;
++ case V4L2_CID_MPEG_VIDEO_ENCODING:
++ if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
++ ret = 0;
++ break;
++/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
++/* if (ctrl->value == 0 || ctrl->value == 128) */
++/* ret = 0; */
++/* break; */
++ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
++ if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR ||
++ ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
++ ret = 0;
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE:
++ {
++ uint bitrate = ctrl->value / 100000;
++ if (bitrate >= 10 && bitrate <= 135)
++ ret = 0;
++ break;
++ }
++ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
++ {
++ uint peak_bitrate = ctrl->value / 100000;
++ if (peak_bitrate >= 10 && peak_bitrate <= 202)
++ ret = 0;
++ break;
++ }
++ case V4L2_CID_MPEG_STREAM_TYPE:
++ if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
++ ret = 0;
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int vidioc_try_ext_ctrls(struct file *file, void *priv,
++ struct v4l2_ext_controls *ctrls)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ int i, err = 0;
++
++ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
++ for (i = 0; i < ctrls->count; i++) {
++ struct v4l2_ext_control *ctrl = ctrls->controls + i;
++
++ err = hdpvr_try_ctrl(ctrl,
++ dev->flags & HDPVR_FLAG_AC3_CAP);
++ if (err) {
++ ctrls->error_idx = i;
++ break;
++ }
++ }
++ return err;
++ }
++
++ return -EINVAL;
++}
++
++
++static int hdpvr_set_ctrl(struct hdpvr_device *dev,
++ struct v4l2_ext_control *ctrl)
++{
++ struct hdpvr_options *opt = &dev->options;
++ int ret = 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_MPEG_AUDIO_ENCODING:
++ if (dev->flags & HDPVR_FLAG_AC3_CAP) {
++ opt->audio_codec = ctrl->value;
++ ret = hdpvr_set_audio(dev, opt->audio_input,
++ opt->audio_codec);
++ }
++ break;
++ case V4L2_CID_MPEG_VIDEO_ENCODING:
++ break;
++/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
++/* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
++/* opt->gop_mode |= 0x2; */
++/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
++/* opt->gop_mode); */
++/* } */
++/* if (ctrl->value == 128 && opt->gop_mode & 0x2) { */
++/* opt->gop_mode &= ~0x2; */
++/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
++/* opt->gop_mode); */
++/* } */
++/* break; */
++ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
++ if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR &&
++ opt->bitrate_mode != HDPVR_CONSTANT) {
++ opt->bitrate_mode = HDPVR_CONSTANT;
++ hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
++ opt->bitrate_mode);
++ }
++ if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
++ opt->bitrate_mode == HDPVR_CONSTANT) {
++ opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
++ hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
++ opt->bitrate_mode);
++ }
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE: {
++ uint bitrate = ctrl->value / 100000;
++
++ opt->bitrate = bitrate;
++ if (bitrate >= opt->peak_bitrate)
++ opt->peak_bitrate = bitrate+1;
++
++ hdpvr_set_bitrate(dev);
++ break;
++ }
++ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: {
++ uint peak_bitrate = ctrl->value / 100000;
++
++ if (opt->bitrate_mode == HDPVR_CONSTANT)
++ break;
++
++ if (opt->bitrate < peak_bitrate) {
++ opt->peak_bitrate = peak_bitrate;
++ hdpvr_set_bitrate(dev);
++ } else
++ ret = -EINVAL;
++ break;
++ }
++ case V4L2_CID_MPEG_STREAM_TYPE:
++ break;
++ default:
++ return -EINVAL;
++ }
++ return ret;
++}
++
++static int vidioc_s_ext_ctrls(struct file *file, void *priv,
++ struct v4l2_ext_controls *ctrls)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ int i, err = 0;
++
++ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
++ for (i = 0; i < ctrls->count; i++) {
++ struct v4l2_ext_control *ctrl = ctrls->controls + i;
++
++ err = hdpvr_try_ctrl(ctrl,
++ dev->flags & HDPVR_FLAG_AC3_CAP);
++ if (err) {
++ ctrls->error_idx = i;
++ break;
++ }
++ err = hdpvr_set_ctrl(dev, ctrl);
++ if (err) {
++ ctrls->error_idx = i;
++ break;
++ }
++ }
++ return err;
++
++ }
++
++ return -EINVAL;
++}
++
++static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
++ struct v4l2_fmtdesc *f)
++{
++
++ if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ f->flags = V4L2_FMT_FLAG_COMPRESSED;
++ strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32);
++ f->pixelformat = V4L2_PIX_FMT_MPEG;
++
++ return 0;
++}
++
++static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
++ struct v4l2_format *f)
++{
++ struct hdpvr_fh *fh = file->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ struct hdpvr_video_info *vid_info;
++
++ if (!dev)
++ return -ENODEV;
++
++ vid_info = get_video_info(dev);
++ if (!vid_info)
++ return -EFAULT;
++
++ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
++ f->fmt.pix.width = vid_info->width;
++ f->fmt.pix.height = vid_info->height;
++ f->fmt.pix.sizeimage = dev->bulk_in_size;
++ f->fmt.pix.colorspace = 0;
++ f->fmt.pix.bytesperline = 0;
++ f->fmt.pix.field = V4L2_FIELD_ANY;
++
++ kfree(vid_info);
++ return 0;
++}
++
++static int vidioc_encoder_cmd(struct file *filp, void *priv,
++ struct v4l2_encoder_cmd *a)
++{
++ struct hdpvr_fh *fh = filp->private_data;
++ struct hdpvr_device *dev = fh->dev;
++ int res;
++
++ mutex_lock(&dev->io_mutex);
++
++ memset(&a->raw, 0, sizeof(a->raw));
++ switch (a->cmd) {
++ case V4L2_ENC_CMD_START:
++ a->flags = 0;
++ res = hdpvr_start_streaming(dev);
++ break;
++ case V4L2_ENC_CMD_STOP:
++ res = hdpvr_stop_streaming(dev);
++ break;
++ default:
++ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
++ "Unsupported encoder cmd %d\n", a->cmd);
++ res = -EINVAL;
++ }
++ mutex_unlock(&dev->io_mutex);
++ return res;
++}
++
++static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
++ struct v4l2_encoder_cmd *a)
++{
++ switch (a->cmd) {
++ case V4L2_ENC_CMD_START:
++ case V4L2_ENC_CMD_STOP:
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_s_std = vidioc_s_std,
++ .vidioc_enum_input = vidioc_enum_input,
++ .vidioc_g_input = vidioc_g_input,
++ .vidioc_s_input = vidioc_s_input,
++ .vidioc_enumaudio = vidioc_enumaudio,
++ .vidioc_g_audio = vidioc_g_audio,
++ .vidioc_s_audio = vidioc_s_audio,
++ .vidioc_queryctrl = vidioc_queryctrl,
++ .vidioc_g_ctrl = vidioc_g_ctrl,
++ .vidioc_s_ctrl = vidioc_s_ctrl,
++ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
++ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
++ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
++ .vidioc_encoder_cmd = vidioc_encoder_cmd,
++ .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
++};
++
++static void hdpvr_device_release(struct video_device *vdev)
++{
++ struct hdpvr_device *dev = video_get_drvdata(vdev);
++
++ hdpvr_delete(dev);
++}
++
++static const struct video_device hdpvr_video_template = {
++/* .type = VFL_TYPE_GRABBER, */
++/* .type2 = VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */
++ .fops = &hdpvr_fops,
++ .release = hdpvr_device_release,
++ .ioctl_ops = &hdpvr_ioctl_ops,
++ .tvnorms =
++ V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_B |
++ V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I |
++ V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N |
++ V4L2_STD_PAL_60,
++};
++
++int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
++ int devnum)
++{
++ /* setup and register video device */
++ dev->video_dev = video_device_alloc();
++ if (!dev->video_dev) {
++ v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
++ goto error;
++ }
++
++ *(dev->video_dev) = hdpvr_video_template;
++ strcpy(dev->video_dev->name, "Hauppauge HD PVR");
++ dev->video_dev->parent = parent;
++ video_set_drvdata(dev->video_dev, dev);
++
++ if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) {
++ v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
++ goto error;
++ }
++
++ return 0;
++error:
++ return -ENOMEM;
++}
+diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h
+new file mode 100644
+index 0000000..1edd875
+--- /dev/null
++++ b/drivers/media/video/hdpvr/hdpvr.h
+@@ -0,0 +1,303 @@
++/*
++ * Hauppauge HD PVR USB driver
++ *
++ * Copyright (C) 2008 Janne Grunau (j@jannau.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, version 2.
++ *
++ */
++
++#include <linux/usb.h>
++#include <linux/i2c.h>
++#include <linux/mutex.h>
++#include <linux/workqueue.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-device.h>
++
++#define HDPVR_MAJOR_VERSION 0
++#define HDPVR_MINOR_VERSION 2
++#define HDPVR_RELEASE 0
++#define HDPVR_VERSION \
++ KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE)
++
++#define HDPVR_MAX 8
++
++/* Define these values to match your devices */
++#define HD_PVR_VENDOR_ID 0x2040
++#define HD_PVR_PRODUCT_ID 0x4900
++#define HD_PVR_PRODUCT_ID1 0x4901
++#define HD_PVR_PRODUCT_ID2 0x4902
++
++#define UNSET (-1U)
++
++#define NUM_BUFFERS 64
++
++#define HDPVR_FIRMWARE_VERSION 0x8
++#define HDPVR_FIRMWARE_VERSION_AC3 0xd
++
++/* #define HDPVR_DEBUG */
++
++extern int hdpvr_debug;
++
++#define MSG_INFO 1
++#define MSG_BUFFER 2
++
++struct hdpvr_options {
++ u8 video_std;
++ u8 video_input;
++ u8 audio_input;
++ u8 bitrate; /* in 100kbps */
++ u8 peak_bitrate; /* in 100kbps */
++ u8 bitrate_mode;
++ u8 gop_mode;
++ enum v4l2_mpeg_audio_encoding audio_codec;
++ u8 brightness;
++ u8 contrast;
++ u8 hue;
++ u8 saturation;
++ u8 sharpness;
++};
++
++/* Structure to hold all of our device specific stuff */
++struct hdpvr_device {
++ /* the v4l device for this device */
++ struct video_device *video_dev;
++ /* the usb device for this device */
++ struct usb_device *udev;
++ /* v4l2-device unused */
++ struct v4l2_device v4l2_dev;
++
++ /* the max packet size of the bulk endpoint */
++ size_t bulk_in_size;
++ /* the address of the bulk in endpoint */
++ __u8 bulk_in_endpointAddr;
++
++ /* holds the current device status */
++ __u8 status;
++ /* count the number of openers */
++ uint open_count;
++
++ /* holds the cureent set options */
++ struct hdpvr_options options;
++
++ uint flags;
++
++ /* synchronize I/O */
++ struct mutex io_mutex;
++ /* available buffers */
++ struct list_head free_buff_list;
++ /* in progress buffers */
++ struct list_head rec_buff_list;
++ /* waitqueue for buffers */
++ wait_queue_head_t wait_buffer;
++ /* waitqueue for data */
++ wait_queue_head_t wait_data;
++ /**/
++ struct workqueue_struct *workqueue;
++ /**/
++ struct work_struct worker;
++
++ /* I2C adapter */
++ struct i2c_adapter *i2c_adapter;
++ /* I2C lock */
++ struct mutex i2c_mutex;
++
++ /* usb control transfer buffer and lock */
++ struct mutex usbc_mutex;
++ u8 *usbc_buf;
++};
++
++
++/* buffer one bulk urb of data */
++struct hdpvr_buffer {
++ struct list_head buff_list;
++
++ struct urb *urb;
++
++ struct hdpvr_device *dev;
++
++ uint pos;
++
++ __u8 status;
++};
++
++/* */
++
++struct hdpvr_video_info {
++ u16 width;
++ u16 height;
++ u8 fps;
++};
++
++enum {
++ STATUS_UNINITIALIZED = 0,
++ STATUS_IDLE,
++ STATUS_STARTING,
++ STATUS_SHUTTING_DOWN,
++ STATUS_STREAMING,
++ STATUS_ERROR,
++ STATUS_DISCONNECTED,
++};
++
++enum {
++ HDPVR_FLAG_AC3_CAP = 1,
++};
++
++enum {
++ BUFSTAT_UNINITIALIZED = 0,
++ BUFSTAT_AVAILABLE,
++ BUFSTAT_INPROGRESS,
++ BUFSTAT_READY,
++};
++
++#define CTRL_START_STREAMING_VALUE 0x0700
++#define CTRL_STOP_STREAMING_VALUE 0x0800
++#define CTRL_BITRATE_VALUE 0x1000
++#define CTRL_BITRATE_MODE_VALUE 0x1200
++#define CTRL_GOP_MODE_VALUE 0x1300
++#define CTRL_VIDEO_INPUT_VALUE 0x1500
++#define CTRL_VIDEO_STD_TYPE 0x1700
++#define CTRL_AUDIO_INPUT_VALUE 0x2500
++#define CTRL_BRIGHTNESS 0x2900
++#define CTRL_CONTRAST 0x2a00
++#define CTRL_HUE 0x2b00
++#define CTRL_SATURATION 0x2c00
++#define CTRL_SHARPNESS 0x2d00
++#define CTRL_LOW_PASS_FILTER_VALUE 0x3100
++
++#define CTRL_DEFAULT_INDEX 0x0003
++
++
++ /* :0 s 38 01 1000 0003 0004 4 = 0a00ca00
++ * BITRATE SETTING
++ * 1st and 2nd byte (little endian): average bitrate in 100 000 bit/s
++ * min: 1 mbit/s, max: 13.5 mbit/s
++ * 3rd and 4th byte (little endian): peak bitrate in 100 000 bit/s
++ * min: average + 100kbit/s,
++ * max: 20.2 mbit/s
++ */
++
++ /* :0 s 38 01 1200 0003 0001 1 = 02
++ * BIT RATE MODE
++ * constant = 1, variable (peak) = 2, variable (average) = 3
++ */
++
++ /* :0 s 38 01 1300 0003 0001 1 = 03
++ * GOP MODE (2 bit)
++ * low bit 0/1: advanced/simple GOP
++ * high bit 0/1: IDR(4/32/128) / no IDR (4/32/0)
++ */
++
++ /* :0 s 38 01 1700 0003 0001 1 = 00
++ * VIDEO STANDARD or FREQUNCY 0 = 60hz, 1 = 50hz
++ */
++
++ /* :0 s 38 01 3100 0003 0004 4 = 03030000
++ * FILTER CONTROL
++ * 1st byte luma low pass filter strength,
++ * 2nd byte chroma low pass filter strength,
++ * 3rd byte MF enable chroma, min=0, max=1
++ * 4th byte n
++ */
++
++
++ /* :0 s 38 b9 0001 0000 0000 0 */
++
++
++
++/* :0 s 38 d3 0000 0000 0001 1 = 00 */
++/* ret = usb_control_msg(dev->udev, */
++/* usb_sndctrlpipe(dev->udev, 0), */
++/* 0xd3, 0x38, */
++/* 0, 0, */
++/* "\0", 1, */
++/* 1000); */
++
++/* info("control request returned %d", ret); */
++/* msleep(5000); */
++
++
++ /* :0 s b8 81 1400 0003 0005 5 <
++ * :0 0 5 = d0024002 19
++ * QUERY FRAME SIZE AND RATE
++ * 1st and 2nd byte (little endian): horizontal resolution
++ * 3rd and 4th byte (little endian): vertical resolution
++ * 5th byte: frame rate
++ */
++
++ /* :0 s b8 81 1800 0003 0003 3 <
++ * :0 0 3 = 030104
++ * QUERY SIGNAL AND DETECTED LINES, maybe INPUT
++ */
++
++enum hdpvr_video_std {
++ HDPVR_60HZ = 0,
++ HDPVR_50HZ,
++};
++
++enum hdpvr_video_input {
++ HDPVR_COMPONENT = 0,
++ HDPVR_SVIDEO,
++ HDPVR_COMPOSITE,
++ HDPVR_VIDEO_INPUTS
++};
++
++enum hdpvr_audio_inputs {
++ HDPVR_RCA_BACK = 0,
++ HDPVR_RCA_FRONT,
++ HDPVR_SPDIF,
++ HDPVR_AUDIO_INPUTS
++};
++
++enum hdpvr_bitrate_mode {
++ HDPVR_CONSTANT = 1,
++ HDPVR_VARIABLE_PEAK,
++ HDPVR_VARIABLE_AVERAGE,
++};
++
++enum hdpvr_gop_mode {
++ HDPVR_ADVANCED_IDR_GOP = 0,
++ HDPVR_SIMPLE_IDR_GOP,
++ HDPVR_ADVANCED_NOIDR_GOP,
++ HDPVR_SIMPLE_NOIDR_GOP,
++};
++
++void hdpvr_delete(struct hdpvr_device *dev);
++
++/*========================================================================*/
++/* hardware control functions */
++int hdpvr_set_options(struct hdpvr_device *dev);
++
++int hdpvr_set_bitrate(struct hdpvr_device *dev);
++
++int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
++ enum v4l2_mpeg_audio_encoding codec);
++
++int hdpvr_config_call(struct hdpvr_device *dev, uint value,
++ unsigned char valbuf);
++
++struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev);
++
++/* :0 s b8 81 1800 0003 0003 3 < */
++/* :0 0 3 = 0301ff */
++int get_input_lines_info(struct hdpvr_device *dev);
++
++
++/*========================================================================*/
++/* v4l2 registration */
++int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
++ int devnumber);
++
++int hdpvr_cancel_queue(struct hdpvr_device *dev);
++
++/*========================================================================*/
++/* i2c adapter registration */
++int hdpvr_register_i2c_adapter(struct hdpvr_device *dev);
++
++/*========================================================================*/
++/* buffer management */
++int hdpvr_free_buffers(struct hdpvr_device *dev);
++int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count);
+diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
+index 79393d1..8e1463e 100644
+--- a/drivers/media/video/hexium_gemini.c
++++ b/drivers/media/video/hexium_gemini.c
+@@ -56,17 +56,6 @@ struct hexium_data
+ u8 byte;
+ };
+
+-static struct saa7146_extension_ioctls ioctls[] = {
+- { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_QUERYCTRL, SAA7146_BEFORE },
+- { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_STD, SAA7146_AFTER },
+- { VIDIOC_G_CTRL, SAA7146_BEFORE },
+- { VIDIOC_S_CTRL, SAA7146_BEFORE },
+- { 0, 0 }
+-};
+-
+ #define HEXIUM_CONTROLS 1
+ static struct v4l2_queryctrl hexium_controls[] = {
+ { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
+@@ -231,6 +220,132 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
+ return 0;
+ }
+
++static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
++{
++ DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
++
++ if (i->index < 0 || i->index >= HEXIUM_INPUTS)
++ return -EINVAL;
++
++ memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
++
++ DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
++ return 0;
++}
++
++static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct hexium *hexium = (struct hexium *) dev->ext_priv;
++
++ *input = hexium->cur_input;
++
++ DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
++ return 0;
++}
++
++static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct hexium *hexium = (struct hexium *) dev->ext_priv;
++
++ DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
++
++ if (input < 0 || input >= HEXIUM_INPUTS)
++ return -EINVAL;
++
++ hexium->cur_input = input;
++ hexium_set_input(hexium, input);
++ return 0;
++}
++
++/* the saa7146 provides some controls (brightness, contrast, saturation)
++ which gets registered *after* this function. because of this we have
++ to return with a value != 0 even if the function succeded.. */
++static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ int i;
++
++ for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
++ if (hexium_controls[i].id == qc->id) {
++ *qc = hexium_controls[i];
++ DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
++ return 0;
++ }
++ }
++ return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
++}
++
++static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct hexium *hexium = (struct hexium *) dev->ext_priv;
++ int i;
++
++ for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
++ if (hexium_controls[i].id == vc->id)
++ break;
++ }
++
++ if (i < 0)
++ return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
++
++ if (vc->id == V4L2_CID_PRIVATE_BASE) {
++ vc->value = hexium->cur_bw;
++ DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
++ return 0;
++ }
++ return -EINVAL;
++}
++
++static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct hexium *hexium = (struct hexium *) dev->ext_priv;
++ int i = 0;
++
++ for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
++ if (hexium_controls[i].id == vc->id)
++ break;
++ }
++
++ if (i < 0)
++ return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
++
++ if (vc->id == V4L2_CID_PRIVATE_BASE)
++ hexium->cur_bw = vc->value;
++
++ DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
++
++ if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
++ hexium_set_standard(hexium, hexium_pal);
++ return 0;
++ }
++ if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
++ hexium_set_standard(hexium, hexium_ntsc);
++ return 0;
++ }
++ if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
++ hexium_set_standard(hexium, hexium_secam);
++ return 0;
++ }
++ if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
++ hexium_set_standard(hexium, hexium_pal_bw);
++ return 0;
++ }
++ if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
++ hexium_set_standard(hexium, hexium_ntsc_bw);
++ return 0;
++ }
++ if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std)
++ /* fixme: is there no bw secam mode? */
++ return -EINVAL;
++
++ return -EINVAL;
++}
++
++
+ static struct saa7146_ext_vv vv_data;
+
+ /* this function only gets called when the probing was successful */
+@@ -279,6 +394,12 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
+ hexium->cur_input = 0;
+
+ saa7146_vv_init(dev, &vv_data);
++ vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
++ vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
++ vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
++ vv_data.ops.vidioc_enum_input = vidioc_enum_input;
++ vv_data.ops.vidioc_g_input = vidioc_g_input;
++ vv_data.ops.vidioc_s_input = vidioc_s_input;
+ if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
+ printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
+ return -1;
+@@ -306,153 +427,6 @@ static int hexium_detach(struct saa7146_dev *dev)
+ return 0;
+ }
+
+-static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+-{
+- struct saa7146_dev *dev = fh->dev;
+- struct hexium *hexium = (struct hexium *) dev->ext_priv;
+-/*
+- struct saa7146_vv *vv = dev->vv_data;
+-*/
+- switch (cmd) {
+- case VIDIOC_ENUMINPUT:
+- {
+- struct v4l2_input *i = arg;
+- DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+-
+- if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
+- return -EINVAL;
+- }
+-
+- memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
+-
+- DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
+- return 0;
+- }
+- case VIDIOC_G_INPUT:
+- {
+- int *input = (int *) arg;
+- *input = hexium->cur_input;
+-
+- DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
+- return 0;
+- }
+- case VIDIOC_S_INPUT:
+- {
+- int input = *(int *) arg;
+-
+- DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
+-
+- if (input < 0 || input >= HEXIUM_INPUTS) {
+- return -EINVAL;
+- }
+-
+- hexium->cur_input = input;
+- hexium_set_input(hexium, input);
+-
+- return 0;
+- }
+- /* the saa7146 provides some controls (brightness, contrast, saturation)
+- which gets registered *after* this function. because of this we have
+- to return with a value != 0 even if the function succeded.. */
+- case VIDIOC_QUERYCTRL:
+- {
+- struct v4l2_queryctrl *qc = arg;
+- int i;
+-
+- for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
+- if (hexium_controls[i].id == qc->id) {
+- *qc = hexium_controls[i];
+- DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
+- return 0;
+- }
+- }
+- return -EAGAIN;
+- }
+- case VIDIOC_G_CTRL:
+- {
+- struct v4l2_control *vc = arg;
+- int i;
+-
+- for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
+- if (hexium_controls[i].id == vc->id) {
+- break;
+- }
+- }
+-
+- if (i < 0) {
+- return -EAGAIN;
+- }
+-
+- switch (vc->id) {
+- case V4L2_CID_PRIVATE_BASE:{
+- vc->value = hexium->cur_bw;
+- DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
+- return 0;
+- }
+- }
+- return -EINVAL;
+- }
+-
+- case VIDIOC_S_CTRL:
+- {
+- struct v4l2_control *vc = arg;
+- int i = 0;
+-
+- for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
+- if (hexium_controls[i].id == vc->id) {
+- break;
+- }
+- }
+-
+- if (i < 0) {
+- return -EAGAIN;
+- }
+-
+- switch (vc->id) {
+- case V4L2_CID_PRIVATE_BASE:{
+- hexium->cur_bw = vc->value;
+- break;
+- }
+- }
+-
+- DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
+-
+- if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
+- hexium_set_standard(hexium, hexium_pal);
+- return 0;
+- }
+- if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
+- hexium_set_standard(hexium, hexium_ntsc);
+- return 0;
+- }
+- if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
+- hexium_set_standard(hexium, hexium_secam);
+- return 0;
+- }
+- if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
+- hexium_set_standard(hexium, hexium_pal_bw);
+- return 0;
+- }
+- if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
+- hexium_set_standard(hexium, hexium_ntsc_bw);
+- return 0;
+- }
+- if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
+- /* fixme: is there no bw secam mode? */
+- return -EINVAL;
+- }
+-
+- return -EINVAL;
+- }
+- default:
+-/*
+- DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
+-*/
+- return -ENOIOCTLCMD;
+- }
+- return 0;
+-}
+-
+ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
+ {
+ struct hexium *hexium = (struct hexium *) dev->ext_priv;
+@@ -514,8 +488,6 @@ static struct saa7146_ext_vv vv_data = {
+ .stds = &hexium_standards[0],
+ .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
+ .std_callback = &std_callback,
+- .ioctls = &ioctls[0],
+- .ioctl = hexium_ioctl,
+ };
+
+ static struct saa7146_extension hexium_extension = {
+diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
+index 074bec7..2bc39f6 100644
+--- a/drivers/media/video/hexium_orion.c
++++ b/drivers/media/video/hexium_orion.c
+@@ -57,14 +57,6 @@ struct hexium_data
+ u8 byte;
+ };
+
+-static struct saa7146_extension_ioctls ioctls[] = {
+- { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_STD, SAA7146_AFTER },
+- { 0, 0 }
+-};
+-
+ struct hexium
+ {
+ int type;
+@@ -329,6 +321,44 @@ static int hexium_set_input(struct hexium *hexium, int input)
+ return 0;
+ }
+
++static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
++{
++ DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
++
++ if (i->index < 0 || i->index >= HEXIUM_INPUTS)
++ return -EINVAL;
++
++ memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
++
++ DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
++ return 0;
++}
++
++static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct hexium *hexium = (struct hexium *) dev->ext_priv;
++
++ *input = hexium->cur_input;
++
++ DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
++ return 0;
++}
++
++static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct hexium *hexium = (struct hexium *) dev->ext_priv;
++
++ if (input < 0 || input >= HEXIUM_INPUTS)
++ return -EINVAL;
++
++ hexium->cur_input = input;
++ hexium_set_input(hexium, input);
++
++ return 0;
++}
++
+ static struct saa7146_ext_vv vv_data;
+
+ /* this function only gets called when the probing was successful */
+@@ -339,6 +369,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
+ DEB_EE((".\n"));
+
+ saa7146_vv_init(dev, &vv_data);
++ vv_data.ops.vidioc_enum_input = vidioc_enum_input;
++ vv_data.ops.vidioc_g_input = vidioc_g_input;
++ vv_data.ops.vidioc_s_input = vidioc_s_input;
+ if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
+ printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
+ return -1;
+@@ -370,58 +403,6 @@ static int hexium_detach(struct saa7146_dev *dev)
+ return 0;
+ }
+
+-static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+-{
+- struct saa7146_dev *dev = fh->dev;
+- struct hexium *hexium = (struct hexium *) dev->ext_priv;
+-/*
+- struct saa7146_vv *vv = dev->vv_data;
+-*/
+- switch (cmd) {
+- case VIDIOC_ENUMINPUT:
+- {
+- struct v4l2_input *i = arg;
+- DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
+-
+- if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
+- return -EINVAL;
+- }
+-
+- memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
+-
+- DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
+- return 0;
+- }
+- case VIDIOC_G_INPUT:
+- {
+- int *input = (int *) arg;
+- *input = hexium->cur_input;
+-
+- DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
+- return 0;
+- }
+- case VIDIOC_S_INPUT:
+- {
+- int input = *(int *) arg;
+-
+- if (input < 0 || input >= HEXIUM_INPUTS) {
+- return -EINVAL;
+- }
+-
+- hexium->cur_input = input;
+- hexium_set_input(hexium, input);
+-
+- return 0;
+- }
+- default:
+-/*
+- DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
+-*/
+- return -ENOIOCTLCMD;
+- }
+- return 0;
+-}
+-
+ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
+ {
+ return 0;
+@@ -479,8 +460,6 @@ static struct saa7146_ext_vv vv_data = {
+ .stds = &hexium_standards[0],
+ .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
+ .std_callback = &std_callback,
+- .ioctls = &ioctls[0],
+- .ioctl = hexium_ioctl,
+ };
+
+ static struct saa7146_extension extension = {
+diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
+index 84b9e4f..3d69401 100644
+--- a/drivers/media/video/indycam.c
++++ b/drivers/media/video/indycam.c
+@@ -19,10 +19,12 @@
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+
+-#include <linux/videodev.h>
+ /* IndyCam decodes stream of photons into digital image representation ;-) */
+-#include <linux/video_decoder.h>
++#include <linux/videodev2.h>
+ #include <linux/i2c.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ #include "indycam.h"
+
+@@ -33,6 +35,7 @@ MODULE_VERSION(INDYCAM_MODULE_VERSION);
+ MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+ MODULE_LICENSE("GPL");
+
++
+ // #define INDYCAM_DEBUG
+
+ #ifdef INDYCAM_DEBUG
+@@ -44,11 +47,14 @@ MODULE_LICENSE("GPL");
+ #endif
+
+ struct indycam {
+- struct i2c_client *client;
++ struct v4l2_subdev sd;
+ u8 version;
+ };
+
+-static struct i2c_driver i2c_driver_indycam;
++static inline struct indycam *to_indycam(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct indycam, sd);
++}
+
+ static const u8 initseq[] = {
+ INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
+@@ -63,8 +69,9 @@ static const u8 initseq[] = {
+
+ /* IndyCam register handling */
+
+-static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
++static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ if (reg == INDYCAM_REG_RESET) {
+@@ -87,12 +94,12 @@ static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value)
+ return 0;
+ }
+
+-static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
++static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int err;
+
+- if ((reg == INDYCAM_REG_BRIGHTNESS)
+- || (reg == INDYCAM_REG_VERSION)) {
++ if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) {
+ dprintk("indycam_write_reg(): "
+ "skipping read-only register %d\n", reg);
+ return 0;
+@@ -108,13 +115,13 @@ static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value)
+ return err;
+ }
+
+-static int indycam_write_block(struct i2c_client *client, u8 reg,
++static int indycam_write_block(struct v4l2_subdev *sd, u8 reg,
+ u8 length, u8 *data)
+ {
+ int i, err;
+
+ for (i = 0; i < length; i++) {
+- err = indycam_write_reg(client, reg + i, data[i]);
++ err = indycam_write_reg(sd, reg + i, data[i]);
+ if (err)
+ return err;
+ }
+@@ -125,79 +132,78 @@ static int indycam_write_block(struct i2c_client *client, u8 reg,
+ /* Helper functions */
+
+ #ifdef INDYCAM_DEBUG
+-static void indycam_regdump_debug(struct i2c_client *client)
++static void indycam_regdump_debug(struct v4l2_subdev *sd)
+ {
+ int i;
+ u8 val;
+
+ for (i = 0; i < 9; i++) {
+- indycam_read_reg(client, i, &val);
++ indycam_read_reg(sd, i, &val);
+ dprintk("Reg %d = 0x%02x\n", i, val);
+ }
+ }
+ #endif
+
+-static int indycam_get_control(struct i2c_client *client,
+- struct indycam_control *ctrl)
++static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ {
+- struct indycam *camera = i2c_get_clientdata(client);
++ struct indycam *camera = to_indycam(sd);
+ u8 reg;
+ int ret = 0;
+
+- switch (ctrl->type) {
+- case INDYCAM_CONTROL_AGC:
+- case INDYCAM_CONTROL_AWB:
+- ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, &reg);
++ switch (ctrl->id) {
++ case V4L2_CID_AUTOGAIN:
++ case V4L2_CID_AUTO_WHITE_BALANCE:
++ ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
+ if (ret)
+ return -EIO;
+- if (ctrl->type == INDYCAM_CONTROL_AGC)
++ if (ctrl->id == V4L2_CID_AUTOGAIN)
+ ctrl->value = (reg & INDYCAM_CONTROL_AGCENA)
+ ? 1 : 0;
+ else
+ ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL)
+ ? 1 : 0;
+ break;
+- case INDYCAM_CONTROL_SHUTTER:
+- ret = indycam_read_reg(client, INDYCAM_REG_SHUTTER, &reg);
++ case V4L2_CID_EXPOSURE:
++ ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1);
+ break;
+- case INDYCAM_CONTROL_GAIN:
+- ret = indycam_read_reg(client, INDYCAM_REG_GAIN, &reg);
++ case V4L2_CID_GAIN:
++ ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+- case INDYCAM_CONTROL_RED_BALANCE:
+- ret = indycam_read_reg(client, INDYCAM_REG_RED_BALANCE, &reg);
++ case V4L2_CID_RED_BALANCE:
++ ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+- case INDYCAM_CONTROL_BLUE_BALANCE:
+- ret = indycam_read_reg(client, INDYCAM_REG_BLUE_BALANCE, &reg);
++ case V4L2_CID_BLUE_BALANCE:
++ ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+ case INDYCAM_CONTROL_RED_SATURATION:
+- ret = indycam_read_reg(client,
++ ret = indycam_read_reg(sd,
+ INDYCAM_REG_RED_SATURATION, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+ case INDYCAM_CONTROL_BLUE_SATURATION:
+- ret = indycam_read_reg(client,
++ ret = indycam_read_reg(sd,
+ INDYCAM_REG_BLUE_SATURATION, &reg);
+ if (ret)
+ return -EIO;
+ ctrl->value = (s32)reg;
+ break;
+- case INDYCAM_CONTROL_GAMMA:
++ case V4L2_CID_GAMMA:
+ if (camera->version == CAMERA_VERSION_MOOSE) {
+- ret = indycam_read_reg(client,
++ ret = indycam_read_reg(sd,
+ INDYCAM_REG_GAMMA, &reg);
+ if (ret)
+ return -EIO;
+@@ -213,21 +219,20 @@ static int indycam_get_control(struct i2c_client *client,
+ return ret;
+ }
+
+-static int indycam_set_control(struct i2c_client *client,
+- struct indycam_control *ctrl)
++static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ {
+- struct indycam *camera = i2c_get_clientdata(client);
++ struct indycam *camera = to_indycam(sd);
+ u8 reg;
+ int ret = 0;
+
+- switch (ctrl->type) {
+- case INDYCAM_CONTROL_AGC:
+- case INDYCAM_CONTROL_AWB:
+- ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, &reg);
++ switch (ctrl->id) {
++ case V4L2_CID_AUTOGAIN:
++ case V4L2_CID_AUTO_WHITE_BALANCE:
++ ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
+ if (ret)
+ break;
+
+- if (ctrl->type == INDYCAM_CONTROL_AGC) {
++ if (ctrl->id == V4L2_CID_AUTOGAIN) {
+ if (ctrl->value)
+ reg |= INDYCAM_CONTROL_AGCENA;
+ else
+@@ -239,34 +244,34 @@ static int indycam_set_control(struct i2c_client *client,
+ reg &= ~INDYCAM_CONTROL_AWBCTL;
+ }
+
+- ret = indycam_write_reg(client, INDYCAM_REG_CONTROL, reg);
++ ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg);
+ break;
+- case INDYCAM_CONTROL_SHUTTER:
++ case V4L2_CID_EXPOSURE:
+ reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1);
+- ret = indycam_write_reg(client, INDYCAM_REG_SHUTTER, reg);
++ ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg);
+ break;
+- case INDYCAM_CONTROL_GAIN:
+- ret = indycam_write_reg(client, INDYCAM_REG_GAIN, ctrl->value);
++ case V4L2_CID_GAIN:
++ ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value);
+ break;
+- case INDYCAM_CONTROL_RED_BALANCE:
+- ret = indycam_write_reg(client, INDYCAM_REG_RED_BALANCE,
++ case V4L2_CID_RED_BALANCE:
++ ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE,
+ ctrl->value);
+ break;
+- case INDYCAM_CONTROL_BLUE_BALANCE:
+- ret = indycam_write_reg(client, INDYCAM_REG_BLUE_BALANCE,
++ case V4L2_CID_BLUE_BALANCE:
++ ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE,
+ ctrl->value);
+ break;
+ case INDYCAM_CONTROL_RED_SATURATION:
+- ret = indycam_write_reg(client, INDYCAM_REG_RED_SATURATION,
++ ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION,
+ ctrl->value);
+ break;
+ case INDYCAM_CONTROL_BLUE_SATURATION:
+- ret = indycam_write_reg(client, INDYCAM_REG_BLUE_SATURATION,
++ ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION,
+ ctrl->value);
+ break;
+- case INDYCAM_CONTROL_GAMMA:
++ case V4L2_CID_GAMMA:
+ if (camera->version == CAMERA_VERSION_MOOSE) {
+- ret = indycam_write_reg(client, INDYCAM_REG_GAMMA,
++ ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA,
+ ctrl->value);
+ }
+ break;
+@@ -279,192 +284,103 @@ static int indycam_set_control(struct i2c_client *client,
+
+ /* I2C-interface */
+
+-static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
++static int indycam_g_chip_ident(struct v4l2_subdev *sd,
++ struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct indycam *camera = to_indycam(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM,
++ camera->version);
++}
++
++/* ----------------------------------------------------------------------- */
++
++static const struct v4l2_subdev_core_ops indycam_core_ops = {
++ .g_chip_ident = indycam_g_chip_ident,
++ .g_ctrl = indycam_g_ctrl,
++ .s_ctrl = indycam_s_ctrl,
++};
++
++static const struct v4l2_subdev_ops indycam_ops = {
++ .core = &indycam_core_ops,
++};
++
++static int indycam_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
+ {
+ int err = 0;
+ struct indycam *camera;
+- struct i2c_client *client;
++ struct v4l2_subdev *sd;
+
+- printk(KERN_INFO "SGI IndyCam driver version %s\n",
+- INDYCAM_MODULE_VERSION);
++ v4l_info(client, "chip found @ 0x%x (%s)\n",
++ client->addr << 1, client->adapter->name);
+
+- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+- if (!client)
+- return -ENOMEM;
+ camera = kzalloc(sizeof(struct indycam), GFP_KERNEL);
+- if (!camera) {
+- err = -ENOMEM;
+- goto out_free_client;
+- }
+-
+- client->addr = addr;
+- client->adapter = adap;
+- client->driver = &i2c_driver_indycam;
+- client->flags = 0;
+- strcpy(client->name, "IndyCam client");
+- i2c_set_clientdata(client, camera);
+-
+- camera->client = client;
++ if (!camera)
++ return -ENOMEM;
+
+- err = i2c_attach_client(client);
+- if (err)
+- goto out_free_camera;
++ sd = &camera->sd;
++ v4l2_i2c_subdev_init(sd, client, &indycam_ops);
+
+ camera->version = i2c_smbus_read_byte_data(client,
+ INDYCAM_REG_VERSION);
+ if (camera->version != CAMERA_VERSION_INDY &&
+ camera->version != CAMERA_VERSION_MOOSE) {
+- err = -ENODEV;
+- goto out_detach_client;
++ kfree(camera);
++ return -ENODEV;
+ }
++
+ printk(KERN_INFO "IndyCam v%d.%d detected\n",
+ INDYCAM_VERSION_MAJOR(camera->version),
+ INDYCAM_VERSION_MINOR(camera->version));
+
+- indycam_regdump(client);
++ indycam_regdump(sd);
+
+ // initialize
+- err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq);
++ err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq);
+ if (err) {
+ printk(KERN_ERR "IndyCam initialization failed\n");
+- err = -EIO;
+- goto out_detach_client;
++ kfree(camera);
++ return -EIO;
+ }
+
+- indycam_regdump(client);
++ indycam_regdump(sd);
+
+ // white balance
+- err = indycam_write_reg(client, INDYCAM_REG_CONTROL,
++ err = indycam_write_reg(sd, INDYCAM_REG_CONTROL,
+ INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
+ if (err) {
+ printk(KERN_ERR "IndyCam: White balancing camera failed\n");
+- err = -EIO;
+- goto out_detach_client;
++ kfree(camera);
++ return -EIO;
+ }
+
+- indycam_regdump(client);
++ indycam_regdump(sd);
+
+ printk(KERN_INFO "IndyCam initialized\n");
+
+ return 0;
+-
+-out_detach_client:
+- i2c_detach_client(client);
+-out_free_camera:
+- kfree(camera);
+-out_free_client:
+- kfree(client);
+- return err;
+ }
+
+-static int indycam_probe(struct i2c_adapter *adap)
++static int indycam_remove(struct i2c_client *client)
+ {
+- /* Indy specific crap */
+- if (adap->id == I2C_HW_SGI_VINO)
+- return indycam_attach(adap, INDYCAM_ADDR, 0);
+- /* Feel free to add probe here :-) */
+- return -ENODEV;
+-}
+-
+-static int indycam_detach(struct i2c_client *client)
+-{
+- struct indycam *camera = i2c_get_clientdata(client);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+- i2c_detach_client(client);
+- kfree(camera);
+- kfree(client);
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_indycam(sd));
+ return 0;
+ }
+
+-static int indycam_command(struct i2c_client *client, unsigned int cmd,
+- void *arg)
+-{
+- // struct indycam *camera = i2c_get_clientdata(client);
+-
+- /* The old video_decoder interface just isn't enough,
+- * so we'll use some custom commands. */
+- switch (cmd) {
+- case DECODER_GET_CAPABILITIES: {
+- struct video_decoder_capability *cap = arg;
+-
+- cap->flags = VIDEO_DECODER_NTSC;
+- cap->inputs = 1;
+- cap->outputs = 1;
+- break;
+- }
+- case DECODER_GET_STATUS: {
+- int *iarg = arg;
+-
+- *iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC |
+- DECODER_STATUS_COLOR;
+- break;
+- }
+- case DECODER_SET_NORM: {
+- int *iarg = arg;
+-
+- switch (*iarg) {
+- case VIDEO_MODE_NTSC:
+- break;
+- default:
+- return -EINVAL;
+- }
+- break;
+- }
+- case DECODER_SET_INPUT: {
+- int *iarg = arg;
+-
+- if (*iarg != 0)
+- return -EINVAL;
+- break;
+- }
+- case DECODER_SET_OUTPUT: {
+- int *iarg = arg;
+-
+- if (*iarg != 0)
+- return -EINVAL;
+- break;
+- }
+- case DECODER_ENABLE_OUTPUT: {
+- /* Always enabled */
+- break;
+- }
+- case DECODER_SET_PICTURE: {
+- // struct video_picture *pic = arg;
+- /* TODO: convert values for indycam_set_controls() */
+- break;
+- }
+- case DECODER_INDYCAM_GET_CONTROL: {
+- return indycam_get_control(client, arg);
+- }
+- case DECODER_INDYCAM_SET_CONTROL: {
+- return indycam_set_control(client, arg);
+- }
+- default:
+- return -EINVAL;
+- }
+-
+- return 0;
+-}
+-
+-static struct i2c_driver i2c_driver_indycam = {
+- .driver = {
+- .name = "indycam",
+- },
+- .id = I2C_DRIVERID_INDYCAM,
+- .attach_adapter = indycam_probe,
+- .detach_client = indycam_detach,
+- .command = indycam_command,
++static const struct i2c_device_id indycam_id[] = {
++ { "indycam", 0 },
++ { }
+ };
++MODULE_DEVICE_TABLE(i2c, indycam_id);
+
+-static int __init indycam_init(void)
+-{
+- return i2c_add_driver(&i2c_driver_indycam);
+-}
+-
+-static void __exit indycam_exit(void)
+-{
+- i2c_del_driver(&i2c_driver_indycam);
+-}
+-
+-module_init(indycam_init);
+-module_exit(indycam_exit);
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++ .name = "indycam",
++ .probe = indycam_probe,
++ .remove = indycam_remove,
++ .id_table = indycam_id,
++};
+diff --git a/drivers/media/video/indycam.h b/drivers/media/video/indycam.h
+index e6ee820..881f21c 100644
+--- a/drivers/media/video/indycam.h
++++ b/drivers/media/video/indycam.h
+@@ -87,22 +87,7 @@
+
+ /* Driver interface definitions */
+
+-#define INDYCAM_CONTROL_AGC 0 /* boolean */
+-#define INDYCAM_CONTROL_AWB 1 /* boolean */
+-#define INDYCAM_CONTROL_SHUTTER 2
+-#define INDYCAM_CONTROL_GAIN 3
+-#define INDYCAM_CONTROL_RED_BALANCE 4
+-#define INDYCAM_CONTROL_BLUE_BALANCE 5
+-#define INDYCAM_CONTROL_RED_SATURATION 6
+-#define INDYCAM_CONTROL_BLUE_SATURATION 7
+-#define INDYCAM_CONTROL_GAMMA 8
+-
+-struct indycam_control {
+- u8 type;
+- s32 value;
+-};
+-
+-#define DECODER_INDYCAM_GET_CONTROL _IOR('d', 193, struct indycam_control)
+-#define DECODER_INDYCAM_SET_CONTROL _IOW('d', 194, struct indycam_control)
++#define INDYCAM_CONTROL_RED_SATURATION (V4L2_CID_PRIVATE_BASE + 0)
++#define INDYCAM_CONTROL_BLUE_SATURATION (V4L2_CID_PRIVATE_BASE + 1)
+
+ #endif
+diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
+index d4658c5..092c7da 100644
+--- a/drivers/media/video/ir-kbd-i2c.c
++++ b/drivers/media/video/ir-kbd-i2c.c
+@@ -16,6 +16,8 @@
+ * Henry Wong <henry@stuffedcow.net>
+ * Mark Schultz <n9xmj@yahoo.com>
+ * Brian Rogers <brian_rogers@comcast.net>
++ * modified for AVerMedia Cardbus by
++ * Oldrich Jedlicka <oldium.pro@seznam.cz>
+ *
+ * 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
+@@ -216,6 +218,46 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+ return 1;
+ }
+
++static int get_key_avermedia_cardbus(struct IR_i2c *ir,
++ u32 *ir_key, u32 *ir_raw)
++{
++ unsigned char subaddr, key, keygroup;
++ struct i2c_msg msg[] = { { .addr = ir->c.addr, .flags = 0,
++ .buf = &subaddr, .len = 1},
++ { .addr = ir->c.addr, .flags = I2C_M_RD,
++ .buf = &key, .len = 1} };
++ subaddr = 0x0d;
++ if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
++ dprintk(1, "read error\n");
++ return -EIO;
++ }
++
++ if (key == 0xff)
++ return 0;
++
++ subaddr = 0x0b;
++ msg[1].buf = &keygroup;
++ if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
++ dprintk(1, "read error\n");
++ return -EIO;
++ }
++
++ if (keygroup == 0xff)
++ return 0;
++
++ dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup);
++ if (keygroup < 2 || keygroup > 3) {
++ /* Only a warning */
++ dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n",
++ keygroup, key);
++ }
++ key |= (keygroup & 1) << 6;
++
++ *ir_key = key;
++ *ir_raw = key;
++ return 1;
++}
++
+ /* ----------------------------------------------------------------------- */
+
+ static void ir_key_poll(struct IR_i2c *ir)
+@@ -237,15 +279,9 @@ static void ir_key_poll(struct IR_i2c *ir)
+ }
+ }
+
+-static void ir_timer(unsigned long data)
+-{
+- struct IR_i2c *ir = (struct IR_i2c*)data;
+- schedule_work(&ir->work);
+-}
+-
+ static void ir_work(struct work_struct *work)
+ {
+- struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
++ struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
+ int polling_interval = 100;
+
+ /* MSI TV@nywhere Plus requires more frequent polling
+@@ -254,7 +290,7 @@ static void ir_work(struct work_struct *work)
+ polling_interval = 50;
+
+ ir_key_poll(ir);
+- mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval));
++ schedule_delayed_work(&ir->work, msecs_to_jiffies(polling_interval));
+ }
+
+ /* ----------------------------------------------------------------------- */
+@@ -360,6 +396,12 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
+ ir_type = IR_TYPE_OTHER;
+ }
+ break;
++ case 0x40:
++ name = "AVerMedia Cardbus remote";
++ ir->get_key = get_key_avermedia_cardbus;
++ ir_type = IR_TYPE_OTHER;
++ ir_codes = ir_codes_avermedia_cardbus;
++ break;
+ default:
+ /* shouldn't happen */
+ printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr);
+@@ -404,11 +446,8 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
+ ir->input->name, ir->input->phys, adap->name);
+
+ /* start polling via eventd */
+- INIT_WORK(&ir->work, ir_work);
+- init_timer(&ir->timer);
+- ir->timer.function = ir_timer;
+- ir->timer.data = (unsigned long)ir;
+- schedule_work(&ir->work);
++ INIT_DELAYED_WORK(&ir->work, ir_work);
++ schedule_delayed_work(&ir->work, 0);
+
+ return 0;
+
+@@ -425,8 +464,7 @@ static int ir_detach(struct i2c_client *client)
+ struct IR_i2c *ir = i2c_get_clientdata(client);
+
+ /* kill outstanding polls */
+- del_timer_sync(&ir->timer);
+- flush_scheduled_work();
++ cancel_delayed_work_sync(&ir->work);
+
+ /* unregister devices */
+ input_unregister_device(ir->input);
+@@ -524,6 +562,22 @@ static int ir_probe(struct i2c_adapter *adap)
+ ir_attach(adap, msg.addr, 0, 0);
+ }
+
++ /* Special case for AVerMedia Cardbus remote */
++ if (adap->id == I2C_HW_SAA7134) {
++ unsigned char subaddr, data;
++ struct i2c_msg msg[] = { { .addr = 0x40, .flags = 0,
++ .buf = &subaddr, .len = 1},
++ { .addr = 0x40, .flags = I2C_M_RD,
++ .buf = &data, .len = 1} };
++ subaddr = 0x0d;
++ rc = i2c_transfer(adap, msg, 2);
++ dprintk(1, "probe 0x%02x/0x%02x @ %s: %s\n",
++ msg[0].addr, subaddr, adap->name,
++ (2 == rc) ? "yes" : "no");
++ if (2 == rc)
++ ir_attach(adap, msg[0].addr, 0, 0);
++ }
++
+ return 0;
+ }
+
+diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
+index 62aa06f..84995bc 100644
+--- a/drivers/media/video/ivtv/ivtv-controls.c
++++ b/drivers/media/video/ivtv/ivtv-controls.c
+@@ -26,6 +26,7 @@
+ #include "ivtv-mailbox.h"
+ #include "ivtv-controls.h"
+
++/* Must be sorted from low to high control ID! */
+ static const u32 user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
+index c46c990..eca8bf9 100644
+--- a/drivers/media/video/ivtv/ivtv-driver.c
++++ b/drivers/media/video/ivtv/ivtv-driver.c
+@@ -357,7 +357,7 @@ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv)
+ static void ivtv_process_eeprom(struct ivtv *itv)
+ {
+ struct tveeprom tv;
+- int pci_slot = PCI_SLOT(itv->dev->devfn);
++ int pci_slot = PCI_SLOT(itv->pdev->devfn);
+
+ ivtv_read_eeprom(itv, &tv);
+
+@@ -604,7 +604,7 @@ static void ivtv_process_options(struct ivtv *itv)
+ itv->std = ivtv_parse_std(itv);
+ if (itv->std == 0 && tunertype >= 0)
+ itv->std = tunertype ? V4L2_STD_MN : (V4L2_STD_ALL & ~V4L2_STD_MN);
+- itv->has_cx23415 = (itv->dev->device == PCI_DEVICE_ID_IVTV15);
++ itv->has_cx23415 = (itv->pdev->device == PCI_DEVICE_ID_IVTV15);
+ chipname = itv->has_cx23415 ? "cx23415" : "cx23416";
+ if (itv->options.cardtype == -1) {
+ IVTV_INFO("Ignore card (detected %s based chip)\n", chipname);
+@@ -617,9 +617,9 @@ static void ivtv_process_options(struct ivtv *itv)
+ IVTV_ERR("Unknown user specified type, trying to autodetect card\n");
+ }
+ if (itv->card == NULL) {
+- if (itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE ||
+- itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 ||
+- itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) {
++ if (itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE ||
++ itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 ||
++ itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) {
+ itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150);
+ IVTV_INFO("Autodetected Hauppauge card (%s based)\n",
+ chipname);
+@@ -630,13 +630,13 @@ static void ivtv_process_options(struct ivtv *itv)
+ if (itv->card->pci_list == NULL)
+ continue;
+ for (j = 0; itv->card->pci_list[j].device; j++) {
+- if (itv->dev->device !=
++ if (itv->pdev->device !=
+ itv->card->pci_list[j].device)
+ continue;
+- if (itv->dev->subsystem_vendor !=
++ if (itv->pdev->subsystem_vendor !=
+ itv->card->pci_list[j].subsystem_vendor)
+ continue;
+- if (itv->dev->subsystem_device !=
++ if (itv->pdev->subsystem_device !=
+ itv->card->pci_list[j].subsystem_device)
+ continue;
+ IVTV_INFO("Autodetected %s card (%s based)\n",
+@@ -650,9 +650,9 @@ done:
+ if (itv->card == NULL) {
+ itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
+ IVTV_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
+- itv->dev->vendor, itv->dev->device);
++ itv->pdev->vendor, itv->pdev->device);
+ IVTV_ERR(" subsystem vendor/device: [%04x:%04x]\n",
+- itv->dev->subsystem_vendor, itv->dev->subsystem_device);
++ itv->pdev->subsystem_vendor, itv->pdev->subsystem_device);
+ IVTV_ERR(" %s based\n", chipname);
+ IVTV_ERR("Defaulting to %s card\n", itv->card->name);
+ IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+@@ -671,7 +671,7 @@ done:
+ */
+ static int __devinit ivtv_init_struct1(struct ivtv *itv)
+ {
+- itv->base_addr = pci_resource_start(itv->dev, 0);
++ itv->base_addr = pci_resource_start(itv->pdev, 0);
+ itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
+ itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
+
+@@ -682,7 +682,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
+ spin_lock_init(&itv->lock);
+ spin_lock_init(&itv->dma_reg_lock);
+
+- itv->irq_work_queues = create_singlethread_workqueue(itv->device.name);
++ itv->irq_work_queues = create_singlethread_workqueue(itv->v4l2_dev.name);
+ if (itv->irq_work_queues == NULL) {
+ IVTV_ERR("Could not create ivtv workqueue\n");
+ return -1;
+@@ -766,7 +766,7 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv)
+ itv->audio_input = itv->card->video_inputs[i].audio_index;
+ }
+
+-static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
++static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+ {
+ u16 cmd;
+@@ -775,11 +775,11 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
+
+ IVTV_DEBUG_INFO("Enabling pci device\n");
+
+- if (pci_enable_device(dev)) {
++ if (pci_enable_device(pdev)) {
+ IVTV_ERR("Can't enable device!\n");
+ return -EIO;
+ }
+- if (pci_set_dma_mask(dev, 0xffffffff)) {
++ if (pci_set_dma_mask(pdev, 0xffffffff)) {
+ IVTV_ERR("No suitable DMA available.\n");
+ return -EIO;
+ }
+@@ -805,11 +805,11 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
+ }
+
+ /* Check for bus mastering */
+- pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_MASTER)) {
+ IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n");
+- pci_set_master(dev);
+- pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ pci_set_master(pdev);
++ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_MASTER)) {
+ IVTV_ERR("Bus Mastering is not enabled\n");
+ return -ENXIO;
+@@ -817,26 +817,26 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
+ }
+ IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
+
+- pci_read_config_byte(dev, PCI_CLASS_REVISION, &card_rev);
+- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
++ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &card_rev);
++ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
+
+ if (pci_latency < 64 && ivtv_pci_latency) {
+ IVTV_INFO("Unreasonably low latency timer, "
+ "setting to 64 (was %d)\n", pci_latency);
+- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
++ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
++ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
+ }
+ /* This config space value relates to DMA latencies. The
+ default value 0x8080 is too low however and will lead
+ to DMA errors. 0xffff is the max value which solves
+ these problems. */
+- pci_write_config_dword(dev, 0x40, 0xffff);
++ pci_write_config_dword(pdev, 0x40, 0xffff);
+
+ IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
+ "irq: %d, latency: %d, memory: 0x%lx\n",
+- itv->dev->device, card_rev, dev->bus->number,
+- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+- itv->dev->irq, pci_latency, (unsigned long)itv->base_addr);
++ pdev->device, card_rev, pdev->bus->number,
++ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
++ pdev->irq, pci_latency, (unsigned long)itv->base_addr);
+
+ return 0;
+ }
+@@ -935,7 +935,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
+ }
+ }
+
+-static int __devinit ivtv_probe(struct pci_dev *dev,
++static int __devinit ivtv_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+ {
+ int retval = 0;
+@@ -945,17 +945,17 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+ itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
+ if (itv == NULL)
+ return -ENOMEM;
+- itv->dev = dev;
++ itv->pdev = pdev;
+ itv->instance = atomic_inc_return(&ivtv_instance) - 1;
+
+- retval = v4l2_device_register(&dev->dev, &itv->device);
++ retval = v4l2_device_register(&pdev->dev, &itv->v4l2_dev);
+ if (retval) {
+ kfree(itv);
+ return retval;
+ }
+ /* "ivtv + PCI ID" is a bit of a mouthful, so use
+ "ivtv + instance" instead. */
+- snprintf(itv->device.name, sizeof(itv->device.name),
++ snprintf(itv->v4l2_dev.name, sizeof(itv->v4l2_dev.name),
+ "ivtv%d", itv->instance);
+ IVTV_INFO("Initializing card %d\n", itv->instance);
+
+@@ -972,12 +972,11 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+ IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
+
+ /* PCI Device Setup */
+- if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) {
+- if (retval == -EIO)
+- goto free_workqueue;
+- else if (retval == -ENXIO)
+- goto free_mem;
+- }
++ retval = ivtv_setup_pci(itv, pdev, pci_id);
++ if (retval == -EIO)
++ goto free_workqueue;
++ if (retval == -ENXIO)
++ goto free_mem;
+
+ /* map io memory */
+ IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
+@@ -1154,8 +1153,8 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+ ivtv_set_irq_mask(itv, 0xffffffff);
+
+ /* Register IRQ */
+- retval = request_irq(itv->dev->irq, ivtv_irq_handler,
+- IRQF_SHARED | IRQF_DISABLED, itv->device.name, (void *)itv);
++ retval = request_irq(itv->pdev->irq, ivtv_irq_handler,
++ IRQF_SHARED | IRQF_DISABLED, itv->v4l2_dev.name, (void *)itv);
+ if (retval) {
+ IVTV_ERR("Failed to register irq %d\n", retval);
+ goto free_i2c;
+@@ -1177,7 +1176,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+ free_streams:
+ ivtv_streams_cleanup(itv, 1);
+ free_irq:
+- free_irq(itv->dev->irq, (void *)itv);
++ free_irq(itv->pdev->irq, (void *)itv);
+ free_i2c:
+ exit_ivtv_i2c(itv);
+ free_io:
+@@ -1194,7 +1193,7 @@ err:
+ retval = -ENODEV;
+ IVTV_ERR("Error %d on initialization\n", retval);
+
+- v4l2_device_unregister(&itv->device);
++ v4l2_device_unregister(&itv->v4l2_dev);
+ kfree(itv);
+ return retval;
+ }
+@@ -1292,10 +1291,10 @@ int ivtv_init_on_first_open(struct ivtv *itv)
+ return 0;
+ }
+
+-static void ivtv_remove(struct pci_dev *pci_dev)
++static void ivtv_remove(struct pci_dev *pdev)
+ {
+- struct v4l2_device *dev = dev_get_drvdata(&pci_dev->dev);
+- struct ivtv *itv = to_ivtv(dev);
++ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
++ struct ivtv *itv = to_ivtv(v4l2_dev);
+ int i;
+
+ IVTV_DEBUG_INFO("Removing card\n");
+@@ -1336,11 +1335,9 @@ static void ivtv_remove(struct pci_dev *pci_dev)
+ ivtv_streams_cleanup(itv, 1);
+ ivtv_udma_free(itv);
+
+- v4l2_device_unregister(&itv->device);
+-
+ exit_ivtv_i2c(itv);
+
+- free_irq(itv->dev->irq, (void *)itv);
++ free_irq(itv->pdev->irq, (void *)itv);
+ ivtv_iounmap(itv);
+
+ release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
+@@ -1348,11 +1345,13 @@ static void ivtv_remove(struct pci_dev *pci_dev)
+ if (itv->has_cx23415)
+ release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
+
+- pci_disable_device(itv->dev);
++ pci_disable_device(itv->pdev);
+ for (i = 0; i < IVTV_VBI_FRAMES; i++)
+ kfree(itv->vbi.sliced_mpeg_data[i]);
+
+ printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name);
++
++ v4l2_device_unregister(&itv->v4l2_dev);
+ kfree(itv);
+ }
+
+diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
+index ce8d9b7..440f732 100644
+--- a/drivers/media/video/ivtv/ivtv-driver.h
++++ b/drivers/media/video/ivtv/ivtv-driver.h
+@@ -133,7 +133,7 @@ extern int ivtv_debug;
+ #define IVTV_DEBUG(x, type, fmt, args...) \
+ do { \
+ if ((x) & ivtv_debug) \
+- v4l2_info(&itv->device, " " type ": " fmt , ##args); \
++ v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args); \
+ } while (0)
+ #define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
+ #define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args)
+@@ -149,7 +149,7 @@ extern int ivtv_debug;
+ #define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+ do { \
+ if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
+- v4l2_info(&itv->device, " " type ": " fmt , ##args); \
++ v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args); \
+ } while (0)
+ #define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
+ #define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args)
+@@ -163,9 +163,9 @@ extern int ivtv_debug;
+ #define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+
+ /* Standard kernel messages */
+-#define IVTV_ERR(fmt, args...) v4l2_err(&itv->device, fmt , ## args)
+-#define IVTV_WARN(fmt, args...) v4l2_warn(&itv->device, fmt , ## args)
+-#define IVTV_INFO(fmt, args...) v4l2_info(&itv->device, fmt , ## args)
++#define IVTV_ERR(fmt, args...) v4l2_err(&itv->v4l2_dev, fmt , ## args)
++#define IVTV_WARN(fmt, args...) v4l2_warn(&itv->v4l2_dev, fmt , ## args)
++#define IVTV_INFO(fmt, args...) v4l2_info(&itv->v4l2_dev, fmt , ## args)
+
+ /* output modes (cx23415 only) */
+ #define OUT_NONE 0
+@@ -315,7 +315,7 @@ struct ivtv; /* forward reference */
+ struct ivtv_stream {
+ /* These first four fields are always set, even if the stream
+ is not actually created. */
+- struct video_device *v4l2dev; /* NULL when stream not created */
++ struct video_device *vdev; /* NULL when stream not created */
+ struct ivtv *itv; /* for ease of use */
+ const char *name; /* name of the stream */
+ int type; /* stream type */
+@@ -592,7 +592,7 @@ struct ivtv_card;
+ /* Struct to hold info about ivtv cards */
+ struct ivtv {
+ /* General fixed card data */
+- struct pci_dev *dev; /* PCI device */
++ struct pci_dev *pdev; /* PCI device */
+ const struct ivtv_card *card; /* card information */
+ const char *card_name; /* full name of the card */
+ const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
+@@ -612,7 +612,7 @@ struct ivtv {
+ volatile void __iomem *reg_mem; /* pointer to mapped registers */
+ struct ivtv_options options; /* user options */
+
+- struct v4l2_device device;
++ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev sd_gpio; /* GPIO sub-device */
+ u16 instance;
+
+@@ -696,7 +696,7 @@ struct ivtv {
+ u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */
+ u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */
+ unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */
+- u16 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */
++ u32 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */
+
+
+ /* VBI state info */
+@@ -719,9 +719,9 @@ struct ivtv {
+ struct osd_info *osd_info; /* ivtvfb private OSD info */
+ };
+
+-static inline struct ivtv *to_ivtv(struct v4l2_device *dev)
++static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
+ {
+- return container_of(dev, struct ivtv, device);
++ return container_of(v4l2_dev, struct ivtv, v4l2_dev);
+ }
+
+ /* Globals */
+@@ -788,7 +788,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
+ /* Call the specified callback for all subdevs matching hw (if 0, then
+ match them all). Ignore any errors. */
+ #define ivtv_call_hw(itv, hw, o, f, args...) \
+- __v4l2_device_call_subdevs(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
++ __v4l2_device_call_subdevs(&(itv)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+ #define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
+
+@@ -796,7 +796,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
+ match them all). If the callback returns an error other than 0 or
+ -ENOIOCTLCMD, then return with that error code. */
+ #define ivtv_call_hw_err(itv, hw, o, f, args...) \
+- __v4l2_device_call_subdevs_until_err(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
++ __v4l2_device_call_subdevs_until_err(&(itv)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+ #define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
+
+diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
+index d594bc2..cfaacf6 100644
+--- a/drivers/media/video/ivtv/ivtv-fileops.c
++++ b/drivers/media/video/ivtv/ivtv-fileops.c
+@@ -148,10 +148,10 @@ void ivtv_release_stream(struct ivtv_stream *s)
+ static void ivtv_dualwatch(struct ivtv *itv)
+ {
+ struct v4l2_tuner vt;
+- u16 new_bitmap;
+- u16 new_stereo_mode;
+- const u16 stereo_mask = 0x0300;
+- const u16 dual = 0x0200;
++ u32 new_bitmap;
++ u32 new_stereo_mode;
++ const u32 stereo_mask = 0x0300;
++ const u32 dual = 0x0200;
+
+ new_stereo_mode = itv->params.audio_properties & stereo_mask;
+ memset(&vt, 0, sizeof(vt));
+@@ -991,7 +991,7 @@ int ivtv_v4l2_open(struct file *filp)
+ mutex_lock(&itv->serialize_lock);
+ if (ivtv_init_on_first_open(itv)) {
+ IVTV_ERR("Failed to initialize on minor %d\n",
+- s->v4l2dev->minor);
++ vdev->minor);
+ mutex_unlock(&itv->serialize_lock);
+ return -ENXIO;
+ }
+diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
+index 6dba55b..c1b7ec4 100644
+--- a/drivers/media/video/ivtv/ivtv-firmware.c
++++ b/drivers/media/video/ivtv/ivtv-firmware.c
+@@ -52,7 +52,7 @@ static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv
+ int retries = 3;
+
+ retry:
+- if (retries && request_firmware(&fw, fn, &itv->dev->dev) == 0) {
++ if (retries && request_firmware(&fw, fn, &itv->pdev->dev) == 0) {
+ int i;
+ volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
+ const u32 *src = (const u32 *)fw->data;
+diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
+index dc2850e..3321983 100644
+--- a/drivers/media/video/ivtv/ivtv-gpio.c
++++ b/drivers/media/video/ivtv/ivtv-gpio.c
+@@ -384,7 +384,7 @@ int ivtv_gpio_init(struct ivtv *itv)
+ write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
+ write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
+ v4l2_subdev_init(&itv->sd_gpio, &subdev_ops);
+- snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->device.name);
++ snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->v4l2_dev.name);
+ itv->sd_gpio.grp_id = IVTV_HW_GPIO;
+- return v4l2_device_register_subdev(&itv->device, &itv->sd_gpio);
++ return v4l2_device_register_subdev(&itv->v4l2_dev, &itv->sd_gpio);
+ }
+diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
+index ca1d955..e73a196 100644
+--- a/drivers/media/video/ivtv/ivtv-i2c.c
++++ b/drivers/media/video/ivtv/ivtv-i2c.c
+@@ -194,14 +194,14 @@ struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw)
+ struct v4l2_subdev *result = NULL;
+ struct v4l2_subdev *sd;
+
+- spin_lock(&itv->device.lock);
+- v4l2_device_for_each_subdev(sd, &itv->device) {
++ spin_lock(&itv->v4l2_dev.lock);
++ v4l2_device_for_each_subdev(sd, &itv->v4l2_dev) {
+ if (sd->grp_id == hw) {
+ result = sd;
+ break;
+ }
+ }
+- spin_unlock(&itv->device.lock);
++ spin_unlock(&itv->v4l2_dev.lock);
+ return result;
+ }
+
+@@ -472,8 +472,8 @@ static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data,
+ intervening stop condition */
+ static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+ {
+- struct v4l2_device *drv = i2c_get_adapdata(i2c_adap);
+- struct ivtv *itv = to_ivtv(drv);
++ struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap);
++ struct ivtv *itv = to_ivtv(v4l2_dev);
+ int retval;
+ int i;
+
+@@ -604,12 +604,12 @@ int init_ivtv_i2c(struct ivtv *itv)
+
+ sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
+ itv->instance);
+- i2c_set_adapdata(&itv->i2c_adap, &itv->device);
++ i2c_set_adapdata(&itv->i2c_adap, &itv->v4l2_dev);
+
+ memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
+ sizeof(struct i2c_client));
+ itv->i2c_client.adapter = &itv->i2c_adap;
+- itv->i2c_adap.dev.parent = &itv->dev->dev;
++ itv->i2c_adap.dev.parent = &itv->pdev->dev;
+
+ IVTV_DEBUG_I2C("setting scl and sda to 1\n");
+ ivtv_setscl(itv, 1);
+diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
+index c13bd2a..9a04242 100644
+--- a/drivers/media/video/ivtv/ivtv-ioctl.c
++++ b/drivers/media/video/ivtv/ivtv-ioctl.c
+@@ -345,10 +345,8 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
+ pixfmt->priv = 0;
+ if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
+ pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+- /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+- pixfmt->sizeimage =
+- pixfmt->height * pixfmt->width +
+- pixfmt->height * (pixfmt->width / 2);
++ /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
++ pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+ pixfmt->bytesperline = 720;
+ } else {
+ pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+@@ -469,11 +467,17 @@ static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format
+ struct ivtv *itv = id->itv;
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
++ int min_h = 2;
+
+ w = min(w, 720);
+ w = max(w, 2);
++ if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
++ /* YUV height must be a multiple of 32 */
++ h &= ~0x1f;
++ min_h = 32;
++ }
+ h = min(h, itv->is_50hz ? 576 : 480);
+- h = max(h, 2);
++ h = max(h, min_h);
+ ivtv_g_fmt_vid_cap(file, fh, fmt);
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+@@ -766,7 +770,7 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
+
+ strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
+- snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->dev));
++ snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
+ vcap->version = IVTV_DRIVER_VERSION; /* version */
+ vcap->capabilities = itv->v4l2_cap; /* capabilities */
+ return 0;
+@@ -1513,12 +1517,12 @@ static int ivtv_log_status(struct file *file, void *fh)
+ }
+ IVTV_INFO("Tuner: %s\n",
+ test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
+- cx2341x_log_status(&itv->params, itv->device.name);
++ cx2341x_log_status(&itv->params, itv->v4l2_dev.name);
+ IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
+ for (i = 0; i < IVTV_MAX_STREAMS; i++) {
+ struct ivtv_stream *s = &itv->streams[i];
+
+- if (s->v4l2dev == NULL || s->buffers == 0)
++ if (s->vdev == NULL || s->buffers == 0)
+ continue;
+ IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
+ (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
+index f5d00ec..01c14d2 100644
+--- a/drivers/media/video/ivtv/ivtv-irq.c
++++ b/drivers/media/video/ivtv/ivtv-irq.c
+@@ -46,7 +46,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
+
+ IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
+ if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
+- s->v4l2dev == NULL || !ivtv_use_pio(s)) {
++ s->vdev == NULL || !ivtv_use_pio(s)) {
+ itv->cur_pio_stream = -1;
+ /* trigger PIO complete user interrupt */
+ write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
+@@ -109,7 +109,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
+ int rc;
+
+ /* sanity checks */
+- if (s->v4l2dev == NULL) {
++ if (s->vdev == NULL) {
+ IVTV_DEBUG_WARN("Stream %s not started\n", s->name);
+ return -1;
+ }
+diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
+index 71bd13e..ff7b7de 100644
+--- a/drivers/media/video/ivtv/ivtv-queue.c
++++ b/drivers/media/video/ivtv/ivtv-queue.c
+@@ -230,7 +230,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
+ return -ENOMEM;
+ }
+ if (ivtv_might_use_dma(s)) {
+- s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
++ s->sg_handle = pci_map_single(itv->pdev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
+ ivtv_stream_sync_for_cpu(s);
+ }
+
+@@ -248,7 +248,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
+ }
+ INIT_LIST_HEAD(&buf->list);
+ if (ivtv_might_use_dma(s)) {
+- buf->dma_handle = pci_map_single(s->itv->dev,
++ buf->dma_handle = pci_map_single(s->itv->pdev,
+ buf->buf, s->buf_size + 256, s->dma);
+ ivtv_buf_sync_for_cpu(s, buf);
+ }
+@@ -271,7 +271,7 @@ void ivtv_stream_free(struct ivtv_stream *s)
+ /* empty q_free */
+ while ((buf = ivtv_dequeue(s, &s->q_free))) {
+ if (ivtv_might_use_dma(s))
+- pci_unmap_single(s->itv->dev, buf->dma_handle,
++ pci_unmap_single(s->itv->pdev, buf->dma_handle,
+ s->buf_size + 256, s->dma);
+ kfree(buf->buf);
+ kfree(buf);
+@@ -280,7 +280,7 @@ void ivtv_stream_free(struct ivtv_stream *s)
+ /* Free SG Array/Lists */
+ if (s->sg_dma != NULL) {
+ if (s->sg_handle != IVTV_DMA_UNMAPPED) {
+- pci_unmap_single(s->itv->dev, s->sg_handle,
++ pci_unmap_single(s->itv->pdev, s->sg_handle,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+ s->sg_handle = IVTV_DMA_UNMAPPED;
+ }
+diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h
+index 476556a..9123383 100644
+--- a/drivers/media/video/ivtv/ivtv-queue.h
++++ b/drivers/media/video/ivtv/ivtv-queue.h
+@@ -53,14 +53,14 @@ static inline int ivtv_use_dma(struct ivtv_stream *s)
+ static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf)
+ {
+ if (ivtv_use_dma(s))
+- pci_dma_sync_single_for_cpu(s->itv->dev, buf->dma_handle,
++ pci_dma_sync_single_for_cpu(s->itv->pdev, buf->dma_handle,
+ s->buf_size + 256, s->dma);
+ }
+
+ static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf)
+ {
+ if (ivtv_use_dma(s))
+- pci_dma_sync_single_for_device(s->itv->dev, buf->dma_handle,
++ pci_dma_sync_single_for_device(s->itv->pdev, buf->dma_handle,
+ s->buf_size + 256, s->dma);
+ }
+
+@@ -82,14 +82,14 @@ void ivtv_stream_free(struct ivtv_stream *s);
+ static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s)
+ {
+ if (ivtv_use_dma(s))
+- pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle,
++ pci_dma_sync_single_for_cpu(s->itv->pdev, s->sg_handle,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+ }
+
+ static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s)
+ {
+ if (ivtv_use_dma(s))
+- pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle,
++ pci_dma_sync_single_for_device(s->itv->pdev, s->sg_handle,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+ }
+
+diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
+index 854a950..15da017 100644
+--- a/drivers/media/video/ivtv/ivtv-streams.c
++++ b/drivers/media/video/ivtv/ivtv-streams.c
+@@ -137,11 +137,11 @@ static struct {
+ static void ivtv_stream_init(struct ivtv *itv, int type)
+ {
+ struct ivtv_stream *s = &itv->streams[type];
+- struct video_device *dev = s->v4l2dev;
++ struct video_device *vdev = s->vdev;
+
+- /* we need to keep v4l2dev, so restore it afterwards */
++ /* we need to keep vdev, so restore it afterwards */
+ memset(s, 0, sizeof(*s));
+- s->v4l2dev = dev;
++ s->vdev = vdev;
+
+ /* initialize ivtv_stream fields */
+ s->itv = itv;
+@@ -172,10 +172,10 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
+ int num_offset = ivtv_stream_info[type].num_offset;
+ int num = itv->instance + ivtv_first_minor + num_offset;
+
+- /* These four fields are always initialized. If v4l2dev == NULL, then
++ /* These four fields are always initialized. If vdev == NULL, then
+ this stream is not in use. In that case no other fields but these
+ four can be used. */
+- s->v4l2dev = NULL;
++ s->vdev = NULL;
+ s->itv = itv;
+ s->type = type;
+ s->name = ivtv_stream_info[type].name;
+@@ -197,21 +197,21 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
+ ivtv_stream_init(itv, type);
+
+ /* allocate and initialize the v4l2 video device structure */
+- s->v4l2dev = video_device_alloc();
+- if (s->v4l2dev == NULL) {
++ s->vdev = video_device_alloc();
++ if (s->vdev == NULL) {
+ IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name);
+ return -ENOMEM;
+ }
+
+- snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "%s %s",
+- itv->device.name, s->name);
++ snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s",
++ itv->v4l2_dev.name, s->name);
+
+- s->v4l2dev->num = num;
+- s->v4l2dev->v4l2_dev = &itv->device;
+- s->v4l2dev->fops = ivtv_stream_info[type].fops;
+- s->v4l2dev->release = video_device_release;
+- s->v4l2dev->tvnorms = V4L2_STD_ALL;
+- ivtv_set_funcs(s->v4l2dev);
++ s->vdev->num = num;
++ s->vdev->v4l2_dev = &itv->v4l2_dev;
++ s->vdev->fops = ivtv_stream_info[type].fops;
++ s->vdev->release = video_device_release;
++ s->vdev->tvnorms = V4L2_STD_ALL;
++ ivtv_set_funcs(s->vdev);
+ return 0;
+ }
+
+@@ -226,7 +226,7 @@ int ivtv_streams_setup(struct ivtv *itv)
+ if (ivtv_prep_dev(itv, type))
+ break;
+
+- if (itv->streams[type].v4l2dev == NULL)
++ if (itv->streams[type].vdev == NULL)
+ continue;
+
+ /* Allocate Stream */
+@@ -247,28 +247,28 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
+ int vfl_type = ivtv_stream_info[type].vfl_type;
+ int num;
+
+- if (s->v4l2dev == NULL)
++ if (s->vdev == NULL)
+ return 0;
+
+- num = s->v4l2dev->num;
++ num = s->vdev->num;
+ /* card number + user defined offset + device offset */
+ if (type != IVTV_ENC_STREAM_TYPE_MPG) {
+ struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
+
+- if (s_mpg->v4l2dev)
+- num = s_mpg->v4l2dev->num + ivtv_stream_info[type].num_offset;
++ if (s_mpg->vdev)
++ num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset;
+ }
+- video_set_drvdata(s->v4l2dev, s);
++ video_set_drvdata(s->vdev, s);
+
+ /* Register device. First try the desired minor, then any free one. */
+- if (video_register_device(s->v4l2dev, vfl_type, num)) {
++ if (video_register_device(s->vdev, vfl_type, num)) {
+ IVTV_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
+ s->name, num);
+- video_device_release(s->v4l2dev);
+- s->v4l2dev = NULL;
++ video_device_release(s->vdev);
++ s->vdev = NULL;
+ return -ENOMEM;
+ }
+- num = s->v4l2dev->num;
++ num = s->vdev->num;
+
+ switch (vfl_type) {
+ case VFL_TYPE_GRABBER:
+@@ -316,9 +316,9 @@ void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
+
+ /* Teardown all streams */
+ for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+- struct video_device *vdev = itv->streams[type].v4l2dev;
++ struct video_device *vdev = itv->streams[type].vdev;
+
+- itv->streams[type].v4l2dev = NULL;
++ itv->streams[type].vdev = NULL;
+ if (vdev == NULL)
+ continue;
+
+@@ -449,7 +449,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
+ int captype = 0, subtype = 0;
+ int enable_passthrough = 0;
+
+- if (s->v4l2dev == NULL)
++ if (s->vdev == NULL)
+ return -EINVAL;
+
+ IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
+@@ -611,7 +611,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
+ struct cx2341x_mpeg_params *p = &itv->params;
+ int datatype;
+
+- if (s->v4l2dev == NULL)
++ if (s->vdev == NULL)
+ return -EINVAL;
+
+ IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
+@@ -657,7 +657,7 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
+ {
+ struct ivtv *itv = s->itv;
+
+- if (s->v4l2dev == NULL)
++ if (s->vdev == NULL)
+ return -EINVAL;
+
+ if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags))
+@@ -705,7 +705,7 @@ void ivtv_stop_all_captures(struct ivtv *itv)
+ for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
+ struct ivtv_stream *s = &itv->streams[i];
+
+- if (s->v4l2dev == NULL)
++ if (s->vdev == NULL)
+ continue;
+ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+ ivtv_stop_v4l2_encode_stream(s, 0);
+@@ -720,7 +720,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
+ int cap_type;
+ int stopmode;
+
+- if (s->v4l2dev == NULL)
++ if (s->vdev == NULL)
+ return -EINVAL;
+
+ /* This function assumes that you are allowed to stop the capture
+@@ -834,7 +834,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
+ {
+ struct ivtv *itv = s->itv;
+
+- if (s->v4l2dev == NULL)
++ if (s->vdev == NULL)
+ return -EINVAL;
+
+ if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG)
+@@ -895,7 +895,7 @@ int ivtv_passthrough_mode(struct ivtv *itv, int enable)
+ struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
+ struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+
+- if (yuv_stream->v4l2dev == NULL || dec_stream->v4l2dev == NULL)
++ if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL)
+ return -EINVAL;
+
+ IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n");
+diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c
+index 460db03..d07ad6c 100644
+--- a/drivers/media/video/ivtv/ivtv-udma.c
++++ b/drivers/media/video/ivtv/ivtv-udma.c
+@@ -93,7 +93,7 @@ void ivtv_udma_alloc(struct ivtv *itv)
+ {
+ if (itv->udma.SG_handle == 0) {
+ /* Map DMA Page Array Buffer */
+- itv->udma.SG_handle = pci_map_single(itv->dev, itv->udma.SGarray,
++ itv->udma.SG_handle = pci_map_single(itv->pdev, itv->udma.SGarray,
+ sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+ ivtv_udma_sync_for_cpu(itv);
+ }
+@@ -147,7 +147,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
+ }
+
+ /* Map SG List */
+- dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
++ dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+
+ /* Fill SG Array with new values */
+ ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1);
+@@ -172,7 +172,7 @@ void ivtv_udma_unmap(struct ivtv *itv)
+
+ /* Unmap Scatterlist */
+ if (dma->SG_length) {
+- pci_unmap_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
++ pci_unmap_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+ dma->SG_length = 0;
+ }
+ /* sync DMA */
+@@ -191,13 +191,13 @@ void ivtv_udma_free(struct ivtv *itv)
+
+ /* Unmap SG Array */
+ if (itv->udma.SG_handle) {
+- pci_unmap_single(itv->dev, itv->udma.SG_handle,
++ pci_unmap_single(itv->pdev, itv->udma.SG_handle,
+ sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+ }
+
+ /* Unmap Scatterlist */
+ if (itv->udma.SG_length) {
+- pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
++ pci_unmap_sg(itv->pdev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
+ }
+
+ for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) {
+diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h
+index df727e2..ee3c9ef 100644
+--- a/drivers/media/video/ivtv/ivtv-udma.h
++++ b/drivers/media/video/ivtv/ivtv-udma.h
+@@ -35,13 +35,13 @@ void ivtv_udma_start(struct ivtv *itv);
+
+ static inline void ivtv_udma_sync_for_device(struct ivtv *itv)
+ {
+- pci_dma_sync_single_for_device((struct pci_dev *)itv->dev, itv->udma.SG_handle,
++ pci_dma_sync_single_for_device(itv->pdev, itv->udma.SG_handle,
+ sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+ }
+
+ static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv)
+ {
+- pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle,
++ pci_dma_sync_single_for_cpu(itv->pdev, itv->udma.SG_handle,
+ sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+ }
+
+diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
+index 5c5d1c4..f420d31 100644
+--- a/drivers/media/video/ivtv/ivtv-vbi.c
++++ b/drivers/media/video/ivtv/ivtv-vbi.c
+@@ -185,6 +185,8 @@ static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
+ size = 4 + ((43 * line + 3) & ~3);
+ } else {
+ memcpy(dst + sd, "itv0", 4);
++ cpu_to_le32s(&linemask[0]);
++ cpu_to_le32s(&linemask[1]);
+ memcpy(dst + sd + 4, &linemask[0], 8);
+ size = 12 + ((43 * line + 3) & ~3);
+ }
+diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
+index 8cd753d..b530dec 100644
+--- a/drivers/media/video/ivtv/ivtv-version.h
++++ b/drivers/media/video/ivtv/ivtv-version.h
+@@ -23,7 +23,7 @@
+ #define IVTV_DRIVER_NAME "ivtv"
+ #define IVTV_DRIVER_VERSION_MAJOR 1
+ #define IVTV_DRIVER_VERSION_MINOR 4
+-#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
++#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
+
+ #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
+ #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
+diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
+index ee91107..7912ed6 100644
+--- a/drivers/media/video/ivtv/ivtv-yuv.c
++++ b/drivers/media/video/ivtv/ivtv-yuv.c
+@@ -103,7 +103,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
+ dma->page_count = 0;
+ return -ENOMEM;
+ }
+- dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
++ dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+
+ /* Fill SG Array with new values */
+ ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
+@@ -910,7 +910,7 @@ static void ivtv_yuv_init(struct ivtv *itv)
+ /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
+ yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
+ if (yi->blanking_ptr) {
+- yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
++ yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
+ } else {
+ yi->blanking_dmaptr = 0;
+ IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
+@@ -1237,7 +1237,7 @@ void ivtv_yuv_close(struct ivtv *itv)
+ if (yi->blanking_ptr) {
+ kfree(yi->blanking_ptr);
+ yi->blanking_ptr = NULL;
+- pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
++ pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
+ }
+
+ /* Invalidate the old dimension information */
+diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
+index 36abd2a..66e6eb5 100644
+--- a/drivers/media/video/ivtv/ivtvfb.c
++++ b/drivers/media/video/ivtv/ivtvfb.c
+@@ -1192,12 +1192,12 @@ static int ivtvfb_init_card(struct ivtv *itv)
+ static int __init ivtvfb_callback_init(struct device *dev, void *p)
+ {
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+- struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
++ struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
+
+ if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (ivtvfb_init_card(itv) == 0) {
+ IVTVFB_INFO("Framebuffer registered on %s\n",
+- itv->device.name);
++ itv->v4l2_dev.name);
+ (*(int *)p)++;
+ }
+ }
+@@ -1207,7 +1207,7 @@ static int __init ivtvfb_callback_init(struct device *dev, void *p)
+ static int ivtvfb_callback_cleanup(struct device *dev, void *p)
+ {
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+- struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
++ struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
+
+ if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
+diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
+index bae2d2b..841024b 100644
+--- a/drivers/media/video/ks0127.c
++++ b/drivers/media/video/ks0127.c
+@@ -39,19 +39,20 @@
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ #include <linux/i2c.h>
+-#include <linux/video_decoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+ #include "ks0127.h"
+
+ MODULE_DESCRIPTION("KS0127 video decoder driver");
+ MODULE_AUTHOR("Ryan Drake");
+ MODULE_LICENSE("GPL");
+
+-#define KS_TYPE_UNKNOWN 0
+-#define KS_TYPE_0122S 1
+-#define KS_TYPE_0127 2
+-#define KS_TYPE_0127B 3
++/* Addresses */
++#define I2C_KS0127_ADDON 0xD8
++#define I2C_KS0127_ONBOARD 0xDA
++
+
+ /* ks0127 control registers */
+ #define KS_STAT 0x00
+@@ -197,15 +198,17 @@ struct adjust {
+ };
+
+ struct ks0127 {
+- int format_width;
+- int format_height;
+- int cap_width;
+- int cap_height;
+- int norm;
+- int ks_type;
++ struct v4l2_subdev sd;
++ v4l2_std_id norm;
++ int ident;
+ u8 regs[256];
+ };
+
++static inline struct ks0127 *to_ks0127(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct ks0127, sd);
++}
++
+
+ static int debug; /* insmod parameter */
+
+@@ -311,43 +314,45 @@ static void init_reg_defaults(void)
+ */
+
+
+-static u8 ks0127_read(struct i2c_client *c, u8 reg)
++static u8 ks0127_read(struct v4l2_subdev *sd, u8 reg)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ char val = 0;
+ struct i2c_msg msgs[] = {
+- { c->addr, 0, sizeof(reg), &reg },
+- { c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val }
++ { client->addr, 0, sizeof(reg), &reg },
++ { client->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val }
+ };
+ int ret;
+
+- ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+- v4l_dbg(1, debug, c, "read error\n");
++ v4l2_dbg(1, debug, sd, "read error\n");
+
+ return val;
+ }
+
+
+-static void ks0127_write(struct i2c_client *c, u8 reg, u8 val)
++static void ks0127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+ {
+- struct ks0127 *ks = i2c_get_clientdata(c);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ks0127 *ks = to_ks0127(sd);
+ char msg[] = { reg, val };
+
+- if (i2c_master_send(c, msg, sizeof(msg)) != sizeof(msg))
+- v4l_dbg(1, debug, c, "write error\n");
++ if (i2c_master_send(client, msg, sizeof(msg)) != sizeof(msg))
++ v4l2_dbg(1, debug, sd, "write error\n");
+
+ ks->regs[reg] = val;
+ }
+
+
+ /* generic bit-twiddling */
+-static void ks0127_and_or(struct i2c_client *client, u8 reg, u8 and_v, u8 or_v)
++static void ks0127_and_or(struct v4l2_subdev *sd, u8 reg, u8 and_v, u8 or_v)
+ {
+- struct ks0127 *ks = i2c_get_clientdata(client);
++ struct ks0127 *ks = to_ks0127(sd);
+
+ u8 val = ks->regs[reg];
+ val = (val & and_v) | or_v;
+- ks0127_write(client, reg, val);
++ ks0127_write(sd, reg, val);
+ }
+
+
+@@ -355,439 +360,363 @@ static void ks0127_and_or(struct i2c_client *client, u8 reg, u8 and_v, u8 or_v)
+ /****************************************************************************
+ * ks0127 private api
+ ****************************************************************************/
+-static void ks0127_reset(struct i2c_client *c)
++static void ks0127_init(struct v4l2_subdev *sd)
+ {
+- struct ks0127 *ks = i2c_get_clientdata(c);
++ struct ks0127 *ks = to_ks0127(sd);
+ u8 *table = reg_defaults;
+ int i;
+
+- ks->ks_type = KS_TYPE_UNKNOWN;
++ ks->ident = V4L2_IDENT_KS0127;
+
+- v4l_dbg(1, debug, c, "reset\n");
++ v4l2_dbg(1, debug, sd, "reset\n");
+ msleep(1);
+
+ /* initialize all registers to known values */
+ /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
+
+ for (i = 1; i < 33; i++)
+- ks0127_write(c, i, table[i]);
++ ks0127_write(sd, i, table[i]);
+
+ for (i = 35; i < 40; i++)
+- ks0127_write(c, i, table[i]);
++ ks0127_write(sd, i, table[i]);
+
+ for (i = 41; i < 56; i++)
+- ks0127_write(c, i, table[i]);
++ ks0127_write(sd, i, table[i]);
+
+ for (i = 58; i < 64; i++)
+- ks0127_write(c, i, table[i]);
++ ks0127_write(sd, i, table[i]);
+
+
+- if ((ks0127_read(c, KS_STAT) & 0x80) == 0) {
+- ks->ks_type = KS_TYPE_0122S;
+- v4l_dbg(1, debug, c, "ks0122s found\n");
++ if ((ks0127_read(sd, KS_STAT) & 0x80) == 0) {
++ ks->ident = V4L2_IDENT_KS0122S;
++ v4l2_dbg(1, debug, sd, "ks0122s found\n");
+ return;
+ }
+
+- switch (ks0127_read(c, KS_CMDE) & 0x0f) {
++ switch (ks0127_read(sd, KS_CMDE) & 0x0f) {
+ case 0:
+- ks->ks_type = KS_TYPE_0127;
+- v4l_dbg(1, debug, c, "ks0127 found\n");
++ v4l2_dbg(1, debug, sd, "ks0127 found\n");
+ break;
+
+ case 9:
+- ks->ks_type = KS_TYPE_0127B;
+- v4l_dbg(1, debug, c, "ks0127B Revision A found\n");
++ ks->ident = V4L2_IDENT_KS0127B;
++ v4l2_dbg(1, debug, sd, "ks0127B Revision A found\n");
+ break;
+
+ default:
+- v4l_dbg(1, debug, c, "unknown revision\n");
++ v4l2_dbg(1, debug, sd, "unknown revision\n");
+ break;
+ }
+ }
+
+-static int ks0127_command(struct i2c_client *c, unsigned cmd, void *arg)
++static int ks0127_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+ {
+- struct ks0127 *ks = i2c_get_clientdata(c);
+- int *iarg = (int *)arg;
+- int status;
+-
+- if (!ks)
+- return -ENODEV;
++ struct ks0127 *ks = to_ks0127(sd);
++
++ switch (route->input) {
++ case KS_INPUT_COMPOSITE_1:
++ case KS_INPUT_COMPOSITE_2:
++ case KS_INPUT_COMPOSITE_3:
++ case KS_INPUT_COMPOSITE_4:
++ case KS_INPUT_COMPOSITE_5:
++ case KS_INPUT_COMPOSITE_6:
++ v4l2_dbg(1, debug, sd,
++ "s_routing %d: Composite\n", route->input);
++ /* autodetect 50/60 Hz */
++ ks0127_and_or(sd, KS_CMDA, 0xfc, 0x00);
++ /* VSE=0 */
++ ks0127_and_or(sd, KS_CMDA, ~0x40, 0x00);
++ /* set input line */
++ ks0127_and_or(sd, KS_CMDB, 0xb0, route->input);
++ /* non-freerunning mode */
++ ks0127_and_or(sd, KS_CMDC, 0x70, 0x0a);
++ /* analog input */
++ ks0127_and_or(sd, KS_CMDD, 0x03, 0x00);
++ /* enable chroma demodulation */
++ ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00);
++ /* chroma trap, HYBWR=1 */
++ ks0127_and_or(sd, KS_LUMA, 0x00,
++ (reg_defaults[KS_LUMA])|0x0c);
++ /* scaler fullbw, luma comb off */
++ ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81);
++ /* manual chroma comb .25 .5 .25 */
++ ks0127_and_or(sd, KS_VERTIC, 0x0f, 0x90);
++
++ /* chroma path delay */
++ ks0127_and_or(sd, KS_CHROMB, 0x0f, 0x90);
++
++ ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]);
++ ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]);
++ ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
++ ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
++ break;
+
+- switch (cmd) {
+- case DECODER_INIT:
+- v4l_dbg(1, debug, c, "DECODER_INIT\n");
+- ks0127_reset(c);
++ case KS_INPUT_SVIDEO_1:
++ case KS_INPUT_SVIDEO_2:
++ case KS_INPUT_SVIDEO_3:
++ v4l2_dbg(1, debug, sd,
++ "s_routing %d: S-Video\n", route->input);
++ /* autodetect 50/60 Hz */
++ ks0127_and_or(sd, KS_CMDA, 0xfc, 0x00);
++ /* VSE=0 */
++ ks0127_and_or(sd, KS_CMDA, ~0x40, 0x00);
++ /* set input line */
++ ks0127_and_or(sd, KS_CMDB, 0xb0, route->input);
++ /* non-freerunning mode */
++ ks0127_and_or(sd, KS_CMDC, 0x70, 0x0a);
++ /* analog input */
++ ks0127_and_or(sd, KS_CMDD, 0x03, 0x00);
++ /* enable chroma demodulation */
++ ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00);
++ ks0127_and_or(sd, KS_LUMA, 0x00,
++ reg_defaults[KS_LUMA]);
++ /* disable luma comb */
++ ks0127_and_or(sd, KS_VERTIA, 0x08,
++ (reg_defaults[KS_VERTIA]&0xf0)|0x01);
++ ks0127_and_or(sd, KS_VERTIC, 0x0f,
++ reg_defaults[KS_VERTIC]&0xf0);
++
++ ks0127_and_or(sd, KS_CHROMB, 0x0f,
++ reg_defaults[KS_CHROMB]&0xf0);
++
++ ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]);
++ ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]);
++ ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
++ ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+ break;
+
+- case DECODER_SET_INPUT:
+- switch(*iarg) {
+- case KS_INPUT_COMPOSITE_1:
+- case KS_INPUT_COMPOSITE_2:
+- case KS_INPUT_COMPOSITE_3:
+- case KS_INPUT_COMPOSITE_4:
+- case KS_INPUT_COMPOSITE_5:
+- case KS_INPUT_COMPOSITE_6:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_INPUT %d: Composite\n", *iarg);
+- /* autodetect 50/60 Hz */
+- ks0127_and_or(c, KS_CMDA, 0xfc, 0x00);
+- /* VSE=0 */
+- ks0127_and_or(c, KS_CMDA, ~0x40, 0x00);
+- /* set input line */
+- ks0127_and_or(c, KS_CMDB, 0xb0, *iarg);
+- /* non-freerunning mode */
+- ks0127_and_or(c, KS_CMDC, 0x70, 0x0a);
+- /* analog input */
+- ks0127_and_or(c, KS_CMDD, 0x03, 0x00);
+- /* enable chroma demodulation */
+- ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
+- /* chroma trap, HYBWR=1 */
+- ks0127_and_or(c, KS_LUMA, 0x00,
+- (reg_defaults[KS_LUMA])|0x0c);
+- /* scaler fullbw, luma comb off */
+- ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
+- /* manual chroma comb .25 .5 .25 */
+- ks0127_and_or(c, KS_VERTIC, 0x0f, 0x90);
+-
+- /* chroma path delay */
+- ks0127_and_or(c, KS_CHROMB, 0x0f, 0x90);
+-
+- ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
+- ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
+- ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+- ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+- break;
+-
+- case KS_INPUT_SVIDEO_1:
+- case KS_INPUT_SVIDEO_2:
+- case KS_INPUT_SVIDEO_3:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_INPUT %d: S-Video\n", *iarg);
+- /* autodetect 50/60 Hz */
+- ks0127_and_or(c, KS_CMDA, 0xfc, 0x00);
+- /* VSE=0 */
+- ks0127_and_or(c, KS_CMDA, ~0x40, 0x00);
+- /* set input line */
+- ks0127_and_or(c, KS_CMDB, 0xb0, *iarg);
+- /* non-freerunning mode */
+- ks0127_and_or(c, KS_CMDC, 0x70, 0x0a);
+- /* analog input */
+- ks0127_and_or(c, KS_CMDD, 0x03, 0x00);
+- /* enable chroma demodulation */
+- ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
+- ks0127_and_or(c, KS_LUMA, 0x00,
+- reg_defaults[KS_LUMA]);
+- /* disable luma comb */
+- ks0127_and_or(c, KS_VERTIA, 0x08,
+- (reg_defaults[KS_VERTIA]&0xf0)|0x01);
+- ks0127_and_or(c, KS_VERTIC, 0x0f,
+- reg_defaults[KS_VERTIC]&0xf0);
+-
+- ks0127_and_or(c, KS_CHROMB, 0x0f,
+- reg_defaults[KS_CHROMB]&0xf0);
+-
+- ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
+- ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
+- ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+- ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+- break;
+-
+- case KS_INPUT_YUV656:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_INPUT 15: YUV656\n");
+- if (ks->norm == VIDEO_MODE_NTSC ||
+- ks->norm == KS_STD_PAL_M)
+- /* force 60 Hz */
+- ks0127_and_or(c, KS_CMDA, 0xfc, 0x03);
+- else
+- /* force 50 Hz */
+- ks0127_and_or(c, KS_CMDA, 0xfc, 0x02);
+-
+- ks0127_and_or(c, KS_CMDA, 0xff, 0x40); /* VSE=1 */
+- /* set input line and VALIGN */
+- ks0127_and_or(c, KS_CMDB, 0xb0, (*iarg | 0x40));
+- /* freerunning mode, */
+- /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/
+- ks0127_and_or(c, KS_CMDC, 0x70, 0x87);
+- /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
+- ks0127_and_or(c, KS_CMDD, 0x03, 0x08);
+- /* disable chroma demodulation */
+- ks0127_and_or(c, KS_CTRACK, 0xcf, 0x30);
+- /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
+- ks0127_and_or(c, KS_LUMA, 0x00, 0x71);
+- ks0127_and_or(c, KS_VERTIC, 0x0f,
+- reg_defaults[KS_VERTIC]&0xf0);
+-
+- /* scaler fullbw, luma comb off */
+- ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
+-
+- ks0127_and_or(c, KS_CHROMB, 0x0f,
+- reg_defaults[KS_CHROMB]&0xf0);
+-
+- ks0127_and_or(c, KS_CON, 0x00, 0x00);
+- ks0127_and_or(c, KS_BRT, 0x00, 32); /* spec: 34 */
+- /* spec: 229 (e5) */
+- ks0127_and_or(c, KS_SAT, 0x00, 0xe8);
+- ks0127_and_or(c, KS_HUE, 0x00, 0);
+-
+- ks0127_and_or(c, KS_UGAIN, 0x00, 238);
+- ks0127_and_or(c, KS_VGAIN, 0x00, 0x00);
+-
+- /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
+- ks0127_and_or(c, KS_UVOFFH, 0x00, 0x4f);
+- ks0127_and_or(c, KS_UVOFFL, 0x00, 0x00);
+- break;
+-
+- default:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_INPUT: Unknown input %d\n", *iarg);
+- break;
+- }
+-
+- /* hack: CDMLPF sometimes spontaneously switches on; */
+- /* force back off */
+- ks0127_write(c, KS_DEMOD, reg_defaults[KS_DEMOD]);
++ case KS_INPUT_YUV656:
++ v4l2_dbg(1, debug, sd, "s_routing 15: YUV656\n");
++ if (ks->norm & V4L2_STD_525_60)
++ /* force 60 Hz */
++ ks0127_and_or(sd, KS_CMDA, 0xfc, 0x03);
++ else
++ /* force 50 Hz */
++ ks0127_and_or(sd, KS_CMDA, 0xfc, 0x02);
++
++ ks0127_and_or(sd, KS_CMDA, 0xff, 0x40); /* VSE=1 */
++ /* set input line and VALIGN */
++ ks0127_and_or(sd, KS_CMDB, 0xb0, (route->input | 0x40));
++ /* freerunning mode, */
++ /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/
++ ks0127_and_or(sd, KS_CMDC, 0x70, 0x87);
++ /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
++ ks0127_and_or(sd, KS_CMDD, 0x03, 0x08);
++ /* disable chroma demodulation */
++ ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x30);
++ /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
++ ks0127_and_or(sd, KS_LUMA, 0x00, 0x71);
++ ks0127_and_or(sd, KS_VERTIC, 0x0f,
++ reg_defaults[KS_VERTIC]&0xf0);
++
++ /* scaler fullbw, luma comb off */
++ ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81);
++
++ ks0127_and_or(sd, KS_CHROMB, 0x0f,
++ reg_defaults[KS_CHROMB]&0xf0);
++
++ ks0127_and_or(sd, KS_CON, 0x00, 0x00);
++ ks0127_and_or(sd, KS_BRT, 0x00, 32); /* spec: 34 */
++ /* spec: 229 (e5) */
++ ks0127_and_or(sd, KS_SAT, 0x00, 0xe8);
++ ks0127_and_or(sd, KS_HUE, 0x00, 0);
++
++ ks0127_and_or(sd, KS_UGAIN, 0x00, 238);
++ ks0127_and_or(sd, KS_VGAIN, 0x00, 0x00);
++
++ /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
++ ks0127_and_or(sd, KS_UVOFFH, 0x00, 0x4f);
++ ks0127_and_or(sd, KS_UVOFFL, 0x00, 0x00);
+ break;
+
+- case DECODER_SET_OUTPUT:
+- switch(*iarg) {
+- case KS_OUTPUT_YUV656E:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_OUTPUT: OUTPUT_YUV656E (Missing)\n");
+- return -EINVAL;
+-
+- case KS_OUTPUT_EXV:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_OUTPUT: OUTPUT_EXV\n");
+- ks0127_and_or(c, KS_OFMTA, 0xf0, 0x09);
+- break;
+- }
++ default:
++ v4l2_dbg(1, debug, sd,
++ "s_routing: Unknown input %d\n", route->input);
+ break;
++ }
+
+- case DECODER_SET_NORM: /* sam This block mixes old and new norm names... */
+- /* Set to automatic SECAM/Fsc mode */
+- ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
+-
+- ks->norm = *iarg;
+- switch (*iarg) {
+- /* this is untested !! */
+- /* It just detects PAL_N/NTSC_M (no special frequencies) */
+- /* And you have to set the standard a second time afterwards */
+- case VIDEO_MODE_AUTO:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_NORM: AUTO\n");
+-
+- /* The chip determines the format */
+- /* based on the current field rate */
+- ks0127_and_or(c, KS_CMDA, 0xfc, 0x00);
+- ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
+- /* This is wrong for PAL ! As I said, */
+- /* you need to set the standard once again !! */
+- ks->format_height = 240;
+- ks->format_width = 704;
+- break;
+-
+- case VIDEO_MODE_NTSC:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_NORM: NTSC_M\n");
+- ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
+- ks->format_height = 240;
+- ks->format_width = 704;
+- break;
+-
+- case KS_STD_NTSC_N:
+- v4l_dbg(1, debug, c,
+- "KS0127_SET_NORM: NTSC_N (fixme)\n");
+- ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
+- ks->format_height = 240;
+- ks->format_width = 704;
+- break;
+-
+- case VIDEO_MODE_PAL:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_NORM: PAL_N\n");
+- ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
+- ks->format_height = 290;
+- ks->format_width = 704;
+- break;
+-
+- case KS_STD_PAL_M:
+- v4l_dbg(1, debug, c,
+- "KS0127_SET_NORM: PAL_M (fixme)\n");
+- ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
+- ks->format_height = 290;
+- ks->format_width = 704;
+- break;
+-
+- case VIDEO_MODE_SECAM:
+- v4l_dbg(1, debug, c,
+- "KS0127_SET_NORM: SECAM\n");
+- ks->format_height = 290;
+- ks->format_width = 704;
+-
+- /* set to secam autodetection */
+- ks0127_and_or(c, KS_CHROMA, 0xdf, 0x20);
+- ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
+- schedule_timeout_interruptible(HZ/10+1);
+-
+- /* did it autodetect? */
+- if (ks0127_read(c, KS_DEMOD) & 0x40)
+- break;
++ /* hack: CDMLPF sometimes spontaneously switches on; */
++ /* force back off */
++ ks0127_write(sd, KS_DEMOD, reg_defaults[KS_DEMOD]);
++ return 0;
++}
+
++static int ks0127_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
++{
++ struct ks0127 *ks = to_ks0127(sd);
++
++ /* Set to automatic SECAM/Fsc mode */
++ ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00);
++
++ ks->norm = std;
++ if (std & V4L2_STD_NTSC) {
++ v4l2_dbg(1, debug, sd,
++ "s_std: NTSC_M\n");
++ ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20);
++ } else if (std & V4L2_STD_PAL_N) {
++ v4l2_dbg(1, debug, sd,
++ "s_std: NTSC_N (fixme)\n");
++ ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40);
++ } else if (std & V4L2_STD_PAL) {
++ v4l2_dbg(1, debug, sd,
++ "s_std: PAL_N\n");
++ ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20);
++ } else if (std & V4L2_STD_PAL_M) {
++ v4l2_dbg(1, debug, sd,
++ "s_std: PAL_M (fixme)\n");
++ ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40);
++ } else if (std & V4L2_STD_SECAM) {
++ v4l2_dbg(1, debug, sd,
++ "s_std: SECAM\n");
++
++ /* set to secam autodetection */
++ ks0127_and_or(sd, KS_CHROMA, 0xdf, 0x20);
++ ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00);
++ schedule_timeout_interruptible(HZ/10+1);
++
++ /* did it autodetect? */
++ if (!(ks0127_read(sd, KS_DEMOD) & 0x40))
+ /* force to secam mode */
+- ks0127_and_or(c, KS_DEMOD, 0xf0, 0x0f);
+- break;
+-
+- default:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_NORM: Unknown norm %d\n", *iarg);
+- break;
+- }
+- break;
+-
+- case DECODER_SET_PICTURE:
+- v4l_dbg(1, debug, c,
+- "DECODER_SET_PICTURE: not yet supported\n");
+- return -EINVAL;
+-
+- /* sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE */
+- /* sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE */
+- /* sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE? */
+- /* sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE */
+- /* sam todo: KS0127_SET_AGC_MODE: */
+- /* sam todo: KS0127_SET_AGC: */
+- /* sam todo: KS0127_SET_CHROMA_MODE: */
+- /* sam todo: KS0127_SET_PIXCLK_MODE: */
+- /* sam todo: KS0127_SET_GAMMA_MODE: */
+- /* sam todo: KS0127_SET_UGAIN: */
+- /* sam todo: KS0127_SET_VGAIN: */
+- /* sam todo: KS0127_SET_INVALY: */
+- /* sam todo: KS0127_SET_INVALU: */
+- /* sam todo: KS0127_SET_INVALV: */
+- /* sam todo: KS0127_SET_UNUSEY: */
+- /* sam todo: KS0127_SET_UNUSEU: */
+- /* sam todo: KS0127_SET_UNUSEV: */
+- /* sam todo: KS0127_SET_VSALIGN_MODE: */
+-
+- case DECODER_ENABLE_OUTPUT:
+- {
+- int enable;
+-
+- iarg = arg;
+- enable = (*iarg != 0);
+- if (enable) {
+- v4l_dbg(1, debug, c,
+- "DECODER_ENABLE_OUTPUT on\n");
+- /* All output pins on */
+- ks0127_and_or(c, KS_OFMTA, 0xcf, 0x30);
+- /* Obey the OEN pin */
+- ks0127_and_or(c, KS_CDEM, 0x7f, 0x00);
+- } else {
+- v4l_dbg(1, debug, c,
+- "DECODER_ENABLE_OUTPUT off\n");
+- /* Video output pins off */
+- ks0127_and_or(c, KS_OFMTA, 0xcf, 0x00);
+- /* Ignore the OEN pin */
+- ks0127_and_or(c, KS_CDEM, 0x7f, 0x80);
+- }
+- break;
++ ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x0f);
++ } else {
++ v4l2_dbg(1, debug, sd, "s_std: Unknown norm %llx\n",
++ (unsigned long long)std);
+ }
++ return 0;
++}
+
+- /* sam todo: KS0127_SET_OUTPUT_MODE: */
+- /* sam todo: KS0127_SET_WIDTH: */
+- /* sam todo: KS0127_SET_HEIGHT: */
+- /* sam todo: KS0127_SET_HSCALE: */
+-
+- case DECODER_GET_STATUS:
+- v4l_dbg(1, debug, c, "DECODER_GET_STATUS\n");
+- *iarg = 0;
+- status = ks0127_read(c, KS_STAT);
+- if (!(status & 0x20)) /* NOVID not set */
+- *iarg = (*iarg | DECODER_STATUS_GOOD);
+- if ((status & 0x01)) /* CLOCK set */
+- *iarg = (*iarg | DECODER_STATUS_COLOR);
+- if ((status & 0x08)) /* PALDET set */
+- *iarg = (*iarg | DECODER_STATUS_PAL);
+- else
+- *iarg = (*iarg | DECODER_STATUS_NTSC);
+- break;
+-
+- /* Catch any unknown command */
+- default:
+- v4l_dbg(1, debug, c, "unknown: 0x%08x\n", cmd);
+- return -EINVAL;
++static int ks0127_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ v4l2_dbg(1, debug, sd, "s_stream(%d)\n", enable);
++ if (enable) {
++ /* All output pins on */
++ ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x30);
++ /* Obey the OEN pin */
++ ks0127_and_or(sd, KS_CDEM, 0x7f, 0x00);
++ } else {
++ /* Video output pins off */
++ ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x00);
++ /* Ignore the OEN pin */
++ ks0127_and_or(sd, KS_CDEM, 0x7f, 0x80);
+ }
+ return 0;
+ }
+
++static int ks0127_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
++{
++ int stat = V4L2_IN_ST_NO_SIGNAL;
++ u8 status;
++ v4l2_std_id std = V4L2_STD_ALL;
++
++ status = ks0127_read(sd, KS_STAT);
++ if (!(status & 0x20)) /* NOVID not set */
++ stat = 0;
++ if (!(status & 0x01)) /* CLOCK set */
++ stat |= V4L2_IN_ST_NO_COLOR;
++ if ((status & 0x08)) /* PALDET set */
++ std = V4L2_STD_PAL;
++ else
++ std = V4L2_STD_NTSC;
++ if (pstd)
++ *pstd = std;
++ if (pstatus)
++ *pstatus = stat;
++ return 0;
++}
++
++static int ks0127_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
++{
++ v4l2_dbg(1, debug, sd, "querystd\n");
++ return ks0127_status(sd, NULL, std);
++}
+
+-/* Addresses to scan */
+-#define I2C_KS0127_ADDON 0xD8
+-#define I2C_KS0127_ONBOARD 0xDA
++static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status)
++{
++ v4l2_dbg(1, debug, sd, "g_input_status\n");
++ return ks0127_status(sd, status, NULL);
++}
++
++static int ks0127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ks0127 *ks = to_ks0127(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, ks->ident, 0);
++}
++
++/* ----------------------------------------------------------------------- */
+
+-static unsigned short normal_i2c[] = {
+- I2C_KS0127_ADDON >> 1,
+- I2C_KS0127_ONBOARD >> 1,
+- I2C_CLIENT_END
++static const struct v4l2_subdev_core_ops ks0127_core_ops = {
++ .g_chip_ident = ks0127_g_chip_ident,
+ };
+
+-I2C_CLIENT_INSMOD;
++static const struct v4l2_subdev_tuner_ops ks0127_tuner_ops = {
++ .s_std = ks0127_s_std,
++};
++
++static const struct v4l2_subdev_video_ops ks0127_video_ops = {
++ .s_routing = ks0127_s_routing,
++ .s_stream = ks0127_s_stream,
++ .querystd = ks0127_querystd,
++ .g_input_status = ks0127_g_input_status,
++};
++
++static const struct v4l2_subdev_ops ks0127_ops = {
++ .core = &ks0127_core_ops,
++ .tuner = &ks0127_tuner_ops,
++ .video = &ks0127_video_ops,
++};
++
++/* ----------------------------------------------------------------------- */
++
+
+-static int ks0127_probe(struct i2c_client *c, const struct i2c_device_id *id)
++static int ks0127_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ {
+ struct ks0127 *ks;
++ struct v4l2_subdev *sd;
+
+- v4l_info(c, "%s chip found @ 0x%x (%s)\n",
+- c->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
+- c->addr << 1, c->adapter->name);
++ v4l_info(client, "%s chip found @ 0x%x (%s)\n",
++ client->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
++ client->addr << 1, client->adapter->name);
+
+ ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+ if (ks == NULL)
+ return -ENOMEM;
+-
+- i2c_set_clientdata(c, ks);
+-
+- ks->ks_type = KS_TYPE_UNKNOWN;
++ sd = &ks->sd;
++ v4l2_i2c_subdev_init(sd, client, &ks0127_ops);
+
+ /* power up */
+ init_reg_defaults();
+- ks0127_write(c, KS_CMDA, 0x2c);
++ ks0127_write(sd, KS_CMDA, 0x2c);
+ mdelay(10);
+
+ /* reset the device */
+- ks0127_reset(c);
++ ks0127_init(sd);
+ return 0;
+ }
+
+-static int ks0127_remove(struct i2c_client *c)
++static int ks0127_remove(struct i2c_client *client)
+ {
+- struct ks0127 *ks = i2c_get_clientdata(c);
+-
+- ks0127_write(c, KS_OFMTA, 0x20); /* tristate */
+- ks0127_write(c, KS_CMDA, 0x2c | 0x80); /* power down */
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+- kfree(ks);
++ v4l2_device_unregister_subdev(sd);
++ ks0127_write(sd, KS_OFMTA, 0x20); /* tristate */
++ ks0127_write(sd, KS_CMDA, 0x2c | 0x80); /* power down */
++ kfree(to_ks0127(sd));
+ return 0;
+ }
+
+-static int ks0127_legacy_probe(struct i2c_adapter *adapter)
+-{
+- return adapter->id == I2C_HW_B_ZR36067;
+-}
+-
+ static const struct i2c_device_id ks0127_id[] = {
+ { "ks0127", 0 },
++ { "ks0127b", 0 },
++ { "ks0122s", 0 },
+ { }
+ };
+ MODULE_DEVICE_TABLE(i2c, ks0127_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "ks0127",
+- .driverid = I2C_DRIVERID_KS0127,
+- .command = ks0127_command,
+ .probe = ks0127_probe,
+ .remove = ks0127_remove,
+- .legacy_probe = ks0127_legacy_probe,
+ .id_table = ks0127_id,
+ };
+diff --git a/drivers/media/video/ks0127.h b/drivers/media/video/ks0127.h
+index 1ec5788..cb8abd5 100644
+--- a/drivers/media/video/ks0127.h
++++ b/drivers/media/video/ks0127.h
+@@ -24,8 +24,6 @@
+ #ifndef KS0127_H
+ #define KS0127_H
+
+-#include <linux/videodev.h>
+-
+ /* input channels */
+ #define KS_INPUT_COMPOSITE_1 0
+ #define KS_INPUT_COMPOSITE_2 1
+diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
+index de397ef..1f340fe 100644
+--- a/drivers/media/video/m52790.c
++++ b/drivers/media/video/m52790.c
+@@ -132,11 +132,6 @@ static int m52790_log_status(struct v4l2_subdev *sd)
+ return 0;
+ }
+
+-static int m52790_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops m52790_core_ops = {
+@@ -210,8 +205,6 @@ MODULE_DEVICE_TABLE(i2c, m52790_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "m52790",
+- .driverid = I2C_DRIVERID_M52790,
+- .command = m52790_command,
+ .probe = m52790_probe,
+ .remove = m52790_remove,
+ .id_table = m52790_id,
+diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
+index b76e33d..2ad11f0 100644
+--- a/drivers/media/video/meye.c
++++ b/drivers/media/video/meye.c
+@@ -1017,7 +1017,6 @@ static int meyeioc_stilljcapt(int *len)
+ static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+ {
+- memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, "meye");
+ strcpy(cap->card, "meye");
+ sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
+@@ -1036,8 +1035,6 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+ if (i->index != 0)
+ return -EINVAL;
+
+- memset(i, 0, sizeof(*i));
+- i->index = 0;
+ strcpy(i->name, "Camera");
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+@@ -1259,22 +1256,13 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+ if (f->index > 1)
+ return -EINVAL;
+
+- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+ if (f->index == 0) {
+ /* standard YUV 422 capture */
+- memset(f, 0, sizeof(*f));
+- f->index = 0;
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = 0;
+ strcpy(f->description, "YUV422");
+ f->pixelformat = V4L2_PIX_FMT_YUYV;
+ } else {
+ /* compressed MJPEG capture */
+- memset(f, 0, sizeof(*f));
+- f->index = 1;
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ strcpy(f->description, "MJPEG");
+ f->pixelformat = V4L2_PIX_FMT_MJPEG;
+@@ -1286,9 +1274,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+ {
+- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+ f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+ return -EINVAL;
+@@ -1319,12 +1304,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+ {
+- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+- memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+-
+ switch (meye.mchip_mode) {
+ case MCHIP_HIC_MODE_CONT_OUT:
+ default:
+@@ -1341,8 +1320,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+- f->fmt.pix.colorspace = 0;
+- f->fmt.pix.priv = 0;
+
+ return 0;
+ }
+@@ -1350,9 +1327,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+ static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+ {
+- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+ f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+ return -EINVAL;
+@@ -1398,9 +1372,6 @@ static int vidioc_reqbufs(struct file *file, void *fh,
+ {
+ int i;
+
+- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+ if (req->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+@@ -1441,15 +1412,11 @@ static int vidioc_reqbufs(struct file *file, void *fh,
+
+ static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+ {
+- int index = buf->index;
++ unsigned int index = buf->index;
+
+- if (index < 0 || index >= gbuffers)
++ if (index >= gbuffers)
+ return -EINVAL;
+
+- memset(buf, 0, sizeof(*buf));
+-
+- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- buf->index = index;
+ buf->bytesused = meye.grab_buffer[index].size;
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+
+@@ -1471,13 +1438,10 @@ static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+
+ static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+ {
+- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+- if (buf->index < 0 || buf->index >= gbuffers)
++ if (buf->index >= gbuffers)
+ return -EINVAL;
+
+ if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
+@@ -1497,9 +1461,6 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+ {
+ int reqnr;
+
+- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
+index 4d7a918..9e8e06c 100644
+--- a/drivers/media/video/msp3400-driver.c
++++ b/drivers/media/video/msp3400-driver.c
+@@ -366,29 +366,6 @@ int msp_sleep(struct msp_state *state, int timeout)
+ }
+
+ /* ------------------------------------------------------------------------ */
+-#ifdef CONFIG_VIDEO_ALLOW_V4L1
+-static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode)
+-{
+- if (rxsubchans == V4L2_TUNER_SUB_MONO)
+- return VIDEO_SOUND_MONO;
+- if (rxsubchans == V4L2_TUNER_SUB_STEREO)
+- return VIDEO_SOUND_STEREO;
+- if (audmode == V4L2_TUNER_MODE_LANG2)
+- return VIDEO_SOUND_LANG2;
+- return VIDEO_SOUND_LANG1;
+-}
+-
+-static int msp_mode_v4l1_to_v4l2(int mode)
+-{
+- if (mode & VIDEO_SOUND_STEREO)
+- return V4L2_TUNER_MODE_STEREO;
+- if (mode & VIDEO_SOUND_LANG2)
+- return V4L2_TUNER_MODE_LANG2;
+- if (mode & VIDEO_SOUND_LANG1)
+- return V4L2_TUNER_MODE_LANG1;
+- return V4L2_TUNER_MODE_MONO;
+-}
+-#endif
+
+ static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ {
+@@ -482,96 +459,6 @@ static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ return 0;
+ }
+
+-#ifdef CONFIG_VIDEO_ALLOW_V4L1
+-static long msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+-{
+- struct msp_state *state = to_state(sd);
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+-
+- switch (cmd) {
+- /* --- v4l ioctls --- */
+- /* take care: bttv does userspace copying, we'll get a
+- kernel pointer here... */
+- case VIDIOCGAUDIO:
+- {
+- struct video_audio *va = arg;
+-
+- va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE;
+- if (state->has_sound_processing)
+- va->flags |= VIDEO_AUDIO_BALANCE |
+- VIDEO_AUDIO_BASS |
+- VIDEO_AUDIO_TREBLE;
+- if (state->muted)
+- va->flags |= VIDEO_AUDIO_MUTE;
+- va->volume = state->volume;
+- va->balance = state->volume ? state->balance : 32768;
+- va->bass = state->bass;
+- va->treble = state->treble;
+-
+- if (state->radio)
+- break;
+- if (state->opmode == OPMODE_AUTOSELECT)
+- msp_detect_stereo(client);
+- va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans, state->audmode);
+- break;
+- }
+-
+- case VIDIOCSAUDIO:
+- {
+- struct video_audio *va = arg;
+-
+- state->muted = (va->flags & VIDEO_AUDIO_MUTE);
+- state->volume = va->volume;
+- state->balance = va->balance;
+- state->bass = va->bass;
+- state->treble = va->treble;
+- msp_set_audio(client);
+-
+- if (va->mode != 0 && state->radio == 0 &&
+- state->audmode != msp_mode_v4l1_to_v4l2(va->mode)) {
+- state->audmode = msp_mode_v4l1_to_v4l2(va->mode);
+- msp_set_audmode(client);
+- }
+- break;
+- }
+-
+- case VIDIOCSCHAN:
+- {
+- struct video_channel *vc = arg;
+- int update = 0;
+- v4l2_std_id std;
+-
+- if (state->radio)
+- update = 1;
+- state->radio = 0;
+- if (vc->norm == VIDEO_MODE_PAL)
+- std = V4L2_STD_PAL;
+- else if (vc->norm == VIDEO_MODE_SECAM)
+- std = V4L2_STD_SECAM;
+- else
+- std = V4L2_STD_NTSC;
+- if (std != state->v4l2_std) {
+- state->v4l2_std = std;
+- update = 1;
+- }
+- if (update)
+- msp_wake_thread(client);
+- break;
+- }
+-
+- case VIDIOCSFREQ:
+- {
+- /* new channel -- kick audio carrier scan */
+- msp_wake_thread(client);
+- break;
+- }
+- default:
+- return -ENOIOCTLCMD;
+- }
+- return 0;
+-}
+-#endif
+-
+ /* --- v4l2 ioctls --- */
+ static int msp_s_radio(struct v4l2_subdev *sd)
+ {
+@@ -713,22 +600,24 @@ static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+ struct msp_state *state = to_state(sd);
+
+ switch (qc->id) {
+- case V4L2_CID_AUDIO_VOLUME:
+- case V4L2_CID_AUDIO_MUTE:
+- return v4l2_ctrl_query_fill_std(qc);
+- default:
+- break;
++ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
++ default:
++ break;
+ }
+ if (!state->has_sound_processing)
+ return -EINVAL;
+ switch (qc->id) {
+- case V4L2_CID_AUDIO_LOUDNESS:
+- case V4L2_CID_AUDIO_BALANCE:
+- case V4L2_CID_AUDIO_BASS:
+- case V4L2_CID_AUDIO_TREBLE:
+- return v4l2_ctrl_query_fill_std(qc);
+- default:
+- return -EINVAL;
++ case V4L2_CID_AUDIO_LOUDNESS:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
++ case V4L2_CID_AUDIO_BALANCE:
++ case V4L2_CID_AUDIO_BASS:
++ case V4L2_CID_AUDIO_TREBLE:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
++ default:
++ return -EINVAL;
+ }
+ return 0;
+ }
+@@ -820,9 +709,6 @@ static const struct v4l2_subdev_core_ops msp_core_ops = {
+ .g_ctrl = msp_g_ctrl,
+ .s_ctrl = msp_s_ctrl,
+ .queryctrl = msp_queryctrl,
+-#ifdef CONFIG_VIDEO_ALLOW_V4L1
+- .ioctl = msp_ioctl,
+-#endif
+ };
+
+ static const struct v4l2_subdev_tuner_ops msp_tuner_ops = {
+diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
+index c1bf75e..fa7e509 100644
+--- a/drivers/media/video/mt9m001.c
++++ b/drivers/media/video/mt9m001.c
+@@ -12,7 +12,6 @@
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
+ #include <linux/log2.h>
+-#include <linux/gpio.h>
+
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
+@@ -73,9 +72,7 @@ struct mt9m001 {
+ struct i2c_client *client;
+ struct soc_camera_device icd;
+ int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+- int switch_gpio;
+ unsigned char autoexposure;
+- unsigned char datawidth;
+ };
+
+ static int reg_read(struct soc_camera_device *icd, const u8 reg)
+@@ -181,92 +178,28 @@ static int mt9m001_stop_capture(struct soc_camera_device *icd)
+ return 0;
+ }
+
+-static int bus_switch_request(struct mt9m001 *mt9m001,
+- struct soc_camera_link *icl)
+-{
+-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+- int ret;
+- unsigned int gpio = icl->gpio;
+-
+- if (gpio_is_valid(gpio)) {
+- /* We have a data bus switch. */
+- ret = gpio_request(gpio, "mt9m001");
+- if (ret < 0) {
+- dev_err(&mt9m001->client->dev, "Cannot get GPIO %u\n",
+- gpio);
+- return ret;
+- }
+-
+- ret = gpio_direction_output(gpio, 0);
+- if (ret < 0) {
+- dev_err(&mt9m001->client->dev,
+- "Cannot set GPIO %u to output\n", gpio);
+- gpio_free(gpio);
+- return ret;
+- }
+- }
+-
+- mt9m001->switch_gpio = gpio;
+-#else
+- mt9m001->switch_gpio = -EINVAL;
+-#endif
+- return 0;
+-}
+-
+-static void bus_switch_release(struct mt9m001 *mt9m001)
+-{
+-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+- if (gpio_is_valid(mt9m001->switch_gpio))
+- gpio_free(mt9m001->switch_gpio);
+-#endif
+-}
+-
+-static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit)
+-{
+-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+- if (!gpio_is_valid(mt9m001->switch_gpio))
+- return -ENODEV;
+-
+- gpio_set_value_cansleep(mt9m001->switch_gpio, go8bit);
+- return 0;
+-#else
+- return -ENODEV;
+-#endif
+-}
+-
+-static int bus_switch_possible(struct mt9m001 *mt9m001)
+-{
+-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+- return gpio_is_valid(mt9m001->switch_gpio);
+-#else
+- return 0;
+-#endif
+-}
+-
+ static int mt9m001_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+ {
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+- unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
+- int ret;
++ struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
++ unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
+
+- /* Flags validity verified in test_bus_param */
++ /* Only one width bit may be set */
++ if (!is_power_of_2(width_flag))
++ return -EINVAL;
+
+- if ((mt9m001->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
+- (mt9m001->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
+- (mt9m001->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
+- /* Well, we actually only can do 10 or 8 bits... */
+- if (width_flag == SOCAM_DATAWIDTH_9)
+- return -EINVAL;
+- ret = bus_switch_act(mt9m001,
+- width_flag == SOCAM_DATAWIDTH_8);
+- if (ret < 0)
+- return ret;
++ if (icl->set_bus_param)
++ return icl->set_bus_param(icl, width_flag);
+
+- mt9m001->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
+- }
++ /*
++ * Without board specific bus width settings we only support the
++ * sensors native bus width
++ */
++ if (width_flag == SOCAM_DATAWIDTH_10)
++ return 0;
+
+- return 0;
++ return -EINVAL;
+ }
+
+ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
+@@ -274,18 +207,20 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ /* MT9M001 has all capture_format parameters fixed */
+- unsigned long flags = SOCAM_DATAWIDTH_10 | SOCAM_PCLK_SAMPLE_RISING |
++ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+- SOCAM_MASTER;
++ SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER;
+
+- if (bus_switch_possible(mt9m001))
+- flags |= SOCAM_DATAWIDTH_8;
++ if (icl->query_bus_param)
++ flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK;
++ else
++ flags |= SOCAM_DATAWIDTH_10;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+ }
+
+-static int mt9m001_set_fmt(struct soc_camera_device *icd,
+- __u32 pixfmt, struct v4l2_rect *rect)
++static int mt9m001_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
+ {
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ int ret;
+@@ -324,6 +259,20 @@ static int mt9m001_set_fmt(struct soc_camera_device *icd,
+ return ret;
+ }
+
++static int mt9m001_set_fmt(struct soc_camera_device *icd,
++ struct v4l2_format *f)
++{
++ struct v4l2_rect rect = {
++ .left = icd->x_current,
++ .top = icd->y_current,
++ .width = f->fmt.pix.width,
++ .height = f->fmt.pix.height,
++ };
++
++ /* No support for scaling so far, just crop. TODO: use skipping */
++ return mt9m001_set_crop(icd, &rect);
++}
++
+ static int mt9m001_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+ {
+@@ -449,6 +398,7 @@ static struct soc_camera_ops mt9m001_ops = {
+ .release = mt9m001_release,
+ .start_capture = mt9m001_start_capture,
+ .stop_capture = mt9m001_stop_capture,
++ .set_crop = mt9m001_set_crop,
+ .set_fmt = mt9m001_set_fmt,
+ .try_fmt = mt9m001_try_fmt,
+ .set_bus_param = mt9m001_set_bus_param,
+@@ -583,6 +533,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
+ struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+ s32 data;
+ int ret;
++ unsigned long flags;
+
+ /* We must have a parent by now. And it cannot be a wrong one.
+ * So this entire test is completely redundant. */
+@@ -603,18 +554,10 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
+ case 0x8421:
+ mt9m001->model = V4L2_IDENT_MT9M001C12ST;
+ icd->formats = mt9m001_colour_formats;
+- if (gpio_is_valid(icl->gpio))
+- icd->num_formats = ARRAY_SIZE(mt9m001_colour_formats);
+- else
+- icd->num_formats = 1;
+ break;
+ case 0x8431:
+ mt9m001->model = V4L2_IDENT_MT9M001C12STM;
+ icd->formats = mt9m001_monochrome_formats;
+- if (gpio_is_valid(icl->gpio))
+- icd->num_formats = ARRAY_SIZE(mt9m001_monochrome_formats);
+- else
+- icd->num_formats = 1;
+ break;
+ default:
+ ret = -ENODEV;
+@@ -623,6 +566,26 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
+ goto ei2c;
+ }
+
++ icd->num_formats = 0;
++
++ /*
++ * This is a 10bit sensor, so by default we only allow 10bit.
++ * The platform may support different bus widths due to
++ * different routing of the data lines.
++ */
++ if (icl->query_bus_param)
++ flags = icl->query_bus_param(icl);
++ else
++ flags = SOCAM_DATAWIDTH_10;
++
++ if (flags & SOCAM_DATAWIDTH_10)
++ icd->num_formats++;
++ else
++ icd->formats++;
++
++ if (flags & SOCAM_DATAWIDTH_8)
++ icd->num_formats++;
++
+ dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
+ data == 0x8431 ? "C12STM" : "C12ST");
+
+@@ -688,18 +651,10 @@ static int mt9m001_probe(struct i2c_client *client,
+ icd->height_max = 1024;
+ icd->y_skip_top = 1;
+ icd->iface = icl->bus_id;
+- /* Default datawidth - this is the only width this camera (normally)
+- * supports. It is only with extra logic that it can support
+- * other widths. Therefore it seems to be a sensible default. */
+- mt9m001->datawidth = 10;
+ /* Simulated autoexposure. If enabled, we calculate shutter width
+ * ourselves in the driver based on vertical blanking and frame width */
+ mt9m001->autoexposure = 1;
+
+- ret = bus_switch_request(mt9m001, icl);
+- if (ret)
+- goto eswinit;
+-
+ ret = soc_camera_device_register(icd);
+ if (ret)
+ goto eisdr;
+@@ -707,8 +662,6 @@ static int mt9m001_probe(struct i2c_client *client,
+ return 0;
+
+ eisdr:
+- bus_switch_release(mt9m001);
+-eswinit:
+ kfree(mt9m001);
+ return ret;
+ }
+@@ -718,7 +671,6 @@ static int mt9m001_remove(struct i2c_client *client)
+ struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
+
+ soc_camera_device_unregister(&mt9m001->icd);
+- bus_switch_release(mt9m001);
+ kfree(mt9m001);
+
+ return 0;
+diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
+index 5b8e209..cdd1ddb 100644
+--- a/drivers/media/video/mt9m111.c
++++ b/drivers/media/video/mt9m111.c
+@@ -152,7 +152,7 @@ struct mt9m111 {
+ struct soc_camera_device icd;
+ int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
+ enum mt9m111_context context;
+- unsigned int left, top, width, height;
++ struct v4l2_rect rect;
+ u32 pixfmt;
+ unsigned char autoexposure;
+ unsigned char datawidth;
+@@ -249,12 +249,13 @@ static int mt9m111_set_context(struct soc_camera_device *icd,
+ return reg_write(CONTEXT_CONTROL, valA);
+ }
+
+-static int mt9m111_setup_rect(struct soc_camera_device *icd)
++static int mt9m111_setup_rect(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
+ {
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ int ret, is_raw_format;
+- int width = mt9m111->width;
+- int height = mt9m111->height;
++ int width = rect->width;
++ int height = rect->height;
+
+ if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8)
+ || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16))
+@@ -262,9 +263,9 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd)
+ else
+ is_raw_format = 0;
+
+- ret = reg_write(COLUMN_START, mt9m111->left);
++ ret = reg_write(COLUMN_START, rect->left);
+ if (!ret)
+- ret = reg_write(ROW_START, mt9m111->top);
++ ret = reg_write(ROW_START, rect->top);
+
+ if (is_raw_format) {
+ if (!ret)
+@@ -393,6 +394,8 @@ static int mt9m111_disable(struct soc_camera_device *icd)
+
+ static int mt9m111_reset(struct soc_camera_device *icd)
+ {
++ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
++ struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+ int ret;
+
+ ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+@@ -401,6 +404,10 @@ static int mt9m111_reset(struct soc_camera_device *icd)
+ if (!ret)
+ ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
+ | MT9M111_RESET_RESET_SOC);
++
++ if (icl->reset)
++ icl->reset(&mt9m111->client->dev);
++
+ return ret;
+ }
+
+@@ -420,7 +427,7 @@ static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
+ struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+ unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+- SOCAM_DATAWIDTH_8;
++ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+ }
+@@ -430,6 +437,22 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
+ return 0;
+ }
+
++static int mt9m111_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
++{
++ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
++ int ret;
++
++ dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
++ __func__, rect->left, rect->top, rect->width,
++ rect->height);
++
++ ret = mt9m111_setup_rect(icd, rect);
++ if (!ret)
++ mt9m111->rect = *rect;
++ return ret;
++}
++
+ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
+ {
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+@@ -480,23 +503,27 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
+ }
+
+ static int mt9m111_set_fmt(struct soc_camera_device *icd,
+- __u32 pixfmt, struct v4l2_rect *rect)
++ struct v4l2_format *f)
+ {
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ struct v4l2_rect rect = {
++ .left = mt9m111->rect.left,
++ .top = mt9m111->rect.top,
++ .width = pix->width,
++ .height = pix->height,
++ };
+ int ret;
+
+- mt9m111->left = rect->left;
+- mt9m111->top = rect->top;
+- mt9m111->width = rect->width;
+- mt9m111->height = rect->height;
+-
+ dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
+- __func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width,
+- mt9m111->height);
++ __func__, pix->pixelformat, rect.left, rect.top, rect.width,
++ rect.height);
+
+- ret = mt9m111_setup_rect(icd);
++ ret = mt9m111_setup_rect(icd, &rect);
++ if (!ret)
++ ret = mt9m111_set_pixfmt(icd, pix->pixelformat);
+ if (!ret)
+- ret = mt9m111_set_pixfmt(icd, pixfmt);
++ mt9m111->rect = rect;
+ return ret;
+ }
+
+@@ -627,6 +654,7 @@ static struct soc_camera_ops mt9m111_ops = {
+ .release = mt9m111_release,
+ .start_capture = mt9m111_start_capture,
+ .stop_capture = mt9m111_stop_capture,
++ .set_crop = mt9m111_set_crop,
+ .set_fmt = mt9m111_set_fmt,
+ .try_fmt = mt9m111_try_fmt,
+ .query_bus_param = mt9m111_query_bus_param,
+@@ -811,7 +839,7 @@ static int mt9m111_restore_state(struct soc_camera_device *icd)
+
+ mt9m111_set_context(icd, mt9m111->context);
+ mt9m111_set_pixfmt(icd, mt9m111->pixfmt);
+- mt9m111_setup_rect(icd);
++ mt9m111_setup_rect(icd, &mt9m111->rect);
+ mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
+ mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
+ mt9m111_set_global_gain(icd, icd->gain);
+diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
+index 349d8e3..23f9ce9 100644
+--- a/drivers/media/video/mt9t031.c
++++ b/drivers/media/video/mt9t031.c
+@@ -144,13 +144,11 @@ static int mt9t031_init(struct soc_camera_device *icd)
+ int ret;
+
+ /* Disable chip output, synchronous option update */
+- dev_dbg(icd->vdev->parent, "%s\n", __func__);
+-
+ ret = reg_write(icd, MT9T031_RESET, 1);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_RESET, 0);
+ if (ret >= 0)
+- ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
++ ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
+
+ return ret >= 0 ? 0 : -EIO;
+ }
+@@ -158,14 +156,14 @@ static int mt9t031_init(struct soc_camera_device *icd)
+ static int mt9t031_release(struct soc_camera_device *icd)
+ {
+ /* Disable the chip */
+- reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
++ reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
+ return 0;
+ }
+
+ static int mt9t031_start_capture(struct soc_camera_device *icd)
+ {
+ /* Switch to master "normal" mode */
+- if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
++ if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
+ return -EIO;
+ return 0;
+ }
+@@ -173,7 +171,7 @@ static int mt9t031_start_capture(struct soc_camera_device *icd)
+ static int mt9t031_stop_capture(struct soc_camera_device *icd)
+ {
+ /* Stop sensor readout */
+- if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
++ if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
+ return -EIO;
+ return 0;
+ }
+@@ -186,9 +184,9 @@ static int mt9t031_set_bus_param(struct soc_camera_device *icd,
+ return -EINVAL;
+
+ if (flags & SOCAM_PCLK_SAMPLE_FALLING)
+- reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+- else
+ reg_clear(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
++ else
++ reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+
+ return 0;
+ }
+@@ -201,67 +199,73 @@ static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
+ return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
+ }
+
+-static int mt9t031_set_fmt(struct soc_camera_device *icd,
+- __u32 pixfmt, struct v4l2_rect *rect)
++/* Round up minima and round down maxima */
++static void recalculate_limits(struct soc_camera_device *icd,
++ u16 xskip, u16 yskip)
++{
++ icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip;
++ icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip;
++ icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip;
++ icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip;
++ icd->width_max = MT9T031_MAX_WIDTH / xskip;
++ icd->height_max = MT9T031_MAX_HEIGHT / yskip;
++}
++
++static int mt9t031_set_params(struct soc_camera_device *icd,
++ struct v4l2_rect *rect, u16 xskip, u16 yskip)
+ {
+ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ int ret;
++ u16 xbin, ybin, width, height, left, top;
+ const u16 hblank = MT9T031_HORIZONTAL_BLANK,
+ vblank = MT9T031_VERTICAL_BLANK;
+- u16 xbin, xskip = mt9t031->xskip, ybin, yskip = mt9t031->yskip,
+- width = rect->width * xskip, height = rect->height * yskip;
+
+- if (pixfmt) {
+- /* S_FMT - use binning and skipping for scaling, recalculate */
+- /* Is this more optimal than just a division? */
+- for (xskip = 8; xskip > 1; xskip--)
+- if (rect->width * xskip <= icd->width_max)
+- break;
++ /* Make sure we don't exceed sensor limits */
++ if (rect->left + rect->width > icd->width_max)
++ rect->left = (icd->width_max - rect->width) / 2 + icd->x_min;
+
+- for (yskip = 8; yskip > 1; yskip--)
+- if (rect->height * yskip <= icd->height_max)
+- break;
++ if (rect->top + rect->height > icd->height_max)
++ rect->top = (icd->height_max - rect->height) / 2 + icd->y_min;
+
+- width = rect->width * xskip;
+- height = rect->height * yskip;
+-
+- dev_dbg(&icd->dev, "xskip %u, width %u, yskip %u, height %u\n",
+- xskip, width, yskip, height);
+- }
++ width = rect->width * xskip;
++ height = rect->height * yskip;
++ left = rect->left * xskip;
++ top = rect->top * yskip;
+
+ xbin = min(xskip, (u16)3);
+ ybin = min(yskip, (u16)3);
+
+- /* Make sure we don't exceed frame limits */
+- if (rect->left + width > icd->width_max)
+- rect->left = (icd->width_max - width) / 2;
+-
+- if (rect->top + height > icd->height_max)
+- rect->top = (icd->height_max - height) / 2;
++ dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n",
++ xskip, width, rect->width, yskip, height, rect->height);
+
+- /* Could just do roundup(rect->left, [xy]bin); but this is cheaper */
++ /* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */
+ switch (xbin) {
+ case 2:
+- rect->left = (rect->left + 1) & ~1;
++ left = (left + 3) & ~3;
+ break;
+ case 3:
+- rect->left = roundup(rect->left, 3);
++ left = roundup(left, 6);
+ }
+
+ switch (ybin) {
+ case 2:
+- rect->top = (rect->top + 1) & ~1;
++ top = (top + 3) & ~3;
+ break;
+ case 3:
+- rect->top = roundup(rect->top, 3);
++ top = roundup(top, 6);
+ }
+
++ /* Disable register update, reconfigure atomically */
++ ret = reg_set(icd, MT9T031_OUTPUT_CONTROL, 1);
++ if (ret < 0)
++ return ret;
++
+ /* Blanking and start values - default... */
+ ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank);
+
+- if (pixfmt) {
++ if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) {
+ /* Binning, skipping */
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE,
+@@ -270,14 +274,14 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
+ ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE,
+ ((ybin - 1) << 4) | (yskip - 1));
+ }
+- dev_dbg(&icd->dev, "new left %u, top %u\n", rect->left, rect->top);
++ dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top);
+
+ /* The caller provides a supported format, as guaranteed by
+ * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
+ if (ret >= 0)
+- ret = reg_write(icd, MT9T031_COLUMN_START, rect->left);
++ ret = reg_write(icd, MT9T031_COLUMN_START, left);
+ if (ret >= 0)
+- ret = reg_write(icd, MT9T031_ROW_START, rect->top);
++ ret = reg_write(icd, MT9T031_ROW_START, top);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1);
+ if (ret >= 0)
+@@ -297,12 +301,58 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
+ }
+ }
+
+- if (!ret && pixfmt) {
++ /* Re-enable register update, commit all changes */
++ if (ret >= 0)
++ ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1);
++
++ return ret < 0 ? ret : 0;
++}
++
++static int mt9t031_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
++{
++ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
++
++ /* CROP - no change in scaling, or in limits */
++ return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip);
++}
++
++static int mt9t031_set_fmt(struct soc_camera_device *icd,
++ struct v4l2_format *f)
++{
++ struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
++ int ret;
++ u16 xskip, yskip;
++ struct v4l2_rect rect = {
++ .left = icd->x_current,
++ .top = icd->y_current,
++ .width = f->fmt.pix.width,
++ .height = f->fmt.pix.height,
++ };
++
++ /*
++ * try_fmt has put rectangle within limits.
++ * S_FMT - use binning and skipping for scaling, recalculate
++ * limits, used for cropping
++ */
++ /* Is this more optimal than just a division? */
++ for (xskip = 8; xskip > 1; xskip--)
++ if (rect.width * xskip <= MT9T031_MAX_WIDTH)
++ break;
++
++ for (yskip = 8; yskip > 1; yskip--)
++ if (rect.height * yskip <= MT9T031_MAX_HEIGHT)
++ break;
++
++ recalculate_limits(icd, xskip, yskip);
++
++ ret = mt9t031_set_params(icd, &rect, xskip, yskip);
++ if (!ret) {
+ mt9t031->xskip = xskip;
+ mt9t031->yskip = yskip;
+ }
+
+- return ret < 0 ? ret : 0;
++ return ret;
+ }
+
+ static int mt9t031_try_fmt(struct soc_camera_device *icd,
+@@ -310,14 +360,14 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd,
+ {
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+- if (pix->height < icd->height_min)
+- pix->height = icd->height_min;
+- if (pix->height > icd->height_max)
+- pix->height = icd->height_max;
+- if (pix->width < icd->width_min)
+- pix->width = icd->width_min;
+- if (pix->width > icd->width_max)
+- pix->width = icd->width_max;
++ if (pix->height < MT9T031_MIN_HEIGHT)
++ pix->height = MT9T031_MIN_HEIGHT;
++ if (pix->height > MT9T031_MAX_HEIGHT)
++ pix->height = MT9T031_MAX_HEIGHT;
++ if (pix->width < MT9T031_MIN_WIDTH)
++ pix->width = MT9T031_MIN_WIDTH;
++ if (pix->width > MT9T031_MAX_WIDTH)
++ pix->width = MT9T031_MAX_WIDTH;
+
+ pix->width &= ~0x01; /* has to be even */
+ pix->height &= ~0x01; /* has to be even */
+@@ -390,6 +440,14 @@ static const struct v4l2_queryctrl mt9t031_controls[] = {
+ .step = 1,
+ .default_value = 0,
+ }, {
++ .id = V4L2_CID_HFLIP,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .name = "Flip Horizontally",
++ .minimum = 0,
++ .maximum = 1,
++ .step = 1,
++ .default_value = 0,
++ }, {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+@@ -431,6 +489,7 @@ static struct soc_camera_ops mt9t031_ops = {
+ .release = mt9t031_release,
+ .start_capture = mt9t031_start_capture,
+ .stop_capture = mt9t031_stop_capture,
++ .set_crop = mt9t031_set_crop,
+ .set_fmt = mt9t031_set_fmt,
+ .try_fmt = mt9t031_try_fmt,
+ .set_bus_param = mt9t031_set_bus_param,
+@@ -513,21 +572,23 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
+ if (data < 0)
+ return -EIO;
+ } else {
+- /* Pack it into 1.125..15 variable step, register values 9..67 */
++ /* Pack it into 1.125..128 variable step, register values 9..0x7860 */
+ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+ unsigned long range = qctrl->maximum - qctrl->default_value - 1;
++ /* calculated gain: map 65..127 to 9..1024 step 0.125 */
+ unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
+- 111 + range / 2) / range + 9;
++ 1015 + range / 2) / range + 9;
+
+- if (gain <= 32)
++ if (gain <= 32) /* calculated gain 9..32 -> 9..32 */
+ data = gain;
+- else if (gain <= 64)
++ else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */
+ data = ((gain - 32) * 16 + 16) / 32 + 80;
+ else
+- data = ((gain - 64) * 7 + 28) / 56 + 96;
++ /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */
++ data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
+
+- dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
+- reg_read(icd, MT9T031_GLOBAL_GAIN), data);
++ dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n",
++ reg_read(icd, MT9T031_GLOBAL_GAIN), data);
+ data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
+ if (data < 0)
+ return -EIO;
+diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
+index b04c8cb..4d3b481 100644
+--- a/drivers/media/video/mt9v022.c
++++ b/drivers/media/video/mt9v022.c
+@@ -13,7 +13,6 @@
+ #include <linux/i2c.h>
+ #include <linux/delay.h>
+ #include <linux/log2.h>
+-#include <linux/gpio.h>
+
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
+@@ -89,9 +88,7 @@ struct mt9v022 {
+ struct i2c_client *client;
+ struct soc_camera_device icd;
+ int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
+- int switch_gpio;
+ u16 chip_control;
+- unsigned char datawidth;
+ };
+
+ static int reg_read(struct soc_camera_device *icd, const u8 reg)
+@@ -209,66 +206,6 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd)
+ return 0;
+ }
+
+-static int bus_switch_request(struct mt9v022 *mt9v022, struct soc_camera_link *icl)
+-{
+-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+- int ret;
+- unsigned int gpio = icl->gpio;
+-
+- if (gpio_is_valid(gpio)) {
+- /* We have a data bus switch. */
+- ret = gpio_request(gpio, "mt9v022");
+- if (ret < 0) {
+- dev_err(&mt9v022->client->dev, "Cannot get GPIO %u\n", gpio);
+- return ret;
+- }
+-
+- ret = gpio_direction_output(gpio, 0);
+- if (ret < 0) {
+- dev_err(&mt9v022->client->dev,
+- "Cannot set GPIO %u to output\n", gpio);
+- gpio_free(gpio);
+- return ret;
+- }
+- }
+-
+- mt9v022->switch_gpio = gpio;
+-#else
+- mt9v022->switch_gpio = -EINVAL;
+-#endif
+- return 0;
+-}
+-
+-static void bus_switch_release(struct mt9v022 *mt9v022)
+-{
+-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+- if (gpio_is_valid(mt9v022->switch_gpio))
+- gpio_free(mt9v022->switch_gpio);
+-#endif
+-}
+-
+-static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
+-{
+-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+- if (!gpio_is_valid(mt9v022->switch_gpio))
+- return -ENODEV;
+-
+- gpio_set_value_cansleep(mt9v022->switch_gpio, go8bit);
+- return 0;
+-#else
+- return -ENODEV;
+-#endif
+-}
+-
+-static int bus_switch_possible(struct mt9v022 *mt9v022)
+-{
+-#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+- return gpio_is_valid(mt9v022->switch_gpio);
+-#else
+- return 0;
+-#endif
+-}
+-
+ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+ {
+@@ -282,19 +219,17 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
+ if (!is_power_of_2(width_flag))
+ return -EINVAL;
+
+- if ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
+- (mt9v022->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
+- (mt9v022->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
+- /* Well, we actually only can do 10 or 8 bits... */
+- if (width_flag == SOCAM_DATAWIDTH_9)
+- return -EINVAL;
+-
+- ret = bus_switch_act(mt9v022,
+- width_flag == SOCAM_DATAWIDTH_8);
+- if (ret < 0)
++ if (icl->set_bus_param) {
++ ret = icl->set_bus_param(icl, width_flag);
++ if (ret)
+ return ret;
+-
+- mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
++ } else {
++ /*
++ * Without board specific bus width settings we only support the
++ * sensors native bus width
++ */
++ if (width_flag != SOCAM_DATAWIDTH_10)
++ return -EINVAL;
+ }
+
+ flags = soc_camera_apply_sensor_flags(icl, flags);
+@@ -328,44 +263,27 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
+ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
+ {
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+- unsigned int width_flag = SOCAM_DATAWIDTH_10;
++ struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
++ unsigned int width_flag;
+
+- if (bus_switch_possible(mt9v022))
+- width_flag |= SOCAM_DATAWIDTH_8;
++ if (icl->query_bus_param)
++ width_flag = icl->query_bus_param(icl) &
++ SOCAM_DATAWIDTH_MASK;
++ else
++ width_flag = SOCAM_DATAWIDTH_10;
+
+ return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
+- SOCAM_MASTER | SOCAM_SLAVE |
++ SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_SLAVE |
+ width_flag;
+ }
+
+-static int mt9v022_set_fmt(struct soc_camera_device *icd,
+- __u32 pixfmt, struct v4l2_rect *rect)
++static int mt9v022_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
+ {
+- struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ int ret;
+
+- /* The caller provides a supported format, as verified per call to
+- * icd->try_fmt(), datawidth is from our supported format list */
+- switch (pixfmt) {
+- case V4L2_PIX_FMT_GREY:
+- case V4L2_PIX_FMT_Y16:
+- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+- return -EINVAL;
+- break;
+- case V4L2_PIX_FMT_SBGGR8:
+- case V4L2_PIX_FMT_SBGGR16:
+- if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+- return -EINVAL;
+- break;
+- case 0:
+- /* No format change, only geometry */
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+ /* Like in example app. Contradicts the datasheet though */
+ ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+ if (ret >= 0) {
+@@ -403,6 +321,42 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd,
+ return 0;
+ }
+
++static int mt9v022_set_fmt(struct soc_camera_device *icd,
++ struct v4l2_format *f)
++{
++ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ struct v4l2_rect rect = {
++ .left = icd->x_current,
++ .top = icd->y_current,
++ .width = pix->width,
++ .height = pix->height,
++ };
++
++ /* The caller provides a supported format, as verified per call to
++ * icd->try_fmt(), datawidth is from our supported format list */
++ switch (pix->pixelformat) {
++ case V4L2_PIX_FMT_GREY:
++ case V4L2_PIX_FMT_Y16:
++ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
++ return -EINVAL;
++ break;
++ case V4L2_PIX_FMT_SBGGR8:
++ case V4L2_PIX_FMT_SBGGR16:
++ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
++ return -EINVAL;
++ break;
++ case 0:
++ /* No format change, only geometry */
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ /* No support for scaling on this camera, just crop. */
++ return mt9v022_set_crop(icd, &rect);
++}
++
+ static int mt9v022_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+ {
+@@ -544,6 +498,7 @@ static struct soc_camera_ops mt9v022_ops = {
+ .release = mt9v022_release,
+ .start_capture = mt9v022_start_capture,
+ .stop_capture = mt9v022_stop_capture,
++ .set_crop = mt9v022_set_crop,
+ .set_fmt = mt9v022_set_fmt,
+ .try_fmt = mt9v022_try_fmt,
+ .set_bus_param = mt9v022_set_bus_param,
+@@ -699,6 +654,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
+ struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+ s32 data;
+ int ret;
++ unsigned long flags;
+
+ if (!icd->dev.parent ||
+ to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+@@ -732,22 +688,36 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
+ ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
+ mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+ icd->formats = mt9v022_colour_formats;
+- if (gpio_is_valid(icl->gpio))
+- icd->num_formats = ARRAY_SIZE(mt9v022_colour_formats);
+- else
+- icd->num_formats = 1;
+ } else {
+ ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
+ mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+ icd->formats = mt9v022_monochrome_formats;
+- if (gpio_is_valid(icl->gpio))
+- icd->num_formats = ARRAY_SIZE(mt9v022_monochrome_formats);
+- else
+- icd->num_formats = 1;
+ }
+
+- if (!ret)
+- ret = soc_camera_video_start(icd);
++ if (ret < 0)
++ goto eisis;
++
++ icd->num_formats = 0;
++
++ /*
++ * This is a 10bit sensor, so by default we only allow 10bit.
++ * The platform may support different bus widths due to
++ * different routing of the data lines.
++ */
++ if (icl->query_bus_param)
++ flags = icl->query_bus_param(icl);
++ else
++ flags = SOCAM_DATAWIDTH_10;
++
++ if (flags & SOCAM_DATAWIDTH_10)
++ icd->num_formats++;
++ else
++ icd->formats++;
++
++ if (flags & SOCAM_DATAWIDTH_8)
++ icd->num_formats++;
++
++ ret = soc_camera_video_start(icd);
+ if (ret < 0)
+ goto eisis;
+
+@@ -812,14 +782,6 @@ static int mt9v022_probe(struct i2c_client *client,
+ icd->height_max = 480;
+ icd->y_skip_top = 1;
+ icd->iface = icl->bus_id;
+- /* Default datawidth - this is the only width this camera (normally)
+- * supports. It is only with extra logic that it can support
+- * other widths. Therefore it seems to be a sensible default. */
+- mt9v022->datawidth = 10;
+-
+- ret = bus_switch_request(mt9v022, icl);
+- if (ret)
+- goto eswinit;
+
+ ret = soc_camera_device_register(icd);
+ if (ret)
+@@ -828,8 +790,6 @@ static int mt9v022_probe(struct i2c_client *client,
+ return 0;
+
+ eisdr:
+- bus_switch_release(mt9v022);
+-eswinit:
+ kfree(mt9v022);
+ return ret;
+ }
+@@ -839,7 +799,6 @@ static int mt9v022_remove(struct i2c_client *client)
+ struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
+
+ soc_camera_device_unregister(&mt9v022->icd);
+- bus_switch_release(mt9v022);
+ kfree(mt9v022);
+
+ return 0;
+diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
+new file mode 100644
+index 0000000..70629e1
+--- /dev/null
++++ b/drivers/media/video/mx3_camera.c
+@@ -0,0 +1,1220 @@
++/*
++ * V4L2 Driver for i.MX3x camera host
++ *
++ * Copyright (C) 2008
++ * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/videodev2.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/vmalloc.h>
++#include <linux/interrupt.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-dev.h>
++#include <media/videobuf-dma-contig.h>
++#include <media/soc_camera.h>
++
++#include <mach/ipu.h>
++#include <mach/mx3_camera.h>
++
++#define MX3_CAM_DRV_NAME "mx3-camera"
++
++/* CMOS Sensor Interface Registers */
++#define CSI_REG_START 0x60
++
++#define CSI_SENS_CONF (0x60 - CSI_REG_START)
++#define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START)
++#define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START)
++#define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START)
++#define CSI_TST_CTRL (0x70 - CSI_REG_START)
++#define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START)
++#define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START)
++#define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START)
++#define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START)
++#define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START)
++
++#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
++#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
++#define CSI_SENS_CONF_DATA_POL_SHIFT 2
++#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
++#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
++#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7
++#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
++#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10
++#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
++#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
++
++#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
++#define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
++#define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
++
++#define MAX_VIDEO_MEM 16
++
++struct mx3_camera_buffer {
++ /* common v4l buffer stuff -- must be first */
++ struct videobuf_buffer vb;
++ const struct soc_camera_data_format *fmt;
++
++ /* One descriptot per scatterlist (per frame) */
++ struct dma_async_tx_descriptor *txd;
++
++ /* We have to "build" a scatterlist ourselves - one element per frame */
++ struct scatterlist sg;
++};
++
++/**
++ * struct mx3_camera_dev - i.MX3x camera (CSI) object
++ * @dev: camera device, to which the coherent buffer is attached
++ * @icd: currently attached camera sensor
++ * @clk: pointer to clock
++ * @base: remapped register base address
++ * @pdata: platform data
++ * @platform_flags: platform flags
++ * @mclk: master clock frequency in Hz
++ * @capture: list of capture videobuffers
++ * @lock: protects video buffer lists
++ * @active: active video buffer
++ * @idmac_channel: array of pointers to IPU DMAC DMA channels
++ * @soc_host: embedded soc_host object
++ */
++struct mx3_camera_dev {
++ struct device *dev;
++ /*
++ * i.MX3x is only supposed to handle one camera on its Camera Sensor
++ * Interface. If anyone ever builds hardware to enable more than one
++ * camera _simultaneously_, they will have to modify this driver too
++ */
++ struct soc_camera_device *icd;
++ struct clk *clk;
++
++ void __iomem *base;
++
++ struct mx3_camera_pdata *pdata;
++
++ unsigned long platform_flags;
++ unsigned long mclk;
++
++ struct list_head capture;
++ spinlock_t lock; /* Protects video buffer lists */
++ struct mx3_camera_buffer *active;
++
++ /* IDMAC / dmaengine interface */
++ struct idmac_channel *idmac_channel[1]; /* We need one channel */
++
++ struct soc_camera_host soc_host;
++};
++
++struct dma_chan_request {
++ struct mx3_camera_dev *mx3_cam;
++ enum ipu_channel id;
++};
++
++static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt);
++
++static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg)
++{
++ return __raw_readl(mx3->base + reg);
++}
++
++static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg)
++{
++ __raw_writel(value, mx3->base + reg);
++}
++
++/* Called from the IPU IDMAC ISR */
++static void mx3_cam_dma_done(void *arg)
++{
++ struct idmac_tx_desc *desc = to_tx_desc(arg);
++ struct dma_chan *chan = desc->txd.chan;
++ struct idmac_channel *ichannel = to_idmac_chan(chan);
++ struct mx3_camera_dev *mx3_cam = ichannel->client;
++ struct videobuf_buffer *vb;
++
++ dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
++ desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0);
++
++ spin_lock(&mx3_cam->lock);
++ if (mx3_cam->active) {
++ vb = &mx3_cam->active->vb;
++
++ list_del_init(&vb->queue);
++ vb->state = VIDEOBUF_DONE;
++ do_gettimeofday(&vb->ts);
++ vb->field_count++;
++ wake_up(&vb->done);
++ }
++
++ if (list_empty(&mx3_cam->capture)) {
++ mx3_cam->active = NULL;
++ spin_unlock(&mx3_cam->lock);
++
++ /*
++ * stop capture - without further buffers IPU_CHA_BUF0_RDY will
++ * not get updated
++ */
++ return;
++ }
++
++ mx3_cam->active = list_entry(mx3_cam->capture.next,
++ struct mx3_camera_buffer, vb.queue);
++ mx3_cam->active->vb.state = VIDEOBUF_ACTIVE;
++ spin_unlock(&mx3_cam->lock);
++}
++
++static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf)
++{
++ struct soc_camera_device *icd = vq->priv_data;
++ struct videobuf_buffer *vb = &buf->vb;
++ struct dma_async_tx_descriptor *txd = buf->txd;
++ struct idmac_channel *ichan;
++
++ BUG_ON(in_interrupt());
++
++ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
++ vb, vb->baddr, vb->bsize);
++
++ /*
++ * This waits until this buffer is out of danger, i.e., until it is no
++ * longer in STATE_QUEUED or STATE_ACTIVE
++ */
++ videobuf_waiton(vb, 0, 0);
++ if (txd) {
++ ichan = to_idmac_chan(txd->chan);
++ async_tx_ack(txd);
++ }
++ videobuf_dma_contig_free(vq, vb);
++ buf->txd = NULL;
++
++ vb->state = VIDEOBUF_NEEDS_INIT;
++}
++
++/*
++ * Videobuf operations
++ */
++
++/*
++ * Calculate the __buffer__ (not data) size and number of buffers.
++ * Called with .vb_lock held
++ */
++static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
++ unsigned int *size)
++{
++ struct soc_camera_device *icd = vq->priv_data;
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ /*
++ * bits-per-pixel (depth) as specified in camera's pixel format does
++ * not necessarily match what the camera interface writes to RAM, but
++ * it should be good enough for now.
++ */
++ unsigned int bpp = DIV_ROUND_UP(icd->current_fmt->depth, 8);
++
++ if (!mx3_cam->idmac_channel[0])
++ return -EINVAL;
++
++ *size = icd->width * icd->height * bpp;
++
++ if (!*count)
++ *count = 32;
++
++ if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
++ *count = MAX_VIDEO_MEM * 1024 * 1024 / *size;
++
++ return 0;
++}
++
++/* Called with .vb_lock held */
++static int mx3_videobuf_prepare(struct videobuf_queue *vq,
++ struct videobuf_buffer *vb, enum v4l2_field field)
++{
++ struct soc_camera_device *icd = vq->priv_data;
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ struct mx3_camera_buffer *buf =
++ container_of(vb, struct mx3_camera_buffer, vb);
++ /* current_fmt _must_ always be set */
++ size_t new_size = icd->width * icd->height *
++ ((icd->current_fmt->depth + 7) >> 3);
++ int ret;
++
++ /*
++ * I think, in buf_prepare you only have to protect global data,
++ * the actual buffer is yours
++ */
++
++ if (buf->fmt != icd->current_fmt ||
++ vb->width != icd->width ||
++ vb->height != icd->height ||
++ vb->field != field) {
++ buf->fmt = icd->current_fmt;
++ vb->width = icd->width;
++ vb->height = icd->height;
++ vb->field = field;
++ if (vb->state != VIDEOBUF_NEEDS_INIT)
++ free_buffer(vq, buf);
++ }
++
++ if (vb->baddr && vb->bsize < new_size) {
++ /* User provided buffer, but it is too small */
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ if (vb->state == VIDEOBUF_NEEDS_INIT) {
++ struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
++ struct scatterlist *sg = &buf->sg;
++
++ /*
++ * The total size of video-buffers that will be allocated / mapped.
++ * *size that we calculated in videobuf_setup gets assigned to
++ * vb->bsize, and now we use the same calculation to get vb->size.
++ */
++ vb->size = new_size;
++
++ /* This actually (allocates and) maps buffers */
++ ret = videobuf_iolock(vq, vb, NULL);
++ if (ret)
++ goto fail;
++
++ /*
++ * We will have to configure the IDMAC channel. It has two slots
++ * for DMA buffers, we shall enter the first two buffers there,
++ * and then submit new buffers in DMA-ready interrupts
++ */
++ sg_init_table(sg, 1);
++ sg_dma_address(sg) = videobuf_to_dma_contig(vb);
++ sg_dma_len(sg) = vb->size;
++
++ buf->txd = ichan->dma_chan.device->device_prep_slave_sg(
++ &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE,
++ DMA_PREP_INTERRUPT);
++ if (!buf->txd) {
++ ret = -EIO;
++ goto fail;
++ }
++
++ buf->txd->callback_param = buf->txd;
++ buf->txd->callback = mx3_cam_dma_done;
++
++ vb->state = VIDEOBUF_PREPARED;
++ }
++
++ return 0;
++
++fail:
++ free_buffer(vq, buf);
++out:
++ return ret;
++}
++
++static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
++{
++ /* Add more formats as need arises and test possibilities appear... */
++ switch (fourcc) {
++ case V4L2_PIX_FMT_RGB565:
++ return IPU_PIX_FMT_RGB565;
++ case V4L2_PIX_FMT_RGB24:
++ return IPU_PIX_FMT_RGB24;
++ case V4L2_PIX_FMT_RGB332:
++ return IPU_PIX_FMT_RGB332;
++ case V4L2_PIX_FMT_YUV422P:
++ return IPU_PIX_FMT_YVU422P;
++ default:
++ return IPU_PIX_FMT_GENERIC;
++ }
++}
++
++/* Called with .vb_lock held */
++static void mx3_videobuf_queue(struct videobuf_queue *vq,
++ struct videobuf_buffer *vb)
++{
++ struct soc_camera_device *icd = vq->priv_data;
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ struct mx3_camera_buffer *buf =
++ container_of(vb, struct mx3_camera_buffer, vb);
++ struct dma_async_tx_descriptor *txd = buf->txd;
++ struct idmac_channel *ichan = to_idmac_chan(txd->chan);
++ struct idmac_video_param *video = &ichan->params.video;
++ const struct soc_camera_data_format *data_fmt = icd->current_fmt;
++ dma_cookie_t cookie;
++ unsigned long flags;
++
++ /* This is the configuration of one sg-element */
++ video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc);
++ video->out_width = icd->width;
++ video->out_height = icd->height;
++ video->out_stride = icd->width;
++
++#ifdef DEBUG
++ /* helps to see what DMA actually has written */
++ memset((void *)vb->baddr, 0xaa, vb->bsize);
++#endif
++
++ spin_lock_irqsave(&mx3_cam->lock, flags);
++
++ list_add_tail(&vb->queue, &mx3_cam->capture);
++
++ if (!mx3_cam->active) {
++ mx3_cam->active = buf;
++ vb->state = VIDEOBUF_ACTIVE;
++ } else {
++ vb->state = VIDEOBUF_QUEUED;
++ }
++
++ spin_unlock_irqrestore(&mx3_cam->lock, flags);
++
++ cookie = txd->tx_submit(txd);
++ dev_dbg(&icd->dev, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg));
++ if (cookie >= 0)
++ return;
++
++ /* Submit error */
++ vb->state = VIDEOBUF_PREPARED;
++
++ spin_lock_irqsave(&mx3_cam->lock, flags);
++
++ list_del_init(&vb->queue);
++
++ if (mx3_cam->active == buf)
++ mx3_cam->active = NULL;
++
++ spin_unlock_irqrestore(&mx3_cam->lock, flags);
++}
++
++/* Called with .vb_lock held */
++static void mx3_videobuf_release(struct videobuf_queue *vq,
++ struct videobuf_buffer *vb)
++{
++ struct soc_camera_device *icd = vq->priv_data;
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ struct mx3_camera_buffer *buf =
++ container_of(vb, struct mx3_camera_buffer, vb);
++ unsigned long flags;
++
++ dev_dbg(&icd->dev, "Release%s DMA 0x%08x (state %d), queue %sempty\n",
++ mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
++ vb->state, list_empty(&vb->queue) ? "" : "not ");
++ spin_lock_irqsave(&mx3_cam->lock, flags);
++ if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
++ !list_empty(&vb->queue)) {
++ vb->state = VIDEOBUF_ERROR;
++
++ list_del_init(&vb->queue);
++ if (mx3_cam->active == buf)
++ mx3_cam->active = NULL;
++ }
++ spin_unlock_irqrestore(&mx3_cam->lock, flags);
++ free_buffer(vq, buf);
++}
++
++static struct videobuf_queue_ops mx3_videobuf_ops = {
++ .buf_setup = mx3_videobuf_setup,
++ .buf_prepare = mx3_videobuf_prepare,
++ .buf_queue = mx3_videobuf_queue,
++ .buf_release = mx3_videobuf_release,
++};
++
++static void mx3_camera_init_videobuf(struct videobuf_queue *q,
++ struct soc_camera_device *icd)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++
++ videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, mx3_cam->dev,
++ &mx3_cam->lock,
++ V4L2_BUF_TYPE_VIDEO_CAPTURE,
++ V4L2_FIELD_NONE,
++ sizeof(struct mx3_camera_buffer), icd);
++}
++
++/* First part of ipu_csi_init_interface() */
++static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
++ struct soc_camera_device *icd)
++{
++ u32 conf;
++ long rate;
++
++ /* Set default size: ipu_csi_set_window_size() */
++ csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE);
++ /* ...and position to 0:0: ipu_csi_set_window_pos() */
++ conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
++ csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL);
++
++ /* We use only gated clock synchronisation mode so far */
++ conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT;
++
++ /* Set generic data, platform-biggest bus-width */
++ conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
++
++ if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
++ conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
++ else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
++ conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
++ else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
++ conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
++ else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/
++ conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
++
++ if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC)
++ conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT;
++ if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC)
++ conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT;
++ if (mx3_cam->platform_flags & MX3_CAMERA_DP)
++ conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
++ if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
++ conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
++ if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
++ conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
++ if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
++ conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
++
++ /* ipu_csi_init_interface() */
++ csi_reg_write(mx3_cam, conf, CSI_SENS_CONF);
++
++ clk_enable(mx3_cam->clk);
++ rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
++ dev_dbg(&icd->dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
++ if (rate)
++ clk_set_rate(mx3_cam->clk, rate);
++}
++
++/* Called with .video_lock held */
++static int mx3_camera_add_device(struct soc_camera_device *icd)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ int ret;
++
++ if (mx3_cam->icd) {
++ ret = -EBUSY;
++ goto ebusy;
++ }
++
++ mx3_camera_activate(mx3_cam, icd);
++ ret = icd->ops->init(icd);
++ if (ret < 0) {
++ clk_disable(mx3_cam->clk);
++ goto einit;
++ }
++
++ mx3_cam->icd = icd;
++
++einit:
++ebusy:
++ if (!ret)
++ dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n",
++ icd->devnum);
++
++ return ret;
++}
++
++/* Called with .video_lock held */
++static void mx3_camera_remove_device(struct soc_camera_device *icd)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
++
++ BUG_ON(icd != mx3_cam->icd);
++
++ if (*ichan) {
++ dma_release_channel(&(*ichan)->dma_chan);
++ *ichan = NULL;
++ }
++
++ icd->ops->release(icd);
++
++ clk_disable(mx3_cam->clk);
++
++ mx3_cam->icd = NULL;
++
++ dev_info(&icd->dev, "MX3 Camera driver detached from camera %d\n",
++ icd->devnum);
++}
++
++static bool channel_change_requested(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
++
++ /* Do buffers have to be re-allocated or channel re-configured? */
++ return ichan && rect->width * rect->height > icd->width * icd->height;
++}
++
++static int test_platform_param(struct mx3_camera_dev *mx3_cam,
++ unsigned char buswidth, unsigned long *flags)
++{
++ /*
++ * Platform specified synchronization and pixel clock polarities are
++ * only a recommendation and are only used during probing. MX3x
++ * camera interface only works in master mode, i.e., uses HSYNC and
++ * VSYNC signals from the sensor
++ */
++ *flags = SOCAM_MASTER |
++ SOCAM_HSYNC_ACTIVE_HIGH |
++ SOCAM_HSYNC_ACTIVE_LOW |
++ SOCAM_VSYNC_ACTIVE_HIGH |
++ SOCAM_VSYNC_ACTIVE_LOW |
++ SOCAM_PCLK_SAMPLE_RISING |
++ SOCAM_PCLK_SAMPLE_FALLING |
++ SOCAM_DATA_ACTIVE_HIGH |
++ SOCAM_DATA_ACTIVE_LOW;
++
++ /* If requested data width is supported by the platform, use it or any
++ * possible lower value - i.MX31 is smart enough to schift bits */
++ switch (buswidth) {
++ case 15:
++ if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15))
++ return -EINVAL;
++ *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 |
++ SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4;
++ break;
++ case 10:
++ if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10))
++ return -EINVAL;
++ *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 |
++ SOCAM_DATAWIDTH_4;
++ break;
++ case 8:
++ if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8))
++ return -EINVAL;
++ *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4;
++ break;
++ case 4:
++ if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4))
++ return -EINVAL;
++ *flags |= SOCAM_DATAWIDTH_4;
++ break;
++ default:
++ dev_info(mx3_cam->dev, "Unsupported bus width %d\n", buswidth);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
++ const unsigned int depth)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ unsigned long bus_flags, camera_flags;
++ int ret = test_platform_param(mx3_cam, depth, &bus_flags);
++
++ dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", depth, ret);
++
++ if (ret < 0)
++ return ret;
++
++ camera_flags = icd->ops->query_bus_param(icd);
++
++ ret = soc_camera_bus_param_compatible(camera_flags, bus_flags);
++ if (ret < 0)
++ dev_warn(&icd->dev, "Flags incompatible: camera %lx, host %lx\n",
++ camera_flags, bus_flags);
++
++ return ret;
++}
++
++static bool chan_filter(struct dma_chan *chan, void *arg)
++{
++ struct dma_chan_request *rq = arg;
++ struct mx3_camera_pdata *pdata;
++
++ if (!rq)
++ return false;
++
++ pdata = rq->mx3_cam->dev->platform_data;
++
++ return rq->id == chan->chan_id &&
++ pdata->dma_dev == chan->device->dev;
++}
++
++static const struct soc_camera_data_format mx3_camera_formats[] = {
++ {
++ .name = "Bayer (sRGB) 8 bit",
++ .depth = 8,
++ .fourcc = V4L2_PIX_FMT_SBGGR8,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ }, {
++ .name = "Monochrome 8 bit",
++ .depth = 8,
++ .fourcc = V4L2_PIX_FMT_GREY,
++ .colorspace = V4L2_COLORSPACE_JPEG,
++ },
++};
++
++static bool buswidth_supported(struct soc_camera_host *ici, int depth)
++{
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++
++ switch (depth) {
++ case 4:
++ return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4);
++ case 8:
++ return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8);
++ case 10:
++ return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10);
++ case 15:
++ return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15);
++ }
++ return false;
++}
++
++static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
++ struct soc_camera_format_xlate *xlate)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ int formats = 0, buswidth, ret;
++
++ buswidth = icd->formats[idx].depth;
++
++ if (!buswidth_supported(ici, buswidth))
++ return 0;
++
++ ret = mx3_camera_try_bus_param(icd, buswidth);
++ if (ret < 0)
++ return 0;
++
++ switch (icd->formats[idx].fourcc) {
++ case V4L2_PIX_FMT_SGRBG10:
++ formats++;
++ if (xlate) {
++ xlate->host_fmt = &mx3_camera_formats[0];
++ xlate->cam_fmt = icd->formats + idx;
++ xlate->buswidth = buswidth;
++ xlate++;
++ dev_dbg(&ici->dev, "Providing format %s using %s\n",
++ mx3_camera_formats[0].name,
++ icd->formats[idx].name);
++ }
++ goto passthrough;
++ case V4L2_PIX_FMT_Y16:
++ formats++;
++ if (xlate) {
++ xlate->host_fmt = &mx3_camera_formats[1];
++ xlate->cam_fmt = icd->formats + idx;
++ xlate->buswidth = buswidth;
++ xlate++;
++ dev_dbg(&ici->dev, "Providing format %s using %s\n",
++ mx3_camera_formats[0].name,
++ icd->formats[idx].name);
++ }
++ default:
++passthrough:
++ /* Generic pass-through */
++ formats++;
++ if (xlate) {
++ xlate->host_fmt = icd->formats + idx;
++ xlate->cam_fmt = icd->formats + idx;
++ xlate->buswidth = buswidth;
++ xlate++;
++ dev_dbg(&ici->dev,
++ "Providing format %s in pass-through mode\n",
++ icd->formats[idx].name);
++ }
++ }
++
++ return formats;
++}
++
++static void configure_geometry(struct mx3_camera_dev *mx3_cam,
++ struct v4l2_rect *rect)
++{
++ u32 ctrl, width_field, height_field;
++
++ /* Setup frame size - this cannot be changed on-the-fly... */
++ width_field = rect->width - 1;
++ height_field = rect->height - 1;
++ csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE);
++
++ csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1);
++ csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2);
++
++ csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE);
++
++ /* ...and position */
++ ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
++ /* Sensor does the cropping */
++ csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL);
++
++ /*
++ * No need to free resources here if we fail, we'll see if we need to
++ * do this next time we are called
++ */
++}
++
++static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
++{
++ dma_cap_mask_t mask;
++ struct dma_chan *chan;
++ struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
++ /* We have to use IDMAC_IC_7 for Bayer / generic data */
++ struct dma_chan_request rq = {.mx3_cam = mx3_cam,
++ .id = IDMAC_IC_7};
++
++ if (*ichan) {
++ struct videobuf_buffer *vb, *_vb;
++ dma_release_channel(&(*ichan)->dma_chan);
++ *ichan = NULL;
++ mx3_cam->active = NULL;
++ list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) {
++ list_del_init(&vb->queue);
++ vb->state = VIDEOBUF_ERROR;
++ wake_up(&vb->done);
++ }
++ }
++
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_SLAVE, mask);
++ dma_cap_set(DMA_PRIVATE, mask);
++ chan = dma_request_channel(mask, chan_filter, &rq);
++ if (!chan)
++ return -EBUSY;
++
++ *ichan = to_idmac_chan(chan);
++ (*ichan)->client = mx3_cam;
++
++ return 0;
++}
++
++static int mx3_camera_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++
++ /*
++ * We now know pixel formats and can decide upon DMA-channel(s)
++ * So far only direct camera-to-memory is supported
++ */
++ if (channel_change_requested(icd, rect)) {
++ int ret = acquire_dma_channel(mx3_cam);
++ if (ret < 0)
++ return ret;
++ }
++
++ configure_geometry(mx3_cam, rect);
++
++ return icd->ops->set_crop(icd, rect);
++}
++
++static int mx3_camera_set_fmt(struct soc_camera_device *icd,
++ struct v4l2_format *f)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ const struct soc_camera_format_xlate *xlate;
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ struct v4l2_rect rect = {
++ .left = icd->x_current,
++ .top = icd->y_current,
++ .width = pix->width,
++ .height = pix->height,
++ };
++ int ret;
++
++ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
++ if (!xlate) {
++ dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
++ return -EINVAL;
++ }
++
++ ret = acquire_dma_channel(mx3_cam);
++ if (ret < 0)
++ return ret;
++
++ /*
++ * Might have to perform a complete interface initialisation like in
++ * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
++ * mxc_v4l2_s_fmt()
++ */
++
++ configure_geometry(mx3_cam, &rect);
++
++ ret = icd->ops->set_fmt(icd, f);
++ if (!ret) {
++ icd->buswidth = xlate->buswidth;
++ icd->current_fmt = xlate->host_fmt;
++ }
++
++ return ret;
++}
++
++static int mx3_camera_try_fmt(struct soc_camera_device *icd,
++ struct v4l2_format *f)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ const struct soc_camera_format_xlate *xlate;
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ __u32 pixfmt = pix->pixelformat;
++ enum v4l2_field field;
++ int ret;
++
++ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
++ if (pixfmt && !xlate) {
++ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
++ return -EINVAL;
++ }
++
++ /* limit to MX3 hardware capabilities */
++ if (pix->height > 4096)
++ pix->height = 4096;
++ if (pix->width > 4096)
++ pix->width = 4096;
++
++ pix->bytesperline = pix->width *
++ DIV_ROUND_UP(xlate->host_fmt->depth, 8);
++ pix->sizeimage = pix->height * pix->bytesperline;
++
++ /* camera has to see its format, but the user the original one */
++ pix->pixelformat = xlate->cam_fmt->fourcc;
++ /* limit to sensor capabilities */
++ ret = icd->ops->try_fmt(icd, f);
++ pix->pixelformat = xlate->host_fmt->fourcc;
++
++ field = pix->field;
++
++ if (field == V4L2_FIELD_ANY) {
++ pix->field = V4L2_FIELD_NONE;
++ } else if (field != V4L2_FIELD_NONE) {
++ dev_err(&icd->dev, "Field type %d unsupported.\n", field);
++ return -EINVAL;
++ }
++
++ return ret;
++}
++
++static int mx3_camera_reqbufs(struct soc_camera_file *icf,
++ struct v4l2_requestbuffers *p)
++{
++ return 0;
++}
++
++static unsigned int mx3_camera_poll(struct file *file, poll_table *pt)
++{
++ struct soc_camera_file *icf = file->private_data;
++
++ return videobuf_poll_stream(file, &icf->vb_vidq, pt);
++}
++
++static int mx3_camera_querycap(struct soc_camera_host *ici,
++ struct v4l2_capability *cap)
++{
++ /* cap->name is set by the firendly caller:-> */
++ strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card));
++ cap->version = KERNEL_VERSION(0, 2, 2);
++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
++
++ return 0;
++}
++
++static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct mx3_camera_dev *mx3_cam = ici->priv;
++ unsigned long bus_flags, camera_flags, common_flags;
++ u32 dw, sens_conf;
++ int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags);
++ const struct soc_camera_format_xlate *xlate;
++
++ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
++ if (!xlate) {
++ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
++ return -EINVAL;
++ }
++
++ dev_dbg(&ici->dev, "requested bus width %d bit: %d\n",
++ icd->buswidth, ret);
++
++ if (ret < 0)
++ return ret;
++
++ camera_flags = icd->ops->query_bus_param(icd);
++
++ common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
++ if (!common_flags) {
++ dev_dbg(&ici->dev, "no common flags: camera %lx, host %lx\n",
++ camera_flags, bus_flags);
++ return -EINVAL;
++ }
++
++ /* Make choices, based on platform preferences */
++ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
++ (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
++ if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
++ common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
++ else
++ common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
++ }
++
++ if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
++ (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
++ if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
++ common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
++ else
++ common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
++ }
++
++ if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) &&
++ (common_flags & SOCAM_DATA_ACTIVE_LOW)) {
++ if (mx3_cam->platform_flags & MX3_CAMERA_DP)
++ common_flags &= ~SOCAM_DATA_ACTIVE_HIGH;
++ else
++ common_flags &= ~SOCAM_DATA_ACTIVE_LOW;
++ }
++
++ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
++ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
++ if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
++ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
++ else
++ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
++ }
++
++ /* Make the camera work in widest common mode, we'll take care of
++ * the rest */
++ if (common_flags & SOCAM_DATAWIDTH_15)
++ common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
++ SOCAM_DATAWIDTH_15;
++ else if (common_flags & SOCAM_DATAWIDTH_10)
++ common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
++ SOCAM_DATAWIDTH_10;
++ else if (common_flags & SOCAM_DATAWIDTH_8)
++ common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
++ SOCAM_DATAWIDTH_8;
++ else
++ common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
++ SOCAM_DATAWIDTH_4;
++
++ ret = icd->ops->set_bus_param(icd, common_flags);
++ if (ret < 0)
++ return ret;
++
++ /*
++ * So far only gated clock mode is supported. Add a line
++ * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) |
++ * below and select the required mode when supporting other
++ * synchronisation protocols.
++ */
++ sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) &
++ ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) |
++ (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) |
++ (1 << CSI_SENS_CONF_DATA_POL_SHIFT) |
++ (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) |
++ (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) |
++ (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT));
++
++ /* TODO: Support RGB and YUV formats */
++
++ /* This has been set in mx3_camera_activate(), but we clear it above */
++ sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
++
++ if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
++ sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
++ if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
++ sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
++ if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
++ sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
++ if (common_flags & SOCAM_DATA_ACTIVE_LOW)
++ sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
++
++ /* Just do what we're asked to do */
++ switch (xlate->host_fmt->depth) {
++ case 4:
++ dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
++ break;
++ case 8:
++ dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
++ break;
++ case 10:
++ dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
++ break;
++ default:
++ /*
++ * Actually it can only be 15 now, default is just to silence
++ * compiler warnings
++ */
++ case 15:
++ dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
++ }
++
++ csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
++
++ dev_dbg(&ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw);
++
++ return 0;
++}
++
++static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
++ .owner = THIS_MODULE,
++ .add = mx3_camera_add_device,
++ .remove = mx3_camera_remove_device,
++#ifdef CONFIG_PM
++ .suspend = mx3_camera_suspend,
++ .resume = mx3_camera_resume,
++#endif
++ .set_crop = mx3_camera_set_crop,
++ .set_fmt = mx3_camera_set_fmt,
++ .try_fmt = mx3_camera_try_fmt,
++ .get_formats = mx3_camera_get_formats,
++ .init_videobuf = mx3_camera_init_videobuf,
++ .reqbufs = mx3_camera_reqbufs,
++ .poll = mx3_camera_poll,
++ .querycap = mx3_camera_querycap,
++ .set_bus_param = mx3_camera_set_bus_param,
++};
++
++static int mx3_camera_probe(struct platform_device *pdev)
++{
++ struct mx3_camera_dev *mx3_cam;
++ struct resource *res;
++ void __iomem *base;
++ int err = 0;
++ struct soc_camera_host *soc_host;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ err = -ENODEV;
++ goto egetres;
++ }
++
++ mx3_cam = vmalloc(sizeof(*mx3_cam));
++ if (!mx3_cam) {
++ dev_err(&pdev->dev, "Could not allocate mx3 camera object\n");
++ err = -ENOMEM;
++ goto ealloc;
++ }
++ memset(mx3_cam, 0, sizeof(*mx3_cam));
++
++ mx3_cam->clk = clk_get(&pdev->dev, "csi_clk");
++ if (IS_ERR(mx3_cam->clk)) {
++ err = PTR_ERR(mx3_cam->clk);
++ goto eclkget;
++ }
++
++ dev_set_drvdata(&pdev->dev, mx3_cam);
++
++ mx3_cam->pdata = pdev->dev.platform_data;
++ mx3_cam->platform_flags = mx3_cam->pdata->flags;
++ if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 |
++ MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 |
++ MX3_CAMERA_DATAWIDTH_15))) {
++ /* Platform hasn't set available data widths. This is bad.
++ * Warn and use a default. */
++ dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
++ "data widths, using default 8 bit\n");
++ mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8;
++ }
++
++ mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000;
++ if (!mx3_cam->mclk) {
++ dev_warn(&pdev->dev,
++ "mclk_10khz == 0! Please, fix your platform data. "
++ "Using default 20MHz\n");
++ mx3_cam->mclk = 20000000;
++ }
++
++ /* list of video-buffers */
++ INIT_LIST_HEAD(&mx3_cam->capture);
++ spin_lock_init(&mx3_cam->lock);
++
++ base = ioremap(res->start, res->end - res->start + 1);
++ if (!base) {
++ err = -ENOMEM;
++ goto eioremap;
++ }
++
++ mx3_cam->base = base;
++ mx3_cam->dev = &pdev->dev;
++
++ soc_host = &mx3_cam->soc_host;
++ soc_host->drv_name = MX3_CAM_DRV_NAME;
++ soc_host->ops = &mx3_soc_camera_host_ops;
++ soc_host->priv = mx3_cam;
++ soc_host->dev.parent = &pdev->dev;
++ soc_host->nr = pdev->id;
++ err = soc_camera_host_register(soc_host);
++ if (err)
++ goto ecamhostreg;
++
++ /* IDMAC interface */
++ dmaengine_get();
++
++ return 0;
++
++ecamhostreg:
++ iounmap(base);
++eioremap:
++ clk_put(mx3_cam->clk);
++eclkget:
++ vfree(mx3_cam);
++ealloc:
++egetres:
++ return err;
++}
++
++static int __devexit mx3_camera_remove(struct platform_device *pdev)
++{
++ struct mx3_camera_dev *mx3_cam = platform_get_drvdata(pdev);
++
++ clk_put(mx3_cam->clk);
++
++ soc_camera_host_unregister(&mx3_cam->soc_host);
++
++ iounmap(mx3_cam->base);
++
++ /*
++ * The channel has either not been allocated,
++ * or should have been released
++ */
++ if (WARN_ON(mx3_cam->idmac_channel[0]))
++ dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan);
++
++ vfree(mx3_cam);
++
++ dmaengine_put();
++
++ dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n");
++
++ return 0;
++}
++
++static struct platform_driver mx3_camera_driver = {
++ .driver = {
++ .name = MX3_CAM_DRV_NAME,
++ },
++ .probe = mx3_camera_probe,
++ .remove = __exit_p(mx3_camera_remove),
++};
++
++
++static int __devinit mx3_camera_init(void)
++{
++ return platform_driver_register(&mx3_camera_driver);
++}
++
++static void __exit mx3_camera_exit(void)
++{
++ platform_driver_unregister(&mx3_camera_driver);
++}
++
++module_init(mx3_camera_init);
++module_exit(mx3_camera_exit);
++
++MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
++MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
+index e3cbe14..84aec62 100644
+--- a/drivers/media/video/mxb.c
++++ b/drivers/media/video/mxb.c
+@@ -25,16 +25,20 @@
+
+ #include <media/saa7146_vv.h>
+ #include <media/tuner.h>
+-#include <linux/video_decoder.h>
+ #include <media/v4l2-common.h>
+ #include <media/saa7115.h>
+
+ #include "mxb.h"
+ #include "tea6415c.h"
+ #include "tea6420.h"
+-#include "tda9840.h"
+
+-#define I2C_SAA7111 0x24
++#define I2C_SAA5246A 0x11
++#define I2C_SAA7111A 0x24
++#define I2C_TDA9840 0x42
++#define I2C_TEA6415C 0x43
++#define I2C_TEA6420_1 0x4c
++#define I2C_TEA6420_2 0x4d
++#define I2C_TUNER 0x60
+
+ #define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
+
+@@ -79,57 +83,35 @@ static struct {
+ static int video_audio_connect[MXB_INPUTS] =
+ { 0, 1, 3, 3 };
+
+-/* these are the necessary input-output-pins for bringing one audio source
+-(see above) to the CD-output */
+-static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
+- {
+- {{1,1,0},{1,1,0}}, /* Tuner */
+- {{5,1,0},{6,1,0}}, /* AUX 1 */
+- {{4,1,0},{6,1,0}}, /* AUX 2 */
+- {{3,1,0},{6,1,0}}, /* AUX 3 */
+- {{1,1,0},{3,1,0}}, /* Radio */
+- {{1,1,0},{2,1,0}}, /* CD-Rom */
+- {{6,1,0},{6,1,0}} /* Mute */
+- };
+-
+-/* these are the necessary input-output-pins for bringing one audio source
+-(see above) to the line-output */
+-static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] =
+- {
+- {{2,3,0},{1,2,0}},
+- {{5,3,0},{6,2,0}},
+- {{4,3,0},{6,2,0}},
+- {{3,3,0},{6,2,0}},
+- {{2,3,0},{3,2,0}},
+- {{2,3,0},{2,2,0}},
+- {{6,3,0},{6,2,0}} /* Mute */
+- };
++/* These are the necessary input-output-pins for bringing one audio source
++ (see above) to the CD-output. Note that gain is set to 0 in this table. */
++static struct v4l2_routing TEA6420_cd[MXB_AUDIOS + 1][2] = {
++ { { 1, 1 }, { 1, 1 } }, /* Tuner */
++ { { 5, 1 }, { 6, 1 } }, /* AUX 1 */
++ { { 4, 1 }, { 6, 1 } }, /* AUX 2 */
++ { { 3, 1 }, { 6, 1 } }, /* AUX 3 */
++ { { 1, 1 }, { 3, 1 } }, /* Radio */
++ { { 1, 1 }, { 2, 1 } }, /* CD-Rom */
++ { { 6, 1 }, { 6, 1 } } /* Mute */
++};
++
++/* These are the necessary input-output-pins for bringing one audio source
++ (see above) to the line-output. Note that gain is set to 0 in this table. */
++static struct v4l2_routing TEA6420_line[MXB_AUDIOS + 1][2] = {
++ { { 2, 3 }, { 1, 2 } },
++ { { 5, 3 }, { 6, 2 } },
++ { { 4, 3 }, { 6, 2 } },
++ { { 3, 3 }, { 6, 2 } },
++ { { 2, 3 }, { 3, 2 } },
++ { { 2, 3 }, { 2, 2 } },
++ { { 6, 3 }, { 6, 2 } } /* Mute */
++};
+
+ #define MAXCONTROLS 1
+ static struct v4l2_queryctrl mxb_controls[] = {
+ { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
+ };
+
+-static struct saa7146_extension_ioctls ioctls[] = {
+- { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
+- { VIDIOC_QUERYCTRL, SAA7146_BEFORE },
+- { VIDIOC_G_CTRL, SAA7146_BEFORE },
+- { VIDIOC_S_CTRL, SAA7146_BEFORE },
+- { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
+- { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
+- { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
+- { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
+- { VIDIOC_DBG_G_REGISTER, SAA7146_EXCLUSIVE },
+- { VIDIOC_DBG_S_REGISTER, SAA7146_EXCLUSIVE },
+- { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
+- { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
+- { 0, 0 }
+-};
+-
+ struct mxb
+ {
+ struct video_device *video_dev;
+@@ -137,12 +119,12 @@ struct mxb
+
+ struct i2c_adapter i2c_adapter;
+
+- struct i2c_client *saa7111a;
+- struct i2c_client *tda9840;
+- struct i2c_client *tea6415c;
+- struct i2c_client *tuner;
+- struct i2c_client *tea6420_1;
+- struct i2c_client *tea6420_2;
++ struct v4l2_subdev *saa7111a;
++ struct v4l2_subdev *tda9840;
++ struct v4l2_subdev *tea6415c;
++ struct v4l2_subdev *tuner;
++ struct v4l2_subdev *tea6420_1;
++ struct v4l2_subdev *tea6420_2;
+
+ int cur_mode; /* current audio mode (mono, stereo, ...) */
+ int cur_input; /* current input */
+@@ -150,84 +132,51 @@ struct mxb
+ struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */
+ };
+
+-static struct saa7146_extension extension;
+-
+-static int mxb_check_clients(struct device *dev, void *data)
+-{
+- struct mxb *mxb = data;
+- struct i2c_client *client = i2c_verify_client(dev);
+-
+- if (!client)
+- return 0;
+-
+- if (I2C_ADDR_TEA6420_1 == client->addr)
+- mxb->tea6420_1 = client;
+- if (I2C_ADDR_TEA6420_2 == client->addr)
+- mxb->tea6420_2 = client;
+- if (I2C_TEA6415C_2 == client->addr)
+- mxb->tea6415c = client;
+- if (I2C_ADDR_TDA9840 == client->addr)
+- mxb->tda9840 = client;
+- if (I2C_SAA7111 == client->addr)
+- mxb->saa7111a = client;
+- if (0x60 == client->addr)
+- mxb->tuner = client;
++#define saa7111a_call(mxb, o, f, args...) \
++ v4l2_subdev_call(mxb->saa7111a, o, f, ##args)
++#define tea6420_1_call(mxb, o, f, args...) \
++ v4l2_subdev_call(mxb->tea6420_1, o, f, ##args)
++#define tea6420_2_call(mxb, o, f, args...) \
++ v4l2_subdev_call(mxb->tea6420_2, o, f, ##args)
++#define tda9840_call(mxb, o, f, args...) \
++ v4l2_subdev_call(mxb->tda9840, o, f, ##args)
++#define tea6415c_call(mxb, o, f, args...) \
++ v4l2_subdev_call(mxb->tea6415c, o, f, ##args)
++#define tuner_call(mxb, o, f, args...) \
++ v4l2_subdev_call(mxb->tuner, o, f, ##args)
++#define call_all(dev, o, f, args...) \
++ v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)
+
+- return 0;
+-}
++static struct saa7146_extension extension;
+
+-static int mxb_probe(struct saa7146_dev* dev)
++static int mxb_probe(struct saa7146_dev *dev)
+ {
+- struct mxb* mxb = NULL;
+- int result;
+-
+- result = request_module("saa7115");
+- if (result < 0) {
+- printk("mxb: saa7111 i2c module not available.\n");
+- return -ENODEV;
+- }
+- result = request_module("tea6420");
+- if (result < 0) {
+- printk("mxb: tea6420 i2c module not available.\n");
+- return -ENODEV;
+- }
+- result = request_module("tea6415c");
+- if (result < 0) {
+- printk("mxb: tea6415c i2c module not available.\n");
+- return -ENODEV;
+- }
+- result = request_module("tda9840");
+- if (result < 0) {
+- printk("mxb: tda9840 i2c module not available.\n");
+- return -ENODEV;
+- }
+- result = request_module("tuner");
+- if (result < 0) {
+- printk("mxb: tuner i2c module not available.\n");
+- return -ENODEV;
+- }
++ struct mxb *mxb = NULL;
+
+ mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
+- if( NULL == mxb ) {
++ if (mxb == NULL) {
+ DEB_D(("not enough kernel memory.\n"));
+ return -ENOMEM;
+ }
+
+- mxb->i2c_adapter = (struct i2c_adapter) {
+- .class = I2C_CLASS_TV_ANALOG,
+- };
+-
+ snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
+
+ saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+- if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
++ if (i2c_add_adapter(&mxb->i2c_adapter) < 0) {
+ DEB_S(("cannot register i2c-device. skipping.\n"));
+ kfree(mxb);
+ return -EFAULT;
+ }
+
+- /* loop through all i2c-devices on the bus and look who is there */
+- device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
++ mxb->saa7111a = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "saa7115", "saa7111", I2C_SAA7111A);
++ mxb->tea6420_1 = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tea6420", "tea6420", I2C_TEA6420_1);
++ mxb->tea6420_2 = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tea6420", "tea6420", I2C_TEA6420_2);
++ mxb->tea6415c = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tea6415c", "tea6415c", I2C_TEA6415C);
++ mxb->tda9840 = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tda9840", "tda9840", I2C_TDA9840);
++ mxb->tuner = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tuner", "tuner", I2C_TUNER);
++ if (v4l2_i2c_new_subdev(&mxb->i2c_adapter, "saa5246a", "saa5246a", I2C_SAA5246A)) {
++ printk(KERN_INFO "mxb: found teletext decoder\n");
++ }
+
+ /* check if all devices are present */
+ if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
+@@ -315,47 +264,45 @@ static int mxb_init_done(struct saa7146_dev* dev)
+ struct v4l2_routing route;
+
+ int i = 0, err = 0;
+- struct tea6415c_multiplex vm;
+
+ /* select video mode in saa7111a */
+- mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_S_STD, &std);
++ saa7111a_call(mxb, tuner, s_std, std);
+
+ /* select tuner-output on saa7111a */
+ i = 0;
+ route.input = SAA7115_COMPOSITE0;
+ route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
+- mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route);
++ saa7111a_call(mxb, video, s_routing, &route);
+
+ /* select a tuner type */
+ tun_setup.mode_mask = T_ANALOG_TV;
+ tun_setup.addr = ADDR_UNSET;
+ tun_setup.type = TUNER_PHILIPS_PAL;
+- mxb->tuner->driver->command(mxb->tuner, TUNER_SET_TYPE_ADDR, &tun_setup);
++ tuner_call(mxb, tuner, s_type_addr, &tun_setup);
+ /* tune in some frequency on tuner */
+ mxb->cur_freq.tuner = 0;
+ mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
+ mxb->cur_freq.frequency = freq;
+- mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
+- &mxb->cur_freq);
++ tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
+
+ /* set a default video standard */
+- mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
++ tuner_call(mxb, tuner, s_std, std);
+
+ /* mute audio on tea6420s */
+- mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[6][0]);
+- mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[6][1]);
+- mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[6][0]);
+- mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[6][1]);
++ tea6420_1_call(mxb, audio, s_routing, &TEA6420_line[6][0]);
++ tea6420_2_call(mxb, audio, s_routing, &TEA6420_line[6][1]);
++ tea6420_1_call(mxb, audio, s_routing, &TEA6420_line[6][0]);
++ tea6420_2_call(mxb, audio, s_routing, &TEA6420_line[6][1]);
+
+- /* switch to tuner-channel on tea6415c*/
+- vm.out = 17;
+- vm.in = 3;
+- mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
++ /* switch to tuner-channel on tea6415c */
++ route.input = 3;
++ route.output = 17;
++ tea6415c_call(mxb, video, s_routing, &route);
+
+- /* select tuner-output on multicable on tea6415c*/
+- vm.in = 3;
+- vm.out = 13;
+- mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
++ /* select tuner-output on multicable on tea6415c */
++ route.input = 3;
++ route.output = 13;
++ tea6415c_call(mxb, video, s_routing, &route);
+
+ /* the rest for mxb */
+ mxb->cur_input = 0;
+@@ -424,395 +371,414 @@ void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
+ }
+ */
+
+-static struct saa7146_ext_vv vv_data;
+-
+-/* this function only gets called when the probing was successful */
+-static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
++static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
+ {
+- struct mxb *mxb = (struct mxb *)dev->ext_priv;
+-
+- DEB_EE(("dev:%p\n", dev));
+-
+- /* checking for i2c-devices can be omitted here, because we
+- already did this in "mxb_vl42_probe" */
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ int i;
+
+- saa7146_vv_init(dev, &vv_data);
+- if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
+- ERR(("cannot register capture v4l2 device. skipping.\n"));
+- return -1;
++ for (i = MAXCONTROLS - 1; i >= 0; i--) {
++ if (mxb_controls[i].id == qc->id) {
++ *qc = mxb_controls[i];
++ DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
++ return 0;
++ }
+ }
++ return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
++}
+
+- /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
+- if (MXB_BOARD_CAN_DO_VBI(dev)) {
+- if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
+- ERR(("cannot register vbi v4l2 device. skipping.\n"));
+- }
++static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
++ int i;
++
++ for (i = MAXCONTROLS - 1; i >= 0; i--) {
++ if (mxb_controls[i].id == vc->id)
++ break;
+ }
+
+- i2c_use_client(mxb->tea6420_1);
+- i2c_use_client(mxb->tea6420_2);
+- i2c_use_client(mxb->tea6415c);
+- i2c_use_client(mxb->tda9840);
+- i2c_use_client(mxb->saa7111a);
+- i2c_use_client(mxb->tuner);
++ if (i < 0)
++ return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
+
+- printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
++ if (vc->id == V4L2_CID_AUDIO_MUTE) {
++ vc->value = mxb->cur_mute;
++ DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
++ return 0;
++ }
+
+- mxb_num++;
+- mxb_init_done(dev);
++ DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
+ return 0;
+ }
+
+-static int mxb_detach(struct saa7146_dev *dev)
++static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
+ {
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct mxb *mxb = (struct mxb *)dev->ext_priv;
++ int i = 0;
+
+- DEB_EE(("dev:%p\n", dev));
+-
+- i2c_release_client(mxb->tea6420_1);
+- i2c_release_client(mxb->tea6420_2);
+- i2c_release_client(mxb->tea6415c);
+- i2c_release_client(mxb->tda9840);
+- i2c_release_client(mxb->saa7111a);
+- i2c_release_client(mxb->tuner);
+-
+- saa7146_unregister_device(&mxb->video_dev,dev);
+- if (MXB_BOARD_CAN_DO_VBI(dev))
+- saa7146_unregister_device(&mxb->vbi_dev, dev);
+- saa7146_vv_release(dev);
+-
+- mxb_num--;
++ for (i = MAXCONTROLS - 1; i >= 0; i--) {
++ if (mxb_controls[i].id == vc->id)
++ break;
++ }
+
+- i2c_del_adapter(&mxb->i2c_adapter);
+- kfree(mxb);
++ if (i < 0)
++ return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
++
++ if (vc->id == V4L2_CID_AUDIO_MUTE) {
++ mxb->cur_mute = vc->value;
++ if (!vc->value) {
++ /* switch the audio-source */
++ tea6420_1_call(mxb, audio, s_routing,
++ &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
++ tea6420_2_call(mxb, audio, s_routing,
++ &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
++ } else {
++ tea6420_1_call(mxb, audio, s_routing,
++ &TEA6420_line[6][0]);
++ tea6420_2_call(mxb, audio, s_routing,
++ &TEA6420_line[6][1]);
++ }
++ DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
++ }
++ return 0;
++}
+
++static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
++{
++ DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
++ if (i->index < 0 || i->index >= MXB_INPUTS)
++ return -EINVAL;
++ memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
+ return 0;
+ }
+
+-static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
++static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+ {
+- struct saa7146_dev *dev = fh->dev;
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct mxb *mxb = (struct mxb *)dev->ext_priv;
+- struct saa7146_vv *vv = dev->vv_data;
++ *i = mxb->cur_input;
+
+- switch(cmd) {
+- case VIDIOC_ENUMINPUT:
+- {
+- struct v4l2_input *i = arg;
++ DEB_EE(("VIDIOC_G_INPUT %d.\n", *i));
++ return 0;
++}
+
+- DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
+- if (i->index < 0 || i->index >= MXB_INPUTS)
+- return -EINVAL;
+- memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
+- return 0;
+- }
+- /* the saa7146 provides some controls (brightness, contrast, saturation)
+- which gets registered *after* this function. because of this we have
+- to return with a value != 0 even if the function succeded.. */
+- case VIDIOC_QUERYCTRL:
+- {
+- struct v4l2_queryctrl *qc = arg;
+- int i;
+-
+- for (i = MAXCONTROLS - 1; i >= 0; i--) {
+- if (mxb_controls[i].id == qc->id) {
+- *qc = mxb_controls[i];
+- DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
+- return 0;
+- }
+- }
+- return -EAGAIN;
+- }
+- case VIDIOC_G_CTRL:
+- {
+- struct v4l2_control *vc = arg;
+- int i;
++static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
++ struct v4l2_routing route;
++ int i = 0;
+
+- for (i = MAXCONTROLS - 1; i >= 0; i--) {
+- if (mxb_controls[i].id == vc->id)
+- break;
+- }
++ DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
+
+- if (i < 0)
+- return -EAGAIN;
++ if (input < 0 || input >= MXB_INPUTS)
++ return -EINVAL;
+
+- if (vc->id == V4L2_CID_AUDIO_MUTE) {
+- vc->value = mxb->cur_mute;
+- DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
+- return 0;
+- }
++ mxb->cur_input = input;
+
+- DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
+- return 0;
+- }
++ saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
++ input_port_selection[input].hps_sync);
+
+- case VIDIOC_S_CTRL:
+- {
+- struct v4l2_control *vc = arg;
+- int i = 0;
++ /* prepare switching of tea6415c and saa7111a;
++ have a look at the 'background'-file for further informations */
++ switch (input) {
++ case TUNER:
++ i = SAA7115_COMPOSITE0;
++ route.input = 3;
++ route.output = 17;
+
+- for (i = MAXCONTROLS - 1; i >= 0; i--) {
+- if (mxb_controls[i].id == vc->id)
+- break;
++ if (tea6415c_call(mxb, video, s_routing, &route)) {
++ printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
++ return -EFAULT;
+ }
++ /* connect tuner-output always to multicable */
++ route.input = 3;
++ route.output = 13;
++ break;
++ case AUX3_YC:
++ /* nothing to be done here. aux3_yc is
++ directly connected to the saa711a */
++ i = SAA7115_SVIDEO1;
++ break;
++ case AUX3:
++ /* nothing to be done here. aux3 is
++ directly connected to the saa711a */
++ i = SAA7115_COMPOSITE1;
++ break;
++ case AUX1:
++ i = SAA7115_COMPOSITE0;
++ route.input = 1;
++ route.output = 17;
++ break;
++ }
+
+- if (i < 0)
+- return -EAGAIN;
+-
+- if (vc->id == V4L2_CID_AUDIO_MUTE) {
+- mxb->cur_mute = vc->value;
+- if (!vc->value) {
+- /* switch the audio-source */
+- mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
+- &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
+- mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
+- &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
+- } else {
+- mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
+- &TEA6420_line[6][0]);
+- mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
+- &TEA6420_line[6][1]);
+- }
+- DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
++ /* switch video in tea6415c only if necessary */
++ switch (input) {
++ case TUNER:
++ case AUX1:
++ if (tea6415c_call(mxb, video, s_routing, &route)) {
++ printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
++ return -EFAULT;
+ }
+- return 0;
++ break;
++ default:
++ break;
+ }
+- case VIDIOC_G_INPUT:
+- {
+- int *input = (int *)arg;
+- *input = mxb->cur_input;
+
+- DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));
+- return 0;
++ /* switch video in saa7111a */
++ route.input = i;
++ route.output = 0;
++ if (saa7111a_call(mxb, video, s_routing, &route))
++ printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n");
++
++ /* switch the audio-source only if necessary */
++ if (0 == mxb->cur_mute) {
++ tea6420_1_call(mxb, audio, s_routing,
++ &TEA6420_line[video_audio_connect[input]][0]);
++ tea6420_2_call(mxb, audio, s_routing,
++ &TEA6420_line[video_audio_connect[input]][1]);
+ }
+- case VIDIOC_S_INPUT:
+- {
+- int input = *(int *)arg;
+- struct tea6415c_multiplex vm;
+- struct v4l2_routing route;
+- int i = 0;
+
+- DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
++ return 0;
++}
+
+- if (input < 0 || input >= MXB_INPUTS)
+- return -EINVAL;
++static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+- mxb->cur_input = input;
++ if (t->index) {
++ DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
++ return -EINVAL;
++ }
+
+- saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
+- input_port_selection[input].hps_sync);
++ DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
+
+- /* prepare switching of tea6415c and saa7111a;
+- have a look at the 'background'-file for further informations */
+- switch (input) {
+- case TUNER:
+- i = SAA7115_COMPOSITE0;
+- vm.in = 3;
+- vm.out = 17;
++ memset(t, 0, sizeof(*t));
++ strlcpy(t->name, "TV Tuner", sizeof(t->name));
++ t->type = V4L2_TUNER_ANALOG_TV;
++ t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
++ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
++ t->audmode = mxb->cur_mode;
++ return call_all(dev, tuner, g_tuner, t);
++}
+
+- if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
+- printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
+- return -EFAULT;
+- }
+- /* connect tuner-output always to multicable */
+- vm.in = 3;
+- vm.out = 13;
+- break;
+- case AUX3_YC:
+- /* nothing to be done here. aux3_yc is
+- directly connected to the saa711a */
+- i = SAA7115_SVIDEO1;
+- break;
+- case AUX3:
+- /* nothing to be done here. aux3 is
+- directly connected to the saa711a */
+- i = SAA7115_COMPOSITE1;
+- break;
+- case AUX1:
+- i = SAA7115_COMPOSITE0;
+- vm.in = 1;
+- vm.out = 17;
+- break;
+- }
++static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+- /* switch video in tea6415c only if necessary */
+- switch (input) {
+- case TUNER:
+- case AUX1:
+- if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
+- printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
+- return -EFAULT;
+- }
+- break;
+- default:
+- break;
+- }
++ if (t->index) {
++ DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index));
++ return -EINVAL;
++ }
+
+- /* switch video in saa7111a */
+- route.input = i;
+- route.output = 0;
+- if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
+- printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
+-
+- /* switch the audio-source only if necessary */
+- if( 0 == mxb->cur_mute ) {
+- mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
+- &TEA6420_line[video_audio_connect[input]][0]);
+- mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
+- &TEA6420_line[video_audio_connect[input]][1]);
+- }
++ mxb->cur_mode = t->audmode;
++ return call_all(dev, tuner, s_tuner, t);
++}
+
+- return 0;
++static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
++
++ if (mxb->cur_input) {
++ DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
++ mxb->cur_input));
++ return -EINVAL;
+ }
+- case VIDIOC_G_TUNER:
+- {
+- struct v4l2_tuner *t = arg;
+
+- if (t->index) {
+- DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
+- return -EINVAL;
+- }
++ *f = mxb->cur_freq;
+
+- DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
++ DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
++ return 0;
++}
+
+- memset(t, 0, sizeof(*t));
+- i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
++static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
++ struct saa7146_vv *vv = dev->vv_data;
+
+- strlcpy(t->name, "TV Tuner", sizeof(t->name));
+- t->type = V4L2_TUNER_ANALOG_TV;
+- t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
+- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+- t->audmode = mxb->cur_mode;
+- return 0;
+- }
+- case VIDIOC_S_TUNER:
+- {
+- struct v4l2_tuner *t = arg;
++ if (f->tuner)
++ return -EINVAL;
+
+- if (t->index) {
+- DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
+- return -EINVAL;
+- }
++ if (V4L2_TUNER_ANALOG_TV != f->type)
++ return -EINVAL;
+
+- mxb->cur_mode = t->audmode;
+- i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
+- return 0;
++ if (mxb->cur_input) {
++ DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
++ return -EINVAL;
+ }
+- case VIDIOC_G_FREQUENCY:
+- {
+- struct v4l2_frequency *f = arg;
+
+- if (mxb->cur_input) {
+- DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
+- mxb->cur_input));
+- return -EINVAL;
+- }
++ mxb->cur_freq = *f;
++ DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
+
+- *f = mxb->cur_freq;
++ /* tune in desired frequency */
++ tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
+
+- DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
+- return 0;
++ /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
++ spin_lock(&dev->slock);
++ vv->vbi_fieldcount = 0;
++ spin_unlock(&dev->slock);
++
++ return 0;
++}
++
++static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
++
++ if (a->index < 0 || a->index > MXB_INPUTS) {
++ DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
++ return -EINVAL;
+ }
+- case VIDIOC_S_FREQUENCY:
+- {
+- struct v4l2_frequency *f = arg;
+
+- if (f->tuner)
+- return -EINVAL;
++ DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
++ memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
++ return 0;
++}
+
+- if (V4L2_TUNER_ANALOG_TV != f->type)
+- return -EINVAL;
++static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
++{
++ DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
++ return 0;
++}
+
+- if (mxb->cur_input) {
+- DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
+- return -EINVAL;
+- }
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+- mxb->cur_freq = *f;
+- DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
++ return call_all(dev, core, g_register, reg);
++}
+
+- /* tune in desired frequency */
+- mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
++static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+- /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
+- spin_lock(&dev->slock);
+- vv->vbi_fieldcount = 0;
+- spin_unlock(&dev->slock);
++ return call_all(dev, core, s_register, reg);
++}
++#endif
+
+- return 0;
+- }
++static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
++{
++ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
++
++ switch (cmd) {
+ case MXB_S_AUDIO_CD:
+ {
+- int i = *(int*)arg;
++ int i = *(int *)arg;
+
+ if (i < 0 || i >= MXB_AUDIOS) {
+- DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
++ DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i));
+ return -EINVAL;
+ }
+
+- DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
++ DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i));
+
+- mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
+- mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
++ tea6420_1_call(mxb, audio, s_routing, &TEA6420_cd[i][0]);
++ tea6420_2_call(mxb, audio, s_routing, &TEA6420_cd[i][1]);
+
+ return 0;
+ }
+ case MXB_S_AUDIO_LINE:
+ {
+- int i = *(int*)arg;
++ int i = *(int *)arg;
+
+ if (i < 0 || i >= MXB_AUDIOS) {
+- DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
++ DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i));
+ return -EINVAL;
+ }
+
+- DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
+- mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
+- mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
++ DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i));
++ tea6420_1_call(mxb, audio, s_routing, &TEA6420_line[i][0]);
++ tea6420_2_call(mxb, audio, s_routing, &TEA6420_line[i][1]);
+
+ return 0;
+ }
+- case VIDIOC_G_AUDIO:
+- {
+- struct v4l2_audio *a = arg;
++ default:
++/*
++ DEB2(printk("does not handle this ioctl.\n"));
++*/
++ return -ENOIOCTLCMD;
++ }
++ return 0;
++}
+
+- if (a->index < 0 || a->index > MXB_INPUTS) {
+- DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
+- return -EINVAL;
+- }
++static struct saa7146_ext_vv vv_data;
+
+- DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
+- memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
++/* this function only gets called when the probing was successful */
++static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
++{
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
+- return 0;
+- }
+- case VIDIOC_S_AUDIO:
+- {
+- struct v4l2_audio *a = arg;
++ DEB_EE(("dev:%p\n", dev));
+
+- DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
+- return 0;
+- }
++ /* checking for i2c-devices can be omitted here, because we
++ already did this in "mxb_vl42_probe" */
++
++ saa7146_vv_init(dev, &vv_data);
++ vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
++ vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
++ vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
++ vv_data.ops.vidioc_enum_input = vidioc_enum_input;
++ vv_data.ops.vidioc_g_input = vidioc_g_input;
++ vv_data.ops.vidioc_s_input = vidioc_s_input;
++ vv_data.ops.vidioc_g_tuner = vidioc_g_tuner;
++ vv_data.ops.vidioc_s_tuner = vidioc_s_tuner;
++ vv_data.ops.vidioc_g_frequency = vidioc_g_frequency;
++ vv_data.ops.vidioc_s_frequency = vidioc_s_frequency;
++ vv_data.ops.vidioc_g_audio = vidioc_g_audio;
++ vv_data.ops.vidioc_s_audio = vidioc_s_audio;
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+- case VIDIOC_DBG_S_REGISTER:
+- case VIDIOC_DBG_G_REGISTER:
+- i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
+- return 0;
++ vv_data.ops.vidioc_g_register = vidioc_g_register;
++ vv_data.ops.vidioc_s_register = vidioc_s_register;
+ #endif
+- default:
+-/*
+- DEB2(printk("does not handle this ioctl.\n"));
+-*/
+- return -ENOIOCTLCMD;
++ vv_data.ops.vidioc_default = vidioc_default;
++ if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
++ ERR(("cannot register capture v4l2 device. skipping.\n"));
++ return -1;
+ }
++
++ /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
++ if (MXB_BOARD_CAN_DO_VBI(dev)) {
++ if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
++ ERR(("cannot register vbi v4l2 device. skipping.\n"));
++ }
++ }
++
++ printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
++
++ mxb_num++;
++ mxb_init_done(dev);
++ return 0;
++}
++
++static int mxb_detach(struct saa7146_dev *dev)
++{
++ struct mxb *mxb = (struct mxb *)dev->ext_priv;
++
++ DEB_EE(("dev:%p\n", dev));
++
++ saa7146_unregister_device(&mxb->video_dev,dev);
++ if (MXB_BOARD_CAN_DO_VBI(dev))
++ saa7146_unregister_device(&mxb->vbi_dev, dev);
++ saa7146_vv_release(dev);
++
++ mxb_num--;
++
++ i2c_del_adapter(&mxb->i2c_adapter);
++ kfree(mxb);
++
+ return 0;
+ }
+
+ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
+ {
+ struct mxb *mxb = (struct mxb *)dev->ext_priv;
+- int zero = 0;
+- int one = 1;
+
+ if (V4L2_STD_PAL_I == standard->id) {
+ v4l2_std_id std = V4L2_STD_PAL_I;
+@@ -821,8 +787,8 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
+ /* set the 7146 gpio register -- I don't know what this does exactly */
+ saa7146_write(dev, GPIO_CTRL, 0x00404050);
+ /* unset the 7111 gpio register -- I don't know what this does exactly */
+- mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
+- mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
++ saa7111a_call(mxb, core, s_gpio, 0);
++ tuner_call(mxb, tuner, s_std, std);
+ } else {
+ v4l2_std_id std = V4L2_STD_PAL_BG;
+
+@@ -830,8 +796,8 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
+ /* set the 7146 gpio register -- I don't know what this does exactly */
+ saa7146_write(dev, GPIO_CTRL, 0x00404050);
+ /* set the 7111 gpio register -- I don't know what this does exactly */
+- mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
+- mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
++ saa7111a_call(mxb, core, s_gpio, 1);
++ tuner_call(mxb, tuner, s_std, std);
+ }
+ return 0;
+ }
+@@ -885,8 +851,6 @@ static struct saa7146_ext_vv vv_data = {
+ .stds = &standard[0],
+ .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
+ .std_callback = &std_callback,
+- .ioctls = &ioctls[0],
+- .ioctl = mxb_ioctl,
+ };
+
+ static struct saa7146_extension extension = {
+diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
+index 73eb656..d828597 100644
+--- a/drivers/media/video/omap24xxcam.c
++++ b/drivers/media/video/omap24xxcam.c
+@@ -1285,9 +1285,6 @@ static int vidioc_g_parm(struct file *file, void *fh,
+ struct omap24xxcam_device *cam = ofh->cam;
+ int rval;
+
+- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+ mutex_lock(&cam->mutex);
+ rval = vidioc_int_g_parm(cam->sdev, a);
+ mutex_unlock(&cam->mutex);
+@@ -1303,9 +1300,6 @@ static int vidioc_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm old_streamparm;
+ int rval;
+
+- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+ mutex_lock(&cam->mutex);
+ if (cam->streaming) {
+ rval = -EBUSY;
+@@ -1665,7 +1659,6 @@ static int omap24xxcam_device_register(struct v4l2_int_device *s)
+ vfd->parent = cam->dev;
+
+ strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+- vfd->vfl_type = VID_TYPE_CAPTURE | VID_TYPE_CHROMAKEY;
+ vfd->fops = &omap24xxcam_fops;
+ vfd->minor = -1;
+ vfd->ioctl_ops = &omap24xxcam_ioctl_fops;
+diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
+index 05c14a2..0e2184e 100644
+--- a/drivers/media/video/ov7670.c
++++ b/drivers/media/video/ov7670.c
+@@ -12,18 +12,22 @@
+ */
+ #include <linux/init.h>
+ #include <linux/module.h>
+-#include <linux/slab.h>
++#include <linux/i2c.h>
+ #include <linux/delay.h>
+-#include <linux/videodev.h>
+-#include <media/v4l2-common.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
+ #include <media/v4l2-chip-ident.h>
+-#include <linux/i2c.h>
++#include <media/v4l2-i2c-drv.h>
+
+
+ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+ MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
+ MODULE_LICENSE("GPL");
+
++static int debug;
++module_param(debug, bool, 0644);
++MODULE_PARM_DESC(debug, "Debug level (0-1)");
++
+ /*
+ * Basic window sizes. These probably belong somewhere more globally
+ * useful.
+@@ -189,11 +193,16 @@ MODULE_LICENSE("GPL");
+ */
+ struct ov7670_format_struct; /* coming later */
+ struct ov7670_info {
++ struct v4l2_subdev sd;
+ struct ov7670_format_struct *fmt; /* Current format */
+ unsigned char sat; /* Saturation value */
+ int hue; /* Hue value */
+ };
+
++static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct ov7670_info, sd);
++}
+
+
+
+@@ -400,24 +409,27 @@ static struct regval_list ov7670_fmt_raw[] = {
+ * Low-level register I/O.
+ */
+
+-static int ov7670_read(struct i2c_client *c, unsigned char reg,
++static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
+ unsigned char *value)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+- ret = i2c_smbus_read_byte_data(c, reg);
++ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret >= 0) {
+- *value = (unsigned char) ret;
++ *value = (unsigned char)ret;
+ ret = 0;
+ }
+ return ret;
+ }
+
+
+-static int ov7670_write(struct i2c_client *c, unsigned char reg,
++static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
+ unsigned char value)
+ {
+- int ret = i2c_smbus_write_byte_data(c, reg, value);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret = i2c_smbus_write_byte_data(client, reg, value);
++
+ if (reg == REG_COM7 && (value & COM7_RESET))
+ msleep(2); /* Wait for reset to run */
+ return ret;
+@@ -427,10 +439,10 @@ static int ov7670_write(struct i2c_client *c, unsigned char reg,
+ /*
+ * Write a list of register settings; ff/ff stops the process.
+ */
+-static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
++static int ov7670_write_array(struct v4l2_subdev *sd, struct regval_list *vals)
+ {
+ while (vals->reg_num != 0xff || vals->value != 0xff) {
+- int ret = ov7670_write(c, vals->reg_num, vals->value);
++ int ret = ov7670_write(sd, vals->reg_num, vals->value);
+ if (ret < 0)
+ return ret;
+ vals++;
+@@ -442,34 +454,35 @@ static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
+ /*
+ * Stuff that knows about the sensor.
+ */
+-static void ov7670_reset(struct i2c_client *client)
++static int ov7670_reset(struct v4l2_subdev *sd, u32 val)
+ {
+- ov7670_write(client, REG_COM7, COM7_RESET);
++ ov7670_write(sd, REG_COM7, COM7_RESET);
+ msleep(1);
++ return 0;
+ }
+
+
+-static int ov7670_init(struct i2c_client *client)
++static int ov7670_init(struct v4l2_subdev *sd, u32 val)
+ {
+- return ov7670_write_array(client, ov7670_default_regs);
++ return ov7670_write_array(sd, ov7670_default_regs);
+ }
+
+
+
+-static int ov7670_detect(struct i2c_client *client)
++static int ov7670_detect(struct v4l2_subdev *sd)
+ {
+ unsigned char v;
+ int ret;
+
+- ret = ov7670_init(client);
++ ret = ov7670_init(sd, 0);
+ if (ret < 0)
+ return ret;
+- ret = ov7670_read(client, REG_MIDH, &v);
++ ret = ov7670_read(sd, REG_MIDH, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x7f) /* OV manuf. id. */
+ return -ENODEV;
+- ret = ov7670_read(client, REG_MIDL, &v);
++ ret = ov7670_read(sd, REG_MIDL, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0xa2)
+@@ -477,12 +490,12 @@ static int ov7670_detect(struct i2c_client *client)
+ /*
+ * OK, we know we have an OmniVision chip...but which one?
+ */
+- ret = ov7670_read(client, REG_PID, &v);
++ ret = ov7670_read(sd, REG_PID, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x76) /* PID + VER = 0x76 / 0x73 */
+ return -ENODEV;
+- ret = ov7670_read(client, REG_VER, &v);
++ ret = ov7670_read(sd, REG_VER, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x73) /* PID + VER = 0x76 / 0x73 */
+@@ -627,7 +640,7 @@ static struct ov7670_win_size {
+ /*
+ * Store a set of start/stop values into the camera.
+ */
+-static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,
++static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
+ int vstart, int vstop)
+ {
+ int ret;
+@@ -637,26 +650,26 @@ static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,
+ * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is
+ * a mystery "edge offset" value in the top two bits of href.
+ */
+- ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff);
+- ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff);
+- ret += ov7670_read(client, REG_HREF, &v);
++ ret = ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff);
++ ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff);
++ ret += ov7670_read(sd, REG_HREF, &v);
+ v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
+ msleep(10);
+- ret += ov7670_write(client, REG_HREF, v);
++ ret += ov7670_write(sd, REG_HREF, v);
+ /*
+ * Vertical: similar arrangement, but only 10 bits.
+ */
+- ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff);
+- ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff);
+- ret += ov7670_read(client, REG_VREF, &v);
++ ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff);
++ ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff);
++ ret += ov7670_read(sd, REG_VREF, &v);
+ v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3);
+ msleep(10);
+- ret += ov7670_write(client, REG_VREF, v);
++ ret += ov7670_write(sd, REG_VREF, v);
+ return ret;
+ }
+
+
+-static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt)
++static int ov7670_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
+ {
+ struct ov7670_format_struct *ofmt;
+
+@@ -671,7 +684,8 @@ static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt)
+ }
+
+
+-static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
++static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
++ struct v4l2_format *fmt,
+ struct ov7670_format_struct **ret_fmt,
+ struct ov7670_win_size **ret_wsize)
+ {
+@@ -715,18 +729,23 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
+ return 0;
+ }
+
++static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
++{
++ return ov7670_try_fmt_internal(sd, fmt, NULL, NULL);
++}
++
+ /*
+ * Set a format.
+ */
+-static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
++static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+ {
+ int ret;
+ struct ov7670_format_struct *ovfmt;
+ struct ov7670_win_size *wsize;
+- struct ov7670_info *info = i2c_get_clientdata(c);
+- unsigned char com7, clkrc;
++ struct ov7670_info *info = to_state(sd);
++ unsigned char com7, clkrc = 0;
+
+- ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize);
++ ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
+ if (ret)
+ return ret;
+ /*
+@@ -735,7 +754,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
+ * the colors.
+ */
+ if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
+- ret = ov7670_read(c, REG_CLKRC, &clkrc);
++ ret = ov7670_read(sd, REG_CLKRC, &clkrc);
+ if (ret)
+ return ret;
+ }
+@@ -747,20 +766,20 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
+ */
+ com7 = ovfmt->regs[0].value;
+ com7 |= wsize->com7_bit;
+- ov7670_write(c, REG_COM7, com7);
++ ov7670_write(sd, REG_COM7, com7);
+ /*
+ * Now write the rest of the array. Also store start/stops
+ */
+- ov7670_write_array(c, ovfmt->regs + 1);
+- ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart,
++ ov7670_write_array(sd, ovfmt->regs + 1);
++ ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
+ wsize->vstop);
+ ret = 0;
+ if (wsize->regs)
+- ret = ov7670_write_array(c, wsize->regs);
++ ret = ov7670_write_array(sd, wsize->regs);
+ info->fmt = ovfmt;
+
+ if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0)
+- ret = ov7670_write(c, REG_CLKRC, clkrc);
++ ret = ov7670_write(sd, REG_CLKRC, clkrc);
+ return ret;
+ }
+
+@@ -768,7 +787,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
+ * Implement G/S_PARM. There is a "high quality" mode we could try
+ * to do someday; for now, we just do the frame rate tweak.
+ */
+-static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
++static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+ {
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ unsigned char clkrc;
+@@ -776,7 +795,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+- ret = ov7670_read(c, REG_CLKRC, &clkrc);
++ ret = ov7670_read(sd, REG_CLKRC, &clkrc);
+ if (ret < 0)
+ return ret;
+ memset(cp, 0, sizeof(struct v4l2_captureparm));
+@@ -788,7 +807,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+ return 0;
+ }
+
+-static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
++static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+ {
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ struct v4l2_fract *tpf = &cp->timeperframe;
+@@ -802,7 +821,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+ /*
+ * CLKRC has a reserved bit, so let's preserve it.
+ */
+- ret = ov7670_read(c, REG_CLKRC, &clkrc);
++ ret = ov7670_read(sd, REG_CLKRC, &clkrc);
+ if (ret < 0)
+ return ret;
+ if (tpf->numerator == 0 || tpf->denominator == 0)
+@@ -816,7 +835,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+ clkrc = (clkrc & 0x80) | div;
+ tpf->numerator = 1;
+ tpf->denominator = OV7670_FRAME_RATE/div;
+- return ov7670_write(c, REG_CLKRC, clkrc);
++ return ov7670_write(sd, REG_CLKRC, clkrc);
+ }
+
+
+@@ -829,7 +848,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+
+
+
+-static int ov7670_store_cmatrix(struct i2c_client *client,
++static int ov7670_store_cmatrix(struct v4l2_subdev *sd,
+ int matrix[CMATRIX_LEN])
+ {
+ int i, ret;
+@@ -839,7 +858,7 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
+ * Weird crap seems to exist in the upper part of
+ * the sign bits register, so let's preserve it.
+ */
+- ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits);
++ ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits);
+ signbits &= 0xc0;
+
+ for (i = 0; i < CMATRIX_LEN; i++) {
+@@ -858,9 +877,9 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
+ else
+ raw = matrix[i] & 0xff;
+ }
+- ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw);
++ ret += ov7670_write(sd, REG_CMATRIX_BASE + i, raw);
+ }
+- ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits);
++ ret += ov7670_write(sd, REG_CMATRIX_SIGN, signbits);
+ return ret;
+ }
+
+@@ -943,29 +962,29 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info,
+
+
+
+-static int ov7670_t_sat(struct i2c_client *client, int value)
++static int ov7670_s_sat(struct v4l2_subdev *sd, int value)
+ {
+- struct ov7670_info *info = i2c_get_clientdata(client);
++ struct ov7670_info *info = to_state(sd);
+ int matrix[CMATRIX_LEN];
+ int ret;
+
+ info->sat = value;
+ ov7670_calc_cmatrix(info, matrix);
+- ret = ov7670_store_cmatrix(client, matrix);
++ ret = ov7670_store_cmatrix(sd, matrix);
+ return ret;
+ }
+
+-static int ov7670_q_sat(struct i2c_client *client, __s32 *value)
++static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value)
+ {
+- struct ov7670_info *info = i2c_get_clientdata(client);
++ struct ov7670_info *info = to_state(sd);
+
+ *value = info->sat;
+ return 0;
+ }
+
+-static int ov7670_t_hue(struct i2c_client *client, int value)
++static int ov7670_s_hue(struct v4l2_subdev *sd, int value)
+ {
+- struct ov7670_info *info = i2c_get_clientdata(client);
++ struct ov7670_info *info = to_state(sd);
+ int matrix[CMATRIX_LEN];
+ int ret;
+
+@@ -973,14 +992,14 @@ static int ov7670_t_hue(struct i2c_client *client, int value)
+ return -EINVAL;
+ info->hue = value;
+ ov7670_calc_cmatrix(info, matrix);
+- ret = ov7670_store_cmatrix(client, matrix);
++ ret = ov7670_store_cmatrix(sd, matrix);
+ return ret;
+ }
+
+
+-static int ov7670_q_hue(struct i2c_client *client, __s32 *value)
++static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value)
+ {
+- struct ov7670_info *info = i2c_get_clientdata(client);
++ struct ov7670_info *info = to_state(sd);
+
+ *value = info->hue;
+ return 0;
+@@ -994,8 +1013,7 @@ static unsigned char ov7670_sm_to_abs(unsigned char v)
+ {
+ if ((v & 0x80) == 0)
+ return v + 128;
+- else
+- return 128 - (v & 0x7f);
++ return 128 - (v & 0x7f);
+ }
+
+
+@@ -1003,369 +1021,275 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
+ {
+ if (v > 127)
+ return v & 0x7f;
+- else
+- return (128 - v) | 0x80;
++ return (128 - v) | 0x80;
+ }
+
+-static int ov7670_t_brightness(struct i2c_client *client, int value)
++static int ov7670_s_brightness(struct v4l2_subdev *sd, int value)
+ {
+ unsigned char com8 = 0, v;
+ int ret;
+
+- ov7670_read(client, REG_COM8, &com8);
++ ov7670_read(sd, REG_COM8, &com8);
+ com8 &= ~COM8_AEC;
+- ov7670_write(client, REG_COM8, com8);
++ ov7670_write(sd, REG_COM8, com8);
+ v = ov7670_abs_to_sm(value);
+- ret = ov7670_write(client, REG_BRIGHT, v);
++ ret = ov7670_write(sd, REG_BRIGHT, v);
+ return ret;
+ }
+
+-static int ov7670_q_brightness(struct i2c_client *client, __s32 *value)
++static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value)
+ {
+ unsigned char v = 0;
+- int ret = ov7670_read(client, REG_BRIGHT, &v);
++ int ret = ov7670_read(sd, REG_BRIGHT, &v);
+
+ *value = ov7670_sm_to_abs(v);
+ return ret;
+ }
+
+-static int ov7670_t_contrast(struct i2c_client *client, int value)
++static int ov7670_s_contrast(struct v4l2_subdev *sd, int value)
+ {
+- return ov7670_write(client, REG_CONTRAS, (unsigned char) value);
++ return ov7670_write(sd, REG_CONTRAS, (unsigned char) value);
+ }
+
+-static int ov7670_q_contrast(struct i2c_client *client, __s32 *value)
++static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value)
+ {
+ unsigned char v = 0;
+- int ret = ov7670_read(client, REG_CONTRAS, &v);
++ int ret = ov7670_read(sd, REG_CONTRAS, &v);
+
+ *value = v;
+ return ret;
+ }
+
+-static int ov7670_q_hflip(struct i2c_client *client, __s32 *value)
++static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value)
+ {
+ int ret;
+ unsigned char v = 0;
+
+- ret = ov7670_read(client, REG_MVFP, &v);
++ ret = ov7670_read(sd, REG_MVFP, &v);
+ *value = (v & MVFP_MIRROR) == MVFP_MIRROR;
+ return ret;
+ }
+
+
+-static int ov7670_t_hflip(struct i2c_client *client, int value)
++static int ov7670_s_hflip(struct v4l2_subdev *sd, int value)
+ {
+ unsigned char v = 0;
+ int ret;
+
+- ret = ov7670_read(client, REG_MVFP, &v);
++ ret = ov7670_read(sd, REG_MVFP, &v);
+ if (value)
+ v |= MVFP_MIRROR;
+ else
+ v &= ~MVFP_MIRROR;
+ msleep(10); /* FIXME */
+- ret += ov7670_write(client, REG_MVFP, v);
++ ret += ov7670_write(sd, REG_MVFP, v);
+ return ret;
+ }
+
+
+
+-static int ov7670_q_vflip(struct i2c_client *client, __s32 *value)
++static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value)
+ {
+ int ret;
+ unsigned char v = 0;
+
+- ret = ov7670_read(client, REG_MVFP, &v);
++ ret = ov7670_read(sd, REG_MVFP, &v);
+ *value = (v & MVFP_FLIP) == MVFP_FLIP;
+ return ret;
+ }
+
+
+-static int ov7670_t_vflip(struct i2c_client *client, int value)
++static int ov7670_s_vflip(struct v4l2_subdev *sd, int value)
+ {
+ unsigned char v = 0;
+ int ret;
+
+- ret = ov7670_read(client, REG_MVFP, &v);
++ ret = ov7670_read(sd, REG_MVFP, &v);
+ if (value)
+ v |= MVFP_FLIP;
+ else
+ v &= ~MVFP_FLIP;
+ msleep(10); /* FIXME */
+- ret += ov7670_write(client, REG_MVFP, v);
++ ret += ov7670_write(sd, REG_MVFP, v);
+ return ret;
+ }
+
+-
+-static struct ov7670_control {
+- struct v4l2_queryctrl qc;
+- int (*query)(struct i2c_client *c, __s32 *value);
+- int (*tweak)(struct i2c_client *c, int value);
+-} ov7670_controls[] =
++static int ov7670_queryctrl(struct v4l2_subdev *sd,
++ struct v4l2_queryctrl *qc)
+ {
+- {
+- .qc = {
+- .id = V4L2_CID_BRIGHTNESS,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "Brightness",
+- .minimum = 0,
+- .maximum = 255,
+- .step = 1,
+- .default_value = 0x80,
+- .flags = V4L2_CTRL_FLAG_SLIDER
+- },
+- .tweak = ov7670_t_brightness,
+- .query = ov7670_q_brightness,
+- },
+- {
+- .qc = {
+- .id = V4L2_CID_CONTRAST,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "Contrast",
+- .minimum = 0,
+- .maximum = 127,
+- .step = 1,
+- .default_value = 0x40, /* XXX ov7670 spec */
+- .flags = V4L2_CTRL_FLAG_SLIDER
+- },
+- .tweak = ov7670_t_contrast,
+- .query = ov7670_q_contrast,
+- },
+- {
+- .qc = {
+- .id = V4L2_CID_SATURATION,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "Saturation",
+- .minimum = 0,
+- .maximum = 256,
+- .step = 1,
+- .default_value = 0x80,
+- .flags = V4L2_CTRL_FLAG_SLIDER
+- },
+- .tweak = ov7670_t_sat,
+- .query = ov7670_q_sat,
+- },
+- {
+- .qc = {
+- .id = V4L2_CID_HUE,
+- .type = V4L2_CTRL_TYPE_INTEGER,
+- .name = "HUE",
+- .minimum = -180,
+- .maximum = 180,
+- .step = 5,
+- .default_value = 0,
+- .flags = V4L2_CTRL_FLAG_SLIDER
+- },
+- .tweak = ov7670_t_hue,
+- .query = ov7670_q_hue,
+- },
+- {
+- .qc = {
+- .id = V4L2_CID_VFLIP,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- .name = "Vertical flip",
+- .minimum = 0,
+- .maximum = 1,
+- .step = 1,
+- .default_value = 0,
+- },
+- .tweak = ov7670_t_vflip,
+- .query = ov7670_q_vflip,
+- },
+- {
+- .qc = {
+- .id = V4L2_CID_HFLIP,
+- .type = V4L2_CTRL_TYPE_BOOLEAN,
+- .name = "Horizontal mirror",
+- .minimum = 0,
+- .maximum = 1,
+- .step = 1,
+- .default_value = 0,
+- },
+- .tweak = ov7670_t_hflip,
+- .query = ov7670_q_hflip,
+- },
+-};
+-#define N_CONTROLS (ARRAY_SIZE(ov7670_controls))
++ /* Fill in min, max, step and default value for these controls. */
++ switch (qc->id) {
++ case V4L2_CID_BRIGHTNESS:
++ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
++ case V4L2_CID_CONTRAST:
++ return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
++ case V4L2_CID_VFLIP:
++ case V4L2_CID_HFLIP:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
++ case V4L2_CID_SATURATION:
++ return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128);
++ case V4L2_CID_HUE:
++ return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0);
++ }
++ return -EINVAL;
++}
+
+-static struct ov7670_control *ov7670_find_control(__u32 id)
++static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ {
+- int i;
+-
+- for (i = 0; i < N_CONTROLS; i++)
+- if (ov7670_controls[i].qc.id == id)
+- return ov7670_controls + i;
+- return NULL;
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ return ov7670_g_brightness(sd, &ctrl->value);
++ case V4L2_CID_CONTRAST:
++ return ov7670_g_contrast(sd, &ctrl->value);
++ case V4L2_CID_SATURATION:
++ return ov7670_g_sat(sd, &ctrl->value);
++ case V4L2_CID_HUE:
++ return ov7670_g_hue(sd, &ctrl->value);
++ case V4L2_CID_VFLIP:
++ return ov7670_g_vflip(sd, &ctrl->value);
++ case V4L2_CID_HFLIP:
++ return ov7670_g_hflip(sd, &ctrl->value);
++ }
++ return -EINVAL;
+ }
+
++static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ return ov7670_s_brightness(sd, ctrl->value);
++ case V4L2_CID_CONTRAST:
++ return ov7670_s_contrast(sd, ctrl->value);
++ case V4L2_CID_SATURATION:
++ return ov7670_s_sat(sd, ctrl->value);
++ case V4L2_CID_HUE:
++ return ov7670_s_hue(sd, ctrl->value);
++ case V4L2_CID_VFLIP:
++ return ov7670_s_vflip(sd, ctrl->value);
++ case V4L2_CID_HFLIP:
++ return ov7670_s_hflip(sd, ctrl->value);
++ }
++ return -EINVAL;
++}
+
+-static int ov7670_queryctrl(struct i2c_client *client,
+- struct v4l2_queryctrl *qc)
++static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
++ struct v4l2_dbg_chip_ident *chip)
+ {
+- struct ov7670_control *ctrl = ov7670_find_control(qc->id);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- if (ctrl == NULL)
+- return -EINVAL;
+- *qc = ctrl->qc;
+- return 0;
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
+ }
+
+-static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+ {
+- struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ unsigned char val = 0;
+ int ret;
+
+- if (octrl == NULL)
++ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+- ret = octrl->query(client, &ctrl->value);
+- if (ret >= 0)
+- return 0;
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ ret = ov7670_read(sd, reg->reg & 0xff, &val);
++ reg->val = val;
++ reg->size = 1;
+ return ret;
+ }
+
+-static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
++static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+ {
+- struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
+- int ret;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- if (octrl == NULL)
++ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+- ret = octrl->tweak(client, ctrl->value);
+- if (ret >= 0)
+- return 0;
+- return ret;
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ ov7670_write(sd, reg->reg & 0xff, reg->val & 0xff);
++ return 0;
+ }
++#endif
++
++/* ----------------------------------------------------------------------- */
++
++static const struct v4l2_subdev_core_ops ov7670_core_ops = {
++ .g_chip_ident = ov7670_g_chip_ident,
++ .g_ctrl = ov7670_g_ctrl,
++ .s_ctrl = ov7670_s_ctrl,
++ .queryctrl = ov7670_queryctrl,
++ .reset = ov7670_reset,
++ .init = ov7670_init,
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ov7670_g_register,
++ .s_register = ov7670_s_register,
++#endif
++};
+
++static const struct v4l2_subdev_video_ops ov7670_video_ops = {
++ .enum_fmt = ov7670_enum_fmt,
++ .try_fmt = ov7670_try_fmt,
++ .s_fmt = ov7670_s_fmt,
++ .s_parm = ov7670_s_parm,
++ .g_parm = ov7670_g_parm,
++};
+
++static const struct v4l2_subdev_ops ov7670_ops = {
++ .core = &ov7670_core_ops,
++ .video = &ov7670_video_ops,
++};
+
++/* ----------------------------------------------------------------------- */
+
+-
+-
+-/*
+- * Basic i2c stuff.
+- */
+-static struct i2c_driver ov7670_driver;
+-
+-static int ov7670_attach(struct i2c_adapter *adapter)
++static int ov7670_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
+ {
+- int ret;
+- struct i2c_client *client;
++ struct v4l2_subdev *sd;
+ struct ov7670_info *info;
++ int ret;
+
+- /*
+- * For now: only deal with adapters we recognize.
+- */
+- if (adapter->id != I2C_HW_SMBUS_CAFE)
+- return -ENODEV;
+-
+- client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL);
+- if (! client)
++ info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
++ if (info == NULL)
+ return -ENOMEM;
+- client->adapter = adapter;
+- client->addr = OV7670_I2C_ADDR;
+- client->driver = &ov7670_driver,
+- strcpy(client->name, "OV7670");
+- /*
+- * Set up our info structure.
+- */
+- info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL);
+- if (! info) {
+- ret = -ENOMEM;
+- goto out_free;
++ sd = &info->sd;
++ v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
++
++ /* Make sure it's an ov7670 */
++ ret = ov7670_detect(sd);
++ if (ret) {
++ v4l_dbg(1, debug, client,
++ "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
++ client->addr << 1, client->adapter->name);
++ kfree(info);
++ return ret;
+ }
++ v4l_info(client, "chip found @ 0x%02x (%s)\n",
++ client->addr << 1, client->adapter->name);
++
+ info->fmt = &ov7670_formats[0];
+ info->sat = 128; /* Review this */
+- i2c_set_clientdata(client, info);
+
+- /*
+- * Make sure it's an ov7670
+- */
+- ret = ov7670_detect(client);
+- if (ret)
+- goto out_free_info;
+- ret = i2c_attach_client(client);
+- if (ret)
+- goto out_free_info;
+ return 0;
+-
+- out_free_info:
+- kfree(info);
+- out_free:
+- kfree(client);
+- return ret;
+ }
+
+
+-static int ov7670_detach(struct i2c_client *client)
++static int ov7670_remove(struct i2c_client *client)
+ {
+- i2c_detach_client(client);
+- kfree(i2c_get_clientdata(client));
+- kfree(client);
+- return 0;
+-}
+-
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+-static int ov7670_command(struct i2c_client *client, unsigned int cmd,
+- void *arg)
+-{
+- switch (cmd) {
+- case VIDIOC_DBG_G_CHIP_IDENT:
+- return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0);
+-
+- case VIDIOC_INT_RESET:
+- ov7670_reset(client);
+- return 0;
+-
+- case VIDIOC_INT_INIT:
+- return ov7670_init(client);
+-
+- case VIDIOC_ENUM_FMT:
+- return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg);
+- case VIDIOC_TRY_FMT:
+- return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL);
+- case VIDIOC_S_FMT:
+- return ov7670_s_fmt(client, (struct v4l2_format *) arg);
+- case VIDIOC_QUERYCTRL:
+- return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg);
+- case VIDIOC_S_CTRL:
+- return ov7670_s_ctrl(client, (struct v4l2_control *) arg);
+- case VIDIOC_G_CTRL:
+- return ov7670_g_ctrl(client, (struct v4l2_control *) arg);
+- case VIDIOC_S_PARM:
+- return ov7670_s_parm(client, (struct v4l2_streamparm *) arg);
+- case VIDIOC_G_PARM:
+- return ov7670_g_parm(client, (struct v4l2_streamparm *) arg);
+- }
+- return -EINVAL;
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_state(sd));
++ return 0;
+ }
+
+-
+-
+-static struct i2c_driver ov7670_driver = {
+- .driver = {
+- .name = "ov7670",
+- },
+- .id = I2C_DRIVERID_OV7670,
+- .attach_adapter = ov7670_attach,
+- .detach_client = ov7670_detach,
+- .command = ov7670_command,
++static const struct i2c_device_id ov7670_id[] = {
++ { "ov7670", 0 },
++ { }
+ };
++MODULE_DEVICE_TABLE(i2c, ov7670_id);
+
+-
+-/*
+- * Module initialization
+- */
+-static int __init ov7670_mod_init(void)
+-{
+- printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n");
+- return i2c_add_driver(&ov7670_driver);
+-}
+-
+-static void __exit ov7670_mod_exit(void)
+-{
+- i2c_del_driver(&ov7670_driver);
+-}
+-
+-module_init(ov7670_mod_init);
+-module_exit(ov7670_mod_exit);
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++ .name = "ov7670",
++ .probe = ov7670_probe,
++ .remove = ov7670_remove,
++ .id_table = ov7670_id,
++};
+diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
+index 3c9e0ba..84b0fc1 100644
+--- a/drivers/media/video/ov772x.c
++++ b/drivers/media/video/ov772x.c
+@@ -217,10 +217,11 @@
+ #define OCAP_4x 0x03 /* 4x */
+
+ /* COM3 */
+-#define SWAP_MASK 0x38
++#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML)
++#define IMG_MASK (VFLIP_IMG | HFLIP_IMG)
+
+-#define VFIMG_ON_OFF 0x80 /* Vertical flip image ON/OFF selection */
+-#define HMIMG_ON_OFF 0x40 /* Horizontal mirror image ON/OFF selection */
++#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */
++#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */
+ #define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */
+ #define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */
+ #define SWAP_ML 0x08 /* Swap output MSB/LSB */
+@@ -271,11 +272,13 @@
+ #define SLCT_QVGA 0x40 /* 1 : QVGA */
+ #define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */
+ /* RGB output format control */
++#define FMT_MASK 0x0c /* Mask of color format */
+ #define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */
+ #define FMT_RGB565 0x04 /* 01 : RGB 565 */
+ #define FMT_RGB555 0x08 /* 10 : RGB 555 */
+ #define FMT_RGB444 0x0c /* 11 : RGB 444 */
+ /* Output format control */
++#define OFMT_MASK 0x03 /* Mask of output format */
+ #define OFMT_YUV 0x00 /* 00 : YUV */
+ #define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */
+ #define OFMT_RGB 0x02 /* 10 : RGB */
+@@ -299,7 +302,7 @@
+ #define GAIN_2x 0x00 /* 000 : 2x */
+ #define GAIN_4x 0x10 /* 001 : 4x */
+ #define GAIN_8x 0x20 /* 010 : 8x */
+-#define GAIN_16x 0x30 /* 011 : 16x */
++#define GAIN_16x 0x30 /* 011 : 16x */
+ #define GAIN_32x 0x40 /* 100 : 32x */
+ #define GAIN_64x 0x50 /* 101 : 64x */
+ #define GAIN_128x 0x60 /* 110 : 128x */
+@@ -356,13 +359,6 @@
+ #define VOSZ_QVGA 0x78
+
+ /*
+- * bit configure (32 bit)
+- * this is used in struct ov772x_color_format :: option
+- */
+-#define OP_UV 0x00000001
+-#define OP_SWAP_RGB 0x00000002
+-
+-/*
+ * ID
+ */
+ #define OV7720 0x7720
+@@ -380,8 +376,9 @@ struct regval_list {
+ struct ov772x_color_format {
+ char *name;
+ __u32 fourcc;
+- const struct regval_list *regs;
+- unsigned int option;
++ u8 dsp3;
++ u8 com3;
++ u8 com7;
+ };
+
+ struct ov772x_win_size {
+@@ -399,39 +396,13 @@ struct ov772x_priv {
+ const struct ov772x_color_format *fmt;
+ const struct ov772x_win_size *win;
+ int model;
++ unsigned int flag_vflip:1;
++ unsigned int flag_hflip:1;
+ };
+
+ #define ENDMARKER { 0xff, 0xff }
+
+ /*
+- * register setting for color format
+- */
+-static const struct regval_list ov772x_RGB555_regs[] = {
+- { COM3, 0x00 },
+- { COM7, FMT_RGB555 | OFMT_RGB },
+- ENDMARKER,
+-};
+-
+-static const struct regval_list ov772x_RGB565_regs[] = {
+- { COM3, 0x00 },
+- { COM7, FMT_RGB565 | OFMT_RGB },
+- ENDMARKER,
+-};
+-
+-static const struct regval_list ov772x_YYUV_regs[] = {
+- { COM3, SWAP_YUV },
+- { COM7, OFMT_YUV },
+- ENDMARKER,
+-};
+-
+-static const struct regval_list ov772x_UVYY_regs[] = {
+- { COM3, 0x00 },
+- { COM7, OFMT_YUV },
+- ENDMARKER,
+-};
+-
+-
+-/*
+ * register setting for window size
+ */
+ static const struct regval_list ov772x_qvga_regs[] = {
+@@ -500,38 +471,48 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = {
+ /*
+ * color format list
+ */
+-#define T_YUYV 0
+ static const struct ov772x_color_format ov772x_cfmts[] = {
+- [T_YUYV] = {
++ {
+ SETFOURCC(YUYV),
+- .regs = ov772x_YYUV_regs,
++ .dsp3 = 0x0,
++ .com3 = SWAP_YUV,
++ .com7 = OFMT_YUV,
+ },
+ {
+ SETFOURCC(YVYU),
+- .regs = ov772x_YYUV_regs,
+- .option = OP_UV,
++ .dsp3 = UV_ON,
++ .com3 = SWAP_YUV,
++ .com7 = OFMT_YUV,
+ },
+ {
+ SETFOURCC(UYVY),
+- .regs = ov772x_UVYY_regs,
++ .dsp3 = 0x0,
++ .com3 = 0x0,
++ .com7 = OFMT_YUV,
+ },
+ {
+ SETFOURCC(RGB555),
+- .regs = ov772x_RGB555_regs,
+- .option = OP_SWAP_RGB,
++ .dsp3 = 0x0,
++ .com3 = SWAP_RGB,
++ .com7 = FMT_RGB555 | OFMT_RGB,
+ },
+ {
+ SETFOURCC(RGB555X),
+- .regs = ov772x_RGB555_regs,
++ .dsp3 = 0x0,
++ .com3 = 0x0,
++ .com7 = FMT_RGB555 | OFMT_RGB,
+ },
+ {
+ SETFOURCC(RGB565),
+- .regs = ov772x_RGB565_regs,
+- .option = OP_SWAP_RGB,
++ .dsp3 = 0x0,
++ .com3 = SWAP_RGB,
++ .com7 = FMT_RGB565 | OFMT_RGB,
+ },
+ {
+ SETFOURCC(RGB565X),
+- .regs = ov772x_RGB565_regs,
++ .dsp3 = 0x0,
++ .com3 = 0x0,
++ .com7 = FMT_RGB565 | OFMT_RGB,
+ },
+ };
+
+@@ -562,6 +543,27 @@ static const struct ov772x_win_size ov772x_win_qvga = {
+ .regs = ov772x_qvga_regs,
+ };
+
++static const struct v4l2_queryctrl ov772x_controls[] = {
++ {
++ .id = V4L2_CID_VFLIP,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .name = "Flip Vertically",
++ .minimum = 0,
++ .maximum = 1,
++ .step = 1,
++ .default_value = 0,
++ },
++ {
++ .id = V4L2_CID_HFLIP,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .name = "Flip Horizontally",
++ .minimum = 0,
++ .maximum = 1,
++ .step = 1,
++ .default_value = 0,
++ },
++};
++
+
+ /*
+ * general function
+@@ -587,8 +589,11 @@ static int ov772x_mask_set(struct i2c_client *client,
+ u8 set)
+ {
+ s32 val = i2c_smbus_read_byte_data(client, command);
++ if (val < 0)
++ return val;
++
+ val &= ~mask;
+- val |= set;
++ val |= set & mask;
+
+ return i2c_smbus_write_byte_data(client, command, val);
+ }
+@@ -635,74 +640,24 @@ static int ov772x_release(struct soc_camera_device *icd)
+ static int ov772x_start_capture(struct soc_camera_device *icd)
+ {
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+- int ret;
+-
+- if (!priv->win)
+- priv->win = &ov772x_win_vga;
+- if (!priv->fmt)
+- priv->fmt = &ov772x_cfmts[T_YUYV];
+-
+- /*
+- * reset hardware
+- */
+- ov772x_reset(priv->client);
+
+- /*
+- * set color format
+- */
+- ret = ov772x_write_array(priv->client, priv->fmt->regs);
+- if (ret < 0)
+- goto start_end;
+-
+- /*
+- * set size format
+- */
+- ret = ov772x_write_array(priv->client, priv->win->regs);
+- if (ret < 0)
+- goto start_end;
+-
+- /*
+- * set COM7 bit ( QVGA or VGA )
+- */
+- ret = ov772x_mask_set(priv->client,
+- COM7, SLCT_MASK, priv->win->com7_bit);
+- if (ret < 0)
+- goto start_end;
+-
+- /*
+- * set UV setting
+- */
+- if (priv->fmt->option & OP_UV) {
+- ret = ov772x_mask_set(priv->client,
+- DSP_CTRL3, UV_MASK, UV_ON);
+- if (ret < 0)
+- goto start_end;
++ if (!priv->win || !priv->fmt) {
++ dev_err(&icd->dev, "norm or win select error\n");
++ return -EPERM;
+ }
+
+- /*
+- * set SWAP setting
+- */
+- if (priv->fmt->option & OP_SWAP_RGB) {
+- ret = ov772x_mask_set(priv->client,
+- COM3, SWAP_MASK, SWAP_RGB);
+- if (ret < 0)
+- goto start_end;
+- }
++ ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, 0);
+
+ dev_dbg(&icd->dev,
+ "format %s, win %s\n", priv->fmt->name, priv->win->name);
+
+-start_end:
+- priv->fmt = NULL;
+- priv->win = NULL;
+-
+- return ret;
++ return 0;
+ }
+
+ static int ov772x_stop_capture(struct soc_camera_device *icd)
+ {
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+- ov772x_reset(priv->client);
++ ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+ return 0;
+ }
+
+@@ -718,11 +673,54 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
+ struct soc_camera_link *icl = priv->client->dev.platform_data;
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+- priv->info->buswidth;
++ SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+ }
+
++static int ov772x_get_control(struct soc_camera_device *icd,
++ struct v4l2_control *ctrl)
++{
++ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
++
++ switch (ctrl->id) {
++ case V4L2_CID_VFLIP:
++ ctrl->value = priv->flag_vflip;
++ break;
++ case V4L2_CID_HFLIP:
++ ctrl->value = priv->flag_hflip;
++ break;
++ }
++ return 0;
++}
++
++static int ov772x_set_control(struct soc_camera_device *icd,
++ struct v4l2_control *ctrl)
++{
++ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
++ int ret = 0;
++ u8 val;
++
++ switch (ctrl->id) {
++ case V4L2_CID_VFLIP:
++ val = ctrl->value ? VFLIP_IMG : 0x00;
++ priv->flag_vflip = ctrl->value;
++ if (priv->info->flags & OV772X_FLAG_VFLIP)
++ val ^= VFLIP_IMG;
++ ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val);
++ break;
++ case V4L2_CID_HFLIP:
++ val = ctrl->value ? HFLIP_IMG : 0x00;
++ priv->flag_hflip = ctrl->value;
++ if (priv->info->flags & OV772X_FLAG_HFLIP)
++ val ^= HFLIP_IMG;
++ ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val);
++ break;
++ }
++
++ return ret;
++}
++
+ static int ov772x_get_chip_id(struct soc_camera_device *icd,
+ struct v4l2_dbg_chip_ident *id)
+ {
+@@ -787,13 +785,11 @@ ov772x_select_win(u32 width, u32 height)
+ return win;
+ }
+
+-
+-static int ov772x_set_fmt(struct soc_camera_device *icd,
+- __u32 pixfmt,
+- struct v4l2_rect *rect)
++static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height,
++ u32 pixfmt)
+ {
+- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ int ret = -EINVAL;
++ u8 val;
+ int i;
+
+ /*
+@@ -803,19 +799,101 @@ static int ov772x_set_fmt(struct soc_camera_device *icd,
+ for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
+ if (pixfmt == ov772x_cfmts[i].fourcc) {
+ priv->fmt = ov772x_cfmts + i;
+- ret = 0;
+ break;
+ }
+ }
++ if (!priv->fmt)
++ goto ov772x_set_fmt_error;
+
+ /*
+ * select win
+ */
+- priv->win = ov772x_select_win(rect->width, rect->height);
++ priv->win = ov772x_select_win(width, height);
++
++ /*
++ * reset hardware
++ */
++ ov772x_reset(priv->client);
++
++ /*
++ * set size format
++ */
++ ret = ov772x_write_array(priv->client, priv->win->regs);
++ if (ret < 0)
++ goto ov772x_set_fmt_error;
++
++ /*
++ * set DSP_CTRL3
++ */
++ val = priv->fmt->dsp3;
++ if (val) {
++ ret = ov772x_mask_set(priv->client,
++ DSP_CTRL3, UV_MASK, val);
++ if (ret < 0)
++ goto ov772x_set_fmt_error;
++ }
++
++ /*
++ * set COM3
++ */
++ val = priv->fmt->com3;
++ if (priv->info->flags & OV772X_FLAG_VFLIP)
++ val |= VFLIP_IMG;
++ if (priv->info->flags & OV772X_FLAG_HFLIP)
++ val |= HFLIP_IMG;
++ if (priv->flag_vflip)
++ val ^= VFLIP_IMG;
++ if (priv->flag_hflip)
++ val ^= HFLIP_IMG;
++
++ ret = ov772x_mask_set(priv->client,
++ COM3, SWAP_MASK | IMG_MASK, val);
++ if (ret < 0)
++ goto ov772x_set_fmt_error;
++
++ /*
++ * set COM7
++ */
++ val = priv->win->com7_bit | priv->fmt->com7;
++ ret = ov772x_mask_set(priv->client,
++ COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK),
++ val);
++ if (ret < 0)
++ goto ov772x_set_fmt_error;
++
++ return ret;
++
++ov772x_set_fmt_error:
++
++ ov772x_reset(priv->client);
++ priv->win = NULL;
++ priv->fmt = NULL;
+
+ return ret;
+ }
+
++static int ov772x_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
++{
++ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
++
++ if (!priv->fmt)
++ return -EINVAL;
++
++ return ov772x_set_params(priv, rect->width, rect->height,
++ priv->fmt->fourcc);
++}
++
++static int ov772x_set_fmt(struct soc_camera_device *icd,
++ struct v4l2_format *f)
++{
++ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++
++ return ov772x_set_params(priv, pix->width, pix->height,
++ pix->pixelformat);
++}
++
+ static int ov772x_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+ {
+@@ -889,7 +967,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
+ i2c_smbus_read_byte_data(priv->client, MIDH),
+ i2c_smbus_read_byte_data(priv->client, MIDL));
+
+-
+ return soc_camera_video_start(icd);
+ }
+
+@@ -906,10 +983,15 @@ static struct soc_camera_ops ov772x_ops = {
+ .release = ov772x_release,
+ .start_capture = ov772x_start_capture,
+ .stop_capture = ov772x_stop_capture,
++ .set_crop = ov772x_set_crop,
+ .set_fmt = ov772x_set_fmt,
+ .try_fmt = ov772x_try_fmt,
+ .set_bus_param = ov772x_set_bus_param,
+ .query_bus_param = ov772x_query_bus_param,
++ .controls = ov772x_controls,
++ .num_controls = ARRAY_SIZE(ov772x_controls),
++ .get_control = ov772x_get_control,
++ .set_control = ov772x_set_control,
+ .get_chip_id = ov772x_get_chip_id,
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ .get_register = ov772x_get_register,
+diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
+index c841f4e..d573d84 100644
+--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
++++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
+@@ -15,6 +15,9 @@
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/delay.h>
++#include <linux/i2c.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-i2c-drv.h>
+ #include "ovcamchip_priv.h"
+
+ #define DRIVER_VERSION "v2.27 for Linux 2.6"
+@@ -44,6 +47,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
+ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_LICENSE("GPL");
+
++
+ /* Registers common to all chips, that are needed for detection */
+ #define GENERIC_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
+ #define GENERIC_REG_ID_LOW 0x1D /* manufacturer ID LSB */
+@@ -61,10 +65,6 @@ static char *chip_names[NUM_CC_TYPES] = {
+ [CC_OV6630AF] = "OV6630AF",
+ };
+
+-/* Forward declarations */
+-static struct i2c_driver driver;
+-static struct i2c_client client_template;
+-
+ /* ----------------------------------------------------------------------- */
+
+ int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
+@@ -253,112 +253,36 @@ static int ovcamchip_detect(struct i2c_client *c)
+
+ /* Test for 7xx0 */
+ PDEBUG(3, "Testing for 0V7xx0");
+- c->addr = OV7xx0_SID;
+- if (init_camchip(c) < 0) {
+- /* Test for 6xx0 */
+- PDEBUG(3, "Testing for 0V6xx0");
+- c->addr = OV6xx0_SID;
+- if (init_camchip(c) < 0) {
+- return -ENODEV;
+- } else {
+- if (ov6xx0_detect(c) < 0) {
+- PERROR("Failed to init OV6xx0");
+- return -EIO;
+- }
+- }
+- } else {
++ if (init_camchip(c) < 0)
++ return -ENODEV;
++ /* 7-bit addresses with bit 0 set are for the OV7xx0 */
++ if (c->addr & 1) {
+ if (ov7xx0_detect(c) < 0) {
+ PERROR("Failed to init OV7xx0");
+ return -EIO;
+ }
++ return 0;
++ }
++ /* Test for 6xx0 */
++ PDEBUG(3, "Testing for 0V6xx0");
++ if (ov6xx0_detect(c) < 0) {
++ PERROR("Failed to init OV6xx0");
++ return -EIO;
+ }
+-
+ return 0;
+ }
+
+ /* ----------------------------------------------------------------------- */
+
+-static int ovcamchip_attach(struct i2c_adapter *adap)
++static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+ {
+- int rc = 0;
+- struct ovcamchip *ov;
+- struct i2c_client *c;
+-
+- /* I2C is not a PnP bus, so we can never be certain that we're talking
+- * to the right chip. To prevent damage to EEPROMS and such, only
+- * attach to adapters that are known to contain OV camera chips. */
+-
+- switch (adap->id) {
+- case I2C_HW_SMBUS_OV511:
+- case I2C_HW_SMBUS_OV518:
+- case I2C_HW_SMBUS_W9968CF:
+- PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id);
+- break;
+- default:
+- PDEBUG(1, "Adapter ID 0x%06x rejected", adap->id);
+- return -ENODEV;
+- }
+-
+- c = kmalloc(sizeof *c, GFP_KERNEL);
+- if (!c) {
+- rc = -ENOMEM;
+- goto no_client;
+- }
+- memcpy(c, &client_template, sizeof *c);
+- c->adapter = adap;
+- strcpy(c->name, "OV????");
+-
+- ov = kzalloc(sizeof *ov, GFP_KERNEL);
+- if (!ov) {
+- rc = -ENOMEM;
+- goto no_ov;
+- }
+- i2c_set_clientdata(c, ov);
+-
+- rc = ovcamchip_detect(c);
+- if (rc < 0)
+- goto error;
+-
+- strcpy(c->name, chip_names[ov->subtype]);
+-
+- PDEBUG(1, "Camera chip detection complete");
+-
+- i2c_attach_client(c);
+-
+- return rc;
+-error:
+- kfree(ov);
+-no_ov:
+- kfree(c);
+-no_client:
+- PDEBUG(1, "returning %d", rc);
+- return rc;
+-}
+-
+-static int ovcamchip_detach(struct i2c_client *c)
+-{
+- struct ovcamchip *ov = i2c_get_clientdata(c);
+- int rc;
+-
+- rc = ov->sops->free(c);
+- if (rc < 0)
+- return rc;
+-
+- i2c_detach_client(c);
+-
+- kfree(ov);
+- kfree(c);
+- return 0;
+-}
+-
+-static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
+-{
+- struct ovcamchip *ov = i2c_get_clientdata(c);
++ struct ovcamchip *ov = to_ovcamchip(sd);
++ struct i2c_client *c = v4l2_get_subdevdata(sd);
+
+ if (!ov->initialized &&
+ cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
+ cmd != OVCAMCHIP_CMD_INITIALIZE) {
+- dev_err(&c->dev, "ERROR: Camera chip not initialized yet!\n");
++ v4l2_err(sd, "Camera chip not initialized yet!\n");
+ return -EPERM;
+ }
+
+@@ -379,10 +303,10 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
+
+ if (ov->mono) {
+ if (ov->subtype != CC_OV7620)
+- dev_warn(&c->dev, "Warning: Monochrome not "
++ v4l2_warn(sd, "Monochrome not "
+ "implemented for this chip\n");
+ else
+- dev_info(&c->dev, "Initializing chip as "
++ v4l2_info(sd, "Initializing chip as "
+ "monochrome\n");
+ }
+
+@@ -400,35 +324,72 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
+
+ /* ----------------------------------------------------------------------- */
+
+-static struct i2c_driver driver = {
+- .driver = {
+- .name = "ovcamchip",
+- },
+- .id = I2C_DRIVERID_OVCAMCHIP,
+- .attach_adapter = ovcamchip_attach,
+- .detach_client = ovcamchip_detach,
+- .command = ovcamchip_command,
++static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
++ .ioctl = ovcamchip_ioctl,
+ };
+
+-static struct i2c_client client_template = {
+- .name = "(unset)",
+- .driver = &driver,
++static const struct v4l2_subdev_ops ovcamchip_ops = {
++ .core = &ovcamchip_core_ops,
+ };
+
+-static int __init ovcamchip_init(void)
++static int ovcamchip_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
+ {
+-#ifdef DEBUG
+- ovcamchip_debug = debug;
+-#endif
++ struct ovcamchip *ov;
++ struct v4l2_subdev *sd;
++ int rc = 0;
++
++ ov = kzalloc(sizeof *ov, GFP_KERNEL);
++ if (!ov) {
++ rc = -ENOMEM;
++ goto no_ov;
++ }
++ sd = &ov->sd;
++ v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
++
++ rc = ovcamchip_detect(client);
++ if (rc < 0)
++ goto error;
++
++ v4l_info(client, "%s found @ 0x%02x (%s)\n",
++ chip_names[ov->subtype], client->addr << 1, client->adapter->name);
++
++ PDEBUG(1, "Camera chip detection complete");
+
+- PINFO(DRIVER_VERSION " : " DRIVER_DESC);
+- return i2c_add_driver(&driver);
++ return rc;
++error:
++ kfree(ov);
++no_ov:
++ PDEBUG(1, "returning %d", rc);
++ return rc;
+ }
+
+-static void __exit ovcamchip_exit(void)
++static int ovcamchip_remove(struct i2c_client *client)
+ {
+- i2c_del_driver(&driver);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct ovcamchip *ov = to_ovcamchip(sd);
++ int rc;
++
++ v4l2_device_unregister_subdev(sd);
++ rc = ov->sops->free(client);
++ if (rc < 0)
++ return rc;
++
++ kfree(ov);
++ return 0;
+ }
+
+-module_init(ovcamchip_init);
+-module_exit(ovcamchip_exit);
++/* ----------------------------------------------------------------------- */
++
++static const struct i2c_device_id ovcamchip_id[] = {
++ { "ovcamchip", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
++
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++ .name = "ovcamchip",
++ .probe = ovcamchip_probe,
++ .remove = ovcamchip_remove,
++ .id_table = ovcamchip_id,
++};
+diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
+index a05650f..4f07b78 100644
+--- a/drivers/media/video/ovcamchip/ovcamchip_priv.h
++++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h
+@@ -16,6 +16,7 @@
+ #define __LINUX_OVCAMCHIP_PRIV_H
+
+ #include <linux/i2c.h>
++#include <media/v4l2-subdev.h>
+ #include <media/ovcamchip.h>
+
+ #ifdef DEBUG
+@@ -46,6 +47,7 @@ struct ovcamchip_ops {
+ };
+
+ struct ovcamchip {
++ struct v4l2_subdev sd;
+ struct ovcamchip_ops *sops;
+ void *spriv; /* Private data for OV7x10.c etc... */
+ int subtype; /* = SEN_OV7610 etc... */
+@@ -53,6 +55,11 @@ struct ovcamchip {
+ int initialized; /* OVCAMCHIP_CMD_INITIALIZE was successful */
+ };
+
++static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct ovcamchip, sd);
++}
++
+ extern struct ovcamchip_ops ov6x20_ops;
+ extern struct ovcamchip_ops ov6x30_ops;
+ extern struct ovcamchip_ops ov7x10_ops;
+diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
+index 854c2a8..f9b6001 100644
+--- a/drivers/media/video/pvrusb2/Kconfig
++++ b/drivers/media/video/pvrusb2/Kconfig
+@@ -40,10 +40,10 @@ config VIDEO_PVRUSB2_DVB
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+- select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
+- select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
++ select DVB_TDA10048 if !DVB_FE_CUSTOMISE
++ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+ ---help---
+
+ This option enables a DVB interface for the pvrusb2 driver.
+diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
+index 4fda2de..de2fc14 100644
+--- a/drivers/media/video/pvrusb2/Makefile
++++ b/drivers/media/video/pvrusb2/Makefile
+@@ -2,14 +2,15 @@ obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
+ obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+ obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
+
+-pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
+- pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
++pvrusb2-objs := pvrusb2-i2c-core.o \
++ pvrusb2-audio.o \
+ pvrusb2-encoder.o pvrusb2-video-v4l.o \
+- pvrusb2-eeprom.o pvrusb2-tuner.o \
++ pvrusb2-eeprom.o \
+ pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
+ pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
+ pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
+ pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
++ pvrusb2-cs53l32a.o \
+ $(obj-pvrusb2-dvb-y) \
+ $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
+
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
+index cdedaa5..ccf2a3c 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
+@@ -26,14 +26,6 @@
+ #include <media/msp3400.h>
+ #include <media/v4l2-common.h>
+
+-struct pvr2_msp3400_handler {
+- struct pvr2_hdw *hdw;
+- struct pvr2_i2c_client *client;
+- struct pvr2_i2c_handler i2c_handler;
+- unsigned long stale_mask;
+-};
+-
+-
+
+ struct routing_scheme {
+ const int *def;
+@@ -63,123 +55,33 @@ static const struct routing_scheme routing_schemes[] = {
+ },
+ };
+
+-/* This function selects the correct audio input source */
+-static void set_stereo(struct pvr2_msp3400_handler *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- struct v4l2_routing route;
+- const struct routing_scheme *sp;
+- unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+-
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
+-
+- if ((sid < ARRAY_SIZE(routing_schemes)) &&
+- ((sp = routing_schemes + sid) != NULL) &&
+- (hdw->input_val >= 0) &&
+- (hdw->input_val < sp->cnt)) {
+- route.input = sp->def[hdw->input_val];
+- } else {
+- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+- "*** WARNING *** i2c msp3400 v4l2 set_stereo:"
+- " Invalid routing scheme (%u) and/or input (%d)",
+- sid,hdw->input_val);
+- return;
+- }
+- route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+-}
+-
+-
+-static int check_stereo(struct pvr2_msp3400_handler *ctxt)
++void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
+ {
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- return hdw->input_dirty;
+-}
+-
+-
+-struct pvr2_msp3400_ops {
+- void (*update)(struct pvr2_msp3400_handler *);
+- int (*check)(struct pvr2_msp3400_handler *);
+-};
+-
+-
+-static const struct pvr2_msp3400_ops msp3400_ops[] = {
+- { .update = set_stereo, .check = check_stereo},
+-};
+-
+-
+-static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
+-{
+- unsigned long msk;
+- unsigned int idx;
+-
+- for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
+- msk = 1 << idx;
+- if (ctxt->stale_mask & msk) continue;
+- if (msp3400_ops[idx].check(ctxt)) {
+- ctxt->stale_mask |= msk;
++ if (hdw->input_dirty || hdw->force_dirty) {
++ struct v4l2_routing route;
++ const struct routing_scheme *sp;
++ unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
++
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo");
++
++ if ((sid < ARRAY_SIZE(routing_schemes)) &&
++ ((sp = routing_schemes + sid) != NULL) &&
++ (hdw->input_val >= 0) &&
++ (hdw->input_val < sp->cnt)) {
++ route.input = sp->def[hdw->input_val];
++ } else {
++ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++ "*** WARNING *** subdev msp3400 set_input:"
++ " Invalid routing scheme (%u)"
++ " and/or input (%d)",
++ sid, hdw->input_val);
++ return;
+ }
++ route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
++ sd->ops->audio->s_routing(sd, &route);
+ }
+- return ctxt->stale_mask != 0;
+ }
+
+-
+-static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
+-{
+- unsigned long msk;
+- unsigned int idx;
+-
+- for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
+- msk = 1 << idx;
+- if (!(ctxt->stale_mask & msk)) continue;
+- ctxt->stale_mask &= ~msk;
+- msp3400_ops[idx].update(ctxt);
+- }
+-}
+-
+-
+-static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
+-{
+- ctxt->client->handler = NULL;
+- kfree(ctxt);
+-}
+-
+-
+-static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt,
+- char *buf,unsigned int cnt)
+-{
+- return scnprintf(buf,cnt,"handler: pvrusb2-audio v4l2");
+-}
+-
+-
+-static const struct pvr2_i2c_handler_functions msp3400_funcs = {
+- .detach = (void (*)(void *))pvr2_msp3400_detach,
+- .check = (int (*)(void *))msp3400_check,
+- .update = (void (*)(void *))msp3400_update,
+- .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_msp3400_describe,
+-};
+-
+-
+-int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+-{
+- struct pvr2_msp3400_handler *ctxt;
+- if (cp->handler) return 0;
+-
+- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
+- if (!ctxt) return 0;
+-
+- ctxt->i2c_handler.func_data = ctxt;
+- ctxt->i2c_handler.func_table = &msp3400_funcs;
+- ctxt->client = cp;
+- ctxt->hdw = hdw;
+- ctxt->stale_mask = (1 << ARRAY_SIZE(msp3400_ops)) - 1;
+- cp->handler = &ctxt->i2c_handler;
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
+- cp->client->addr);
+- return !0;
+-}
+-
+-
+ /*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.h b/drivers/media/video/pvrusb2/pvrusb2-audio.h
+index ac54eed..e3e63d7 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-audio.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-audio.h
+@@ -22,10 +22,8 @@
+ #ifndef __PVRUSB2_AUDIO_H
+ #define __PVRUSB2_AUDIO_H
+
+-#include "pvrusb2-i2c-core.h"
+-
+-int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+-
++#include "pvrusb2-hdw-internal.h"
++void pvr2_msp3400_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
+ #endif /* __PVRUSB2_AUDIO_H */
+
+ /*
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
+new file mode 100644
+index 0000000..b5c3428
+--- /dev/null
++++ b/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
+@@ -0,0 +1,95 @@
++/*
++ *
++ *
++ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
++ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
++ *
++ * 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
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++/*
++
++ This source file is specifically designed to interface with the
++ v4l-dvb cs53l32a module.
++
++*/
++
++#include "pvrusb2-cs53l32a.h"
++
++
++#include "pvrusb2-hdw-internal.h"
++#include "pvrusb2-debug.h"
++#include <linux/videodev2.h>
++#include <media/v4l2-common.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++
++struct routing_scheme {
++ const int *def;
++ unsigned int cnt;
++};
++
++
++static const int routing_scheme1[] = {
++ [PVR2_CVAL_INPUT_TV] = 2, /* 1 or 2 seems to work here */
++ [PVR2_CVAL_INPUT_RADIO] = 2,
++ [PVR2_CVAL_INPUT_COMPOSITE] = 0,
++ [PVR2_CVAL_INPUT_SVIDEO] = 0,
++};
++
++static const struct routing_scheme routing_schemes[] = {
++ [PVR2_ROUTING_SCHEME_ONAIR] = {
++ .def = routing_scheme1,
++ .cnt = ARRAY_SIZE(routing_scheme1),
++ },
++};
++
++
++void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
++{
++ if (hdw->input_dirty || hdw->force_dirty) {
++ struct v4l2_routing route;
++ const struct routing_scheme *sp;
++ unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
++ hdw->input_val);
++ if ((sid < ARRAY_SIZE(routing_schemes)) &&
++ ((sp = routing_schemes + sid) != NULL) &&
++ (hdw->input_val >= 0) &&
++ (hdw->input_val < sp->cnt)) {
++ route.input = sp->def[hdw->input_val];
++ } else {
++ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++ "*** WARNING *** subdev v4l2 set_input:"
++ " Invalid routing scheme (%u)"
++ " and/or input (%d)",
++ sid, hdw->input_val);
++ return;
++ }
++ route.output = 0;
++ sd->ops->audio->s_routing(sd, &route);
++ }
++}
++
++
++/*
++ Stuff for Emacs to see, in order to encourage consistent editing style:
++ *** Local Variables: ***
++ *** mode: c ***
++ *** fill-column: 70 ***
++ *** tab-width: 8 ***
++ *** c-basic-offset: 8 ***
++ *** End: ***
++ */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h b/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h
+new file mode 100644
+index 0000000..53ba548
+--- /dev/null
++++ b/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h
+@@ -0,0 +1,48 @@
++/*
++ *
++ *
++ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
++ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
++ *
++ * 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
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#ifndef __PVRUSB2_CS53L32A_H
++#define __PVRUSB2_CS53L32A_H
++
++/*
++
++ This module connects the pvrusb2 driver to the I2C chip level
++ driver which handles device video processing. This interface is
++ used internally by the driver; higher level code should only
++ interact through the interface provided by pvrusb2-hdw.h.
++
++*/
++
++
++#include "pvrusb2-hdw-internal.h"
++void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
++
++#endif /* __PVRUSB2_AUDIO_CS53L32A_H */
++
++/*
++ Stuff for Emacs to see, in order to encourage consistent editing style:
++ *** Local Variables: ***
++ *** mode: c ***
++ *** fill-column: 70 ***
++ *** tab-width: 8 ***
++ *** c-basic-offset: 8 ***
++ *** End: ***
++ */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+index 895859e..4e017ff 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+@@ -28,7 +28,6 @@
+
+ #include "pvrusb2-cx2584x-v4l.h"
+ #include "pvrusb2-video-v4l.h"
+-#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+ #include "pvrusb2-hdw-internal.h"
+@@ -39,14 +38,6 @@
+ #include <linux/errno.h>
+ #include <linux/slab.h>
+
+-struct pvr2_v4l_cx2584x {
+- struct pvr2_i2c_handler handler;
+- struct pvr2_decoder_ctrl ctrl;
+- struct pvr2_i2c_client *client;
+- struct pvr2_hdw *hdw;
+- unsigned long stale_mask;
+-};
+-
+
+ struct routing_scheme_item {
+ int vid;
+@@ -110,218 +101,44 @@ static const struct routing_scheme routing_schemes[] = {
+ },
+ };
+
+-static void set_input(struct pvr2_v4l_cx2584x *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- struct v4l2_routing route;
+- enum cx25840_video_input vid_input;
+- enum cx25840_audio_input aud_input;
+- const struct routing_scheme *sp;
+- unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+-
+- memset(&route,0,sizeof(route));
+-
+- if ((sid < ARRAY_SIZE(routing_schemes)) &&
+- ((sp = routing_schemes + sid) != NULL) &&
+- (hdw->input_val >= 0) &&
+- (hdw->input_val < sp->cnt)) {
+- vid_input = sp->def[hdw->input_val].vid;
+- aud_input = sp->def[hdw->input_val].aud;
+- } else {
+- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+- "*** WARNING *** i2c cx2584x set_input:"
+- " Invalid routing scheme (%u) and/or input (%d)",
+- sid,hdw->input_val);
+- return;
+- }
+-
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
+- vid_input,aud_input);
+- route.input = (u32)vid_input;
+- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
+- route.input = (u32)aud_input;
+- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+-}
+-
+-
+-static int check_input(struct pvr2_v4l_cx2584x *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- return hdw->input_dirty != 0;
+-}
+-
+-
+-static void set_audio(struct pvr2_v4l_cx2584x *ctxt)
+-{
+- u32 val;
+- struct pvr2_hdw *hdw = ctxt->hdw;
+-
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_audio %d",
+- hdw->srate_val);
+- switch (hdw->srate_val) {
+- default:
+- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+- val = 48000;
+- break;
+- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+- val = 44100;
+- break;
+- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+- val = 32000;
+- break;
+- }
+- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
+-}
+-
+-
+-static int check_audio(struct pvr2_v4l_cx2584x *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- return hdw->srate_dirty != 0;
+-}
+-
+-
+-struct pvr2_v4l_cx2584x_ops {
+- void (*update)(struct pvr2_v4l_cx2584x *);
+- int (*check)(struct pvr2_v4l_cx2584x *);
+-};
+-
+-
+-static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
+- { .update = set_input, .check = check_input},
+- { .update = set_audio, .check = check_audio},
+-};
+-
+-
+-static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
++void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
+ {
+- ctxt->client->handler = NULL;
+- pvr2_hdw_set_decoder(ctxt->hdw,NULL);
+- kfree(ctxt);
+-}
+-
+-
+-static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
+-{
+- unsigned long msk;
+- unsigned int idx;
+-
+- for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
+- msk = 1 << idx;
+- if (ctxt->stale_mask & msk) continue;
+- if (decoder_ops[idx].check(ctxt)) {
+- ctxt->stale_mask |= msk;
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev cx2584x update...");
++ if (hdw->input_dirty || hdw->force_dirty) {
++ struct v4l2_routing route;
++ enum cx25840_video_input vid_input;
++ enum cx25840_audio_input aud_input;
++ const struct routing_scheme *sp;
++ unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
++
++ memset(&route, 0, sizeof(route));
++
++ if ((sid < ARRAY_SIZE(routing_schemes)) &&
++ ((sp = routing_schemes + sid) != NULL) &&
++ (hdw->input_val >= 0) &&
++ (hdw->input_val < sp->cnt)) {
++ vid_input = sp->def[hdw->input_val].vid;
++ aud_input = sp->def[hdw->input_val].aud;
++ } else {
++ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++ "*** WARNING *** subdev cx2584x set_input:"
++ " Invalid routing scheme (%u)"
++ " and/or input (%d)",
++ sid, hdw->input_val);
++ return;
+ }
+- }
+- return ctxt->stale_mask != 0;
+-}
+-
+
+-static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
+-{
+- unsigned long msk;
+- unsigned int idx;
+-
+- for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
+- msk = 1 << idx;
+- if (!(ctxt->stale_mask & msk)) continue;
+- ctxt->stale_mask &= ~msk;
+- decoder_ops[idx].update(ctxt);
++ pvr2_trace(PVR2_TRACE_CHIPS,
++ "subdev cx2584x set_input vid=0x%x aud=0x%x",
++ vid_input, aud_input);
++ route.input = (u32)vid_input;
++ sd->ops->video->s_routing(sd, &route);
++ route.input = (u32)aud_input;
++ sd->ops->audio->s_routing(sd, &route);
+ }
+ }
+
+
+-static void decoder_enable(struct pvr2_v4l_cx2584x *ctxt,int fl)
+-{
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_enable(%d)",fl);
+- pvr2_v4l2_cmd_stream(ctxt->client,fl);
+-}
+-
+-
+-static int decoder_detect(struct pvr2_i2c_client *cp)
+-{
+- int ret;
+- /* Attempt to query the decoder - let's see if it will answer */
+- struct v4l2_queryctrl qc;
+-
+- memset(&qc,0,sizeof(qc));
+-
+- qc.id = V4L2_CID_BRIGHTNESS;
+-
+- ret = pvr2_i2c_client_cmd(cp,VIDIOC_QUERYCTRL,&qc);
+- return ret == 0; /* Return true if it answered */
+-}
+-
+-
+-static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
+- char *buf,unsigned int cnt)
+-{
+- return scnprintf(buf,cnt,"handler: pvrusb2-cx2584x-v4l");
+-}
+-
+-
+-static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
+-{
+- int ret;
+- ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,NULL);
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret);
+-}
+-
+-
+-static const struct pvr2_i2c_handler_functions hfuncs = {
+- .detach = (void (*)(void *))decoder_detach,
+- .check = (int (*)(void *))decoder_check,
+- .update = (void (*)(void *))decoder_update,
+- .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
+-};
+-
+-
+-int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
+- struct pvr2_i2c_client *cp)
+-{
+- struct pvr2_v4l_cx2584x *ctxt;
+-
+- if (hdw->decoder_ctrl) return 0;
+- if (cp->handler) return 0;
+- if (!decoder_detect(cp)) return 0;
+-
+- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
+- if (!ctxt) return 0;
+-
+- ctxt->handler.func_data = ctxt;
+- ctxt->handler.func_table = &hfuncs;
+- ctxt->ctrl.ctxt = ctxt;
+- ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
+- ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
+- ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
+- ctxt->client = cp;
+- ctxt->hdw = hdw;
+- ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
+- pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
+- cp->handler = &ctxt->handler;
+- {
+- /*
+- Mike Isely <isely@pobox.com> 19-Nov-2006 - This bit
+- of nuttiness for cx25840 causes that module to
+- correctly set up its video scaling. This is really
+- a problem in the cx25840 module itself, but we work
+- around it here. The problem has not been seen in
+- ivtv because there VBI is supported and set up. We
+- don't do VBI here (at least not yet) and thus we
+- never attempted to even set it up.
+- */
+- struct v4l2_format fmt;
+- memset(&fmt,0,sizeof(fmt));
+- fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_FMT,&fmt);
+- }
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up",
+- cp->client->addr);
+- return !0;
+-}
+-
+-
+-
+
+ /*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
+index 66abf77..e35c232 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
+@@ -34,9 +34,9 @@
+
+
+
+-#include "pvrusb2-i2c-core.h"
++#include "pvrusb2-hdw-internal.h"
+
+-int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
++void pvr2_cx25840_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd);
+
+
+ #endif /* __PVRUSB2_CX2584X_V4L_H */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+index ca892fb..fbe3856 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+@@ -23,7 +23,6 @@
+ #include "pvrusb2-debugifc.h"
+ #include "pvrusb2-hdw.h"
+ #include "pvrusb2-debug.h"
+-#include "pvrusb2-i2c-core.h"
+
+ struct debugifc_mask_item {
+ const char *name;
+@@ -147,10 +146,6 @@ int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+- ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
+- bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+- ccnt = pvr2_i2c_report(hdw,buf,acnt);
+- bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ return bcnt;
+ }
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
+index e24ff59..2f8d467 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
+@@ -22,16 +22,16 @@
+
+ struct pvr2_hdw;
+
+-/* Non-intrusively print some useful debugging info from inside the
+- driver. This should work even if the driver appears to be
+- wedged. */
+-int pvr2_debugifc_print_info(struct pvr2_hdw *,
+- char *buf_ptr,unsigned int buf_size);
+-
+ /* Print general status of driver. This will also trigger a probe of
+ the USB link. Unlike print_info(), this one synchronizes with the
+ driver so the information should be self-consistent (but it will
+ hang if the driver is wedged). */
++int pvr2_debugifc_print_info(struct pvr2_hdw *,
++ char *buf_ptr, unsigned int buf_size);
++
++/* Non-intrusively print some useful debugging info from inside the
++ driver. This should work even if the driver appears to be
++ wedged. */
+ int pvr2_debugifc_print_status(struct pvr2_hdw *,
+ char *buf_ptr,unsigned int buf_size);
+
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+index cbe2a34..1cb6a26 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+@@ -46,10 +46,11 @@ pvr2_device_desc structures.
+ /*------------------------------------------------------------------------*/
+ /* Hauppauge PVR-USB2 Model 29xxx */
+
+-static const char *pvr2_client_29xxx[] = {
+- "msp3400",
+- "saa7115",
+- "tuner",
++static const struct pvr2_device_client_desc pvr2_cli_29xxx[] = {
++ { .module_id = PVR2_CLIENT_ID_SAA7115 },
++ { .module_id = PVR2_CLIENT_ID_MSP3400 },
++ { .module_id = PVR2_CLIENT_ID_TUNER },
++ { .module_id = PVR2_CLIENT_ID_DEMOD },
+ };
+
+ static const char *pvr2_fw1_names_29xxx[] = {
+@@ -59,8 +60,8 @@ static const char *pvr2_fw1_names_29xxx[] = {
+ static const struct pvr2_device_desc pvr2_device_29xxx = {
+ .description = "WinTV PVR USB2 Model Category 29xxx",
+ .shortname = "29xxx",
+- .client_modules.lst = pvr2_client_29xxx,
+- .client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx),
++ .client_table.lst = pvr2_cli_29xxx,
++ .client_table.cnt = ARRAY_SIZE(pvr2_cli_29xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_29xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
+ .flag_has_hauppauge_rom = !0,
+@@ -77,10 +78,11 @@ static const struct pvr2_device_desc pvr2_device_29xxx = {
+ /*------------------------------------------------------------------------*/
+ /* Hauppauge PVR-USB2 Model 24xxx */
+
+-static const char *pvr2_client_24xxx[] = {
+- "cx25840",
+- "tuner",
+- "wm8775",
++static const struct pvr2_device_client_desc pvr2_cli_24xxx[] = {
++ { .module_id = PVR2_CLIENT_ID_CX25840 },
++ { .module_id = PVR2_CLIENT_ID_TUNER },
++ { .module_id = PVR2_CLIENT_ID_WM8775 },
++ { .module_id = PVR2_CLIENT_ID_DEMOD },
+ };
+
+ static const char *pvr2_fw1_names_24xxx[] = {
+@@ -90,8 +92,8 @@ static const char *pvr2_fw1_names_24xxx[] = {
+ static const struct pvr2_device_desc pvr2_device_24xxx = {
+ .description = "WinTV PVR USB2 Model Category 24xxx",
+ .shortname = "24xxx",
+- .client_modules.lst = pvr2_client_24xxx,
+- .client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
++ .client_table.lst = pvr2_cli_24xxx,
++ .client_table.cnt = ARRAY_SIZE(pvr2_cli_24xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_24xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx),
+ .flag_has_cx25840 = !0,
+@@ -111,16 +113,16 @@ static const struct pvr2_device_desc pvr2_device_24xxx = {
+ /*------------------------------------------------------------------------*/
+ /* GOTVIEW USB2.0 DVD2 */
+
+-static const char *pvr2_client_gotview_2[] = {
+- "cx25840",
+- "tuner",
++static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = {
++ { .module_id = PVR2_CLIENT_ID_CX25840 },
++ { .module_id = PVR2_CLIENT_ID_TUNER },
+ };
+
+ static const struct pvr2_device_desc pvr2_device_gotview_2 = {
+ .description = "Gotview USB 2.0 DVD 2",
+ .shortname = "gv2",
+- .client_modules.lst = pvr2_client_gotview_2,
+- .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
++ .client_table.lst = pvr2_cli_gotview_2,
++ .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
+ .flag_has_cx25840 = !0,
+ .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .flag_has_analogtuner = !0,
+@@ -140,8 +142,8 @@ static const struct pvr2_device_desc pvr2_device_gotview_2 = {
+ static const struct pvr2_device_desc pvr2_device_gotview_2d = {
+ .description = "Gotview USB 2.0 DVD Deluxe",
+ .shortname = "gv2d",
+- .client_modules.lst = pvr2_client_gotview_2,
+- .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
++ .client_table.lst = pvr2_cli_gotview_2,
++ .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2),
+ .flag_has_cx25840 = !0,
+ .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .flag_has_analogtuner = !0,
+@@ -181,29 +183,29 @@ static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap)
+ return 0;
+ }
+
+-static struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
++static const struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
+ .frontend_attach = pvr2_lgdt3303_attach,
+ .tuner_attach = pvr2_lgh06xf_attach,
+ };
+ #endif
+
+-static const char *pvr2_client_onair_creator[] = {
+- "saa7115",
+- "tuner",
+- "cs53l32a",
++static const struct pvr2_device_client_desc pvr2_cli_onair_creator[] = {
++ { .module_id = PVR2_CLIENT_ID_SAA7115 },
++ { .module_id = PVR2_CLIENT_ID_CS53L32A },
++ { .module_id = PVR2_CLIENT_ID_TUNER },
+ };
+
+ static const struct pvr2_device_desc pvr2_device_onair_creator = {
+ .description = "OnAir Creator Hybrid USB tuner",
+ .shortname = "oac",
+- .client_modules.lst = pvr2_client_onair_creator,
+- .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator),
++ .client_table.lst = pvr2_cli_onair_creator,
++ .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_creator),
+ .default_tuner_type = TUNER_LG_TDVS_H06XF,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .flag_digital_requires_cx23416 = !0,
+- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
++ .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+ .default_std_mask = V4L2_STD_NTSC_M,
+ #ifdef CONFIG_VIDEO_PVRUSB2_DVB
+@@ -241,29 +243,29 @@ static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap)
+ return 0;
+ }
+
+-static struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
++static const struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
+ .frontend_attach = pvr2_lgdt3302_attach,
+ .tuner_attach = pvr2_fcv1236d_attach,
+ };
+ #endif
+
+-static const char *pvr2_client_onair_usb2[] = {
+- "saa7115",
+- "tuner",
+- "cs53l32a",
++static const struct pvr2_device_client_desc pvr2_cli_onair_usb2[] = {
++ { .module_id = PVR2_CLIENT_ID_SAA7115 },
++ { .module_id = PVR2_CLIENT_ID_CS53L32A },
++ { .module_id = PVR2_CLIENT_ID_TUNER },
+ };
+
+ static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
+ .description = "OnAir USB2 Hybrid USB tuner",
+ .shortname = "oa2",
+- .client_modules.lst = pvr2_client_onair_usb2,
+- .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2),
++ .client_table.lst = pvr2_cli_onair_usb2,
++ .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_usb2),
+ .default_tuner_type = TUNER_PHILIPS_FCV1236D,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .flag_digital_requires_cx23416 = !0,
+- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
++ .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+ .default_std_mask = V4L2_STD_NTSC_M,
+ #ifdef CONFIG_VIDEO_PVRUSB2_DVB
+@@ -314,15 +316,16 @@ static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+ return 0;
+ }
+
+-static struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
++static const struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
+ .frontend_attach = pvr2_tda10048_attach,
+ .tuner_attach = pvr2_73xxx_tda18271_8295_attach,
+ };
+ #endif
+
+-static const char *pvr2_client_73xxx[] = {
+- "cx25840",
+- "tuner",
++static const struct pvr2_device_client_desc pvr2_cli_73xxx[] = {
++ { .module_id = PVR2_CLIENT_ID_CX25840 },
++ { .module_id = PVR2_CLIENT_ID_TUNER,
++ .i2c_address_list = "\x42"},
+ };
+
+ static const char *pvr2_fw1_names_73xxx[] = {
+@@ -332,8 +335,8 @@ static const char *pvr2_fw1_names_73xxx[] = {
+ static const struct pvr2_device_desc pvr2_device_73xxx = {
+ .description = "WinTV HVR-1900 Model Category 73xxx",
+ .shortname = "73xxx",
+- .client_modules.lst = pvr2_client_73xxx,
+- .client_modules.cnt = ARRAY_SIZE(pvr2_client_73xxx),
++ .client_table.lst = pvr2_cli_73xxx,
++ .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_73xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_73xxx),
+ .flag_has_cx25840 = !0,
+@@ -418,22 +421,17 @@ static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+ return 0;
+ }
+
+-static struct pvr2_dvb_props pvr2_750xx_dvb_props = {
++static const struct pvr2_dvb_props pvr2_750xx_dvb_props = {
+ .frontend_attach = pvr2_s5h1409_attach,
+ .tuner_attach = pvr2_tda18271_8295_attach,
+ };
+
+-static struct pvr2_dvb_props pvr2_751xx_dvb_props = {
++static const struct pvr2_dvb_props pvr2_751xx_dvb_props = {
+ .frontend_attach = pvr2_s5h1411_attach,
+ .tuner_attach = pvr2_tda18271_8295_attach,
+ };
+ #endif
+
+-static const char *pvr2_client_75xxx[] = {
+- "cx25840",
+- "tuner",
+-};
+-
+ static const char *pvr2_fw1_names_75xxx[] = {
+ "v4l-pvrusb2-73xxx-01.fw",
+ };
+@@ -441,8 +439,8 @@ static const char *pvr2_fw1_names_75xxx[] = {
+ static const struct pvr2_device_desc pvr2_device_750xx = {
+ .description = "WinTV HVR-1950 Model Category 750xx",
+ .shortname = "750xx",
+- .client_modules.lst = pvr2_client_75xxx,
+- .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
++ .client_table.lst = pvr2_cli_73xxx,
++ .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_75xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
+ .flag_has_cx25840 = !0,
+@@ -463,8 +461,8 @@ static const struct pvr2_device_desc pvr2_device_750xx = {
+ static const struct pvr2_device_desc pvr2_device_751xx = {
+ .description = "WinTV HVR-1950 Model Category 751xx",
+ .shortname = "751xx",
+- .client_modules.lst = pvr2_client_75xxx,
+- .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
++ .client_table.lst = pvr2_cli_73xxx,
++ .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_75xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
+ .flag_has_cx25840 = !0,
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+index cb3a33e..3e55338 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+@@ -33,6 +33,34 @@
+ */
+
+
++#define PVR2_CLIENT_ID_NULL 0
++#define PVR2_CLIENT_ID_MSP3400 1
++#define PVR2_CLIENT_ID_CX25840 2
++#define PVR2_CLIENT_ID_SAA7115 3
++#define PVR2_CLIENT_ID_TUNER 4
++#define PVR2_CLIENT_ID_CS53L32A 5
++#define PVR2_CLIENT_ID_WM8775 6
++#define PVR2_CLIENT_ID_DEMOD 7
++
++struct pvr2_device_client_desc {
++ /* One ovr PVR2_CLIENT_ID_xxxx */
++ unsigned char module_id;
++
++ /* Null-terminated array of I2C addresses to try in order
++ initialize the module. It's safe to make this null terminated
++ since we're never going to encounter an i2c device with an
++ address of zero. If this is a null pointer or zero-length,
++ then no I2C addresses have been specified, in which case we'll
++ try some compiled in defaults for now. */
++ unsigned char *i2c_address_list;
++};
++
++struct pvr2_device_client_table {
++ const struct pvr2_device_client_desc *lst;
++ unsigned char cnt;
++};
++
++
+ struct pvr2_string_table {
+ const char **lst;
+ unsigned int cnt;
+@@ -40,6 +68,7 @@ struct pvr2_string_table {
+
+ #define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
+ #define PVR2_ROUTING_SCHEME_GOTVIEW 1
++#define PVR2_ROUTING_SCHEME_ONAIR 2
+
+ #define PVR2_DIGITAL_SCHEME_NONE 0
+ #define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1
+@@ -66,6 +95,9 @@ struct pvr2_device_desc {
+ /* List of additional client modules we need to load */
+ struct pvr2_string_table client_modules;
+
++ /* List of defined client modules we need to load */
++ struct pvr2_device_client_table client_table;
++
+ /* List of FX2 firmware file names we should search; if empty then
+ FX2 firmware check / load is skipped and we assume the device
+ was initialized from internal ROM. */
+@@ -73,7 +105,7 @@ struct pvr2_device_desc {
+
+ #ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ /* callback functions to handle attachment of digital tuner & demod */
+- struct pvr2_dvb_props *dvb_props;
++ const struct pvr2_dvb_props *dvb_props;
+
+ #endif
+ /* Initial standard bits to use for this device, if not zero.
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
+index 77b3c33..b7f5c49 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
+@@ -321,7 +321,7 @@ static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap)
+ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
+ {
+ struct pvr2_hdw *hdw = adap->channel.hdw;
+- struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
++ const struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
+ int ret = 0;
+
+ if (dvb_props == NULL) {
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+index 273d2a1..54ac534 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+@@ -347,7 +347,7 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
+ int encMisc3Arg = 0;
+
+ #if 0
+- /* This inexplicable bit happens in the Hauppage windows
++ /* This inexplicable bit happens in the Hauppauge windows
+ driver (for both 24xxx and 29xxx devices). However I
+ currently see no difference in behavior with or without
+ this stuff. Leave this here as a note of its existence,
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+index de7ee72..5d75eb5 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+@@ -38,6 +38,7 @@
+ #include <linux/mutex.h>
+ #include "pvrusb2-hdw.h"
+ #include "pvrusb2-io.h"
++#include <media/v4l2-device.h>
+ #include <media/cx2341x.h>
+ #include "pvrusb2-devattr.h"
+
+@@ -57,8 +58,6 @@
+ #define LOCK_TAKE(x) do { mutex_lock(&x##_mutex); x##_held = !0; } while (0)
+ #define LOCK_GIVE(x) do { x##_held = 0; mutex_unlock(&x##_mutex); } while (0)
+
+-struct pvr2_decoder;
+-
+ typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
+ typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
+ typedef int (*pvr2_ctlf_check_value)(struct pvr2_ctrl *,int);
+@@ -139,22 +138,6 @@ struct pvr2_ctrl {
+ };
+
+
+-struct pvr2_decoder_ctrl {
+- void *ctxt;
+- void (*detach)(void *);
+- void (*enable)(void *,int);
+- void (*force_reset)(void *);
+-};
+-
+-#define PVR2_I2C_PEND_DETECT 0x01 /* Need to detect a client type */
+-#define PVR2_I2C_PEND_CLIENT 0x02 /* Client needs a specific update */
+-#define PVR2_I2C_PEND_REFRESH 0x04 /* Client has specific pending bits */
+-#define PVR2_I2C_PEND_STALE 0x08 /* Broadcast pending bits */
+-
+-#define PVR2_I2C_PEND_ALL (PVR2_I2C_PEND_DETECT |\
+- PVR2_I2C_PEND_CLIENT |\
+- PVR2_I2C_PEND_REFRESH |\
+- PVR2_I2C_PEND_STALE)
+
+ /* Disposition of firmware1 loading situation */
+ #define FW1_STATE_UNKNOWN 0
+@@ -179,6 +162,8 @@ struct pvr2_hdw {
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_intf;
+
++ /* Our handle into the v4l2 sub-device architecture */
++ struct v4l2_device v4l2_dev;
+ /* Device description, anything that must adjust behavior based on
+ device specific info will use information held here. */
+ const struct pvr2_device_desc *hdw_desc;
+@@ -186,7 +171,6 @@ struct pvr2_hdw {
+ /* Kernel worker thread handling */
+ struct workqueue_struct *workqueue;
+ struct work_struct workpoll; /* Update driver state */
+- struct work_struct worki2csync; /* Update i2c clients */
+
+ /* Video spigot */
+ struct pvr2_stream *vid_stream;
+@@ -195,20 +179,26 @@ struct pvr2_hdw {
+ struct mutex big_lock_mutex;
+ int big_lock_held; /* For debugging */
+
++ /* This is a simple string which identifies the instance of this
++ driver. It is unique within the set of existing devices, but
++ there is no attempt to keep the name consistent with the same
++ physical device each time. */
+ char name[32];
+
++ /* This is a simple string which identifies the physical device
++ instance itself - if possible. (If not possible, then it is
++ based on the specific driver instance, similar to name above.)
++ The idea here is that userspace might hopefully be able to use
++ this recognize specific tuners. It will encode a serial number,
++ if available. */
++ char identifier[32];
++
+ /* I2C stuff */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algorithm i2c_algo;
+ pvr2_i2c_func i2c_func[PVR2_I2C_FUNC_CNT];
+ int i2c_cx25840_hack_state;
+ int i2c_linked;
+- unsigned int i2c_pend_types; /* Which types of update are needed */
+- unsigned long i2c_pend_mask; /* Change bits we need to scan */
+- unsigned long i2c_stale_mask; /* Pending broadcast change bits */
+- unsigned long i2c_active_mask; /* All change bits currently in use */
+- struct list_head i2c_clients;
+- struct mutex i2c_list_lock;
+
+ /* Frequency table */
+ unsigned int freqTable[FREQTABLE_SIZE];
+@@ -275,6 +265,7 @@ struct pvr2_hdw {
+ wait_queue_head_t state_wait_data;
+
+
++ int force_dirty; /* consider all controls dirty if true */
+ int flag_ok; /* device in known good state */
+ int flag_disconnected; /* flag_ok == 0 due to disconnect */
+ int flag_init_ok; /* true if structure is fully initialized */
+@@ -283,17 +274,13 @@ struct pvr2_hdw {
+ int flag_decoder_missed;/* We've noticed missing decoder */
+ int flag_tripped; /* Indicates overall failure to start */
+
+- struct pvr2_decoder_ctrl *decoder_ctrl;
++ unsigned int decoder_client_id;
+
+ // CPU firmware info (used to help find / save firmware data)
+ char *fw_buffer;
+ unsigned int fw_size;
+ int fw_cpu_flag; /* True if we are dealing with the CPU */
+
+- // True if there is a request to trigger logging of state in each
+- // module.
+- int log_requested;
+-
+ /* Tuner / frequency control stuff */
+ unsigned int tuner_type;
+ int tuner_updated;
+@@ -391,7 +378,8 @@ struct pvr2_hdw {
+
+ /* This function gets the current frequency */
+ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
+-void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *);
++
++void pvr2_hdw_status_poll(struct pvr2_hdw *);
+
+ #endif /* __PVRUSB2_HDW_INTERNAL_H */
+
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+index fa304e5..7a65b42 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+@@ -24,17 +24,22 @@
+ #include <linux/firmware.h>
+ #include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
++#include <media/tuner.h>
+ #include "pvrusb2.h"
+ #include "pvrusb2-std.h"
+ #include "pvrusb2-util.h"
+ #include "pvrusb2-hdw.h"
+ #include "pvrusb2-i2c-core.h"
+-#include "pvrusb2-tuner.h"
+ #include "pvrusb2-eeprom.h"
+ #include "pvrusb2-hdw-internal.h"
+ #include "pvrusb2-encoder.h"
+ #include "pvrusb2-debug.h"
+ #include "pvrusb2-fx2-cmd.h"
++#include "pvrusb2-wm8775.h"
++#include "pvrusb2-video-v4l.h"
++#include "pvrusb2-cx2584x-v4l.h"
++#include "pvrusb2-cs53l32a.h"
++#include "pvrusb2-audio.h"
+
+ #define TV_MIN_FREQ 55250000L
+ #define TV_MAX_FREQ 850000000L
+@@ -104,6 +109,39 @@ MODULE_PARM_DESC(radio_freq, "specify initial radio frequency");
+ /* size of a firmware chunk */
+ #define FIRMWARE_CHUNK_SIZE 0x2000
+
++typedef void (*pvr2_subdev_update_func)(struct pvr2_hdw *,
++ struct v4l2_subdev *);
++
++static const pvr2_subdev_update_func pvr2_module_update_functions[] = {
++ [PVR2_CLIENT_ID_WM8775] = pvr2_wm8775_subdev_update,
++ [PVR2_CLIENT_ID_SAA7115] = pvr2_saa7115_subdev_update,
++ [PVR2_CLIENT_ID_MSP3400] = pvr2_msp3400_subdev_update,
++ [PVR2_CLIENT_ID_CX25840] = pvr2_cx25840_subdev_update,
++ [PVR2_CLIENT_ID_CS53L32A] = pvr2_cs53l32a_subdev_update,
++};
++
++static const char *module_names[] = {
++ [PVR2_CLIENT_ID_MSP3400] = "msp3400",
++ [PVR2_CLIENT_ID_CX25840] = "cx25840",
++ [PVR2_CLIENT_ID_SAA7115] = "saa7115",
++ [PVR2_CLIENT_ID_TUNER] = "tuner",
++ [PVR2_CLIENT_ID_DEMOD] = "tuner",
++ [PVR2_CLIENT_ID_CS53L32A] = "cs53l32a",
++ [PVR2_CLIENT_ID_WM8775] = "wm8775",
++};
++
++
++static const unsigned char *module_i2c_addresses[] = {
++ [PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63",
++ [PVR2_CLIENT_ID_DEMOD] = "\x43",
++ [PVR2_CLIENT_ID_MSP3400] = "\x40",
++ [PVR2_CLIENT_ID_SAA7115] = "\x21",
++ [PVR2_CLIENT_ID_WM8775] = "\x1b",
++ [PVR2_CLIENT_ID_CX25840] = "\x44",
++ [PVR2_CLIENT_ID_CS53L32A] = "\x11",
++};
++
++
+ /* Define the list of additional controls we'll dynamically construct based
+ on query of the cx2341x module. */
+ struct pvr2_mpeg_ids {
+@@ -277,7 +315,6 @@ static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v);
+ static void pvr2_hdw_state_sched(struct pvr2_hdw *);
+ static int pvr2_hdw_state_eval(struct pvr2_hdw *);
+ static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
+-static void pvr2_hdw_worker_i2c(struct work_struct *work);
+ static void pvr2_hdw_worker_poll(struct work_struct *work);
+ static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
+ static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
+@@ -642,7 +679,7 @@ static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+- pvr2_i2c_core_status_poll(hdw);
++ pvr2_hdw_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangehigh;
+ if (!fv) {
+@@ -664,7 +701,7 @@ static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+- pvr2_i2c_core_status_poll(hdw);
++ pvr2_hdw_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangelow;
+ if (!fv) {
+@@ -858,7 +895,7 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
+ static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
+ {
+ struct pvr2_hdw *hdw = cptr->hdw;
+- pvr2_i2c_core_status_poll(hdw);
++ pvr2_hdw_status_poll(hdw);
+ *vp = hdw->tuner_signal_info.signal;
+ return 0;
+ }
+@@ -868,7 +905,7 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
+ int val = 0;
+ unsigned int subchan;
+ struct pvr2_hdw *hdw = cptr->hdw;
+- pvr2_i2c_core_status_poll(hdw);
++ pvr2_hdw_status_poll(hdw);
+ subchan = hdw->tuner_signal_info.rxsubchans;
+ if (subchan & V4L2_TUNER_SUB_MONO) {
+ val |= (1 << V4L2_TUNER_MODE_MONO);
+@@ -1283,6 +1320,12 @@ const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw)
+ }
+
+
++const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *hdw)
++{
++ return hdw->identifier;
++}
++
++
+ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
+ {
+ return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
+@@ -1634,33 +1677,27 @@ static const char *pvr2_get_state_name(unsigned int st)
+
+ static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
+ {
+- if (!hdw->decoder_ctrl) {
+- if (!hdw->flag_decoder_missed) {
+- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+- "WARNING: No decoder present");
+- hdw->flag_decoder_missed = !0;
+- trace_stbit("flag_decoder_missed",
+- hdw->flag_decoder_missed);
+- }
+- return -EIO;
++ /* Even though we really only care about the video decoder chip at
++ this point, we'll broadcast stream on/off to all sub-devices
++ anyway, just in case somebody else wants to hear the
++ command... */
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s",
++ (enablefl ? "on" : "off"));
++ v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl);
++ if (hdw->decoder_client_id) {
++ /* We get here if the encoder has been noticed. Otherwise
++ we'll issue a warning to the user (which should
++ normally never happen). */
++ return 0;
+ }
+- hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl);
+- return 0;
+-}
+-
+-
+-void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr)
+-{
+- if (hdw->decoder_ctrl == ptr) return;
+- hdw->decoder_ctrl = ptr;
+- if (hdw->decoder_ctrl && hdw->flag_decoder_missed) {
+- hdw->flag_decoder_missed = 0;
++ if (!hdw->flag_decoder_missed) {
++ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++ "WARNING: No decoder present");
++ hdw->flag_decoder_missed = !0;
+ trace_stbit("flag_decoder_missed",
+ hdw->flag_decoder_missed);
+- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+- "Decoder has appeared");
+- pvr2_hdw_state_sched(hdw);
+ }
++ return -EIO;
+ }
+
+
+@@ -1927,6 +1964,166 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
+ }
+
+
++static unsigned int pvr2_copy_i2c_addr_list(
++ unsigned short *dst, const unsigned char *src,
++ unsigned int dst_max)
++{
++ unsigned int cnt = 0;
++ if (!src) return 0;
++ while (src[cnt] && (cnt + 1) < dst_max) {
++ dst[cnt] = src[cnt];
++ cnt++;
++ }
++ dst[cnt] = I2C_CLIENT_END;
++ return cnt;
++}
++
++
++static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
++ const struct pvr2_device_client_desc *cd)
++{
++ const char *fname;
++ unsigned char mid;
++ struct v4l2_subdev *sd;
++ unsigned int i2ccnt;
++ const unsigned char *p;
++ /* Arbitrary count - max # i2c addresses we will probe */
++ unsigned short i2caddr[25];
++
++ mid = cd->module_id;
++ fname = (mid < ARRAY_SIZE(module_names)) ? module_names[mid] : NULL;
++ if (!fname) {
++ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++ "Module ID %u for device %s has no name",
++ mid,
++ hdw->hdw_desc->description);
++ return -EINVAL;
++ }
++ pvr2_trace(PVR2_TRACE_INIT,
++ "Module ID %u (%s) for device %s being loaded...",
++ mid, fname,
++ hdw->hdw_desc->description);
++
++ i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, cd->i2c_address_list,
++ ARRAY_SIZE(i2caddr));
++ if (!i2ccnt && ((p = (mid < ARRAY_SIZE(module_i2c_addresses)) ?
++ module_i2c_addresses[mid] : NULL) != NULL)) {
++ /* Second chance: Try default i2c address list */
++ i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, p,
++ ARRAY_SIZE(i2caddr));
++ if (i2ccnt) {
++ pvr2_trace(PVR2_TRACE_INIT,
++ "Module ID %u:"
++ " Using default i2c address list",
++ mid);
++ }
++ }
++
++ if (!i2ccnt) {
++ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++ "Module ID %u (%s) for device %s:"
++ " No i2c addresses",
++ mid, fname, hdw->hdw_desc->description);
++ return -EINVAL;
++ }
++
++ /* Note how the 2nd and 3rd arguments are the same for both
++ * v4l2_i2c_new_subdev() and v4l2_i2c_new_probed_subdev(). Why?
++ * Well the 2nd argument is the module name to load, while the 3rd
++ * argument is documented in the framework as being the "chipid" -
++ * and every other place where I can find examples of this, the
++ * "chipid" appears to just be the module name again. So here we
++ * just do the same thing. */
++ if (i2ccnt == 1) {
++ pvr2_trace(PVR2_TRACE_INIT,
++ "Module ID %u:"
++ " Setting up with specified i2c address 0x%x",
++ mid, i2caddr[0]);
++ sd = v4l2_i2c_new_subdev(&hdw->i2c_adap,
++ fname, fname,
++ i2caddr[0]);
++ } else {
++ pvr2_trace(PVR2_TRACE_INIT,
++ "Module ID %u:"
++ " Setting up with address probe list",
++ mid);
++ sd = v4l2_i2c_new_probed_subdev(&hdw->i2c_adap,
++ fname, fname,
++ i2caddr);
++ }
++
++ if (!sd) {
++ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++ "Module ID %u (%s) for device %s failed to load",
++ mid, fname, hdw->hdw_desc->description);
++ return -EIO;
++ }
++
++ /* Tag this sub-device instance with the module ID we know about.
++ In other places we'll use that tag to determine if the instance
++ requires special handling. */
++ sd->grp_id = mid;
++
++ pvr2_trace(PVR2_TRACE_INFO, "Attached sub-driver %s", fname);
++
++
++ /* client-specific setup... */
++ switch (mid) {
++ case PVR2_CLIENT_ID_CX25840:
++ hdw->decoder_client_id = mid;
++ {
++ /*
++ Mike Isely <isely@pobox.com> 19-Nov-2006 - This
++ bit of nuttiness for cx25840 causes that module
++ to correctly set up its video scaling. This is
++ really a problem in the cx25840 module itself,
++ but we work around it here. The problem has not
++ been seen in ivtv because there VBI is supported
++ and set up. We don't do VBI here (at least not
++ yet) and thus we never attempted to even set it
++ up.
++ */
++ struct v4l2_format fmt;
++ pvr2_trace(PVR2_TRACE_INIT,
++ "Module ID %u:"
++ " Executing cx25840 VBI hack",
++ mid);
++ memset(&fmt, 0, sizeof(fmt));
++ fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
++ v4l2_device_call_all(&hdw->v4l2_dev, mid,
++ video, s_fmt, &fmt);
++ }
++ break;
++ case PVR2_CLIENT_ID_SAA7115:
++ hdw->decoder_client_id = mid;
++ break;
++ default: break;
++ }
++
++ return 0;
++}
++
++
++static void pvr2_hdw_load_modules(struct pvr2_hdw *hdw)
++{
++ unsigned int idx;
++ const struct pvr2_string_table *cm;
++ const struct pvr2_device_client_table *ct;
++ int okFl = !0;
++
++ cm = &hdw->hdw_desc->client_modules;
++ for (idx = 0; idx < cm->cnt; idx++) {
++ request_module(cm->lst[idx]);
++ }
++
++ ct = &hdw->hdw_desc->client_table;
++ for (idx = 0; idx < ct->cnt; idx++) {
++ if (pvr2_hdw_load_subdev(hdw, &ct->lst[idx]) < 0) okFl = 0;
++ }
++ if (!okFl) pvr2_hdw_render_useless(hdw);
++}
++
++
+ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+ {
+ int ret;
+@@ -1966,9 +2163,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+- for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
+- request_module(hdw->hdw_desc->client_modules.lst[idx]);
+- }
++ hdw->force_dirty = !0;
+
+ if (!hdw->hdw_desc->flag_no_powerup) {
+ pvr2_hdw_cmd_powerup(hdw);
+@@ -1987,6 +2182,11 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+ pvr2_i2c_core_init(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
++ pvr2_hdw_load_modules(hdw);
++ if (!pvr2_hdw_dev_ok(hdw)) return;
++
++ v4l2_device_call_all(&hdw->v4l2_dev, 0, core, init, 0);
++
+ for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
+ cptr = hdw->controls + idx;
+ if (cptr->info->skip_init) continue;
+@@ -2024,6 +2224,19 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+ hdw->std_mask_eeprom = V4L2_STD_ALL;
+ }
+
++ if (hdw->serial_number) {
++ idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1,
++ "sn-%lu", hdw->serial_number);
++ } else if (hdw->unit_number >= 0) {
++ idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1,
++ "unit-%c",
++ hdw->unit_number + 'a');
++ } else {
++ idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1,
++ "unit-??");
++ }
++ hdw->identifier[idx] = 0;
++
+ pvr2_hdw_setup_std(hdw);
+
+ if (!get_default_tuner_type(hdw)) {
+@@ -2032,8 +2245,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+ hdw->tuner_type);
+ }
+
+- pvr2_i2c_core_check_stale(hdw);
+- hdw->tuner_updated = 0;
+
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+@@ -2171,11 +2382,14 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ struct pvr2_hdw *hdw = NULL;
+ int valid_std_mask;
+ struct pvr2_ctrl *cptr;
++ struct usb_device *usb_dev;
+ const struct pvr2_device_desc *hdw_desc;
+ __u8 ifnum;
+ struct v4l2_queryctrl qctrl;
+ struct pvr2_ctl_info *ciptr;
+
++ usb_dev = interface_to_usbdev(intf);
++
+ hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
+
+ if (hdw_desc == NULL) {
+@@ -2360,6 +2574,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
+ if (!hdw->ctl_read_urb) goto fail;
+
++ if (v4l2_device_register(&usb_dev->dev, &hdw->v4l2_dev) != 0) {
++ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++ "Error registering with v4l core, giving up");
++ goto fail;
++ }
+ mutex_lock(&pvr2_unit_mtx); do {
+ for (idx = 0; idx < PVR_NUM; idx++) {
+ if (unit_pointers[idx]) continue;
+@@ -2382,7 +2601,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+
+ hdw->workqueue = create_singlethread_workqueue(hdw->name);
+ INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
+- INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
+
+ pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
+ hdw->unit_number,hdw->name);
+@@ -2391,12 +2609,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ hdw->flag_ok = !0;
+
+ hdw->usb_intf = intf;
+- hdw->usb_dev = interface_to_usbdev(intf);
++ hdw->usb_dev = usb_dev;
+
+- scnprintf(hdw->bus_info,sizeof(hdw->bus_info),
+- "usb %s address %d",
+- dev_name(&hdw->usb_dev->dev),
+- hdw->usb_dev->devnum);
++ usb_make_path(hdw->usb_dev, hdw->bus_info, sizeof(hdw->bus_info));
+
+ ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
+ usb_set_interface(hdw->usb_dev,ifnum,0);
+@@ -2454,6 +2669,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
+ hdw->ctl_write_buffer = NULL;
+ }
+ hdw->flag_disconnected = !0;
++ /* If we don't do this, then there will be a dangling struct device
++ reference to our disappearing device persisting inside the V4L
++ core... */
++ v4l2_device_disconnect(&hdw->v4l2_dev);
+ hdw->usb_dev = NULL;
+ hdw->usb_intf = NULL;
+ pvr2_hdw_render_useless(hdw);
+@@ -2481,10 +2700,8 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
+ pvr2_stream_destroy(hdw->vid_stream);
+ hdw->vid_stream = NULL;
+ }
+- if (hdw->decoder_ctrl) {
+- hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
+- }
+ pvr2_i2c_core_done(hdw);
++ v4l2_device_unregister(&hdw->v4l2_dev);
+ pvr2_hdw_remove_usb_stuff(hdw);
+ mutex_lock(&pvr2_unit_mtx); do {
+ if ((hdw->unit_number >= 0) &&
+@@ -2678,6 +2895,150 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
+ }
+
+
++static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id,
++ const char *name, int val)
++{
++ struct v4l2_control ctrl;
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 %s=%d", name, val);
++ memset(&ctrl, 0, sizeof(ctrl));
++ ctrl.id = id;
++ ctrl.value = val;
++ v4l2_device_call_all(&hdw->v4l2_dev, 0, core, s_ctrl, &ctrl);
++}
++
++#define PVR2_SUBDEV_SET_CONTROL(hdw, id, lab) \
++ if ((hdw)->lab##_dirty || (hdw)->force_dirty) { \
++ pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
++ }
++
++/* Execute whatever commands are required to update the state of all the
++ sub-devices so that they match our current control values. */
++static void pvr2_subdev_update(struct pvr2_hdw *hdw)
++{
++ struct v4l2_subdev *sd;
++ unsigned int id;
++ pvr2_subdev_update_func fp;
++
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev update...");
++
++ if (hdw->tuner_updated || hdw->force_dirty) {
++ struct tuner_setup setup;
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev tuner set_type(%d)",
++ hdw->tuner_type);
++ if (((int)(hdw->tuner_type)) >= 0) {
++ setup.addr = ADDR_UNSET;
++ setup.type = hdw->tuner_type;
++ setup.mode_mask = T_RADIO | T_ANALOG_TV;
++ v4l2_device_call_all(&hdw->v4l2_dev, 0,
++ tuner, s_type_addr, &setup);
++ }
++ }
++
++ if (hdw->input_dirty || hdw->std_dirty || hdw->force_dirty) {
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_standard");
++ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
++ v4l2_device_call_all(&hdw->v4l2_dev, 0,
++ tuner, s_radio);
++ } else {
++ v4l2_std_id vs;
++ vs = hdw->std_mask_cur;
++ v4l2_device_call_all(&hdw->v4l2_dev, 0,
++ tuner, s_std, vs);
++ }
++ hdw->tuner_signal_stale = !0;
++ hdw->cropcap_stale = !0;
++ }
++
++ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_BRIGHTNESS, brightness);
++ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_CONTRAST, contrast);
++ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_SATURATION, saturation);
++ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_HUE, hue);
++ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_MUTE, mute);
++ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_VOLUME, volume);
++ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BALANCE, balance);
++ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BASS, bass);
++ PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_TREBLE, treble);
++
++ if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) {
++ struct v4l2_tuner vt;
++ memset(&vt, 0, sizeof(vt));
++ vt.audmode = hdw->audiomode_val;
++ v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt);
++ }
++
++ if (hdw->freqDirty || hdw->force_dirty) {
++ unsigned long fv;
++ struct v4l2_frequency freq;
++ fv = pvr2_hdw_get_cur_freq(hdw);
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_freq(%lu)", fv);
++ if (hdw->tuner_signal_stale) pvr2_hdw_status_poll(hdw);
++ memset(&freq, 0, sizeof(freq));
++ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
++ /* ((fv * 1000) / 62500) */
++ freq.frequency = (fv * 2) / 125;
++ } else {
++ freq.frequency = fv / 62500;
++ }
++ /* tuner-core currently doesn't seem to care about this, but
++ let's set it anyway for completeness. */
++ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
++ freq.type = V4L2_TUNER_RADIO;
++ } else {
++ freq.type = V4L2_TUNER_ANALOG_TV;
++ }
++ freq.tuner = 0;
++ v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner,
++ s_frequency, &freq);
++ }
++
++ if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) {
++ struct v4l2_format fmt;
++ memset(&fmt, 0, sizeof(fmt));
++ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ fmt.fmt.pix.width = hdw->res_hor_val;
++ fmt.fmt.pix.height = hdw->res_ver_val;
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)",
++ fmt.fmt.pix.width, fmt.fmt.pix.height);
++ v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_fmt, &fmt);
++ }
++
++ if (hdw->srate_dirty || hdw->force_dirty) {
++ u32 val;
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_audio %d",
++ hdw->srate_val);
++ switch (hdw->srate_val) {
++ default:
++ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
++ val = 48000;
++ break;
++ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
++ val = 44100;
++ break;
++ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
++ val = 32000;
++ break;
++ }
++ v4l2_device_call_all(&hdw->v4l2_dev, 0,
++ audio, s_clock_freq, val);
++ }
++
++ /* Unable to set crop parameters; there is apparently no equivalent
++ for VIDIOC_S_CROP */
++
++ v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
++ id = sd->grp_id;
++ if (id >= ARRAY_SIZE(pvr2_module_update_functions)) continue;
++ fp = pvr2_module_update_functions[id];
++ if (!fp) continue;
++ (*fp)(hdw, sd);
++ }
++
++ if (hdw->tuner_signal_stale || hdw->cropcap_stale) {
++ pvr2_hdw_status_poll(hdw);
++ }
++}
++
++
+ /* Figure out if we need to commit control changes. If so, mark internal
+ state flags to indicate this fact and return true. Otherwise do nothing
+ else and return false. */
+@@ -2686,7 +3047,7 @@ static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
+ unsigned int idx;
+ struct pvr2_ctrl *cptr;
+ int value;
+- int commit_flag = 0;
++ int commit_flag = hdw->force_dirty;
+ char buf[100];
+ unsigned int bcnt,ccnt;
+
+@@ -2842,18 +3203,6 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
+ cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS);
+ }
+
+- /* Scan i2c core at this point - before we clear all the dirty
+- bits. Various parts of the i2c core will notice dirty bits as
+- appropriate and arrange to broadcast or directly send updates to
+- the client drivers in order to keep everything in sync */
+- pvr2_i2c_core_check_stale(hdw);
+-
+- for (idx = 0; idx < hdw->control_cnt; idx++) {
+- cptr = hdw->controls + idx;
+- if (!cptr->info->clear_dirty) continue;
+- cptr->info->clear_dirty(cptr);
+- }
+-
+ if (hdw->active_stream_type != hdw->desired_stream_type) {
+ /* Handle any side effects of stream config here */
+ hdw->active_stream_type = hdw->desired_stream_type;
+@@ -2873,8 +3222,16 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
+ }
+ }
+
+- /* Now execute i2c core update */
+- pvr2_i2c_core_sync(hdw);
++ /* Check and update state for all sub-devices. */
++ pvr2_subdev_update(hdw);
++
++ hdw->tuner_updated = 0;
++ hdw->force_dirty = 0;
++ for (idx = 0; idx < hdw->control_cnt; idx++) {
++ cptr = hdw->controls + idx;
++ if (!cptr->info->clear_dirty) continue;
++ cptr->info->clear_dirty(cptr);
++ }
+
+ if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) &&
+ hdw->state_encoder_run) {
+@@ -2904,15 +3261,6 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
+ }
+
+
+-static void pvr2_hdw_worker_i2c(struct work_struct *work)
+-{
+- struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync);
+- LOCK_TAKE(hdw->big_lock); do {
+- pvr2_i2c_core_sync(hdw);
+- } while (0); LOCK_GIVE(hdw->big_lock);
+-}
+-
+-
+ static void pvr2_hdw_worker_poll(struct work_struct *work)
+ {
+ int fl = 0;
+@@ -2973,7 +3321,7 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
+ void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
+ {
+ LOCK_TAKE(hdw->big_lock); do {
+- pvr2_i2c_core_status_poll(hdw);
++ pvr2_hdw_status_poll(hdw);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ }
+
+@@ -2983,7 +3331,7 @@ static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw)
+ if (!hdw->cropcap_stale) {
+ return 0;
+ }
+- pvr2_i2c_core_status_poll(hdw);
++ pvr2_hdw_status_poll(hdw);
+ if (hdw->cropcap_stale) {
+ return -EIO;
+ }
+@@ -3010,7 +3358,7 @@ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
+ {
+ LOCK_TAKE(hdw->big_lock); do {
+ if (hdw->tuner_signal_stale) {
+- pvr2_i2c_core_status_poll(hdw);
++ pvr2_hdw_status_poll(hdw);
+ }
+ memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
+ } while (0); LOCK_GIVE(hdw->big_lock);
+@@ -3029,11 +3377,8 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
+ {
+ int nr = pvr2_hdw_get_unit_number(hdw);
+ LOCK_TAKE(hdw->big_lock); do {
+- hdw->log_requested = !0;
+ printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr);
+- pvr2_i2c_core_check_stale(hdw);
+- hdw->log_requested = 0;
+- pvr2_i2c_core_sync(hdw);
++ v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status);
+ pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
+ cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
+ pvr2_hdw_state_log_state(hdw);
+@@ -3716,22 +4061,16 @@ int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
+
+ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
+ {
+- if (!hdw->decoder_ctrl) {
+- pvr2_trace(PVR2_TRACE_INIT,
+- "Unable to reset decoder: nothing attached");
+- return -ENOTTY;
+- }
+-
+- if (!hdw->decoder_ctrl->force_reset) {
+- pvr2_trace(PVR2_TRACE_INIT,
+- "Unable to reset decoder: not implemented");
+- return -ENOTTY;
+- }
+-
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Requesting decoder reset");
+- hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt);
+- return 0;
++ if (hdw->decoder_client_id) {
++ v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
++ core, reset, 0);
++ return 0;
++ }
++ pvr2_trace(PVR2_TRACE_INIT,
++ "Unable to reset decoder: nothing attached");
++ return -ENOTTY;
+ }
+
+
+@@ -4476,6 +4815,79 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
+ }
+
+
++/* Generate report containing info about attached sub-devices and attached
++ i2c clients, including an indication of which attached i2c clients are
++ actually sub-devices. */
++static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw,
++ char *buf, unsigned int acnt)
++{
++ struct v4l2_subdev *sd;
++ unsigned int tcnt = 0;
++ unsigned int ccnt;
++ struct i2c_client *client;
++ struct list_head *item;
++ void *cd;
++ const char *p;
++ unsigned int id;
++
++ ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers:");
++ tcnt += ccnt;
++ v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
++ id = sd->grp_id;
++ p = NULL;
++ if (id < ARRAY_SIZE(module_names)) p = module_names[id];
++ if (p) {
++ ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s", p);
++ tcnt += ccnt;
++ } else {
++ ccnt = scnprintf(buf + tcnt, acnt - tcnt,
++ " (unknown id=%u)", id);
++ tcnt += ccnt;
++ }
++ }
++ ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
++ tcnt += ccnt;
++
++ ccnt = scnprintf(buf + tcnt, acnt - tcnt, "I2C clients:\n");
++ tcnt += ccnt;
++
++ mutex_lock(&hdw->i2c_adap.clist_lock);
++ list_for_each(item, &hdw->i2c_adap.clients) {
++ client = list_entry(item, struct i2c_client, list);
++ ccnt = scnprintf(buf + tcnt, acnt - tcnt,
++ " %s: i2c=%02x", client->name, client->addr);
++ tcnt += ccnt;
++ cd = i2c_get_clientdata(client);
++ v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
++ if (cd == sd) {
++ id = sd->grp_id;
++ p = NULL;
++ if (id < ARRAY_SIZE(module_names)) {
++ p = module_names[id];
++ }
++ if (p) {
++ ccnt = scnprintf(buf + tcnt,
++ acnt - tcnt,
++ " subdev=%s", p);
++ tcnt += ccnt;
++ } else {
++ ccnt = scnprintf(buf + tcnt,
++ acnt - tcnt,
++ " subdev= id %u)",
++ id);
++ tcnt += ccnt;
++ }
++ break;
++ }
++ }
++ ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
++ tcnt += ccnt;
++ }
++ mutex_unlock(&hdw->i2c_adap.clist_lock);
++ return tcnt;
++}
++
++
+ unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
+ char *buf,unsigned int acnt)
+ {
+@@ -4490,6 +4902,8 @@ unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
+ buf[0] = '\n'; ccnt = 1;
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ }
++ ccnt = pvr2_hdw_report_clients(hdw, buf, acnt);
++ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ LOCK_GIVE(hdw->big_lock);
+ return bcnt;
+ }
+@@ -4497,14 +4911,25 @@ unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
+
+ static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
+ {
+- char buf[128];
+- unsigned int idx,ccnt;
++ char buf[256];
++ unsigned int idx, ccnt;
++ unsigned int lcnt, ucnt;
+
+ for (idx = 0; ; idx++) {
+ ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
+ if (!ccnt) break;
+ printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
+ }
++ ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf));
++ ucnt = 0;
++ while (ucnt < ccnt) {
++ lcnt = 0;
++ while ((lcnt + ucnt < ccnt) && (buf[lcnt + ucnt] != '\n')) {
++ lcnt++;
++ }
++ printk(KERN_INFO "%s %.*s\n", hdw->name, lcnt, buf + ucnt);
++ ucnt += lcnt + 1;
++ }
+ }
+
+
+@@ -4641,6 +5066,30 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
+ }
+
+
++void pvr2_hdw_status_poll(struct pvr2_hdw *hdw)
++{
++ struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
++ memset(vtp, 0, sizeof(*vtp));
++ hdw->tuner_signal_stale = 0;
++ /* Note: There apparently is no replacement for VIDIOC_CROPCAP
++ using v4l2-subdev - therefore we can't support that AT ALL right
++ now. (Of course, no sub-drivers seem to implement it either.
++ But now it's a a chicken and egg problem...) */
++ v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner,
++ &hdw->tuner_signal_info);
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll"
++ " type=%u strength=%u audio=0x%x cap=0x%x"
++ " low=%u hi=%u",
++ vtp->type,
++ vtp->signal, vtp->rxsubchans, vtp->capability,
++ vtp->rangelow, vtp->rangehigh);
++
++ /* We have to do this to avoid getting into constant polling if
++ there's nobody to answer a poll of cropcap info. */
++ hdw->cropcap_stale = 0;
++}
++
++
+ unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw)
+ {
+ return hdw->input_avail_mask;
+@@ -4736,7 +5185,6 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
+ int setFl, u64 *val_ptr)
+ {
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+- struct pvr2_i2c_client *cp;
+ struct v4l2_dbg_register req;
+ int stat = 0;
+ int okFl = 0;
+@@ -4746,21 +5194,9 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
+ req.match = *match;
+ req.reg = reg_id;
+ if (setFl) req.val = *val_ptr;
+- mutex_lock(&hdw->i2c_list_lock); do {
+- list_for_each_entry(cp, &hdw->i2c_clients, list) {
+- if (!v4l2_chip_match_i2c_client(
+- cp->client,
+- &req.match)) {
+- continue;
+- }
+- stat = pvr2_i2c_client_cmd(
+- cp,(setFl ? VIDIOC_DBG_S_REGISTER :
+- VIDIOC_DBG_G_REGISTER),&req);
+- if (!setFl) *val_ptr = req.val;
+- okFl = !0;
+- break;
+- }
+- } while (0); mutex_unlock(&hdw->i2c_list_lock);
++ /* It would be nice to know if a sub-device answered the request */
++ v4l2_device_call_all(&hdw->v4l2_dev, 0, core, g_register, &req);
++ if (!setFl) *val_ptr = req.val;
+ if (okFl) {
+ return stat;
+ }
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+index 1b4fec3..7b69405 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+@@ -132,6 +132,9 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *);
+ /* Retrieve bus location info of device */
+ const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *);
+
++/* Retrieve per-instance string identifier for this specific device */
++const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *);
++
+ /* Called when hardware has been unplugged */
+ void pvr2_hdw_disconnect(struct pvr2_hdw *);
+
+@@ -236,8 +239,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
+ enum pvr2_v4l_type index,int);
+
+ /* Direct read/write access to chip's registers:
+- match_type - how to interpret match_chip (e.g. driver ID, i2c address)
+- match_chip - chip match value (e.g. I2C_DRIVERD_xxxx)
++ match - specify criteria to identify target chip (this is a v4l dbg struct)
+ reg_id - register number to access
+ setFl - true to set the register, false to read it
+ val_ptr - storage location for source / result. */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+deleted file mode 100644
+index 94a4771..0000000
+--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
++++ /dev/null
+@@ -1,113 +0,0 @@
+-/*
+- *
+- *
+- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License
+- *
+- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include "pvrusb2-i2c-core.h"
+-#include "pvrusb2-hdw-internal.h"
+-#include "pvrusb2-debug.h"
+-#include "pvrusb2-i2c-cmd-v4l2.h"
+-#include "pvrusb2-audio.h"
+-#include "pvrusb2-tuner.h"
+-#include "pvrusb2-video-v4l.h"
+-#include "pvrusb2-cx2584x-v4l.h"
+-#include "pvrusb2-wm8775.h"
+-
+-#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
+-
+-#define OP_STANDARD 0
+-#define OP_AUDIOMODE 1
+-#define OP_BCSH 2
+-#define OP_VOLUME 3
+-#define OP_FREQ 4
+-#define OP_AUDIORATE 5
+-#define OP_CROP 6
+-#define OP_SIZE 7
+-#define OP_LOG 8
+-
+-static const struct pvr2_i2c_op * const ops[] = {
+- [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
+- [OP_AUDIOMODE] = &pvr2_i2c_op_v4l2_audiomode,
+- [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
+- [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
+- [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
+- [OP_CROP] = &pvr2_i2c_op_v4l2_crop,
+- [OP_SIZE] = &pvr2_i2c_op_v4l2_size,
+- [OP_LOG] = &pvr2_i2c_op_v4l2_log,
+-};
+-
+-void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+-{
+- int id;
+- id = cp->client->driver->id;
+- cp->ctl_mask = ((1 << OP_STANDARD) |
+- (1 << OP_AUDIOMODE) |
+- (1 << OP_BCSH) |
+- (1 << OP_VOLUME) |
+- (1 << OP_FREQ) |
+- (1 << OP_CROP) |
+- (1 << OP_SIZE) |
+- (1 << OP_LOG));
+- cp->status_poll = pvr2_v4l2_cmd_status_poll;
+-
+- if (id == I2C_DRIVERID_MSP3400) {
+- if (pvr2_i2c_msp3400_setup(hdw,cp)) {
+- return;
+- }
+- }
+- if (id == I2C_DRIVERID_TUNER) {
+- if (pvr2_i2c_tuner_setup(hdw,cp)) {
+- return;
+- }
+- }
+- if (id == I2C_DRIVERID_CX25840) {
+- if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
+- return;
+- }
+- }
+- if (id == I2C_DRIVERID_WM8775) {
+- if (pvr2_i2c_wm8775_setup(hdw,cp)) {
+- return;
+- }
+- }
+- if (id == I2C_DRIVERID_SAA711X) {
+- if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
+- return;
+- }
+- }
+-}
+-
+-
+-const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx)
+-{
+- if (idx >= ARRAY_SIZE(ops))
+- return NULL;
+- return ops[idx];
+-}
+-
+-
+-/*
+- Stuff for Emacs to see, in order to encourage consistent editing style:
+- *** Local Variables: ***
+- *** mode: c ***
+- *** fill-column: 75 ***
+- *** tab-width: 8 ***
+- *** c-basic-offset: 8 ***
+- *** End: ***
+- */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+deleted file mode 100644
+index 16bb119..0000000
+--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
++++ /dev/null
+@@ -1,322 +0,0 @@
+-/*
+- *
+- *
+- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+- * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+- *
+- * 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
+- *
+- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+- *
+- */
+-
+-#include "pvrusb2-i2c-cmd-v4l2.h"
+-#include "pvrusb2-hdw-internal.h"
+-#include "pvrusb2-debug.h"
+-#include <linux/videodev2.h>
+-#include <media/v4l2-common.h>
+-
+-static void set_standard(struct pvr2_hdw *hdw)
+-{
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_standard");
+-
+- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+- pvr2_i2c_core_cmd(hdw,AUDC_SET_RADIO,NULL);
+- } else {
+- v4l2_std_id vs;
+- vs = hdw->std_mask_cur;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+- }
+- hdw->tuner_signal_stale = !0;
+- hdw->cropcap_stale = !0;
+-}
+-
+-
+-static int check_standard(struct pvr2_hdw *hdw)
+-{
+- return (hdw->input_dirty != 0) || (hdw->std_dirty != 0);
+-}
+-
+-
+-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard = {
+- .check = check_standard,
+- .update = set_standard,
+- .name = "v4l2_standard",
+-};
+-
+-
+-static void set_bcsh(struct pvr2_hdw *hdw)
+-{
+- struct v4l2_control ctrl;
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_bcsh"
+- " b=%d c=%d s=%d h=%d",
+- hdw->brightness_val,hdw->contrast_val,
+- hdw->saturation_val,hdw->hue_val);
+- memset(&ctrl,0,sizeof(ctrl));
+- ctrl.id = V4L2_CID_BRIGHTNESS;
+- ctrl.value = hdw->brightness_val;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+- ctrl.id = V4L2_CID_CONTRAST;
+- ctrl.value = hdw->contrast_val;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+- ctrl.id = V4L2_CID_SATURATION;
+- ctrl.value = hdw->saturation_val;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+- ctrl.id = V4L2_CID_HUE;
+- ctrl.value = hdw->hue_val;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+-}
+-
+-
+-static int check_bcsh(struct pvr2_hdw *hdw)
+-{
+- return (hdw->brightness_dirty ||
+- hdw->contrast_dirty ||
+- hdw->saturation_dirty ||
+- hdw->hue_dirty);
+-}
+-
+-
+-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh = {
+- .check = check_bcsh,
+- .update = set_bcsh,
+- .name = "v4l2_bcsh",
+-};
+-
+-
+-static void set_volume(struct pvr2_hdw *hdw)
+-{
+- struct v4l2_control ctrl;
+- pvr2_trace(PVR2_TRACE_CHIPS,
+- "i2c v4l2 set_volume"
+- "(vol=%d bal=%d bas=%d treb=%d mute=%d)",
+- hdw->volume_val,
+- hdw->balance_val,
+- hdw->bass_val,
+- hdw->treble_val,
+- hdw->mute_val);
+- memset(&ctrl,0,sizeof(ctrl));
+- ctrl.id = V4L2_CID_AUDIO_MUTE;
+- ctrl.value = hdw->mute_val ? 1 : 0;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+- ctrl.id = V4L2_CID_AUDIO_VOLUME;
+- ctrl.value = hdw->volume_val;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+- ctrl.id = V4L2_CID_AUDIO_BALANCE;
+- ctrl.value = hdw->balance_val;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+- ctrl.id = V4L2_CID_AUDIO_BASS;
+- ctrl.value = hdw->bass_val;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+- ctrl.id = V4L2_CID_AUDIO_TREBLE;
+- ctrl.value = hdw->treble_val;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+-}
+-
+-
+-static int check_volume(struct pvr2_hdw *hdw)
+-{
+- return (hdw->volume_dirty ||
+- hdw->balance_dirty ||
+- hdw->bass_dirty ||
+- hdw->treble_dirty ||
+- hdw->mute_dirty);
+-}
+-
+-
+-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
+- .check = check_volume,
+- .update = set_volume,
+- .name = "v4l2_volume",
+-};
+-
+-
+-static void set_audiomode(struct pvr2_hdw *hdw)
+-{
+- struct v4l2_tuner vt;
+- memset(&vt,0,sizeof(vt));
+- vt.audmode = hdw->audiomode_val;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_TUNER,&vt);
+-}
+-
+-
+-static int check_audiomode(struct pvr2_hdw *hdw)
+-{
+- return (hdw->input_dirty ||
+- hdw->audiomode_dirty);
+-}
+-
+-
+-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode = {
+- .check = check_audiomode,
+- .update = set_audiomode,
+- .name = "v4l2_audiomode",
+-};
+-
+-
+-static void set_frequency(struct pvr2_hdw *hdw)
+-{
+- unsigned long fv;
+- struct v4l2_frequency freq;
+- fv = pvr2_hdw_get_cur_freq(hdw);
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+- if (hdw->tuner_signal_stale) {
+- pvr2_i2c_core_status_poll(hdw);
+- }
+- memset(&freq,0,sizeof(freq));
+- if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+- // ((fv * 1000) / 62500)
+- freq.frequency = (fv * 2) / 125;
+- } else {
+- freq.frequency = fv / 62500;
+- }
+- /* tuner-core currently doesn't seem to care about this, but
+- let's set it anyway for completeness. */
+- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+- freq.type = V4L2_TUNER_RADIO;
+- } else {
+- freq.type = V4L2_TUNER_ANALOG_TV;
+- }
+- freq.tuner = 0;
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
+-}
+-
+-
+-static int check_frequency(struct pvr2_hdw *hdw)
+-{
+- return hdw->freqDirty != 0;
+-}
+-
+-
+-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency = {
+- .check = check_frequency,
+- .update = set_frequency,
+- .name = "v4l2_freq",
+-};
+-
+-
+-static void set_size(struct pvr2_hdw *hdw)
+-{
+- struct v4l2_format fmt;
+-
+- memset(&fmt,0,sizeof(fmt));
+-
+- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- fmt.fmt.pix.width = hdw->res_hor_val;
+- fmt.fmt.pix.height = hdw->res_ver_val;
+-
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_size(%dx%d)",
+- fmt.fmt.pix.width,fmt.fmt.pix.height);
+-
+- pvr2_i2c_core_cmd(hdw,VIDIOC_S_FMT,&fmt);
+-}
+-
+-
+-static int check_size(struct pvr2_hdw *hdw)
+-{
+- return (hdw->res_hor_dirty || hdw->res_ver_dirty);
+-}
+-
+-
+-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = {
+- .check = check_size,
+- .update = set_size,
+- .name = "v4l2_size",
+-};
+-
+-
+-static void set_crop(struct pvr2_hdw *hdw)
+-{
+- struct v4l2_crop crop;
+-
+- memset(&crop, 0, sizeof crop);
+- crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- crop.c.left = hdw->cropl_val;
+- crop.c.top = hdw->cropt_val;
+- crop.c.height = hdw->croph_val;
+- crop.c.width = hdw->cropw_val;
+-
+- pvr2_trace(PVR2_TRACE_CHIPS,
+- "i2c v4l2 set_crop crop=%d:%d:%d:%d",
+- crop.c.width, crop.c.height, crop.c.left, crop.c.top);
+-
+- pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop);
+-}
+-
+-static int check_crop(struct pvr2_hdw *hdw)
+-{
+- return (hdw->cropl_dirty || hdw->cropt_dirty ||
+- hdw->cropw_dirty || hdw->croph_dirty);
+-}
+-
+-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop = {
+- .check = check_crop,
+- .update = set_crop,
+- .name = "v4l2_crop",
+-};
+-
+-
+-static void do_log(struct pvr2_hdw *hdw)
+-{
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()");
+- pvr2_i2c_core_cmd(hdw,VIDIOC_LOG_STATUS,NULL);
+-
+-}
+-
+-
+-static int check_log(struct pvr2_hdw *hdw)
+-{
+- return hdw->log_requested != 0;
+-}
+-
+-
+-const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log = {
+- .check = check_log,
+- .update = do_log,
+- .name = "v4l2_log",
+-};
+-
+-
+-void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
+-{
+- pvr2_i2c_client_cmd(cp,
+- (fl ? VIDIOC_STREAMON : VIDIOC_STREAMOFF),NULL);
+-}
+-
+-
+-void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
+-{
+- int stat;
+- struct pvr2_hdw *hdw = cp->hdw;
+- if (hdw->cropcap_stale) {
+- hdw->cropcap_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- stat = pvr2_i2c_client_cmd(cp, VIDIOC_CROPCAP,
+- &hdw->cropcap_info);
+- if (stat == 0) {
+- /* Check was successful, so the data is no
+- longer considered stale. */
+- hdw->cropcap_stale = 0;
+- }
+- }
+- pvr2_i2c_client_cmd(cp, VIDIOC_G_TUNER, &hdw->tuner_signal_info);
+-}
+-
+-
+-/*
+- Stuff for Emacs to see, in order to encourage consistent editing style:
+- *** Local Variables: ***
+- *** mode: c ***
+- *** fill-column: 70 ***
+- *** tab-width: 8 ***
+- *** c-basic-offset: 8 ***
+- *** End: ***
+- */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+deleted file mode 100644
+index eb744a2..0000000
+--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
++++ /dev/null
+@@ -1,50 +0,0 @@
+-/*
+- *
+- *
+- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+- * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+- *
+- * 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
+- *
+- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+- *
+- */
+-
+-#ifndef __PVRUSB2_CMD_V4L2_H
+-#define __PVRUSB2_CMD_V4L2_H
+-
+-#include "pvrusb2-i2c-core.h"
+-
+-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
+-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio;
+-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
+-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
+-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
+-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop;
+-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
+-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
+-extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
+-
+-void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+-void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *);
+-
+-#endif /* __PVRUSB2_CMD_V4L2_H */
+-
+-/*
+- Stuff for Emacs to see, in order to encourage consistent editing style:
+- *** Local Variables: ***
+- *** mode: c ***
+- *** fill-column: 70 ***
+- *** tab-width: 8 ***
+- *** c-basic-offset: 8 ***
+- *** End: ***
+- */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+index d6a3540..9464862 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+@@ -18,6 +18,7 @@
+ *
+ */
+
++#include <linux/i2c.h>
+ #include "pvrusb2-i2c-core.h"
+ #include "pvrusb2-hdw-internal.h"
+ #include "pvrusb2-debug.h"
+@@ -29,8 +30,7 @@
+ /*
+
+ This module attempts to implement a compliant I2C adapter for the pvrusb2
+- device. By doing this we can then make use of existing functionality in
+- V4L (e.g. tuner.c) rather than rolling our own.
++ device.
+
+ */
+
+@@ -42,10 +42,6 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
+ module_param_array(ir_mode, int, NULL, 0444);
+ MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
+
+-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
+- unsigned int detail,
+- char *buf,unsigned int maxlen);
+-
+ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
+ u8 i2c_addr, /* I2C address we're talking to */
+ u8 *data, /* Data to write */
+@@ -524,414 +520,13 @@ static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+ }
+
+-static int pvr2_i2c_core_singleton(struct i2c_client *cp,
+- unsigned int cmd,void *arg)
+-{
+- int stat;
+- if (!cp) return -EINVAL;
+- if (!(cp->driver)) return -EINVAL;
+- if (!(cp->driver->command)) return -EINVAL;
+- if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
+- stat = cp->driver->command(cp,cmd,arg);
+- module_put(cp->driver->driver.owner);
+- return stat;
+-}
+-
+-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
+-{
+- int stat;
+- if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+- char buf[100];
+- unsigned int cnt;
+- cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+- buf,sizeof(buf));
+- pvr2_trace(PVR2_TRACE_I2C_CMD,
+- "i2c COMMAND (code=%u 0x%x) to %.*s",
+- cmd,cmd,cnt,buf);
+- }
+- stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
+- if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+- char buf[100];
+- unsigned int cnt;
+- cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+- buf,sizeof(buf));
+- pvr2_trace(PVR2_TRACE_I2C_CMD,
+- "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
+- }
+- return stat;
+-}
+-
+-int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
+-{
+- struct pvr2_i2c_client *cp, *ncp;
+- int stat = -EINVAL;
+-
+- if (!hdw) return stat;
+-
+- mutex_lock(&hdw->i2c_list_lock);
+- list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
+- if (!cp->recv_enable) continue;
+- mutex_unlock(&hdw->i2c_list_lock);
+- stat = pvr2_i2c_client_cmd(cp,cmd,arg);
+- mutex_lock(&hdw->i2c_list_lock);
+- }
+- mutex_unlock(&hdw->i2c_list_lock);
+- return stat;
+-}
+-
+-
+-static int handler_check(struct pvr2_i2c_client *cp)
+-{
+- struct pvr2_i2c_handler *hp = cp->handler;
+- if (!hp) return 0;
+- if (!hp->func_table->check) return 0;
+- return hp->func_table->check(hp->func_data) != 0;
+-}
+-
+-#define BUFSIZE 500
+-
+-
+-void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
+-{
+- struct pvr2_i2c_client *cp;
+- mutex_lock(&hdw->i2c_list_lock); do {
+- struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+- memset(vtp,0,sizeof(*vtp));
+- list_for_each_entry(cp, &hdw->i2c_clients, list) {
+- if (!cp->detected_flag) continue;
+- if (!cp->status_poll) continue;
+- cp->status_poll(cp);
+- }
+- hdw->tuner_signal_stale = 0;
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
+- " type=%u strength=%u audio=0x%x cap=0x%x"
+- " low=%u hi=%u",
+- vtp->type,
+- vtp->signal,vtp->rxsubchans,vtp->capability,
+- vtp->rangelow,vtp->rangehigh);
+- } while (0); mutex_unlock(&hdw->i2c_list_lock);
+-}
+-
+-
+-/* Issue various I2C operations to bring chip-level drivers into sync with
+- state stored in this driver. */
+-void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
+-{
+- unsigned long msk;
+- unsigned int idx;
+- struct pvr2_i2c_client *cp, *ncp;
+-
+- if (!hdw->i2c_linked) return;
+- if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
+- return;
+- }
+- mutex_lock(&hdw->i2c_list_lock); do {
+- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
+- if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
+- /* One or more I2C clients have attached since we
+- last synced. So scan the list and identify the
+- new clients. */
+- char *buf;
+- unsigned int cnt;
+- unsigned long amask = 0;
+- buf = kmalloc(BUFSIZE,GFP_KERNEL);
+- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
+- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
+- list_for_each_entry(cp, &hdw->i2c_clients, list) {
+- if (!cp->detected_flag) {
+- cp->ctl_mask = 0;
+- pvr2_i2c_probe(hdw,cp);
+- cp->detected_flag = !0;
+- msk = cp->ctl_mask;
+- cnt = 0;
+- if (buf) {
+- cnt = pvr2_i2c_client_describe(
+- cp,
+- PVR2_I2C_DETAIL_ALL,
+- buf,BUFSIZE);
+- }
+- trace_i2c("Probed: %.*s",cnt,buf);
+- if (handler_check(cp)) {
+- hdw->i2c_pend_types |=
+- PVR2_I2C_PEND_CLIENT;
+- }
+- cp->pend_mask = msk;
+- hdw->i2c_pend_mask |= msk;
+- hdw->i2c_pend_types |=
+- PVR2_I2C_PEND_REFRESH;
+- }
+- amask |= cp->ctl_mask;
+- }
+- hdw->i2c_active_mask = amask;
+- if (buf) kfree(buf);
+- }
+- if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
+- /* Need to do one or more global updates. Arrange
+- for this to happen. */
+- unsigned long m2;
+- pvr2_trace(PVR2_TRACE_I2C_CORE,
+- "i2c: PEND_STALE (0x%lx)",
+- hdw->i2c_stale_mask);
+- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
+- list_for_each_entry(cp, &hdw->i2c_clients, list) {
+- m2 = hdw->i2c_stale_mask;
+- m2 &= cp->ctl_mask;
+- m2 &= ~cp->pend_mask;
+- if (m2) {
+- pvr2_trace(PVR2_TRACE_I2C_CORE,
+- "i2c: cp=%p setting 0x%lx",
+- cp,m2);
+- cp->pend_mask |= m2;
+- }
+- }
+- hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+- hdw->i2c_stale_mask = 0;
+- hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
+- }
+- if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
+- /* One or more client handlers are asking for an
+- update. Run through the list of known clients
+- and update each one. */
+- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
+- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
+- list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
+- list) {
+- if (!cp->handler) continue;
+- if (!cp->handler->func_table->update) continue;
+- pvr2_trace(PVR2_TRACE_I2C_CORE,
+- "i2c: cp=%p update",cp);
+- mutex_unlock(&hdw->i2c_list_lock);
+- cp->handler->func_table->update(
+- cp->handler->func_data);
+- mutex_lock(&hdw->i2c_list_lock);
+- /* If client's update function set some
+- additional pending bits, account for that
+- here. */
+- if (cp->pend_mask & ~hdw->i2c_pend_mask) {
+- hdw->i2c_pend_mask |= cp->pend_mask;
+- hdw->i2c_pend_types |=
+- PVR2_I2C_PEND_REFRESH;
+- }
+- }
+- }
+- if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
+- const struct pvr2_i2c_op *opf;
+- unsigned long pm;
+- /* Some actual updates are pending. Walk through
+- each update type and perform it. */
+- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
+- " (0x%lx)",hdw->i2c_pend_mask);
+- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
+- pm = hdw->i2c_pend_mask;
+- hdw->i2c_pend_mask = 0;
+- for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+- if (!(pm & msk)) continue;
+- pm &= ~msk;
+- list_for_each_entry(cp, &hdw->i2c_clients,
+- list) {
+- if (cp->pend_mask & msk) {
+- cp->pend_mask &= ~msk;
+- cp->recv_enable = !0;
+- } else {
+- cp->recv_enable = 0;
+- }
+- }
+- opf = pvr2_i2c_get_op(idx);
+- if (!opf) continue;
+- mutex_unlock(&hdw->i2c_list_lock);
+- opf->update(hdw);
+- mutex_lock(&hdw->i2c_list_lock);
+- }
+- }
+- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
+- } while (0); mutex_unlock(&hdw->i2c_list_lock);
+-}
+-
+-int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
+-{
+- unsigned long msk,sm,pm;
+- unsigned int idx;
+- const struct pvr2_i2c_op *opf;
+- struct pvr2_i2c_client *cp;
+- unsigned int pt = 0;
+-
+- pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
+-
+- pm = hdw->i2c_active_mask;
+- sm = 0;
+- for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+- if (!(msk & pm)) continue;
+- pm &= ~msk;
+- opf = pvr2_i2c_get_op(idx);
+- if (!opf) continue;
+- if (opf->check(hdw)) {
+- sm |= msk;
+- }
+- }
+- if (sm) pt |= PVR2_I2C_PEND_STALE;
+-
+- list_for_each_entry(cp, &hdw->i2c_clients, list)
+- if (handler_check(cp))
+- pt |= PVR2_I2C_PEND_CLIENT;
+-
+- if (pt) {
+- mutex_lock(&hdw->i2c_list_lock); do {
+- hdw->i2c_pend_types |= pt;
+- hdw->i2c_stale_mask |= sm;
+- hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+- } while (0); mutex_unlock(&hdw->i2c_list_lock);
+- }
+-
+- pvr2_trace(PVR2_TRACE_I2C_CORE,
+- "i2c: types=0x%x stale=0x%lx pend=0x%lx",
+- hdw->i2c_pend_types,
+- hdw->i2c_stale_mask,
+- hdw->i2c_pend_mask);
+- pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
+-
+- return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
+-}
+-
+-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
+- unsigned int detail,
+- char *buf,unsigned int maxlen)
+-{
+- unsigned int ccnt,bcnt;
+- int spcfl = 0;
+- const struct pvr2_i2c_op *opf;
+-
+- ccnt = 0;
+- if (detail & PVR2_I2C_DETAIL_DEBUG) {
+- bcnt = scnprintf(buf,maxlen,
+- "ctxt=%p ctl_mask=0x%lx",
+- cp,cp->ctl_mask);
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- spcfl = !0;
+- }
+- bcnt = scnprintf(buf,maxlen,
+- "%s%s @ 0x%x",
+- (spcfl ? " " : ""),
+- cp->client->name,
+- cp->client->addr);
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
+- cp->handler && cp->handler->func_table->describe) {
+- bcnt = scnprintf(buf,maxlen," (");
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- bcnt = cp->handler->func_table->describe(
+- cp->handler->func_data,buf,maxlen);
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- bcnt = scnprintf(buf,maxlen,")");
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- }
+- if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
+- unsigned int idx;
+- unsigned long msk,sm;
+-
+- bcnt = scnprintf(buf,maxlen," [");
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- sm = 0;
+- spcfl = 0;
+- for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
+- if (!(cp->ctl_mask & msk)) continue;
+- opf = pvr2_i2c_get_op(idx);
+- if (opf) {
+- bcnt = scnprintf(buf,maxlen,"%s%s",
+- spcfl ? " " : "",
+- opf->name);
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- spcfl = !0;
+- } else {
+- sm |= msk;
+- }
+- }
+- if (sm) {
+- bcnt = scnprintf(buf,maxlen,"%s%lx",
+- idx != 0 ? " " : "",sm);
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- }
+- bcnt = scnprintf(buf,maxlen,"]");
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- }
+- return ccnt;
+-}
+-
+-unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
+- char *buf,unsigned int maxlen)
+-{
+- unsigned int ccnt,bcnt;
+- struct pvr2_i2c_client *cp;
+- ccnt = 0;
+- mutex_lock(&hdw->i2c_list_lock); do {
+- list_for_each_entry(cp, &hdw->i2c_clients, list) {
+- bcnt = pvr2_i2c_client_describe(
+- cp,
+- (PVR2_I2C_DETAIL_HANDLER|
+- PVR2_I2C_DETAIL_CTLMASK),
+- buf,maxlen);
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- bcnt = scnprintf(buf,maxlen,"\n");
+- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+- }
+- } while (0); mutex_unlock(&hdw->i2c_list_lock);
+- return ccnt;
+-}
+-
+ static int pvr2_i2c_attach_inform(struct i2c_client *client)
+ {
+- struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+- struct pvr2_i2c_client *cp;
+- int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
+- cp = kzalloc(sizeof(*cp),GFP_KERNEL);
+- trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
+- client->name,
+- client->addr,cp);
+- if (!cp) return -ENOMEM;
+- cp->hdw = hdw;
+- INIT_LIST_HEAD(&cp->list);
+- cp->client = client;
+- mutex_lock(&hdw->i2c_list_lock); do {
+- hdw->cropcap_stale = !0;
+- list_add_tail(&cp->list,&hdw->i2c_clients);
+- hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
+- } while (0); mutex_unlock(&hdw->i2c_list_lock);
+- if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
+ return 0;
+ }
+
+ static int pvr2_i2c_detach_inform(struct i2c_client *client)
+ {
+- struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+- struct pvr2_i2c_client *cp, *ncp;
+- unsigned long amask = 0;
+- int foundfl = 0;
+- mutex_lock(&hdw->i2c_list_lock); do {
+- hdw->cropcap_stale = !0;
+- list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
+- if (cp->client == client) {
+- trace_i2c("pvr2_i2c_detach"
+- " [client=%s @ 0x%x ctxt=%p]",
+- client->name,
+- client->addr,cp);
+- if (cp->handler &&
+- cp->handler->func_table->detach) {
+- cp->handler->func_table->detach(
+- cp->handler->func_data);
+- }
+- list_del(&cp->list);
+- kfree(cp);
+- foundfl = !0;
+- continue;
+- }
+- amask |= cp->ctl_mask;
+- }
+- hdw->i2c_active_mask = amask;
+- } while (0); mutex_unlock(&hdw->i2c_list_lock);
+- if (!foundfl) {
+- trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
+- client->name,
+- client->addr);
+- }
+ return 0;
+ }
+
+@@ -942,7 +537,7 @@ static struct i2c_algorithm pvr2_i2c_algo_template = {
+
+ static struct i2c_adapter pvr2_i2c_adap_template = {
+ .owner = THIS_MODULE,
+- .class = I2C_CLASS_TV_ANALOG,
++ .class = 0,
+ .id = I2C_HW_B_BT848,
+ .client_register = pvr2_i2c_attach_inform,
+ .client_unregister = pvr2_i2c_detach_inform,
+@@ -1009,12 +604,8 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
+ hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
+ hdw->i2c_adap.algo = &hdw->i2c_algo;
+ hdw->i2c_adap.algo_data = hdw;
+- hdw->i2c_pend_mask = 0;
+- hdw->i2c_stale_mask = 0;
+- hdw->i2c_active_mask = 0;
+- INIT_LIST_HEAD(&hdw->i2c_clients);
+- mutex_init(&hdw->i2c_list_lock);
+ hdw->i2c_linked = !0;
++ i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
+ i2c_add_adapter(&hdw->i2c_adap);
+ if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
+ /* Probe for a different type of IR receiver on this
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+index 6ef7a1c..6a75769 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+@@ -20,68 +20,13 @@
+ #ifndef __PVRUSB2_I2C_CORE_H
+ #define __PVRUSB2_I2C_CORE_H
+
+-#include <linux/list.h>
+-#include <linux/i2c.h>
+-
+ struct pvr2_hdw;
+-struct pvr2_i2c_client;
+-struct pvr2_i2c_handler;
+-struct pvr2_i2c_handler_functions;
+-struct pvr2_i2c_op;
+-struct pvr2_i2c_op_functions;
+-
+-struct pvr2_i2c_client {
+- struct i2c_client *client;
+- struct pvr2_i2c_handler *handler;
+- struct list_head list;
+- struct pvr2_hdw *hdw;
+- int detected_flag;
+- int recv_enable;
+- unsigned long pend_mask;
+- unsigned long ctl_mask;
+- void (*status_poll)(struct pvr2_i2c_client *);
+-};
+-
+-struct pvr2_i2c_handler {
+- void *func_data;
+- const struct pvr2_i2c_handler_functions *func_table;
+-};
+-
+-struct pvr2_i2c_handler_functions {
+- void (*detach)(void *);
+- int (*check)(void *);
+- void (*update)(void *);
+- unsigned int (*describe)(void *,char *,unsigned int);
+-};
+-
+-struct pvr2_i2c_op {
+- int (*check)(struct pvr2_hdw *);
+- void (*update)(struct pvr2_hdw *);
+- const char *name;
+-};
+
+ void pvr2_i2c_core_init(struct pvr2_hdw *);
+ void pvr2_i2c_core_done(struct pvr2_hdw *);
+
+-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
+-int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
+-
+-int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
+-void pvr2_i2c_core_sync(struct pvr2_hdw *);
+-void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
+-unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
+-#define PVR2_I2C_DETAIL_DEBUG 0x0001
+-#define PVR2_I2C_DETAIL_HANDLER 0x0002
+-#define PVR2_I2C_DETAIL_CTLMASK 0x0004
+-#define PVR2_I2C_DETAIL_ALL (\
+- PVR2_I2C_DETAIL_DEBUG |\
+- PVR2_I2C_DETAIL_HANDLER |\
+- PVR2_I2C_DETAIL_CTLMASK)
+-
+-void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
+-const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
+
+-#endif /* __PVRUSB2_I2C_CORE_H */
++#endif /* __PVRUSB2_I2C_ADAPTER_H */
+
+
+ /*
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
+index 9b3c874..8689ddb 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
+@@ -137,10 +137,10 @@ static int __init pvr_init(void)
+ ret = usb_register(&pvr_driver);
+
+ if (ret == 0)
+- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
++ printk(KERN_INFO "pvrusb2: " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
+ if (pvrusb2_debug)
+- printk(KERN_INFO KBUILD_MODNAME ": Debug mask is %d (0x%x)\n",
++ printk(KERN_INFO "pvrusb2: Debug mask is %d (0x%x)\n",
+ pvrusb2_debug,pvrusb2_debug);
+
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete");
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+index e641cd9..e20ba1e 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+@@ -627,16 +627,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
+ pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
+
+ class_dev->class = &class_ptr->class;
+- if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
+- dev_set_name(class_dev, "sn-%lu",
+- pvr2_hdw_get_sn(sfp->channel.hdw));
+- } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
+- dev_set_name(class_dev, "unit-%c",
+- pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
+- } else {
+- kfree(class_dev);
+- return;
+- }
++ dev_set_name(class_dev, "%s",
++ pvr2_hdw_get_device_identifier(sfp->channel.hdw));
+
+ class_dev->parent = &usb_dev->dev;
+
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
+deleted file mode 100644
+index 07775d1..0000000
+--- a/drivers/media/video/pvrusb2/pvrusb2-tuner.c
++++ /dev/null
+@@ -1,120 +0,0 @@
+-/*
+- *
+- *
+- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+- * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+- *
+- * 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
+- *
+- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+- *
+- */
+-
+-#include "pvrusb2.h"
+-#include "pvrusb2-util.h"
+-#include "pvrusb2-tuner.h"
+-#include "pvrusb2-hdw-internal.h"
+-#include "pvrusb2-debug.h"
+-#include <linux/videodev2.h>
+-#include <media/tuner.h>
+-#include <media/v4l2-common.h>
+-
+-struct pvr2_tuner_handler {
+- struct pvr2_hdw *hdw;
+- struct pvr2_i2c_client *client;
+- struct pvr2_i2c_handler i2c_handler;
+- int type_update_fl;
+-};
+-
+-
+-static void set_type(struct pvr2_tuner_handler *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- struct tuner_setup setup;
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c tuner set_type(%d)",hdw->tuner_type);
+- if (((int)(hdw->tuner_type)) < 0) return;
+-
+- setup.addr = ADDR_UNSET;
+- setup.type = hdw->tuner_type;
+- setup.mode_mask = T_RADIO | T_ANALOG_TV;
+- /* We may really want mode_mask to be T_ANALOG_TV for now */
+- pvr2_i2c_client_cmd(ctxt->client,TUNER_SET_TYPE_ADDR,&setup);
+- ctxt->type_update_fl = 0;
+-}
+-
+-
+-static int tuner_check(struct pvr2_tuner_handler *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- if (hdw->tuner_updated) ctxt->type_update_fl = !0;
+- return ctxt->type_update_fl != 0;
+-}
+-
+-
+-static void tuner_update(struct pvr2_tuner_handler *ctxt)
+-{
+- if (ctxt->type_update_fl) set_type(ctxt);
+-}
+-
+-
+-static void pvr2_tuner_detach(struct pvr2_tuner_handler *ctxt)
+-{
+- ctxt->client->handler = NULL;
+- kfree(ctxt);
+-}
+-
+-
+-static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *buf,unsigned int cnt)
+-{
+- return scnprintf(buf,cnt,"handler: pvrusb2-tuner");
+-}
+-
+-
+-static const struct pvr2_i2c_handler_functions tuner_funcs = {
+- .detach = (void (*)(void *))pvr2_tuner_detach,
+- .check = (int (*)(void *))tuner_check,
+- .update = (void (*)(void *))tuner_update,
+- .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_tuner_describe,
+-};
+-
+-
+-int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+-{
+- struct pvr2_tuner_handler *ctxt;
+- if (cp->handler) return 0;
+-
+- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
+- if (!ctxt) return 0;
+-
+- ctxt->i2c_handler.func_data = ctxt;
+- ctxt->i2c_handler.func_table = &tuner_funcs;
+- ctxt->type_update_fl = !0;
+- ctxt->client = cp;
+- ctxt->hdw = hdw;
+- cp->handler = &ctxt->i2c_handler;
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tuner handler set up",
+- cp->client->addr);
+- return !0;
+-}
+-
+-
+-
+-
+-/*
+- Stuff for Emacs to see, in order to encourage consistent editing style:
+- *** Local Variables: ***
+- *** mode: c ***
+- *** fill-column: 70 ***
+- *** tab-width: 8 ***
+- *** c-basic-offset: 8 ***
+- *** End: ***
+- */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/drivers/media/video/pvrusb2/pvrusb2-tuner.h
+deleted file mode 100644
+index ef4afaf..0000000
+--- a/drivers/media/video/pvrusb2/pvrusb2-tuner.h
++++ /dev/null
+@@ -1,37 +0,0 @@
+-/*
+- *
+- *
+- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License
+- *
+- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+- *
+- */
+-#ifndef __PVRUSB2_TUNER_H
+-#define __PVRUSB2_TUNER_H
+-
+-#include "pvrusb2-i2c-core.h"
+-
+-int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+-
+-#endif /* __PVRUSB2_TUNER_H */
+-
+-/*
+- Stuff for Emacs to see, in order to encourage consistent editing style:
+- *** Local Variables: ***
+- *** mode: c ***
+- *** fill-column: 70 ***
+- *** tab-width: 8 ***
+- *** c-basic-offset: 8 ***
+- *** End: ***
+- */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+index 878fd52..9e0f2b0 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+@@ -91,7 +91,7 @@ static struct v4l2_capability pvr_capability ={
+ .card = "Hauppauge WinTV pvr-usb2",
+ .bus_info = "usb",
+ .version = KERNEL_VERSION(0,8,0),
+- .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
++ .capabilities = (V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
+ V4L2_CAP_READWRITE),
+ .reserved = {0,0,0,0}
+@@ -952,10 +952,6 @@ static long pvr2_v4l2_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+
+-/* Temporary hack : use ivtv api until a v4l2 one is available. */
+-#define IVTV_IOC_G_CODEC 0xFFEE7703
+-#define IVTV_IOC_S_CODEC 0xFFEE7704
+- if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0;
+ return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
+ }
+
+@@ -1268,8 +1264,9 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
+ dip->minor_type = pvr2_v4l_type_video;
+ nr_ptr = video_nr;
+ if (!dip->stream) {
+- err("Failed to set up pvrusb2 v4l video dev"
+- " due to missing stream instance");
++ pr_err(KBUILD_MODNAME
++ ": Failed to set up pvrusb2 v4l video dev"
++ " due to missing stream instance\n");
+ return;
+ }
+ break;
+@@ -1286,8 +1283,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
+ break;
+ default:
+ /* Bail out (this should be impossible) */
+- err("Failed to set up pvrusb2 v4l dev"
+- " due to unrecognized config");
++ pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev"
++ " due to unrecognized config\n");
+ return;
+ }
+
+@@ -1303,7 +1300,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
+ dip->v4l_type, mindevnum) < 0) &&
+ (video_register_device(&dip->devbase,
+ dip->v4l_type, -1) < 0)) {
+- err("Failed to register pvrusb2 v4l device");
++ pr_err(KBUILD_MODNAME
++ ": Failed to register pvrusb2 v4l device\n");
+ }
+
+ printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+index 4059648..b3862f5 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+@@ -28,7 +28,7 @@
+ */
+
+ #include "pvrusb2-video-v4l.h"
+-#include "pvrusb2-i2c-cmd-v4l2.h"
++
+
+
+ #include "pvrusb2-hdw-internal.h"
+@@ -39,15 +39,6 @@
+ #include <linux/errno.h>
+ #include <linux/slab.h>
+
+-struct pvr2_v4l_decoder {
+- struct pvr2_i2c_handler handler;
+- struct pvr2_decoder_ctrl ctrl;
+- struct pvr2_i2c_client *client;
+- struct pvr2_hdw *hdw;
+- unsigned long stale_mask;
+-};
+-
+-
+ struct routing_scheme {
+ const int *def;
+ unsigned int cnt;
+@@ -63,190 +54,51 @@ static const int routing_scheme0[] = {
+ [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2,
+ };
+
++static const int routing_scheme1[] = {
++ [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4,
++ [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5,
++ [PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE3,
++ [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, /* or SVIDEO0, it seems */
++};
++
+ static const struct routing_scheme routing_schemes[] = {
+ [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
+ .def = routing_scheme0,
+ .cnt = ARRAY_SIZE(routing_scheme0),
+ },
++ [PVR2_ROUTING_SCHEME_ONAIR] = {
++ .def = routing_scheme1,
++ .cnt = ARRAY_SIZE(routing_scheme1),
++ },
+ };
+
+-static void set_input(struct pvr2_v4l_decoder *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- struct v4l2_routing route;
+- const struct routing_scheme *sp;
+- unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+-
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
+-
+- if ((sid < ARRAY_SIZE(routing_schemes)) &&
+- ((sp = routing_schemes + sid) != NULL) &&
+- (hdw->input_val >= 0) &&
+- (hdw->input_val < sp->cnt)) {
+- route.input = sp->def[hdw->input_val];
+- } else {
+- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+- "*** WARNING *** i2c v4l2 set_input:"
+- " Invalid routing scheme (%u) and/or input (%d)",
+- sid,hdw->input_val);
+- return;
+- }
+-
+- route.output = 0;
+- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
+-}
+-
+-
+-static int check_input(struct pvr2_v4l_decoder *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- return hdw->input_dirty != 0;
+-}
+-
+-
+-static void set_audio(struct pvr2_v4l_decoder *ctxt)
+-{
+- u32 val;
+- struct pvr2_hdw *hdw = ctxt->hdw;
+-
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_audio %d",
+- hdw->srate_val);
+- switch (hdw->srate_val) {
+- default:
+- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+- val = 48000;
+- break;
+- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+- val = 44100;
+- break;
+- case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+- val = 32000;
+- break;
+- }
+- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
+-}
+-
+-
+-static int check_audio(struct pvr2_v4l_decoder *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- return hdw->srate_dirty != 0;
+-}
+-
+-
+-struct pvr2_v4l_decoder_ops {
+- void (*update)(struct pvr2_v4l_decoder *);
+- int (*check)(struct pvr2_v4l_decoder *);
+-};
+-
+-
+-static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
+- { .update = set_input, .check = check_input},
+- { .update = set_audio, .check = check_audio},
+-};
+-
+-
+-static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
++void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
+ {
+- ctxt->client->handler = NULL;
+- pvr2_hdw_set_decoder(ctxt->hdw,NULL);
+- kfree(ctxt);
+-}
+-
+-
+-static int decoder_check(struct pvr2_v4l_decoder *ctxt)
+-{
+- unsigned long msk;
+- unsigned int idx;
+-
+- for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
+- msk = 1 << idx;
+- if (ctxt->stale_mask & msk) continue;
+- if (decoder_ops[idx].check(ctxt)) {
+- ctxt->stale_mask |= msk;
++ if (hdw->input_dirty || hdw->force_dirty) {
++ struct v4l2_routing route;
++ const struct routing_scheme *sp;
++ unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
++ hdw->input_val);
++ if ((sid < ARRAY_SIZE(routing_schemes)) &&
++ ((sp = routing_schemes + sid) != NULL) &&
++ (hdw->input_val >= 0) &&
++ (hdw->input_val < sp->cnt)) {
++ route.input = sp->def[hdw->input_val];
++ } else {
++ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++ "*** WARNING *** subdev v4l2 set_input:"
++ " Invalid routing scheme (%u)"
++ " and/or input (%d)",
++ sid, hdw->input_val);
++ return;
+ }
++ route.output = 0;
++ sd->ops->video->s_routing(sd, &route);
+ }
+- return ctxt->stale_mask != 0;
+-}
+-
+-
+-static void decoder_update(struct pvr2_v4l_decoder *ctxt)
+-{
+- unsigned long msk;
+- unsigned int idx;
+-
+- for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
+- msk = 1 << idx;
+- if (!(ctxt->stale_mask & msk)) continue;
+- ctxt->stale_mask &= ~msk;
+- decoder_ops[idx].update(ctxt);
+- }
+-}
+-
+-
+-static int decoder_detect(struct pvr2_i2c_client *cp)
+-{
+- /* Attempt to query the decoder - let's see if it will answer */
+- struct v4l2_tuner vt;
+- int ret;
+-
+- memset(&vt,0,sizeof(vt));
+- ret = pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&vt);
+- return ret == 0; /* Return true if it answered */
+-}
+-
+-
+-static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
+-{
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 decoder_enable(%d)",fl);
+- pvr2_v4l2_cmd_stream(ctxt->client,fl);
+-}
+-
+-
+-static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
+-{
+- return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
+-}
+-
+-
+-static const struct pvr2_i2c_handler_functions hfuncs = {
+- .detach = (void (*)(void *))decoder_detach,
+- .check = (int (*)(void *))decoder_check,
+- .update = (void (*)(void *))decoder_update,
+- .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
+-};
+-
+-
+-int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
+- struct pvr2_i2c_client *cp)
+-{
+- struct pvr2_v4l_decoder *ctxt;
+-
+- if (hdw->decoder_ctrl) return 0;
+- if (cp->handler) return 0;
+- if (!decoder_detect(cp)) return 0;
+-
+- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
+- if (!ctxt) return 0;
+-
+- ctxt->handler.func_data = ctxt;
+- ctxt->handler.func_table = &hfuncs;
+- ctxt->ctrl.ctxt = ctxt;
+- ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
+- ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
+- ctxt->client = cp;
+- ctxt->hdw = hdw;
+- ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
+- pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
+- cp->handler = &ctxt->handler;
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
+- cp->client->addr);
+- return !0;
+ }
+
+
+-
+-
+ /*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
+index 4ff5b89..3b0bd5d 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
+@@ -32,11 +32,8 @@
+ */
+
+
+-
+-#include "pvrusb2-i2c-core.h"
+-
+-int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+-
++#include "pvrusb2-hdw-internal.h"
++void pvr2_saa7115_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
+
+ #endif /* __PVRUSB2_VIDEO_V4L_H */
+
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+index f6fcf0a..1670aa4 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+@@ -27,7 +27,6 @@
+ */
+
+ #include "pvrusb2-wm8775.h"
+-#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+ #include "pvrusb2-hdw-internal.h"
+@@ -37,128 +36,31 @@
+ #include <linux/errno.h>
+ #include <linux/slab.h>
+
+-struct pvr2_v4l_wm8775 {
+- struct pvr2_i2c_handler handler;
+- struct pvr2_i2c_client *client;
+- struct pvr2_hdw *hdw;
+- unsigned long stale_mask;
+-};
+-
+-
+-static void set_input(struct pvr2_v4l_wm8775 *ctxt)
+-{
+- struct v4l2_routing route;
+- struct pvr2_hdw *hdw = ctxt->hdw;
+-
+- memset(&route,0,sizeof(route));
+-
+- switch(hdw->input_val) {
+- case PVR2_CVAL_INPUT_RADIO:
+- route.input = 1;
+- break;
+- default:
+- /* All other cases just use the second input */
+- route.input = 2;
+- break;
+- }
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d route=0x%x)",
+- hdw->input_val,route.input);
+-
+- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+-}
+-
+-static int check_input(struct pvr2_v4l_wm8775 *ctxt)
+-{
+- struct pvr2_hdw *hdw = ctxt->hdw;
+- return hdw->input_dirty != 0;
+-}
+-
+-
+-struct pvr2_v4l_wm8775_ops {
+- void (*update)(struct pvr2_v4l_wm8775 *);
+- int (*check)(struct pvr2_v4l_wm8775 *);
+-};
+-
+-
+-static const struct pvr2_v4l_wm8775_ops wm8775_ops[] = {
+- { .update = set_input, .check = check_input},
+-};
+-
+-
+-static unsigned int wm8775_describe(struct pvr2_v4l_wm8775 *ctxt,
+- char *buf,unsigned int cnt)
+-{
+- return scnprintf(buf,cnt,"handler: pvrusb2-wm8775");
+-}
+-
+-
+-static void wm8775_detach(struct pvr2_v4l_wm8775 *ctxt)
++void pvr2_wm8775_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
+ {
+- ctxt->client->handler = NULL;
+- kfree(ctxt);
+-}
+-
+-
+-static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
+-{
+- unsigned long msk;
+- unsigned int idx;
+-
+- for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
+- msk = 1 << idx;
+- if (ctxt->stale_mask & msk) continue;
+- if (wm8775_ops[idx].check(ctxt)) {
+- ctxt->stale_mask |= msk;
++ if (hdw->input_dirty || hdw->force_dirty) {
++ struct v4l2_routing route;
++
++ memset(&route, 0, sizeof(route));
++
++ switch (hdw->input_val) {
++ case PVR2_CVAL_INPUT_RADIO:
++ route.input = 1;
++ break;
++ default:
++ /* All other cases just use the second input */
++ route.input = 2;
++ break;
+ }
+- }
+- return ctxt->stale_mask != 0;
+-}
+-
+-
+-static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
+-{
+- unsigned long msk;
+- unsigned int idx;
++ pvr2_trace(PVR2_TRACE_CHIPS, "subdev wm8775"
++ " set_input(val=%d route=0x%x)",
++ hdw->input_val, route.input);
+
+- for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
+- msk = 1 << idx;
+- if (!(ctxt->stale_mask & msk)) continue;
+- ctxt->stale_mask &= ~msk;
+- wm8775_ops[idx].update(ctxt);
++ sd->ops->audio->s_routing(sd, &route);
+ }
+ }
+
+
+-static const struct pvr2_i2c_handler_functions hfuncs = {
+- .detach = (void (*)(void *))wm8775_detach,
+- .check = (int (*)(void *))wm8775_check,
+- .update = (void (*)(void *))wm8775_update,
+- .describe = (unsigned int (*)(void *,char *,unsigned int))wm8775_describe,
+-};
+-
+-
+-int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+-{
+- struct pvr2_v4l_wm8775 *ctxt;
+-
+- if (cp->handler) return 0;
+-
+- ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
+- if (!ctxt) return 0;
+-
+- ctxt->handler.func_data = ctxt;
+- ctxt->handler.func_table = &hfuncs;
+- ctxt->client = cp;
+- ctxt->hdw = hdw;
+- ctxt->stale_mask = (1 << ARRAY_SIZE(wm8775_ops)) - 1;
+- cp->handler = &ctxt->handler;
+- pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
+- cp->client->addr);
+- return !0;
+-}
+-
+-
+-
+
+ /*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
+index 8070909..0577bc7 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
+@@ -34,9 +34,9 @@
+
+
+
+-#include "pvrusb2-i2c-core.h"
++#include "pvrusb2-hdw-internal.h"
+
+-int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
++void pvr2_wm8775_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd);
+
+
+ #endif /* __PVRUSB2_WM8775_H */
+diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig
+index 7298cf2..8b9f0aa 100644
+--- a/drivers/media/video/pwc/Kconfig
++++ b/drivers/media/video/pwc/Kconfig
+@@ -35,3 +35,13 @@ config USB_PWC_DEBUG
+ Say Y here in order to have the pwc driver generate verbose debugging
+ messages.
+ A special module options 'trace' is used to control the verbosity.
++
++config USB_PWC_INPUT_EVDEV
++ bool "USB Philips Cameras input events device support"
++ default y
++ depends on USB_PWC && INPUT
++ ---help---
++ This option makes USB Philips cameras register the snapshot button as
++ an input device to report button events.
++
++ If you are in doubt, say Y.
+diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
+index 0d81018..7c542ca 100644
+--- a/drivers/media/video/pwc/pwc-if.c
++++ b/drivers/media/video/pwc/pwc-if.c
+@@ -53,6 +53,7 @@
+ - Xavier Roche: QuickCam Pro 4000 ID
+ - Jens Knudsen: QuickCam Zoom ID
+ - J. Debert: QuickCam for Notebooks ID
++ - Pham Thanh Nam: webcam snapshot button as an event input device
+ */
+
+ #include <linux/errno.h>
+@@ -61,6 +62,9 @@
+ #include <linux/module.h>
+ #include <linux/poll.h>
+ #include <linux/slab.h>
++#ifdef CONFIG_USB_PWC_INPUT_EVDEV
++#include <linux/usb/input.h>
++#endif
+ #include <linux/vmalloc.h>
+ #include <asm/io.h>
+
+@@ -586,6 +590,23 @@ static void pwc_frame_dumped(struct pwc_device *pdev)
+ pdev->vframe_count);
+ }
+
++static void pwc_snapshot_button(struct pwc_device *pdev, int down)
++{
++ if (down) {
++ PWC_TRACE("Snapshot button pressed.\n");
++ pdev->snapshot_button_status = 1;
++ } else {
++ PWC_TRACE("Snapshot button released.\n");
++ }
++
++#ifdef CONFIG_USB_PWC_INPUT_EVDEV
++ if (pdev->button_dev) {
++ input_report_key(pdev->button_dev, BTN_0, down);
++ input_sync(pdev->button_dev);
++ }
++#endif
++}
++
+ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
+ {
+ int awake = 0;
+@@ -603,13 +624,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
+ pdev->vframes_error++;
+ }
+ if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+- if (ptr[0] & 0x01) {
+- pdev->snapshot_button_status = 1;
+- PWC_TRACE("Snapshot button pressed.\n");
+- }
+- else {
+- PWC_TRACE("Snapshot button released.\n");
+- }
++ pwc_snapshot_button(pdev, ptr[0] & 0x01);
+ }
+ if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+ if (ptr[0] & 0x02)
+@@ -633,12 +648,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
+ else if (pdev->type == 740 || pdev->type == 720) {
+ unsigned char *ptr = (unsigned char *)fbuf->data;
+ if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+- if (ptr[0] & 0x01) {
+- pdev->snapshot_button_status = 1;
+- PWC_TRACE("Snapshot button pressed.\n");
+- }
+- else
+- PWC_TRACE("Snapshot button released.\n");
++ pwc_snapshot_button(pdev, ptr[0] & 0x01);
+ }
+ pdev->vmirror = ptr[0] & 0x03;
+ }
+@@ -1115,6 +1125,7 @@ static int pwc_video_open(struct file *file)
+ }
+
+ mutex_lock(&pdev->modlock);
++ pwc_construct(pdev); /* set min/max sizes correct */
+ if (!pdev->usb_init) {
+ PWC_DEBUG_OPEN("Doing first time initialization.\n");
+ pdev->usb_init = 1;
+@@ -1139,7 +1150,6 @@ static int pwc_video_open(struct file *file)
+ if (pwc_set_leds(pdev, led_on, led_off) < 0)
+ PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
+
+- pwc_construct(pdev); /* set min/max sizes correct */
+
+ /* So far, so good. Allocate memory. */
+ i = pwc_allocate_buffers(pdev);
+@@ -1216,6 +1226,15 @@ static void pwc_cleanup(struct pwc_device *pdev)
+ {
+ pwc_remove_sysfs_files(pdev->vdev);
+ video_unregister_device(pdev->vdev);
++
++#ifdef CONFIG_USB_PWC_INPUT_EVDEV
++ if (pdev->button_dev) {
++ input_unregister_device(pdev->button_dev);
++ input_free_device(pdev->button_dev);
++ kfree(pdev->button_dev->phys);
++ pdev->button_dev = NULL;
++ }
++#endif
+ }
+
+ /* Note that all cleanup is done in the reverse order as in _open */
+@@ -1483,6 +1502,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
+ int features = 0;
+ int video_nr = -1; /* default: use next available device */
+ char serial_number[30], *name;
++#ifdef CONFIG_USB_PWC_INPUT_EVDEV
++ char *phys = NULL;
++#endif
+
+ vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+ product_id = le16_to_cpu(udev->descriptor.idProduct);
+@@ -1807,6 +1829,35 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
+ pwc_set_leds(pdev, 0, 0);
+ pwc_camera_power(pdev, 0);
+
++#ifdef CONFIG_USB_PWC_INPUT_EVDEV
++ /* register webcam snapshot button input device */
++ pdev->button_dev = input_allocate_device();
++ if (!pdev->button_dev) {
++ PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
++ return -ENOMEM;
++ }
++
++ pdev->button_dev->name = "PWC snapshot button";
++ phys = kasprintf(GFP_KERNEL,"usb-%s-%s", pdev->udev->bus->bus_name, pdev->udev->devpath);
++ if (!phys) {
++ input_free_device(pdev->button_dev);
++ return -ENOMEM;
++ }
++ pdev->button_dev->phys = phys;
++ usb_to_input_id(pdev->udev, &pdev->button_dev->id);
++ pdev->button_dev->dev.parent = &pdev->udev->dev;
++ pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
++ pdev->button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
++
++ rc = input_register_device(pdev->button_dev);
++ if (rc) {
++ input_free_device(pdev->button_dev);
++ kfree(pdev->button_dev->phys);
++ pdev->button_dev = NULL;
++ return rc;
++ }
++#endif
++
+ return 0;
+
+ err_unreg:
+diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
+index 01411fb..0be6f81 100644
+--- a/drivers/media/video/pwc/pwc.h
++++ b/drivers/media/video/pwc/pwc.h
+@@ -37,6 +37,9 @@
+ #include <linux/videodev.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-ioctl.h>
++#ifdef CONFIG_USB_PWC_INPUT_EVDEV
++#include <linux/input.h>
++#endif
+
+ #include "pwc-uncompress.h"
+ #include <media/pwc-ioctl.h>
+@@ -255,6 +258,9 @@ struct pwc_device
+ int pan_angle; /* in degrees * 100 */
+ int tilt_angle; /* absolute angle; 0,0 is home position */
+ int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */
++#ifdef CONFIG_USB_PWC_INPUT_EVDEV
++ struct input_dev *button_dev; /* webcam snapshot button input */
++#endif
+
+ /*** Misc. data ***/
+ wait_queue_head_t frameq; /* When waiting for a frame to finish... */
+diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
+index 07c334f..a30747f 100644
+--- a/drivers/media/video/pxa_camera.c
++++ b/drivers/media/video/pxa_camera.c
+@@ -879,6 +879,7 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
+ SOCAM_HSYNC_ACTIVE_LOW |
+ SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_VSYNC_ACTIVE_LOW |
++ SOCAM_DATA_ACTIVE_HIGH |
+ SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_PCLK_SAMPLE_FALLING;
+
+@@ -1150,8 +1151,43 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
+ return formats;
+ }
+
++static int pxa_camera_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct pxa_camera_dev *pcdev = ici->priv;
++ struct soc_camera_sense sense = {
++ .master_clock = pcdev->mclk,
++ .pixel_clock_max = pcdev->ciclk / 4,
++ };
++ int ret;
++
++ /* If PCLK is used to latch data from the sensor, check sense */
++ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
++ icd->sense = &sense;
++
++ ret = icd->ops->set_crop(icd, rect);
++
++ icd->sense = NULL;
++
++ if (ret < 0) {
++ dev_warn(&ici->dev, "Failed to crop to %ux%u@%u:%u\n",
++ rect->width, rect->height, rect->left, rect->top);
++ } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
++ if (sense.pixel_clock > sense.pixel_clock_max) {
++ dev_err(&ici->dev,
++ "pixel clock %lu set by the camera too high!",
++ sense.pixel_clock);
++ return -EIO;
++ }
++ recalculate_fifo_timeout(pcdev, sense.pixel_clock);
++ }
++
++ return ret;
++}
++
+ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
+- __u32 pixfmt, struct v4l2_rect *rect)
++ struct v4l2_format *f)
+ {
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+@@ -1161,35 +1197,30 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
+ .master_clock = pcdev->mclk,
+ .pixel_clock_max = pcdev->ciclk / 4,
+ };
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ struct v4l2_format cam_f = *f;
+ int ret;
+
+- if (pixfmt) {
+- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+- if (!xlate) {
+- dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+- return -EINVAL;
+- }
+-
+- cam_fmt = xlate->cam_fmt;
++ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
++ if (!xlate) {
++ dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
++ return -EINVAL;
+ }
+
++ cam_fmt = xlate->cam_fmt;
++
+ /* If PCLK is used to latch data from the sensor, check sense */
+ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+ icd->sense = &sense;
+
+- switch (pixfmt) {
+- case 0: /* Only geometry change */
+- ret = icd->ops->set_fmt(icd, pixfmt, rect);
+- break;
+- default:
+- ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect);
+- }
++ cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
++ ret = icd->ops->set_fmt(icd, &cam_f);
+
+ icd->sense = NULL;
+
+ if (ret < 0) {
+ dev_warn(&ici->dev, "Failed to configure for format %x\n",
+- pixfmt);
++ pix->pixelformat);
+ } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
+ if (sense.pixel_clock > sense.pixel_clock_max) {
+ dev_err(&ici->dev,
+@@ -1200,7 +1231,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
+ recalculate_fifo_timeout(pcdev, sense.pixel_clock);
+ }
+
+- if (pixfmt && !ret) {
++ if (!ret) {
+ icd->buswidth = xlate->buswidth;
+ icd->current_fmt = xlate->host_fmt;
+ }
+@@ -1364,6 +1395,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
+ .remove = pxa_camera_remove_device,
+ .suspend = pxa_camera_suspend,
+ .resume = pxa_camera_resume,
++ .set_crop = pxa_camera_set_crop,
+ .get_formats = pxa_camera_get_formats,
+ .set_fmt = pxa_camera_set_fmt,
+ .try_fmt = pxa_camera_try_fmt,
+diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
+index 13f85ad..b5be633 100644
+--- a/drivers/media/video/s2255drv.c
++++ b/drivers/media/video/s2255drv.c
+@@ -336,14 +336,19 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
+ u16 index, u16 value, void *buf,
+ s32 buf_len, int bOut);
+
++/* dev_err macro with driver name */
++#define S2255_DRIVER_NAME "s2255"
++#define s2255_dev_err(dev, fmt, arg...) \
++ dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg)
++
+ #define dprintk(level, fmt, arg...) \
+ do { \
+ if (*s2255_debug >= (level)) { \
+- printk(KERN_DEBUG "s2255: " fmt, ##arg); \
++ printk(KERN_DEBUG S2255_DRIVER_NAME \
++ ": " fmt, ##arg); \
+ } \
+ } while (0)
+
+-
+ static struct usb_driver s2255_driver;
+
+
+@@ -528,14 +533,14 @@ static void s2255_fwchunk_complete(struct urb *urb)
+ int len;
+ dprintk(100, "udev %p urb %p", udev, urb);
+ if (urb->status) {
+- dev_err(&udev->dev, "URB failed with status %d", urb->status);
++ dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
+ atomic_set(&data->fw_state, S2255_FW_FAILED);
+ /* wake up anything waiting for the firmware */
+ wake_up(&data->wait_fw);
+ return;
+ }
+ if (data->fw_urb == NULL) {
+- dev_err(&udev->dev, "s2255 disconnected\n");
++ s2255_dev_err(&udev->dev, "disconnected\n");
+ atomic_set(&data->fw_state, S2255_FW_FAILED);
+ /* wake up anything waiting for the firmware */
+ wake_up(&data->wait_fw);
+@@ -841,8 +846,7 @@ static int vidioc_querycap(struct file *file, void *priv,
+ struct s2255_dev *dev = fh->dev;
+ strlcpy(cap->driver, "s2255", sizeof(cap->driver));
+ strlcpy(cap->card, "s2255", sizeof(cap->card));
+- strlcpy(cap->bus_info, dev_name(&dev->udev->dev),
+- sizeof(cap->bus_info));
++ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->version = S2255_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ return 0;
+@@ -1278,7 +1282,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+ }
+
+ if (!res_get(dev, fh)) {
+- dev_err(&dev->udev->dev, "s2255: stream busy\n");
++ s2255_dev_err(&dev->udev->dev, "stream busy\n");
+ return -EBUSY;
+ }
+
+@@ -1545,7 +1549,8 @@ static int s2255_open(struct file *file)
+
+ switch (atomic_read(&dev->fw_data->fw_state)) {
+ case S2255_FW_FAILED:
+- err("2255 firmware load failed. retrying.\n");
++ s2255_dev_err(&dev->udev->dev,
++ "firmware load failed. retrying.\n");
+ s2255_fwload_start(dev, 1);
+ wait_event_timeout(dev->fw_data->wait_fw,
+ ((atomic_read(&dev->fw_data->fw_state)
+@@ -2173,7 +2178,8 @@ static int s2255_board_init(struct s2255_dev *dev)
+
+ printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver);
+ if (fw_ver < CUR_USB_FWVER)
+- err("usb firmware not up to date %d\n", fw_ver);
++ dev_err(&dev->udev->dev,
++ "usb firmware not up to date %d\n", fw_ver);
+
+ for (j = 0; j < MAX_CHANNELS; j++) {
+ dev->b_acquire[j] = 0;
+@@ -2228,13 +2234,13 @@ static void read_pipe_completion(struct urb *purb)
+ dprintk(100, "read pipe completion %p, status %d\n", purb,
+ purb->status);
+ if (pipe_info == NULL) {
+- err("no context !");
++ dev_err(&purb->dev->dev, "no context!\n");
+ return;
+ }
+
+ dev = pipe_info->dev;
+ if (dev == NULL) {
+- err("no context !");
++ dev_err(&purb->dev->dev, "no context!\n");
+ return;
+ }
+ status = purb->status;
+@@ -2286,7 +2292,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
+ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pipe_info->stream_urb) {
+ dev_err(&dev->udev->dev,
+- "ReadStream: Unable to alloc URB");
++ "ReadStream: Unable to alloc URB\n");
+ return -ENOMEM;
+ }
+ /* transfer buffer allocated in board_init */
+@@ -2391,7 +2397,7 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
+ int j;
+
+ if (dev == NULL) {
+- err("s2255: invalid device");
++ s2255_dev_err(&dev->udev->dev, "invalid device\n");
+ return;
+ }
+ dprintk(4, "stop read pipe\n");
+@@ -2453,7 +2459,7 @@ static int s2255_probe(struct usb_interface *interface,
+ /* allocate memory for our device state and initialize it to zero */
+ dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
+ if (dev == NULL) {
+- err("s2255: out of memory");
++ s2255_dev_err(&interface->dev, "out of memory\n");
+ goto error;
+ }
+
+@@ -2487,7 +2493,7 @@ static int s2255_probe(struct usb_interface *interface,
+ }
+
+ if (!dev->read_endpoint) {
+- dev_err(&interface->dev, "Could not find bulk-in endpoint");
++ dev_err(&interface->dev, "Could not find bulk-in endpoint\n");
+ goto error;
+ }
+
+@@ -2583,7 +2589,7 @@ static void s2255_disconnect(struct usb_interface *interface)
+ }
+
+ static struct usb_driver s2255_driver = {
+- .name = "s2255",
++ .name = S2255_DRIVER_NAME,
+ .probe = s2255_probe,
+ .disconnect = s2255_disconnect,
+ .id_table = s2255_table,
+@@ -2597,7 +2603,8 @@ static int __init usb_s2255_init(void)
+ result = usb_register(&s2255_driver);
+
+ if (result)
+- err("usb_register failed. Error number %d", result);
++ pr_err(KBUILD_MODNAME
++ ": usb_register failed. Error number %d\n", result);
+
+ dprintk(2, "s2255_init: done\n");
+ return result;
+diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
+index e637e44..da47b2f 100644
+--- a/drivers/media/video/saa5246a.c
++++ b/drivers/media/video/saa5246a.c
+@@ -46,10 +46,11 @@
+ #include <linux/smp_lock.h>
+ #include <linux/mutex.h>
+ #include <linux/videotext.h>
+-#include <linux/videodev.h>
+-#include <media/v4l2-common.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
+ #include <media/v4l2-ioctl.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
+ MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver");
+@@ -388,13 +389,19 @@ MODULE_LICENSE("GPL");
+
+ struct saa5246a_device
+ {
++ struct v4l2_subdev sd;
++ struct video_device *vdev;
+ u8 pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
+ int is_searching[NUM_DAUS];
+- struct i2c_client *client;
+ unsigned long in_use;
+ struct mutex lock;
+ };
+
++static inline struct saa5246a_device *to_dev(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct saa5246a_device, sd);
++}
++
+ static struct video_device saa_template; /* Declared near bottom */
+
+ /*
+@@ -403,12 +410,13 @@ static struct video_device saa_template; /* Declared near bottom */
+
+ static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
+ char buf[64];
+
+ buf[0] = reg;
+ memcpy(buf+1, data, count);
+
+- if(i2c_master_send(t->client, buf, count+1)==count+1)
++ if (i2c_master_send(client, buf, count + 1) == count + 1)
+ return 0;
+ return -1;
+ }
+@@ -436,7 +444,9 @@ static int i2c_senddata(struct saa5246a_device *t, ...)
+ */
+ static int i2c_getdata(struct saa5246a_device *t, int count, u8 *buf)
+ {
+- if(i2c_master_recv(t->client, buf, count)!=count)
++ struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
++
++ if (i2c_master_recv(client, buf, count) != count)
+ return -1;
+ return 0;
+ }
+@@ -961,9 +971,6 @@ static int saa5246a_open(struct file *file)
+ {
+ struct saa5246a_device *t = video_drvdata(file);
+
+- if (t->client == NULL)
+- return -ENODEV;
+-
+ if (test_and_set_bit(0, &t->in_use))
+ return -EBUSY;
+
+@@ -1033,18 +1040,29 @@ static struct video_device saa_template =
+ .minor = -1,
+ };
+
+-/* Addresses to scan */
+-static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
++static int saa5246a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5246A, 0);
++}
++
++static const struct v4l2_subdev_core_ops saa5246a_core_ops = {
++ .g_chip_ident = saa5246a_g_chip_ident,
++};
++
++static const struct v4l2_subdev_ops saa5246a_ops = {
++ .core = &saa5246a_core_ops,
++};
+
+-I2C_CLIENT_INSMOD;
+
+ static int saa5246a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ int pgbuf;
+ int err;
+- struct video_device *vd;
+ struct saa5246a_device *t;
++ struct v4l2_subdev *sd;
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
+@@ -1053,40 +1071,43 @@ static int saa5246a_probe(struct i2c_client *client,
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
+ if (t == NULL)
+ return -ENOMEM;
++ sd = &t->sd;
++ v4l2_i2c_subdev_init(sd, client, &saa5246a_ops);
+ mutex_init(&t->lock);
+
+ /* Now create a video4linux device */
+- vd = video_device_alloc();
+- if (vd == NULL) {
++ t->vdev = video_device_alloc();
++ if (t->vdev == NULL) {
+ kfree(t);
+ return -ENOMEM;
+ }
+- i2c_set_clientdata(client, vd);
+- memcpy(vd, &saa_template, sizeof(*vd));
++ memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
+
+ for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
+ memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
+ t->is_searching[pgbuf] = false;
+ }
+- video_set_drvdata(vd, t);
++ video_set_drvdata(t->vdev, t);
+
+ /* Register it */
+- err = video_register_device(vd, VFL_TYPE_VTX, -1);
++ err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
+ if (err < 0) {
+ kfree(t);
+- video_device_release(vd);
++ video_device_release(t->vdev);
++ t->vdev = NULL;
+ return err;
+ }
+- t->client = client;
+ return 0;
+ }
+
+ static int saa5246a_remove(struct i2c_client *client)
+ {
+- struct video_device *vd = i2c_get_clientdata(client);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct saa5246a_device *t = to_dev(sd);
+
+- video_unregister_device(vd);
+- kfree(video_get_drvdata(vd));
++ video_unregister_device(t->vdev);
++ v4l2_device_unregister_subdev(sd);
++ kfree(t);
+ return 0;
+ }
+
+@@ -1098,7 +1119,6 @@ MODULE_DEVICE_TABLE(i2c, saa5246a_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa5246a",
+- .driverid = I2C_DRIVERID_SAA5249,
+ .probe = saa5246a_probe,
+ .remove = saa5246a_remove,
+ .id_table = saa5246a_id,
+diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
+index e297651..48b27fe 100644
+--- a/drivers/media/video/saa5249.c
++++ b/drivers/media/video/saa5249.c
+@@ -50,15 +50,17 @@
+ #include <linux/mutex.h>
+ #include <linux/delay.h>
+ #include <linux/videotext.h>
+-#include <linux/videodev.h>
+-#include <media/v4l2-common.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
+ #include <media/v4l2-ioctl.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
+ MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
+ MODULE_LICENSE("GPL");
+
++
+ #define VTX_VER_MAJ 1
+ #define VTX_VER_MIN 8
+
+@@ -95,17 +97,23 @@ typedef struct {
+
+ struct saa5249_device
+ {
++ struct v4l2_subdev sd;
++ struct video_device *vdev;
+ vdau_t vdau[NUM_DAUS]; /* Data for virtual DAUs (the 5249 only has one */
+ /* real DAU, so we have to simulate some more) */
+ int vtx_use_count;
+ int is_searching[NUM_DAUS];
+ int disp_mode;
+ int virtual_mode;
+- struct i2c_client *client;
+ unsigned long in_use;
+ struct mutex lock;
+ };
+
++static inline struct saa5249_device *to_dev(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct saa5249_device, sd);
++}
++
+
+ #define CCTWR 34 /* IC write/read-address of vtx-chip */
+ #define CCTRD 35
+@@ -147,12 +155,13 @@ static void jdelay(unsigned long delay)
+
+ static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
+ char buf[64];
+
+ buf[0] = reg;
+ memcpy(buf+1, data, count);
+
+- if (i2c_master_send(t->client, buf, count + 1) == count + 1)
++ if (i2c_master_send(client, buf, count + 1) == count + 1)
+ return 0;
+ return -1;
+ }
+@@ -180,7 +189,9 @@ static int i2c_senddata(struct saa5249_device *t, ...)
+
+ static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
+ {
+- if(i2c_master_recv(t->client, buf, count)!=count)
++ struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
++
++ if (i2c_master_recv(client, buf, count) != count)
+ return -1;
+ return 0;
+ }
+@@ -497,9 +508,6 @@ static int saa5249_open(struct file *file)
+ struct saa5249_device *t = video_drvdata(file);
+ int pgbuf;
+
+- if (t->client == NULL)
+- return -ENODEV;
+-
+ if (test_and_set_bit(0, &t->in_use))
+ return -EBUSY;
+
+@@ -553,18 +561,28 @@ static struct video_device saa_template =
+ .release = video_device_release,
+ };
+
+-/* Addresses to scan */
+-static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
++static int saa5249_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5249, 0);
++}
+
+-I2C_CLIENT_INSMOD;
++static const struct v4l2_subdev_core_ops saa5249_core_ops = {
++ .g_chip_ident = saa5249_g_chip_ident,
++};
++
++static const struct v4l2_subdev_ops saa5249_ops = {
++ .core = &saa5249_core_ops,
++};
+
+ static int saa5249_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ int pgbuf;
+ int err;
+- struct video_device *vd;
+ struct saa5249_device *t;
++ struct v4l2_subdev *sd;
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
+@@ -573,16 +591,17 @@ static int saa5249_probe(struct i2c_client *client,
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
+ if (t == NULL)
+ return -ENOMEM;
++ sd = &t->sd;
++ v4l2_i2c_subdev_init(sd, client, &saa5249_ops);
+ mutex_init(&t->lock);
+
+ /* Now create a video4linux device */
+- vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);
+- if (vd == NULL) {
++ t->vdev = video_device_alloc();
++ if (t->vdev == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+- i2c_set_clientdata(client, vd);
+- memcpy(vd, &saa_template, sizeof(*vd));
++ memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
+
+ for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
+ memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
+@@ -593,26 +612,27 @@ static int saa5249_probe(struct i2c_client *client,
+ t->vdau[pgbuf].stopped = true;
+ t->is_searching[pgbuf] = false;
+ }
+- video_set_drvdata(vd, t);
++ video_set_drvdata(t->vdev, t);
+
+ /* Register it */
+- err = video_register_device(vd, VFL_TYPE_VTX, -1);
++ err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
+ if (err < 0) {
+ kfree(t);
+- kfree(vd);
++ video_device_release(t->vdev);
++ t->vdev = NULL;
+ return err;
+ }
+- t->client = client;
+ return 0;
+ }
+
+ static int saa5249_remove(struct i2c_client *client)
+ {
+- struct video_device *vd = i2c_get_clientdata(client);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct saa5249_device *t = to_dev(sd);
+
+- video_unregister_device(vd);
+- kfree(video_get_drvdata(vd));
+- kfree(vd);
++ video_unregister_device(t->vdev);
++ v4l2_device_unregister_subdev(sd);
++ kfree(t);
+ return 0;
+ }
+
+@@ -624,7 +644,6 @@ MODULE_DEVICE_TABLE(i2c, saa5249_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa5249",
+- .driverid = I2C_DRIVERID_SAA5249,
+ .probe = saa5249_probe,
+ .remove = saa5249_remove,
+ .id_table = saa5249_id,
+diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
+index f050242..c25e81a 100644
+--- a/drivers/media/video/saa6588.c
++++ b/drivers/media/video/saa6588.c
+@@ -23,7 +23,7 @@
+ #include <linux/kernel.h>
+ #include <linux/i2c.h>
+ #include <linux/types.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <linux/init.h>
+ #include <linux/errno.h>
+ #include <linux/slab.h>
+@@ -32,15 +32,10 @@
+ #include <asm/uaccess.h>
+
+ #include <media/rds.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+-/* Addresses to scan */
+-static unsigned short normal_i2c[] = {
+- 0x20 >> 1,
+- 0x22 >> 1,
+- I2C_CLIENT_END,
+-};
+-
+-I2C_CLIENT_INSMOD;
+
+ /* insmod options */
+ static unsigned int debug;
+@@ -72,9 +67,8 @@ MODULE_LICENSE("GPL");
+ #define dprintk if (debug) printk
+
+ struct saa6588 {
+- struct i2c_client client;
+- struct work_struct work;
+- struct timer_list timer;
++ struct v4l2_subdev sd;
++ struct delayed_work work;
+ spinlock_t lock;
+ unsigned char *buffer;
+ unsigned int buf_size;
+@@ -86,8 +80,10 @@ struct saa6588 {
+ int data_available_for_read;
+ };
+
+-static struct i2c_driver driver;
+-static struct i2c_client client_template;
++static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct saa6588, sd);
++}
+
+ /* ---------------------------------------------------------------------- */
+
+@@ -258,6 +254,7 @@ static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
+
+ static void saa6588_i2c_poll(struct saa6588 *s)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
+ unsigned long flags;
+ unsigned char tmpbuf[6];
+ unsigned char blocknum;
+@@ -265,7 +262,7 @@ static void saa6588_i2c_poll(struct saa6588 *s)
+
+ /* Although we only need 3 bytes, we have to read at least 6.
+ SAA6588 returns garbage otherwise */
+- if (6 != i2c_master_recv(&s->client, &tmpbuf[0], 6)) {
++ if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
+ if (debug > 1)
+ dprintk(PREFIX "read error!\n");
+ return;
+@@ -316,23 +313,17 @@ static void saa6588_i2c_poll(struct saa6588 *s)
+ wake_up_interruptible(&s->read_queue);
+ }
+
+-static void saa6588_timer(unsigned long data)
+-{
+- struct saa6588 *s = (struct saa6588 *)data;
+-
+- schedule_work(&s->work);
+-}
+-
+ static void saa6588_work(struct work_struct *work)
+ {
+- struct saa6588 *s = container_of(work, struct saa6588, work);
++ struct saa6588 *s = container_of(work, struct saa6588, work.work);
+
+ saa6588_i2c_poll(s);
+- mod_timer(&s->timer, jiffies + msecs_to_jiffies(20));
++ schedule_delayed_work(&s->work, msecs_to_jiffies(20));
+ }
+
+ static int saa6588_configure(struct saa6588 *s)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
+ unsigned char buf[3];
+ int rc;
+
+@@ -380,7 +371,8 @@ static int saa6588_configure(struct saa6588 *s)
+ dprintk(PREFIX "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n",
+ buf[0], buf[1], buf[2]);
+
+- if (3 != (rc = i2c_master_send(&s->client, buf, 3)))
++ rc = i2c_master_send(client, buf, 3);
++ if (rc != 3)
+ printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
+
+ return 0;
+@@ -388,70 +380,10 @@ static int saa6588_configure(struct saa6588 *s)
+
+ /* ---------------------------------------------------------------------- */
+
+-static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
+-{
+- struct saa6588 *s;
+- client_template.adapter = adap;
+- client_template.addr = addr;
+-
+- printk(PREFIX "chip found @ 0x%x\n", addr << 1);
+-
+- if (NULL == (s = kmalloc(sizeof(*s), GFP_KERNEL)))
+- return -ENOMEM;
+-
+- s->buf_size = bufblocks * 3;
+-
+- if (NULL == (s->buffer = kmalloc(s->buf_size, GFP_KERNEL))) {
+- kfree(s);
+- return -ENOMEM;
+- }
+- spin_lock_init(&s->lock);
+- s->client = client_template;
+- s->block_count = 0;
+- s->wr_index = 0;
+- s->rd_index = 0;
+- s->last_blocknum = 0xff;
+- init_waitqueue_head(&s->read_queue);
+- s->data_available_for_read = 0;
+- i2c_set_clientdata(&s->client, s);
+- i2c_attach_client(&s->client);
+-
+- saa6588_configure(s);
+-
+- /* start polling via eventd */
+- INIT_WORK(&s->work, saa6588_work);
+- init_timer(&s->timer);
+- s->timer.function = saa6588_timer;
+- s->timer.data = (unsigned long)s;
+- schedule_work(&s->work);
+- return 0;
+-}
+-
+-static int saa6588_probe(struct i2c_adapter *adap)
+-{
+- if (adap->class & I2C_CLASS_TV_ANALOG)
+- return i2c_probe(adap, &addr_data, saa6588_attach);
+- return 0;
+-}
+-
+-static int saa6588_detach(struct i2c_client *client)
+-{
+- struct saa6588 *s = i2c_get_clientdata(client);
+-
+- del_timer_sync(&s->timer);
+- flush_scheduled_work();
+-
+- i2c_detach_client(client);
+- kfree(s->buffer);
+- kfree(s);
+- return 0;
+-}
+-
+-static int saa6588_command(struct i2c_client *client, unsigned int cmd,
+- void *arg)
++static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+ {
+- struct saa6588 *s = i2c_get_clientdata(client);
+- struct rds_command *a = (struct rds_command *)arg;
++ struct saa6588 *s = to_saa6588(sd);
++ struct rds_command *a = arg;
+
+ switch (cmd) {
+ /* --- open() for /dev/radio --- */
+@@ -479,45 +411,94 @@ static int saa6588_command(struct i2c_client *client, unsigned int cmd,
+
+ default:
+ /* nothing */
+- break;
++ return -ENOIOCTLCMD;
+ }
+ return 0;
+ }
+
++static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA6588, 0);
++}
++
+ /* ----------------------------------------------------------------------- */
+
+-static struct i2c_driver driver = {
+- .driver = {
+- .name = "saa6588",
+- },
+- .id = -1, /* FIXME */
+- .attach_adapter = saa6588_probe,
+- .detach_client = saa6588_detach,
+- .command = saa6588_command,
++static const struct v4l2_subdev_core_ops saa6588_core_ops = {
++ .g_chip_ident = saa6588_g_chip_ident,
++ .ioctl = saa6588_ioctl,
+ };
+
+-static struct i2c_client client_template = {
+- .name = "saa6588",
+- .driver = &driver,
++static const struct v4l2_subdev_ops saa6588_ops = {
++ .core = &saa6588_core_ops,
+ };
+
+-static int __init saa6588_init_module(void)
++/* ---------------------------------------------------------------------- */
++
++static int saa6588_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
+ {
+- return i2c_add_driver(&driver);
++ struct saa6588 *s;
++ struct v4l2_subdev *sd;
++
++ v4l_info(client, "saa6588 found @ 0x%x (%s)\n",
++ client->addr << 1, client->adapter->name);
++
++ s = kzalloc(sizeof(*s), GFP_KERNEL);
++ if (s == NULL)
++ return -ENOMEM;
++
++ s->buf_size = bufblocks * 3;
++
++ s->buffer = kmalloc(s->buf_size, GFP_KERNEL);
++ if (s->buffer == NULL) {
++ kfree(s);
++ return -ENOMEM;
++ }
++ sd = &s->sd;
++ v4l2_i2c_subdev_init(sd, client, &saa6588_ops);
++ spin_lock_init(&s->lock);
++ s->block_count = 0;
++ s->wr_index = 0;
++ s->rd_index = 0;
++ s->last_blocknum = 0xff;
++ init_waitqueue_head(&s->read_queue);
++ s->data_available_for_read = 0;
++
++ saa6588_configure(s);
++
++ /* start polling via eventd */
++ INIT_DELAYED_WORK(&s->work, saa6588_work);
++ schedule_delayed_work(&s->work, 0);
++ return 0;
+ }
+
+-static void __exit saa6588_cleanup_module(void)
++static int saa6588_remove(struct i2c_client *client)
+ {
+- i2c_del_driver(&driver);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct saa6588 *s = to_saa6588(sd);
++
++ v4l2_device_unregister_subdev(sd);
++
++ cancel_delayed_work_sync(&s->work);
++
++ kfree(s->buffer);
++ kfree(s);
++ return 0;
+ }
+
+-module_init(saa6588_init_module);
+-module_exit(saa6588_cleanup_module);
++/* ----------------------------------------------------------------------- */
+
+-/*
+- * Overrides for Emacs so that we follow Linus's tabbing style.
+- * ---------------------------------------------------------------------------
+- * Local variables:
+- * c-basic-offset: 8
+- * End:
+- */
++static const struct i2c_device_id saa6588_id[] = {
++ { "saa6588", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, saa6588_id);
++
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++ .name = "saa6588",
++ .probe = saa6588_probe,
++ .remove = saa6588_remove,
++ .id_table = saa6588_id,
++};
+diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
+index 3786069..df4e08d 100644
+--- a/drivers/media/video/saa7110.c
++++ b/drivers/media/video/saa7110.c
+@@ -33,15 +33,16 @@
+ #include <linux/wait.h>
+ #include <asm/uaccess.h>
+ #include <linux/i2c.h>
+-#include <linux/videodev.h>
+-#include <linux/video_decoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
+ MODULE_AUTHOR("Pauline Middelink");
+ MODULE_LICENSE("GPL");
+
++
+ static int debug;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+@@ -52,9 +53,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ #define SAA7110_NR_REG 0x35
+
+ struct saa7110 {
++ struct v4l2_subdev sd;
+ u8 reg[SAA7110_NR_REG];
+
+- int norm;
++ v4l2_std_id norm;
+ int input;
+ int enable;
+ int bright;
+@@ -65,20 +67,28 @@ struct saa7110 {
+ wait_queue_head_t wq;
+ };
+
++static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct saa7110, sd);
++}
++
+ /* ----------------------------------------------------------------------- */
+ /* I2C support functions */
+ /* ----------------------------------------------------------------------- */
+
+-static int saa7110_write(struct i2c_client *client, u8 reg, u8 value)
++static int saa7110_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+ {
+- struct saa7110 *decoder = i2c_get_clientdata(client);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct saa7110 *decoder = to_saa7110(sd);
+
+ 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)
++static int saa7110_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct saa7110 *decoder = to_saa7110(sd);
+ int ret = -1;
+ u8 reg = *data; /* first register to write to */
+
+@@ -89,15 +99,13 @@ static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsign
+ /* 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);
+-
+ ret = i2c_master_send(client, data, len);
+
+ /* Cache the written data */
+ memcpy(decoder->reg + reg, data + 1, len - 1);
+ } else {
+ for (++data, --len; len; len--) {
+- ret = saa7110_write(client, reg++, *data++);
++ ret = saa7110_write(sd, reg++, *data++);
+ if (ret < 0)
+ break;
+ }
+@@ -106,8 +114,10 @@ static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsign
+ return ret;
+ }
+
+-static inline int saa7110_read(struct i2c_client *client)
++static inline int saa7110_read(struct v4l2_subdev *sd)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
+ return i2c_smbus_read_byte(client);
+ }
+
+@@ -115,11 +125,11 @@ static inline int saa7110_read(struct i2c_client *client)
+ /* SAA7110 functions */
+ /* ----------------------------------------------------------------------- */
+
+-#define FRESP_06H_COMPST 0x03 //0x13
+-#define FRESP_06H_SVIDEO 0x83 //0xC0
++#define FRESP_06H_COMPST 0x03 /*0x13*/
++#define FRESP_06H_SVIDEO 0x83 /*0xC0*/
+
+
+-static int saa7110_selmux(struct i2c_client *client, int chan)
++static int saa7110_selmux(struct v4l2_subdev *sd, int chan)
+ {
+ static const unsigned char modes[9][8] = {
+ /* mode 0 */
+@@ -150,17 +160,17 @@ static int saa7110_selmux(struct i2c_client *client, int chan)
+ {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
+ 0x44, 0x75, 0x21}
+ };
+- struct saa7110 *decoder = i2c_get_clientdata(client);
++ struct saa7110 *decoder = to_saa7110(sd);
+ 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 */
++ saa7110_write(sd, 0x06, ptr[0]); /* Luminance control */
++ saa7110_write(sd, 0x20, ptr[1]); /* Analog Control #1 */
++ saa7110_write(sd, 0x21, ptr[2]); /* Analog Control #2 */
++ saa7110_write(sd, 0x22, ptr[3]); /* Mixer Control #1 */
++ saa7110_write(sd, 0x2C, ptr[4]); /* Mixer Control #2 */
++ saa7110_write(sd, 0x30, ptr[5]); /* ADCs gain control */
++ saa7110_write(sd, 0x31, ptr[6]); /* Mixer Control #3 */
++ saa7110_write(sd, 0x21, ptr[7]); /* Analog Control #2 */
+ decoder->input = chan;
+
+ return 0;
+@@ -176,246 +186,260 @@ static const unsigned char initseq[1 + SAA7110_NR_REG] = {
+ /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
+ };
+
+-static int determine_norm(struct i2c_client *client)
++static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
+ {
+ DEFINE_WAIT(wait);
+- struct saa7110 *decoder = i2c_get_clientdata(client);
++ struct saa7110 *decoder = to_saa7110(sd);
+ int status;
+
+ /* mode changed, start automatic detection */
+- saa7110_write_block(client, initseq, sizeof(initseq));
+- saa7110_selmux(client, decoder->input);
++ saa7110_write_block(sd, initseq, sizeof(initseq));
++ saa7110_selmux(sd, decoder->input);
+ prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(250));
+ finish_wait(&decoder->wq, &wait);
+- status = saa7110_read(client);
++ status = saa7110_read(sd);
+ if (status & 0x40) {
+- v4l_dbg(1, debug, client, "status=0x%02x (no signal)\n", status);
+- return decoder->norm; // no change
++ v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status);
++ return decoder->norm; /* no change*/
+ }
+ if ((status & 3) == 0) {
+- saa7110_write(client, 0x06, 0x83);
++ saa7110_write(sd, 0x06, 0x83);
+ if (status & 0x20) {
+- v4l_dbg(1, debug, client, "status=0x%02x (NTSC/no color)\n", status);
+- //saa7110_write(client,0x2E,0x81);
+- return VIDEO_MODE_NTSC;
++ v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC/no color)\n", status);
++ /*saa7110_write(sd,0x2E,0x81);*/
++ return V4L2_STD_NTSC;
+ }
+- v4l_dbg(1, debug, client, "status=0x%02x (PAL/no color)\n", status);
+- //saa7110_write(client,0x2E,0x9A);
+- return VIDEO_MODE_PAL;
++ v4l2_dbg(1, debug, sd, "status=0x%02x (PAL/no color)\n", status);
++ /*saa7110_write(sd,0x2E,0x9A);*/
++ return V4L2_STD_PAL;
+ }
+- //saa7110_write(client,0x06,0x03);
++ /*saa7110_write(sd,0x06,0x03);*/
+ if (status & 0x20) { /* 60Hz */
+- v4l_dbg(1, debug, client, "status=0x%02x (NTSC)\n", 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;
++ v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC)\n", status);
++ saa7110_write(sd, 0x0D, 0x86);
++ saa7110_write(sd, 0x0F, 0x50);
++ saa7110_write(sd, 0x11, 0x2C);
++ /*saa7110_write(sd,0x2E,0x81);*/
++ return V4L2_STD_NTSC;
+ }
+
+ /* 50Hz -> PAL/SECAM */
+- saa7110_write(client, 0x0D, 0x86);
+- saa7110_write(client, 0x0F, 0x10);
+- saa7110_write(client, 0x11, 0x59);
+- //saa7110_write(client,0x2E,0x9A);
++ saa7110_write(sd, 0x0D, 0x86);
++ saa7110_write(sd, 0x0F, 0x10);
++ saa7110_write(sd, 0x11, 0x59);
++ /*saa7110_write(sd,0x2E,0x9A);*/
+
+ prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(250));
+ finish_wait(&decoder->wq, &wait);
+
+- status = saa7110_read(client);
++ status = saa7110_read(sd);
+ if ((status & 0x03) == 0x01) {
+- v4l_dbg(1, debug, client, "status=0x%02x (SECAM)\n", status);
+- saa7110_write(client, 0x0D, 0x87);
+- return VIDEO_MODE_SECAM;
++ v4l2_dbg(1, debug, sd, "status=0x%02x (SECAM)\n", status);
++ saa7110_write(sd, 0x0D, 0x87);
++ return V4L2_STD_SECAM;
+ }
+- v4l_dbg(1, debug, client, "status=0x%02x (PAL)\n", status);
+- return VIDEO_MODE_PAL;
++ v4l2_dbg(1, debug, sd, "status=0x%02x (PAL)\n", status);
++ return V4L2_STD_PAL;
+ }
+
+-static int
+-saa7110_command (struct i2c_client *client,
+- unsigned int cmd,
+- void *arg)
++static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
+ {
+- struct saa7110 *decoder = i2c_get_clientdata(client);
+- int v;
++ struct saa7110 *decoder = to_saa7110(sd);
++ int res = V4L2_IN_ST_NO_SIGNAL;
++ int status = saa7110_read(sd);
++
++ v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n",
++ status, (unsigned long long)decoder->norm);
++ if (!(status & 0x40))
++ res = 0;
++ if (!(status & 0x03))
++ res |= V4L2_IN_ST_NO_COLOR;
++
++ *pstatus = res;
++ return 0;
++}
+
+- switch (cmd) {
+- case 0:
+- //saa7110_write_block(client, initseq, sizeof(initseq));
+- break;
++static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
++{
++ *(v4l2_std_id *)std = determine_norm(sd);
++ return 0;
++}
+
+- case DECODER_GET_CAPABILITIES:
+- {
+- struct video_decoder_capability *dc = arg;
++static int saa7110_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
++{
++ struct saa7110 *decoder = to_saa7110(sd);
++
++ if (decoder->norm != std) {
++ decoder->norm = std;
++ /*saa7110_write(sd, 0x06, 0x03);*/
++ if (std & V4L2_STD_NTSC) {
++ saa7110_write(sd, 0x0D, 0x86);
++ saa7110_write(sd, 0x0F, 0x50);
++ saa7110_write(sd, 0x11, 0x2C);
++ /*saa7110_write(sd, 0x2E, 0x81);*/
++ v4l2_dbg(1, debug, sd, "switched to NTSC\n");
++ } else if (std & V4L2_STD_PAL) {
++ saa7110_write(sd, 0x0D, 0x86);
++ saa7110_write(sd, 0x0F, 0x10);
++ saa7110_write(sd, 0x11, 0x59);
++ /*saa7110_write(sd, 0x2E, 0x9A);*/
++ v4l2_dbg(1, debug, sd, "switched to PAL\n");
++ } else if (std & V4L2_STD_SECAM) {
++ saa7110_write(sd, 0x0D, 0x87);
++ saa7110_write(sd, 0x0F, 0x10);
++ saa7110_write(sd, 0x11, 0x59);
++ /*saa7110_write(sd, 0x2E, 0x9A);*/
++ v4l2_dbg(1, debug, sd, "switched to SECAM\n");
++ } else {
++ return -EINVAL;
++ }
++ }
++ return 0;
++}
+
+- dc->flags =
+- VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
+- VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
+- dc->inputs = SAA7110_MAX_INPUT;
+- dc->outputs = SAA7110_MAX_OUTPUT;
+- break;
++static int saa7110_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
++{
++ struct saa7110 *decoder = to_saa7110(sd);
++
++ if (route->input < 0 || route->input >= SAA7110_MAX_INPUT) {
++ v4l2_dbg(1, debug, sd, "input=%d not available\n", route->input);
++ return -EINVAL;
++ }
++ if (decoder->input != route->input) {
++ saa7110_selmux(sd, route->input);
++ v4l2_dbg(1, debug, sd, "switched to input=%d\n", route->input);
+ }
++ return 0;
++}
+
+- case DECODER_GET_STATUS:
+- {
+- int status;
+- int res = 0;
+-
+- status = saa7110_read(client);
+- v4l_dbg(1, debug, client, "status=0x%02x norm=%d\n",
+- 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;
++static int saa7110_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct saa7110 *decoder = to_saa7110(sd);
++
++ if (decoder->enable != enable) {
++ decoder->enable = enable;
++ saa7110_write(sd, 0x0E, enable ? 0x18 : 0x80);
++ v4l2_dbg(1, debug, sd, "YUV %s\n", enable ? "on" : "off");
+ }
++ return 0;
++}
+
+- case DECODER_SET_NORM:
+- v = *(int *) arg;
+- if (decoder->norm != v) {
+- decoder->norm = v;
+- //saa7110_write(client, 0x06, 0x03);
+- switch (v) {
+- case VIDEO_MODE_NTSC:
+- saa7110_write(client, 0x0D, 0x86);
+- saa7110_write(client, 0x0F, 0x50);
+- saa7110_write(client, 0x11, 0x2C);
+- //saa7110_write(client, 0x2E, 0x81);
+- v4l_dbg(1, debug, client, "switched to NTSC\n");
+- break;
+- case VIDEO_MODE_PAL:
+- saa7110_write(client, 0x0D, 0x86);
+- saa7110_write(client, 0x0F, 0x10);
+- saa7110_write(client, 0x11, 0x59);
+- //saa7110_write(client, 0x2E, 0x9A);
+- v4l_dbg(1, debug, client, "switched to PAL\n");
+- break;
+- case VIDEO_MODE_SECAM:
+- saa7110_write(client, 0x0D, 0x87);
+- saa7110_write(client, 0x0F, 0x10);
+- saa7110_write(client, 0x11, 0x59);
+- //saa7110_write(client, 0x2E, 0x9A);
+- v4l_dbg(1, debug, client, "switched to SECAM\n");
+- break;
+- case VIDEO_MODE_AUTO:
+- v4l_dbg(1, debug, client, "switched to AUTO\n");
+- decoder->norm = determine_norm(client);
+- *(int *) arg = decoder->norm;
+- break;
+- default:
+- return -EPERM;
+- }
+- }
+- break;
++static int saa7110_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
++{
++ switch (qc->id) {
++ case V4L2_CID_BRIGHTNESS:
++ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
++ case V4L2_CID_HUE:
++ return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
+
+- case DECODER_SET_INPUT:
+- v = *(int *) arg;
+- if (v < 0 || v >= SAA7110_MAX_INPUT) {
+- v4l_dbg(1, debug, client, "input=%d not available\n", v);
+- return -EINVAL;
+- }
+- if (decoder->input != v) {
+- saa7110_selmux(client, v);
+- v4l_dbg(1, debug, client, "switched to input=%d\n", v);
+- }
+- break;
++static int saa7110_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct saa7110 *decoder = to_saa7110(sd);
+
+- case DECODER_SET_OUTPUT:
+- v = *(int *) arg;
+- /* not much choice of outputs */
+- if (v != 0)
+- return -EINVAL;
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ ctrl->value = decoder->bright;
+ break;
+-
+- case DECODER_ENABLE_OUTPUT:
+- v = *(int *) arg;
+- if (decoder->enable != v) {
+- decoder->enable = v;
+- saa7110_write(client, 0x0E, v ? 0x18 : 0x80);
+- v4l_dbg(1, debug, client, "YUV %s\n", v ? "on" : "off");
+- }
++ case V4L2_CID_CONTRAST:
++ ctrl->value = decoder->contrast;
++ break;
++ case V4L2_CID_SATURATION:
++ ctrl->value = decoder->sat;
++ break;
++ case V4L2_CID_HUE:
++ ctrl->value = decoder->hue;
+ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
+
+- case DECODER_SET_PICTURE:
+- {
+- struct video_picture *pic = arg;
++static int saa7110_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct saa7110 *decoder = to_saa7110(sd);
+
+- 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);
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ if (decoder->bright != ctrl->value) {
++ decoder->bright = ctrl->value;
++ saa7110_write(sd, 0x19, decoder->bright);
+ }
+- 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);
++ break;
++ case V4L2_CID_CONTRAST:
++ if (decoder->contrast != ctrl->value) {
++ decoder->contrast = ctrl->value;
++ saa7110_write(sd, 0x13, decoder->contrast);
+ }
+- 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 V4L2_CID_SATURATION:
++ if (decoder->sat != ctrl->value) {
++ decoder->sat = ctrl->value;
++ saa7110_write(sd, 0x12, decoder->sat);
+ }
+ break;
+- }
+-
+- case DECODER_DUMP:
+- if (!debug)
+- break;
+- for (v = 0; v < SAA7110_NR_REG; v += 16) {
+- int j;
+- v4l_dbg(1, debug, client, "%02x:", v);
+- for (j = 0; j < 16 && v + j < SAA7110_NR_REG; j++)
+- printk(KERN_CONT " %02x", decoder->reg[v + j]);
+- printk(KERN_CONT "\n");
++ case V4L2_CID_HUE:
++ if (decoder->hue != ctrl->value) {
++ decoder->hue = ctrl->value;
++ saa7110_write(sd, 0x07, decoder->hue);
+ }
+ break;
+-
+ default:
+- v4l_dbg(1, debug, client, "unknown command %08x\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+ }
+
++static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7110, 0);
++}
++
+ /* ----------------------------------------------------------------------- */
+
+-/*
+- * Generic i2c probe
+- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+- */
++static const struct v4l2_subdev_core_ops saa7110_core_ops = {
++ .g_chip_ident = saa7110_g_chip_ident,
++ .g_ctrl = saa7110_g_ctrl,
++ .s_ctrl = saa7110_s_ctrl,
++ .queryctrl = saa7110_queryctrl,
++};
+
+-static unsigned short normal_i2c[] = { 0x9c >> 1, 0x9e >> 1, I2C_CLIENT_END };
++static const struct v4l2_subdev_tuner_ops saa7110_tuner_ops = {
++ .s_std = saa7110_s_std,
++};
+
+-I2C_CLIENT_INSMOD;
++static const struct v4l2_subdev_video_ops saa7110_video_ops = {
++ .s_routing = saa7110_s_routing,
++ .s_stream = saa7110_s_stream,
++ .querystd = saa7110_querystd,
++ .g_input_status = saa7110_g_input_status,
++};
++
++static const struct v4l2_subdev_ops saa7110_ops = {
++ .core = &saa7110_core_ops,
++ .tuner = &saa7110_tuner_ops,
++ .video = &saa7110_video_ops,
++};
++
++/* ----------------------------------------------------------------------- */
+
+ static int saa7110_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ struct saa7110 *decoder;
++ struct v4l2_subdev *sd;
+ int rv;
+
+ /* Check if the adapter supports the needed features */
+@@ -429,7 +453,9 @@ static int saa7110_probe(struct i2c_client *client,
+ decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
+ if (!decoder)
+ return -ENOMEM;
+- decoder->norm = VIDEO_MODE_PAL;
++ sd = &decoder->sd;
++ v4l2_i2c_subdev_init(sd, client, &saa7110_ops);
++ decoder->norm = V4L2_STD_PAL;
+ decoder->input = 0;
+ decoder->enable = 1;
+ decoder->bright = 32768;
+@@ -437,30 +463,29 @@ static int saa7110_probe(struct i2c_client *client,
+ decoder->hue = 32768;
+ decoder->sat = 32768;
+ init_waitqueue_head(&decoder->wq);
+- i2c_set_clientdata(client, decoder);
+
+- rv = saa7110_write_block(client, initseq, sizeof(initseq));
++ rv = saa7110_write_block(sd, initseq, sizeof(initseq));
+ if (rv < 0) {
+- v4l_dbg(1, debug, client, "init status %d\n", rv);
++ v4l2_dbg(1, debug, sd, "init status %d\n", 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);
+- v4l_dbg(1, debug, client, "version %x, status=0x%02x\n",
++ saa7110_write(sd, 0x21, 0x10);
++ saa7110_write(sd, 0x0e, 0x18);
++ saa7110_write(sd, 0x0D, 0x04);
++ ver = saa7110_read(sd);
++ saa7110_write(sd, 0x0D, 0x06);
++ /*mdelay(150);*/
++ status = saa7110_read(sd);
++ v4l2_dbg(1, debug, sd, "version %x, status=0x%02x\n",
+ ver, status);
+- saa7110_write(client, 0x0D, 0x86);
+- saa7110_write(client, 0x0F, 0x10);
+- saa7110_write(client, 0x11, 0x59);
+- //saa7110_write(client, 0x2E, 0x9A);
++ saa7110_write(sd, 0x0D, 0x86);
++ saa7110_write(sd, 0x0F, 0x10);
++ saa7110_write(sd, 0x11, 0x59);
++ /*saa7110_write(sd, 0x2E, 0x9A);*/
+ }
+
+- //saa7110_selmux(client,0);
+- //determine_norm(client);
++ /*saa7110_selmux(sd,0);*/
++ /*determine_norm(sd);*/
+ /* setup and implicit mode 0 select has been performed */
+
+ return 0;
+@@ -468,7 +493,10 @@ static int saa7110_probe(struct i2c_client *client,
+
+ static int saa7110_remove(struct i2c_client *client)
+ {
+- kfree(i2c_get_clientdata(client));
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_saa7110(sd));
+ return 0;
+ }
+
+@@ -482,8 +510,6 @@ MODULE_DEVICE_TABLE(i2c, saa7110_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa7110",
+- .driverid = I2C_DRIVERID_SAA7110,
+- .command = saa7110_command,
+ .probe = saa7110_probe,
+ .remove = saa7110_remove,
+ .id_table = saa7110_id,
+diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
+deleted file mode 100644
+index a4738a2..0000000
+--- a/drivers/media/video/saa7111.c
++++ /dev/null
+@@ -1,492 +0,0 @@
+-/*
+- * 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)
+- *
+- * Changes by Michael Hunold <michael@mihu.de>
+- * - implemented DECODER_SET_GPIO, DECODER_INIT, DECODER_SET_VBI_BYPASS
+- *
+- * 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/module.h>
+-#include <linux/types.h>
+-#include <linux/ioctl.h>
+-#include <asm/uaccess.h>
+-#include <linux/i2c.h>
+-#include <linux/i2c-id.h>
+-#include <linux/videodev.h>
+-#include <linux/video_decoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
+-
+-MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
+-MODULE_AUTHOR("Dave Perks");
+-MODULE_LICENSE("GPL");
+-
+-static int debug;
+-module_param(debug, int, 0644);
+-MODULE_PARM_DESC(debug, "Debug level (0-1)");
+-
+-/* ----------------------------------------------------------------------- */
+-
+-#define SAA7111_NR_REG 0x18
+-
+-struct saa7111 {
+- unsigned char reg[SAA7111_NR_REG];
+-
+- int norm;
+- int input;
+- int enable;
+-};
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static inline int saa7111_write(struct i2c_client *client, u8 reg, u8 value)
+-{
+- struct saa7111 *decoder = i2c_get_clientdata(client);
+-
+- decoder->reg[reg] = value;
+- return i2c_smbus_write_byte_data(client, reg, value);
+-}
+-
+-static inline void saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
+-{
+- struct saa7111 *decoder = i2c_get_clientdata(client);
+-
+- if (decoder->reg[reg] != value) {
+- decoder->reg[reg] = value;
+- i2c_smbus_write_byte_data(client, reg, value);
+- }
+-}
+-
+-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);
+- u8 block_data[32];
+- int block_len;
+-
+- while (len >= 2) {
+- block_len = 0;
+- block_data[block_len++] = reg = data[0];
+- do {
+- block_data[block_len++] =
+- decoder->reg[reg++] = data[1];
+- len -= 2;
+- data += 2;
+- } while (len >= 2 && data[0] == reg && block_len < 32);
+- ret = i2c_master_send(client, block_data, block_len);
+- if (ret < 0)
+- break;
+- }
+- } else {
+- /* do some slow I2C emulation kind of thing */
+- while (len >= 2) {
+- reg = *data++;
+- ret = saa7111_write(client, reg, *data++);
+- if (ret < 0)
+- break;
+- len -= 2;
+- }
+- }
+-
+- return ret;
+-}
+-
+-static int saa7111_init_decoder(struct i2c_client *client,
+- struct video_decoder_init *init)
+-{
+- return saa7111_write_block(client, init->data, init->len);
+-}
+-
+-static inline int saa7111_read(struct i2c_client *client, u8 reg)
+-{
+- return i2c_smbus_read_byte_data(client, reg);
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static const unsigned char saa7111_i2c_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 cmd, void *arg)
+-{
+- struct saa7111 *decoder = i2c_get_clientdata(client);
+-
+- switch (cmd) {
+- case 0:
+- break;
+- case DECODER_INIT:
+- {
+- struct video_decoder_init *init = arg;
+- struct video_decoder_init vdi;
+-
+- if (NULL != init)
+- return saa7111_init_decoder(client, init);
+- vdi.data = saa7111_i2c_init;
+- vdi.len = sizeof(saa7111_i2c_init);
+- return saa7111_init_decoder(client, &vdi);
+- }
+-
+- case DECODER_DUMP:
+- {
+- int i;
+-
+- for (i = 0; i < SAA7111_NR_REG; i += 16) {
+- int j;
+-
+- v4l_info(client, "%03x", i);
+- for (j = 0; j < 16 && i + j < SAA7111_NR_REG; ++j) {
+- printk(KERN_CONT " %02x",
+- saa7111_read(client, i + j));
+- }
+- printk(KERN_CONT "\n");
+- }
+- break;
+- }
+-
+- case DECODER_GET_CAPABILITIES:
+- {
+- 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 = saa7111_read(client, 0x1f);
+- v4l_dbg(1, debug, client, "status: 0x%02x\n", 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_GPIO:
+- {
+- int *iarg = arg;
+- if (0 != *iarg) {
+- saa7111_write(client, 0x11,
+- (decoder->reg[0x11] | 0x80));
+- } else {
+- saa7111_write(client, 0x11,
+- (decoder->reg[0x11] & 0x7f));
+- }
+- break;
+- }
+-
+- case DECODER_SET_VBI_BYPASS:
+- {
+- int *iarg = arg;
+- if (0 != *iarg) {
+- saa7111_write(client, 0x13,
+- (decoder->reg[0x13] & 0xf0) | 0x0a);
+- } else {
+- saa7111_write(client, 0x13,
+- (decoder->reg[0x13] & 0xf0));
+- }
+- break;
+- }
+-
+- case DECODER_SET_NORM:
+- {
+- 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[0x08] & 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;
+- break;
+- }
+-
+- case DECODER_SET_INPUT:
+- {
+- int *iarg = arg;
+-
+- if (*iarg < 0 || *iarg > 7) {
+- return -EINVAL;
+- }
+-
+- 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;
+-
+- /* 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) {
+- 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;
+-
+- /* We want 0 to 255 we get 0-65535 */
+- saa7111_write_if_changed(client, 0x0a, pic->brightness >> 8);
+- /* We want 0 to 127 we get 0-65535 */
+- saa7111_write(client, 0x0b, pic->contrast >> 9);
+- /* We want 0 to 127 we get 0-65535 */
+- saa7111_write(client, 0x0c, pic->colour >> 9);
+- /* We want -128 to 127 we get 0-65535 */
+- saa7111_write(client, 0x0d, (pic->hue - 32768) >> 8);
+- break;
+- }
+-
+- default:
+- return -EINVAL;
+- }
+-
+- return 0;
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static unsigned short normal_i2c[] = { 0x48 >> 1, I2C_CLIENT_END };
+-
+-I2C_CLIENT_INSMOD;
+-
+-static int saa7111_probe(struct i2c_client *client,
+- const struct i2c_device_id *id)
+-{
+- int i;
+- struct saa7111 *decoder;
+- struct video_decoder_init vdi;
+-
+- /* Check if the adapter supports the needed features */
+- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+- return -ENODEV;
+-
+- v4l_info(client, "chip found @ 0x%x (%s)\n",
+- client->addr << 1, client->adapter->name);
+-
+- decoder = kzalloc(sizeof(struct saa7111), GFP_KERNEL);
+- if (decoder == NULL) {
+- kfree(client);
+- return -ENOMEM;
+- }
+- decoder->norm = VIDEO_MODE_NTSC;
+- decoder->input = 0;
+- decoder->enable = 1;
+- i2c_set_clientdata(client, decoder);
+-
+- vdi.data = saa7111_i2c_init;
+- vdi.len = sizeof(saa7111_i2c_init);
+- i = saa7111_init_decoder(client, &vdi);
+- if (i < 0) {
+- v4l_dbg(1, debug, client, "init status %d\n", i);
+- } else {
+- v4l_dbg(1, debug, client, "revision %x\n",
+- saa7111_read(client, 0x00) >> 4);
+- }
+- return 0;
+-}
+-
+-static int saa7111_remove(struct i2c_client *client)
+-{
+- kfree(i2c_get_clientdata(client));
+- return 0;
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static const struct i2c_device_id saa7111_id[] = {
+- { "saa7111_old", 0 }, /* "saa7111" maps to the saa7115 driver */
+- { }
+-};
+-MODULE_DEVICE_TABLE(i2c, saa7111_id);
+-
+-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+- .name = "saa7111",
+- .driverid = I2C_DRIVERID_SAA7111A,
+- .command = saa7111_command,
+- .probe = saa7111_probe,
+- .remove = saa7111_remove,
+- .id_table = saa7111_id,
+-};
+diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
+deleted file mode 100644
+index 7ca709f..0000000
+--- a/drivers/media/video/saa7114.c
++++ /dev/null
+@@ -1,1068 +0,0 @@
+-/*
+- * 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/module.h>
+-#include <linux/types.h>
+-#include <linux/ioctl.h>
+-#include <asm/uaccess.h>
+-#include <linux/i2c.h>
+-#include <linux/i2c-id.h>
+-#include <linux/videodev.h>
+-#include <linux/video_decoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
+-
+-MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
+-MODULE_AUTHOR("Maxim Yevtyushkin");
+-MODULE_LICENSE("GPL");
+-
+-static int debug;
+-module_param(debug, int, 0);
+-MODULE_PARM_DESC(debug, "Debug level (0-1)");
+-
+-/* ----------------------------------------------------------------------- */
+-
+-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_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)
+-{
+- 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 */
+- u8 block_data[32];
+- int block_len;
+-
+- while (len >= 2) {
+- block_len = 0;
+- block_data[block_len++] = reg = data[0];
+- do {
+- block_data[block_len++] = data[1];
+- reg++;
+- len -= 2;
+- data += 2;
+- } while (len >= 2 && data[0] == reg && block_len < 32);
+- ret = i2c_master_send(client, block_data, block_len);
+- if (ret < 0)
+- break;
+- }
+- } else {
+- /* do some slow I2C emulation kind of thing */
+- while (len >= 2) {
+- reg = *data++;
+- ret = saa7114_write(client, reg, *data++);
+- if (ret < 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 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;
+-
+- if (!debug)
+- break;
+- v4l_info(client, "decoder dump\n");
+-
+- for (i = 0; i < 32; i += 16) {
+- int j;
+-
+- v4l_info(client, "%03x", i);
+- for (j = 0; j < 16; ++j) {
+- printk(KERN_CONT " %02x",
+- saa7114_read(client, i + j));
+- }
+- printk(KERN_CONT "\n");
+- }
+- break;
+- }
+-
+- case DECODER_GET_CAPABILITIES:
+- {
+- struct video_decoder_capability *cap = arg;
+-
+- v4l_dbg(1, debug, client, "get capabilities\n");
+-
+- 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);
+-
+- v4l_dbg(1, debug, client, "status: 0x%02x\n", 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;
+-
+- v4l_dbg(1, debug, client, "set norm\n");
+-
+- switch (*iarg) {
+- case VIDEO_MODE_NTSC:
+- v4l_dbg(1, debug, client, "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:
+- v4l_dbg(1, debug, client, "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:
+- v4l_dbg(1, debug, client, "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;
+-
+- v4l_dbg(1, debug, client, "set input (%d)\n", *iarg);
+- if (*iarg < 0 || *iarg > 7) {
+- return -EINVAL;
+- }
+-
+- if (decoder->input != *iarg) {
+- v4l_dbg(1, debug, client, "now setting %s input\n",
+- *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;
+-
+- v4l_dbg(1, debug, client, "set output\n");
+-
+- /* not much choice of outputs */
+- if (*iarg != 0) {
+- return -EINVAL;
+- }
+- break;
+- }
+-
+- case DECODER_ENABLE_OUTPUT:
+- {
+- int *iarg = arg;
+- int enable = (*iarg != 0);
+-
+- v4l_dbg(1, debug, client, "%s output\n",
+- 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;
+-
+- v4l_dbg(1, debug, client,
+- "decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
+- 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;
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
+-
+-I2C_CLIENT_INSMOD;
+-
+-static int saa7114_probe(struct i2c_client *client,
+- const struct i2c_device_id *id)
+-{
+- 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 saa7114 *decoder;
+-
+- /* Check if the adapter supports the needed features */
+- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+- return -ENODEV;
+-
+- v4l_info(client, "chip found @ 0x%x (%s)\n",
+- client->addr << 1, client->adapter->name);
+-
+- decoder = kzalloc(sizeof(struct saa7114), GFP_KERNEL);
+- if (decoder == NULL)
+- return -ENOMEM;
+- 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
+-
+-
+- v4l_dbg(1, debug, client, "starting init\n");
+-
+- 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) {
+- v4l_dbg(1, debug, client,
+- "init error %d at stage %d, leaving attach.\n",
+- i, err[i]);
+- kfree(decoder);
+- return -EIO;
+- }
+- }
+-
+- for (i = 6; i < 8; i++) {
+- v4l_dbg(1, debug, client,
+- "reg[0x%02x] = 0x%02x (0x%02x)\n",
+- i, saa7114_read(client, i),
+- decoder->reg[REG_ADDR(i)]);
+- }
+-
+- v4l_dbg(1, debug, client,
+- "performing decoder reset sequence\n");
+-
+- 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) {
+- v4l_dbg(1, debug, client,
+- "init error %d at stage %d, leaving attach.\n",
+- i, err[i]);
+- kfree(decoder);
+- return -EIO;
+- }
+- }
+-
+- v4l_dbg(1, debug, client, "performing the rest of init\n");
+-
+- 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) {
+- v4l_dbg(1, debug, client,
+- "init error %d at stage %d, leaving attach.\n",
+- i, err[i]);
+- kfree(decoder);
+- return -EIO;
+- }
+- }
+-
+-
+- for (i = 6; i < 8; i++) {
+- v4l_dbg(1, debug, client,
+- "reg[0x%02x] = 0x%02x (0x%02x)\n",
+- i, saa7114_read(client, i),
+- decoder->reg[REG_ADDR(i)]);
+- }
+-
+-
+- for (i = 0x11; i <= 0x13; i++) {
+- v4l_dbg(1, debug, client,
+- "reg[0x%02x] = 0x%02x (0x%02x)\n",
+- i, saa7114_read(client, i),
+- decoder->reg[REG_ADDR(i)]);
+- }
+-
+-
+- v4l_dbg(1, debug, client, "setting video input\n");
+-
+- 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) {
+- v4l_dbg(1, debug, client,
+- "init error %d at stage %d, leaving attach.\n",
+- i, err[i]);
+- kfree(decoder);
+- return -EIO;
+- }
+- }
+-
+- v4l_dbg(1, debug, client, "performing decoder reset sequence\n");
+-
+- 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) {
+- v4l_dbg(1, debug, client,
+- "init error %d at stage %d, leaving attach.\n",
+- i, err[i]);
+- kfree(decoder);
+- return -EIO;
+- }
+- }
+-
+- 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)]);
+-
+- v4l_dbg(1, debug, client, "chip version %x, decoder status 0x%02x\n",
+- saa7114_read(client, 0x00) >> 4,
+- saa7114_read(client, 0x1f));
+- v4l_dbg(1, debug, client,
+- "power save control: 0x%02x, scaler status: 0x%02x\n",
+- saa7114_read(client, 0x88),
+- saa7114_read(client, 0x8f));
+-
+-
+- for (i = 0x94; i < 0x96; i++) {
+- v4l_dbg(1, debug, client,
+- "reg[0x%02x] = 0x%02x (0x%02x)\n",
+- i, saa7114_read(client, i),
+- decoder->reg[REG_ADDR(i)]);
+- }
+-
+- //i = saa7114_write_block(client, init, sizeof(init));
+- return 0;
+-}
+-
+-static int saa7114_remove(struct i2c_client *client)
+-{
+- kfree(i2c_get_clientdata(client));
+- return 0;
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static const struct i2c_device_id saa7114_id[] = {
+- { "saa7114_old", 0 }, /* "saa7114" maps to the saa7115 driver */
+- { }
+-};
+-MODULE_DEVICE_TABLE(i2c, saa7114_id);
+-
+-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+- .name = "saa7114",
+- .driverid = I2C_DRIVERID_SAA7114,
+- .command = saa7114_command,
+- .probe = saa7114_probe,
+- .remove = saa7114_remove,
+- .id_table = saa7114_id,
+-};
+diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
+index 46c796c..cebf159 100644
+--- a/drivers/media/video/saa7115.c
++++ b/drivers/media/video/saa7115.c
+@@ -778,7 +778,7 @@ static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ break;
+
+ case V4L2_CID_HUE:
+- if (ctrl->value < -127 || ctrl->value > 127) {
++ if (ctrl->value < -128 || ctrl->value > 127) {
+ v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+@@ -931,8 +931,8 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
+ /* Prevent unnecessary standard changes. During a standard
+ change the I-Port is temporarily disabled. Any devices
+ reading from that port can get confused.
+- Note that VIDIOC_S_STD is also used to switch from
+- radio to TV mode, so if a VIDIOC_S_STD is broadcast to
++ Note that s_std is also used to switch from
++ radio to TV mode, so if a s_std is broadcast to
+ all I2C devices then you do not want to have an unwanted
+ side-effect here. */
+ if (std == state->std)
+@@ -1206,10 +1206,12 @@ static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+ {
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
++ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
++ return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
+ case V4L2_CID_HUE:
+- return v4l2_ctrl_query_fill_std(qc);
++ return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+ default:
+ return -EINVAL;
+ }
+@@ -1308,11 +1310,12 @@ static int saa711x_s_stream(struct v4l2_subdev *sd, int enable)
+ v4l2_dbg(1, debug, sd, "%s output\n",
+ enable ? "enable" : "disable");
+
+- if (state->enable != enable) {
+- state->enable = enable;
+- saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
+- state->enable);
+- }
++ if (state->enable == enable)
++ return 0;
++ state->enable = enable;
++ if (!saa711x_has_reg(state->ident, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED))
++ return 0;
++ saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, state->enable);
+ return 0;
+ }
+
+@@ -1370,6 +1373,47 @@ static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_dat
+ }
+ }
+
++static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
++{
++ struct saa711x_state *state = to_state(sd);
++ int reg1e;
++
++ *std = V4L2_STD_ALL;
++ if (state->ident != V4L2_IDENT_SAA7115)
++ return 0;
++ reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
++
++ switch (reg1e & 0x03) {
++ case 1:
++ *std = V4L2_STD_NTSC;
++ break;
++ case 2:
++ *std = V4L2_STD_PAL;
++ break;
++ case 3:
++ *std = V4L2_STD_SECAM;
++ break;
++ default:
++ break;
++ }
++ return 0;
++}
++
++static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status)
++{
++ struct saa711x_state *state = to_state(sd);
++ int reg1e = 0x80;
++ int reg1f;
++
++ *status = V4L2_IN_ST_NO_SIGNAL;
++ if (state->ident == V4L2_IDENT_SAA7115)
++ reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
++ reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
++ if ((reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80)
++ *status = 0;
++ return 0;
++}
++
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+ {
+@@ -1493,6 +1537,8 @@ static const struct v4l2_subdev_video_ops saa711x_video_ops = {
+ .g_vbi_data = saa711x_g_vbi_data,
+ .decode_vbi_line = saa711x_decode_vbi_line,
+ .s_stream = saa711x_s_stream,
++ .querystd = saa711x_querystd,
++ .g_input_status = saa711x_g_input_status,
+ };
+
+ static const struct v4l2_subdev_ops saa711x_ops = {
+diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
+index 05221d4..128bb8b 100644
+--- a/drivers/media/video/saa7127.c
++++ b/drivers/media/video/saa7127.c
+@@ -810,7 +810,6 @@ MODULE_DEVICE_TABLE(i2c, saa7127_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa7127",
+- .driverid = I2C_DRIVERID_SAA7127,
+ .probe = saa7127_probe,
+ .remove = saa7127_remove,
+ .id_table = saa7127_id,
+diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
+index fc2164e..0ba6898 100644
+--- a/drivers/media/video/saa7134/Kconfig
++++ b/drivers/media/video/saa7134/Kconfig
+@@ -6,6 +6,7 @@ config VIDEO_SAA7134
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select CRC32
++ select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO
+ ---help---
+ This is a video4linux driver for Philips SAA713x based
+ TV cards.
+@@ -35,8 +36,16 @@ config VIDEO_SAA7134_DVB
+ select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+ select DVB_TDA826X if !DVB_FE_CUSTOMISE
+ select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+- select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
+- select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
++ select DVB_ISL6405 if !DVB_FE_CUSTOMISE
++ select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
++ select DVB_ZL10036 if !DVB_FE_CUSTOMISE
++ select DVB_MT312 if !DVB_FE_CUSTOMISE
++ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
++ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
++ select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
++ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
++ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+ ---help---
+ This adds support for DVB cards based on the
+ Philips saa7134 chip.
+diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
+index 1fee6e8..dc2213e 100644
+--- a/drivers/media/video/saa7134/saa6752hs.c
++++ b/drivers/media/video/saa7134/saa6752hs.c
+@@ -33,9 +33,10 @@
+ #include <linux/i2c.h>
+ #include <linux/types.h>
+ #include <linux/videodev2.h>
++#include <media/v4l2-device.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
+ #include <linux/init.h>
+ #include <linux/crc32.h>
+
+@@ -44,10 +45,6 @@
+ #define MPEG_TOTAL_TARGET_BITRATE_MAX 27000
+ #define MPEG_PID_MAX ((1 << 14) - 1)
+
+-/* Addresses to scan */
+-static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
+-
+-I2C_CLIENT_INSMOD;
+
+ MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
+ MODULE_AUTHOR("Andrew de Quincey");
+@@ -95,6 +92,7 @@ static const struct v4l2_format v4l2_format_table[] =
+ };
+
+ struct saa6752hs_state {
++ struct v4l2_subdev sd;
+ int chip;
+ u32 revision;
+ int has_ac3;
+@@ -115,6 +113,11 @@ enum saa6752hs_command {
+ SAA6752HS_COMMAND_MAX
+ };
+
++static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct saa6752hs_state, sd);
++}
++
+ /* ---------------------------------------------------------------------- */
+
+ static u8 PAT[] = {
+@@ -360,185 +363,191 @@ static int saa6752hs_set_bitrate(struct i2c_client *client,
+ return 0;
+ }
+
+-static void saa6752hs_set_subsampling(struct i2c_client *client,
+- struct v4l2_format *f)
+-{
+- struct saa6752hs_state *h = i2c_get_clientdata(client);
+- int dist_352, dist_480, dist_720;
+-
+- /*
+- FIXME: translate and round width/height into EMPRESS
+- subsample type:
+
+- type | PAL | NTSC
+- ---------------------------
+- SIF | 352x288 | 352x240
+- 1/2 D1 | 352x576 | 352x480
+- 2/3 D1 | 480x576 | 480x480
+- D1 | 720x576 | 720x480
+- */
+-
+- dist_352 = abs(f->fmt.pix.width - 352);
+- dist_480 = abs(f->fmt.pix.width - 480);
+- dist_720 = abs(f->fmt.pix.width - 720);
+- if (dist_720 < dist_480) {
+- f->fmt.pix.width = 720;
+- f->fmt.pix.height = 576;
+- h->video_format = SAA6752HS_VF_D1;
+- }
+- else if (dist_480 < dist_352) {
+- f->fmt.pix.width = 480;
+- f->fmt.pix.height = 576;
+- h->video_format = SAA6752HS_VF_2_3_D1;
+- }
+- else {
+- f->fmt.pix.width = 352;
+- if (abs(f->fmt.pix.height - 576) <
+- abs(f->fmt.pix.height - 288)) {
+- f->fmt.pix.height = 576;
+- h->video_format = SAA6752HS_VF_1_2_D1;
+- }
+- else {
+- f->fmt.pix.height = 288;
+- h->video_format = SAA6752HS_VF_SIF;
+- }
++static int get_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
++ struct v4l2_ext_control *ctrl)
++{
++ switch (ctrl->id) {
++ case V4L2_CID_MPEG_STREAM_TYPE:
++ ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
++ break;
++ case V4L2_CID_MPEG_STREAM_PID_PMT:
++ ctrl->value = params->ts_pid_pmt;
++ break;
++ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
++ ctrl->value = params->ts_pid_audio;
++ break;
++ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
++ ctrl->value = params->ts_pid_video;
++ break;
++ case V4L2_CID_MPEG_STREAM_PID_PCR:
++ ctrl->value = params->ts_pid_pcr;
++ break;
++ case V4L2_CID_MPEG_AUDIO_ENCODING:
++ ctrl->value = params->au_encoding;
++ break;
++ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
++ ctrl->value = params->au_l2_bitrate;
++ break;
++ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
++ if (!has_ac3)
++ return -EINVAL;
++ ctrl->value = params->au_ac3_bitrate;
++ break;
++ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
++ ctrl->value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
++ break;
++ case V4L2_CID_MPEG_VIDEO_ENCODING:
++ ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
++ break;
++ case V4L2_CID_MPEG_VIDEO_ASPECT:
++ ctrl->value = params->vi_aspect;
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE:
++ ctrl->value = params->vi_bitrate * 1000;
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
++ ctrl->value = params->vi_bitrate_peak * 1000;
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
++ ctrl->value = params->vi_bitrate_mode;
++ break;
++ default:
++ return -EINVAL;
+ }
++ return 0;
+ }
+
+-
+ static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
+- struct v4l2_ext_control *ctrl, unsigned int cmd)
++ struct v4l2_ext_control *ctrl, int set)
+ {
+ int old = 0, new;
+- int set = (cmd == VIDIOC_S_EXT_CTRLS);
+
+ new = ctrl->value;
+ switch (ctrl->id) {
+- case V4L2_CID_MPEG_STREAM_TYPE:
+- old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+- if (set && new != old)
+- return -ERANGE;
+- new = old;
+- break;
+- case V4L2_CID_MPEG_STREAM_PID_PMT:
+- old = params->ts_pid_pmt;
+- if (set && new > MPEG_PID_MAX)
+- return -ERANGE;
+- if (new > MPEG_PID_MAX)
+- new = MPEG_PID_MAX;
+- params->ts_pid_pmt = new;
+- break;
+- case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+- old = params->ts_pid_audio;
+- if (set && new > MPEG_PID_MAX)
+- return -ERANGE;
+- if (new > MPEG_PID_MAX)
+- new = MPEG_PID_MAX;
+- params->ts_pid_audio = new;
+- break;
+- case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+- old = params->ts_pid_video;
+- if (set && new > MPEG_PID_MAX)
+- return -ERANGE;
+- if (new > MPEG_PID_MAX)
+- new = MPEG_PID_MAX;
+- params->ts_pid_video = new;
+- break;
+- case V4L2_CID_MPEG_STREAM_PID_PCR:
+- old = params->ts_pid_pcr;
+- if (set && new > MPEG_PID_MAX)
+- return -ERANGE;
+- if (new > MPEG_PID_MAX)
+- new = MPEG_PID_MAX;
+- params->ts_pid_pcr = new;
+- break;
+- case V4L2_CID_MPEG_AUDIO_ENCODING:
+- old = params->au_encoding;
+- if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+- (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
+- return -ERANGE;
+- new = old;
+- break;
+- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+- old = params->au_l2_bitrate;
+- if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
+- new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
+- return -ERANGE;
+- if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
+- new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+- else
+- new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+- params->au_l2_bitrate = new;
+- break;
+- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+- if (!has_ac3)
+- return -EINVAL;
+- old = params->au_ac3_bitrate;
+- if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
+- new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
+- return -ERANGE;
+- if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
+- new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
+- else
+- new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
+- params->au_ac3_bitrate = new;
+- break;
+- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+- old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+- if (set && new != old)
+- return -ERANGE;
+- new = old;
+- break;
+- case V4L2_CID_MPEG_VIDEO_ENCODING:
+- old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+- if (set && new != old)
+- return -ERANGE;
+- new = old;
+- break;
+- case V4L2_CID_MPEG_VIDEO_ASPECT:
+- old = params->vi_aspect;
+- if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
+- new != V4L2_MPEG_VIDEO_ASPECT_4x3)
+- return -ERANGE;
+- if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
+- new = V4L2_MPEG_VIDEO_ASPECT_4x3;
+- params->vi_aspect = new;
+- break;
+- case V4L2_CID_MPEG_VIDEO_BITRATE:
+- old = params->vi_bitrate * 1000;
+- new = 1000 * (new / 1000);
+- if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+- return -ERANGE;
+- if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+- new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+- params->vi_bitrate = new / 1000;
+- break;
+- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+- old = params->vi_bitrate_peak * 1000;
+- new = 1000 * (new / 1000);
+- if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+- return -ERANGE;
+- if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+- new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+- params->vi_bitrate_peak = new / 1000;
+- break;
+- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+- old = params->vi_bitrate_mode;
+- params->vi_bitrate_mode = new;
+- break;
+- default:
++ case V4L2_CID_MPEG_STREAM_TYPE:
++ old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
++ if (set && new != old)
++ return -ERANGE;
++ new = old;
++ break;
++ case V4L2_CID_MPEG_STREAM_PID_PMT:
++ old = params->ts_pid_pmt;
++ if (set && new > MPEG_PID_MAX)
++ return -ERANGE;
++ if (new > MPEG_PID_MAX)
++ new = MPEG_PID_MAX;
++ params->ts_pid_pmt = new;
++ break;
++ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
++ old = params->ts_pid_audio;
++ if (set && new > MPEG_PID_MAX)
++ return -ERANGE;
++ if (new > MPEG_PID_MAX)
++ new = MPEG_PID_MAX;
++ params->ts_pid_audio = new;
++ break;
++ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
++ old = params->ts_pid_video;
++ if (set && new > MPEG_PID_MAX)
++ return -ERANGE;
++ if (new > MPEG_PID_MAX)
++ new = MPEG_PID_MAX;
++ params->ts_pid_video = new;
++ break;
++ case V4L2_CID_MPEG_STREAM_PID_PCR:
++ old = params->ts_pid_pcr;
++ if (set && new > MPEG_PID_MAX)
++ return -ERANGE;
++ if (new > MPEG_PID_MAX)
++ new = MPEG_PID_MAX;
++ params->ts_pid_pcr = new;
++ break;
++ case V4L2_CID_MPEG_AUDIO_ENCODING:
++ old = params->au_encoding;
++ if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
++ (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
++ return -ERANGE;
++ new = old;
++ break;
++ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
++ old = params->au_l2_bitrate;
++ if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
++ new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
++ return -ERANGE;
++ if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
++ new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
++ else
++ new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
++ params->au_l2_bitrate = new;
++ break;
++ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
++ if (!has_ac3)
+ return -EINVAL;
++ old = params->au_ac3_bitrate;
++ if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
++ new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
++ return -ERANGE;
++ if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
++ new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
++ else
++ new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
++ params->au_ac3_bitrate = new;
++ break;
++ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
++ old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
++ if (set && new != old)
++ return -ERANGE;
++ new = old;
++ break;
++ case V4L2_CID_MPEG_VIDEO_ENCODING:
++ old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
++ if (set && new != old)
++ return -ERANGE;
++ new = old;
++ break;
++ case V4L2_CID_MPEG_VIDEO_ASPECT:
++ old = params->vi_aspect;
++ if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
++ new != V4L2_MPEG_VIDEO_ASPECT_4x3)
++ return -ERANGE;
++ if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
++ new = V4L2_MPEG_VIDEO_ASPECT_4x3;
++ params->vi_aspect = new;
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE:
++ old = params->vi_bitrate * 1000;
++ new = 1000 * (new / 1000);
++ if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
++ return -ERANGE;
++ if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
++ new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
++ params->vi_bitrate = new / 1000;
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
++ old = params->vi_bitrate_peak * 1000;
++ new = 1000 * (new / 1000);
++ if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
++ return -ERANGE;
++ if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
++ new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
++ params->vi_bitrate_peak = new / 1000;
++ break;
++ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
++ old = params->vi_bitrate_mode;
++ params->vi_bitrate_mode = new;
++ break;
++ default:
++ return -EINVAL;
+ }
+- if (cmd == VIDIOC_G_EXT_CTRLS)
+- ctrl->value = old;
+- else
+- ctrl->value = new;
++ ctrl->value = new;
+ return 0;
+ }
+
+-static int saa6752hs_qctrl(struct saa6752hs_state *h,
+- struct v4l2_queryctrl *qctrl)
++
++static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
+ {
++ struct saa6752hs_state *h = to_state(sd);
+ struct saa6752hs_mpeg_params *params = &h->params;
+ int err;
+
+@@ -583,7 +592,7 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+- err = v4l2_ctrl_query_fill_std(qctrl);
++ err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+ if (err == 0 &&
+ params->vi_bitrate_mode ==
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+@@ -597,12 +606,20 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
++ return v4l2_ctrl_query_fill(qctrl,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
++ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+ case V4L2_CID_MPEG_STREAM_PID_PMT:
++ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
++ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
++ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
+ case V4L2_CID_MPEG_STREAM_PID_PCR:
+- return v4l2_ctrl_query_fill_std(qctrl);
++ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
+
+ default:
+ break;
+@@ -610,8 +627,7 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h,
+ return -EINVAL;
+ }
+
+-static int saa6752hs_qmenu(struct saa6752hs_state *h,
+- struct v4l2_querymenu *qmenu)
++static int saa6752hs_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qmenu)
+ {
+ static const u32 mpeg_audio_encoding[] = {
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+@@ -632,11 +648,12 @@ static int saa6752hs_qmenu(struct saa6752hs_state *h,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
+ V4L2_CTRL_MENU_IDS_END
+ };
++ struct saa6752hs_state *h = to_state(sd);
+ struct v4l2_queryctrl qctrl;
+ int err;
+
+ qctrl.id = qmenu->id;
+- err = saa6752hs_qctrl(h, &qctrl);
++ err = saa6752hs_queryctrl(sd, &qctrl);
+ if (err)
+ return err;
+ switch (qmenu->id) {
+@@ -656,17 +673,16 @@ static int saa6752hs_qmenu(struct saa6752hs_state *h,
+ return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
+ }
+
+-static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
++static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
+ {
+ unsigned char buf[9], buf2[4];
+- struct saa6752hs_state *h;
++ struct saa6752hs_state *h = to_state(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ unsigned size;
+ u32 crc;
+ unsigned char localPAT[256];
+ unsigned char localPMT[256];
+
+- h = i2c_get_clientdata(client);
+-
+ /* Set video format - must be done first as it resets other settings */
+ set_reg8(client, 0x41, h->video_format);
+
+@@ -762,7 +778,7 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
+ buf[3] = 0x82;
+ buf[4] = 0xB0;
+ buf[5] = buf2[0];
+- switch(h->params.vi_aspect) {
++ switch (h->params.vi_aspect) {
+ case V4L2_MPEG_VIDEO_ASPECT_16x9:
+ buf[6] = buf2[1] | 0x40;
+ break;
+@@ -770,7 +786,6 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
+ default:
+ buf[6] = buf2[1] & 0xBF;
+ break;
+- break;
+ }
+ buf[7] = buf2[2];
+ buf[8] = buf2[3];
+@@ -779,81 +794,162 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes)
+ return 0;
+ }
+
+-static int
+-saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
++static int saa6752hs_do_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls, int set)
+ {
+- struct saa6752hs_state *h = i2c_get_clientdata(client);
+- struct v4l2_ext_controls *ctrls = arg;
++ struct saa6752hs_state *h = to_state(sd);
+ struct saa6752hs_mpeg_params params;
+- int err = 0;
+ int i;
+
+- switch (cmd) {
+- case VIDIOC_INT_INIT:
+- /* apply settings and start encoder */
+- saa6752hs_init(client, *(u32 *)arg);
+- break;
+- case VIDIOC_S_EXT_CTRLS:
+- if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+- return -EINVAL;
+- /* fall through */
+- case VIDIOC_TRY_EXT_CTRLS:
+- case VIDIOC_G_EXT_CTRLS:
+- if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+- return -EINVAL;
+- params = h->params;
+- for (i = 0; i < ctrls->count; i++) {
+- err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, cmd);
+- if (err) {
+- ctrls->error_idx = i;
+- return err;
+- }
++ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
++ return -EINVAL;
++
++ params = h->params;
++ for (i = 0; i < ctrls->count; i++) {
++ int err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, set);
++
++ if (err) {
++ ctrls->error_idx = i;
++ return err;
+ }
+- h->params = params;
+- break;
+- case VIDIOC_QUERYCTRL:
+- return saa6752hs_qctrl(h, arg);
+- case VIDIOC_QUERYMENU:
+- return saa6752hs_qmenu(h, arg);
+- case VIDIOC_G_FMT:
+- {
+- struct v4l2_format *f = arg;
+-
+- if (h->video_format == SAA6752HS_VF_UNKNOWN)
+- h->video_format = SAA6752HS_VF_D1;
+- f->fmt.pix.width =
+- v4l2_format_table[h->video_format].fmt.pix.width;
+- f->fmt.pix.height =
+- v4l2_format_table[h->video_format].fmt.pix.height;
+- break ;
+ }
+- case VIDIOC_S_FMT:
+- {
+- struct v4l2_format *f = arg;
++ if (set)
++ h->params = params;
++ return 0;
++}
+
+- saa6752hs_set_subsampling(client, f);
+- break;
++static int saa6752hs_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
++{
++ return saa6752hs_do_ext_ctrls(sd, ctrls, 1);
++}
++
++static int saa6752hs_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
++{
++ return saa6752hs_do_ext_ctrls(sd, ctrls, 0);
++}
++
++static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
++{
++ struct saa6752hs_state *h = to_state(sd);
++ int i;
++
++ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
++ return -EINVAL;
++
++ for (i = 0; i < ctrls->count; i++) {
++ int err = get_ctrl(h->has_ac3, &h->params, ctrls->controls + i);
++
++ if (err) {
++ ctrls->error_idx = i;
++ return err;
++ }
+ }
+- case VIDIOC_S_STD:
+- h->standard = *((v4l2_std_id *) arg);
+- break;
++ return 0;
++}
+
+- case VIDIOC_DBG_G_CHIP_IDENT:
+- return v4l2_chip_ident_i2c_client(client,
+- arg, h->chip, h->revision);
++static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
++{
++ struct saa6752hs_state *h = to_state(sd);
+
+- default:
+- /* nothing */
+- break;
++ if (h->video_format == SAA6752HS_VF_UNKNOWN)
++ h->video_format = SAA6752HS_VF_D1;
++ f->fmt.pix.width =
++ v4l2_format_table[h->video_format].fmt.pix.width;
++ f->fmt.pix.height =
++ v4l2_format_table[h->video_format].fmt.pix.height;
++ return 0;
++}
++
++static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
++{
++ struct saa6752hs_state *h = to_state(sd);
++ int dist_352, dist_480, dist_720;
++
++ /*
++ FIXME: translate and round width/height into EMPRESS
++ subsample type:
++
++ type | PAL | NTSC
++ ---------------------------
++ SIF | 352x288 | 352x240
++ 1/2 D1 | 352x576 | 352x480
++ 2/3 D1 | 480x576 | 480x480
++ D1 | 720x576 | 720x480
++ */
++
++ dist_352 = abs(f->fmt.pix.width - 352);
++ dist_480 = abs(f->fmt.pix.width - 480);
++ dist_720 = abs(f->fmt.pix.width - 720);
++ if (dist_720 < dist_480) {
++ f->fmt.pix.width = 720;
++ f->fmt.pix.height = 576;
++ h->video_format = SAA6752HS_VF_D1;
++ } else if (dist_480 < dist_352) {
++ f->fmt.pix.width = 480;
++ f->fmt.pix.height = 576;
++ h->video_format = SAA6752HS_VF_2_3_D1;
++ } else {
++ f->fmt.pix.width = 352;
++ if (abs(f->fmt.pix.height - 576) <
++ abs(f->fmt.pix.height - 288)) {
++ f->fmt.pix.height = 576;
++ h->video_format = SAA6752HS_VF_1_2_D1;
++ } else {
++ f->fmt.pix.height = 288;
++ h->video_format = SAA6752HS_VF_SIF;
++ }
+ }
++ return 0;
++}
++
++static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
++{
++ struct saa6752hs_state *h = to_state(sd);
++
++ h->standard = std;
++ return 0;
++}
+
+- return err;
++static int saa6752hs_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct saa6752hs_state *h = to_state(sd);
++
++ return v4l2_chip_ident_i2c_client(client,
++ chip, h->chip, h->revision);
+ }
+
++/* ----------------------------------------------------------------------- */
++
++static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
++ .g_chip_ident = saa6752hs_g_chip_ident,
++ .init = saa6752hs_init,
++ .queryctrl = saa6752hs_queryctrl,
++ .querymenu = saa6752hs_querymenu,
++ .g_ext_ctrls = saa6752hs_g_ext_ctrls,
++ .s_ext_ctrls = saa6752hs_s_ext_ctrls,
++ .try_ext_ctrls = saa6752hs_try_ext_ctrls,
++};
++
++static const struct v4l2_subdev_tuner_ops saa6752hs_tuner_ops = {
++ .s_std = saa6752hs_s_std,
++};
++
++static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
++ .s_fmt = saa6752hs_s_fmt,
++ .g_fmt = saa6752hs_g_fmt,
++};
++
++static const struct v4l2_subdev_ops saa6752hs_ops = {
++ .core = &saa6752hs_core_ops,
++ .tuner = &saa6752hs_tuner_ops,
++ .video = &saa6752hs_video_ops,
++};
++
+ static int saa6752hs_probe(struct i2c_client *client,
+- const struct i2c_device_id *id)
++ const struct i2c_device_id *id)
+ {
+ struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
++ struct v4l2_subdev *sd;
+ u8 addr = 0x13;
+ u8 data[12];
+
+@@ -861,6 +957,8 @@ static int saa6752hs_probe(struct i2c_client *client,
+ client->addr << 1, client->adapter->name);
+ if (h == NULL)
+ return -ENOMEM;
++ sd = &h->sd;
++ v4l2_i2c_subdev_init(sd, client, &saa6752hs_ops);
+
+ i2c_master_send(client, &addr, 1);
+ i2c_master_recv(client, data, sizeof(data));
+@@ -874,14 +972,15 @@ static int saa6752hs_probe(struct i2c_client *client,
+ }
+ h->params = param_defaults;
+ h->standard = 0; /* Assume 625 input lines */
+-
+- i2c_set_clientdata(client, h);
+ return 0;
+ }
+
+ static int saa6752hs_remove(struct i2c_client *client)
+ {
+- kfree(i2c_get_clientdata(client));
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_state(sd));
+ return 0;
+ }
+
+@@ -893,8 +992,6 @@ MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa6752hs",
+- .driverid = I2C_DRIVERID_SAA6752HS,
+- .command = saa6752hs_command,
+ .probe = saa6752hs_probe,
+ .remove = saa6752hs_remove,
+ .id_table = saa6752hs_id,
+diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
+index e2febcd..a790a72 100644
+--- a/drivers/media/video/saa7134/saa7134-cards.c
++++ b/drivers/media/video/saa7134/saa7134-cards.c
+@@ -31,6 +31,7 @@
+ #include <media/v4l2-common.h>
+ #include <media/tveeprom.h>
+ #include "tea5767.h"
++#include "tda18271.h"
+
+ /* commly used strings */
+ static char name_mute[] = "mute";
+@@ -272,6 +273,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .empress_addr = 0x20,
+
+ .inputs = {{
+ .name = name_comp1,
+@@ -408,6 +410,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .empress_addr = 0x20,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x820000,
+ .inputs = {{
+@@ -818,6 +821,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .empress_addr = 0x20,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 4,
+@@ -977,6 +981,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .empress_addr = 0x20,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 1,
+@@ -1699,6 +1704,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+@@ -2364,6 +2370,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .empress_addr = 0x21,
+ .inputs = {{
+ .name = "Composite 0",
+ .vmux = 0,
+@@ -3291,6 +3298,68 @@ struct saa7134_board saa7134_boards[] = {
+ .gpio = 0x0200100,
+ },
+ },
++ [SAA7134_BOARD_HAUPPAUGE_HVR1120] = {
++ .name = "Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid",
++ .audio_clock = 0x00187de7,
++ .tuner_type = TUNER_PHILIPS_TDA8290,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .tuner_config = 3,
++ .mpeg = SAA7134_MPEG_DVB,
++ .ts_type = SAA7134_MPEG_TS_SERIAL,
++ .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
++ .inputs = {{
++ .name = name_tv,
++ .vmux = 1,
++ .amux = TV,
++ .tv = 1,
++ .gpio = 0x0000100,
++ }, {
++ .name = name_comp1,
++ .vmux = 3,
++ .amux = LINE1,
++ }, {
++ .name = name_svideo,
++ .vmux = 8,
++ .amux = LINE1,
++ } },
++ .radio = {
++ .name = name_radio,
++ .amux = TV,
++ .gpio = 0x0800100, /* GPIO 23 HI for FM */
++ },
++ },
++ [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = {
++ .name = "Hauppauge WinTV-HVR1110r3",
++ .audio_clock = 0x00187de7,
++ .tuner_type = TUNER_PHILIPS_TDA8290,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .tuner_config = 3,
++ .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
++ .inputs = {{
++ .name = name_tv,
++ .vmux = 1,
++ .amux = TV,
++ .tv = 1,
++ .gpio = 0x0000100,
++ }, {
++ .name = name_comp1,
++ .vmux = 3,
++ .amux = LINE1,
++ }, {
++ .name = name_svideo,
++ .vmux = 8,
++ .amux = LINE1,
++ } },
++ .radio = {
++ .name = name_radio,
++ .amux = TV,
++ .gpio = 0x0800100, /* GPIO 23 HI for FM */
++ },
++ },
+ [SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
+ .name = "Terratec Cinergy HT PCMCIA",
+ .audio_clock = 0x00187de7,
+@@ -4070,6 +4139,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .empress_addr = 0x20,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .name = name_tv,
+@@ -4106,6 +4176,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .empress_addr = 0x20,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .name = name_tv,
+@@ -4143,6 +4214,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .empress_addr = 0x20,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .name = name_tv,
+@@ -4323,13 +4395,13 @@ struct saa7134_board saa7134_boards[] = {
+ .amux = TV,
+ .tv = 1,
+ }, {
+- .name = name_comp,
+- .vmux = 0,
++ .name = name_comp1,
++ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+- .amux = LINE1,
++ .amux = LINE2,
+ } },
+ .radio = {
+ .name = name_radio,
+@@ -4421,8 +4493,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+- /* no DVB support for now */
+- /* .mpeg = SAA7134_MPEG_DVB, */
++ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .name = name_comp,
+ .vmux = 1,
+@@ -4441,8 +4512,7 @@ struct saa7134_board saa7134_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+- /* no DVB support for now */
+- /* .mpeg = SAA7134_MPEG_DVB, */
++ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .name = name_comp,
+ .vmux = 1,
+@@ -4611,7 +4681,7 @@ struct saa7134_board saa7134_boards[] = {
+ .tuner_type = TUNER_YMEC_TVF_5533MF,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = ADDR_UNSET,
+- .radio_addr = ADDR_UNSET,
++ .radio_addr = 0x60,
+ .gpiomask = 0x80000700,
+ .inputs = { {
+ .name = name_tv,
+@@ -5405,6 +5475,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x0070,
++ .subdevice = 0x6706,
++ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x0070,
++ .subdevice = 0x6707,
++ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x0070,
++ .subdevice = 0x6708,
++ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x0070,
++ .subdevice = 0x6709,
++ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x0070,
++ .subdevice = 0x670a,
++ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3,
++ },{
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x153b,
+ .subdevice = 0x1172,
+ .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA,
+@@ -5821,8 +5921,8 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev,
+ }
+
+
+-static int saa7134_tda8290_callback(struct saa7134_dev *dev,
+- int command, int arg)
++static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev,
++ int command, int arg)
+ {
+ u8 sync_control;
+
+@@ -5848,6 +5948,65 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
+ return 0;
+ }
+
++static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev,
++ enum tda18271_mode mode)
++{
++ /* toggle AGC switch through GPIO 26 */
++ switch (mode) {
++ case TDA18271_ANALOG:
++ saa7134_set_gpio(dev, 26, 0);
++ break;
++ case TDA18271_DIGITAL:
++ saa7134_set_gpio(dev, 26, 1);
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
++ int command, int arg)
++{
++ int ret = 0;
++
++ switch (command) {
++ case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */
++ switch (dev->board) {
++ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
++ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
++ ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
++static int saa7134_tda8290_callback(struct saa7134_dev *dev,
++ int command, int arg)
++{
++ int ret;
++
++ switch (dev->board) {
++ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
++ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
++ /* tda8290 + tda18271 */
++ ret = saa7134_tda8290_18271_callback(dev, command, arg);
++ break;
++ default:
++ /* tda8290 + tda827x */
++ ret = saa7134_tda8290_827x_callback(dev, command, arg);
++ break;
++ }
++ return ret;
++}
++
+ int saa7134_tuner_callback(void *priv, int component, int command, int arg)
+ {
+ struct saa7134_dev *dev = priv;
+@@ -5878,11 +6037,16 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
+ switch (tv.model) {
+ case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+ case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
++ case 67201: /* WinTV-HVR1120 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
++ case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
++ case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+ case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+ case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
+ case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
+ case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+ case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
++ case 67651: /* WinTV-HVR1120 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
++ case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+ break;
+ default:
+ printk(KERN_WARNING "%s: warning: "
+@@ -6019,6 +6183,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
+ msleep(10);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
++ saa7134_set_gpio(dev, 23, 0);
++ msleep(10);
++ saa7134_set_gpio(dev, 23, 1);
++ dev->has_remote = SAA7134_REMOTE_I2C;
++ break;
+ case SAA7134_BOARD_AVERMEDIA_M103:
+ saa7134_set_gpio(dev, 23, 0);
+ msleep(10);
+@@ -6054,6 +6223,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
+
+ saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
+ break;
++ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
++ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
++ /* GPIO 26 high for digital, low for analog */
++ saa7134_set_gpio(dev, 26, 0);
++ msleep(1);
++
++ saa7134_set_gpio(dev, 22, 0);
++ msleep(10);
++ saa7134_set_gpio(dev, 22, 1);
++ break;
+ /* i2c remotes */
+ case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
+@@ -6079,15 +6258,15 @@ int saa7134_board_init1(struct saa7134_dev *dev)
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
+ break;
+- case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+- /* write windows gpio values */
+- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
+- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
+ printk("%s: %s: hybrid analog/dvb card\n"
+- "%s: Sorry, only analog s-video and composite input "
++ "%s: Sorry, of the analog inputs, only analog s-video and composite "
+ "are supported for now.\n",
+ dev->name, card(dev).name, dev->name);
++ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
++ /* write windows gpio values */
++ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
++ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
+ break;
+ }
+ return 0;
+@@ -6109,7 +6288,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
+
+ tun_setup.mode_mask = T_RADIO;
+
+- saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
++ saa_call_all(dev, tuner, s_type_addr, &tun_setup);
+ mode_mask &= ~T_RADIO;
+ }
+
+@@ -6121,7 +6300,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
+
+ tun_setup.mode_mask = mode_mask;
+
+- saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
++ saa_call_all(dev, tuner, s_type_addr, &tun_setup);
+ }
+
+ if (dev->tda9887_conf) {
+@@ -6130,8 +6309,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+
+- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
+- &tda9887_cfg);
++ saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+ }
+
+ if (dev->tuner_type == TUNER_XC2028) {
+@@ -6158,7 +6336,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+
+- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
++ saa_call_all(dev, tuner, s_config, &xc2028_cfg);
+ }
+ }
+
+@@ -6168,9 +6346,20 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ unsigned char buf;
+ int board;
+
++ /* Put here the code that enables the chips that are needed
++ for analog mode and doesn't depend on the tuner attachment.
++ It is also a good idea to get tuner type from eeprom, etc before
++ initializing tuner, since we can avoid loading tuner driver
++ on devices that has TUNER_ABSENT
++ */
+ switch (dev->board) {
+ case SAA7134_BOARD_BMK_MPEX_NOTUNER:
+ case SAA7134_BOARD_BMK_MPEX_TUNER:
++ /* Checks if the device has a tuner at 0x60 addr
++ If the device doesn't have a tuner, TUNER_ABSENT
++ will be used at tuner_type, avoiding loading tuner
++ without needing it
++ */
+ dev->i2c_client.addr = 0x60;
+ board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0)
+ ? SAA7134_BOARD_BMK_MPEX_NOTUNER
+@@ -6188,11 +6377,15 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ u8 subaddr;
+ u8 data[3];
+ int ret, tuner_t;
+-
+ struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1},
+ {.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}};
++
+ subaddr= 0x14;
+ tuner_t = 0;
++
++ /* Retrieve device data from eeprom, checking for the
++ proper tuner_type.
++ */
+ ret = i2c_transfer(&dev->i2c_adap, msg, 2);
+ if (ret != 2) {
+ printk(KERN_ERR "EEPROM read failure\n");
+@@ -6248,12 +6441,14 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ dev->name, saa7134_boards[dev->board].name);
+ break;
+ }
++ /* break intentionally omitted */
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+ {
+
+- /* The Philips EUROPA based hybrid boards have the tuner connected through
+- * the channel decoder. We have to make it transparent to find it
++ /* The Philips EUROPA based hybrid boards have the tuner
++ connected through the channel decoder. We have to make it
++ transparent to find it
+ */
+ u8 data[] = { 0x07, 0x02};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+@@ -6274,21 +6469,15 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
+ dev->tuner_type = TUNER_PHILIPS_TDA8290;
+
+- saa7134_tuner_setup(dev);
+-
+ data[2] = 0x68;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+-
+- /* Tuner setup is handled before I2C transfer.
+- Due to that, there's no need to do it later
+- */
+- return 0;
++ break;
+ }
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
+- case SAA7134_BOARD_ASUSTeK_TVFM7135:
+- /* The card below is detected as card=53, but is different */
++ case SAA7134_BOARD_ASUSTeK_TVFM7135:
++ /* The card below is detected as card=53, but is different */
+ if (dev->autodetected && (dev->eedata[0x27] == 0x03)) {
+ dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG;
+ printk(KERN_INFO "%s: P7131 analog only, using "
+@@ -6296,6 +6485,10 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ dev->name, saa7134_boards[dev->board].name);
+ }
+ break;
++ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
++ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
++ hauppauge_eeprom(dev, dev->eedata+0x80);
++ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+ hauppauge_eeprom(dev, dev->eedata+0x80);
+ /* break intentionally omitted */
+@@ -6351,22 +6544,6 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
+- case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
+- case SAA7134_BOARD_KWORLD_ATSC110:
+- {
+- /* enable tuner */
+- int i;
+- static const u8 buffer [] = { 0x10, 0x12, 0x13, 0x04, 0x16,
+- 0x00, 0x14, 0x04, 0x17, 0x00 };
+- dev->i2c_client.addr = 0x0a;
+- for (i = 0; i < 5; i++)
+- if (2 != i2c_master_send(&dev->i2c_client,
+- &buffer[i*2], 2))
+- printk(KERN_WARNING
+- "%s: Unable to enable tuner(%i).\n",
+- dev->name, i);
+- break;
+- }
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+ /* The T200 and the T200A share the same pci id. Consequently,
+@@ -6375,9 +6552,9 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+
+ /* Don't do this if the board was specifically selected with an
+ * insmod option or if we have the default configuration T200*/
+- if(!dev->autodetected || (dev->eedata[0x41] == 0xd0))
++ if (!dev->autodetected || (dev->eedata[0x41] == 0xd0))
+ break;
+- if(dev->eedata[0x41] == 0x02) {
++ if (dev->eedata[0x41] == 0x02) {
+ /* Reconfigure board as T200A */
+ dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A;
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+@@ -6390,6 +6567,58 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ break;
+ }
+ break;
++ case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
++ case SAA7134_BOARD_KWORLD_ATSC110:
++ {
++ struct i2c_msg msg = { .addr = 0x0a, .flags = 0 };
++ int i;
++ static u8 buffer[][2] = {
++ { 0x10, 0x12 },
++ { 0x13, 0x04 },
++ { 0x16, 0x00 },
++ { 0x14, 0x04 },
++ { 0x17, 0x00 },
++ };
++
++ for (i = 0; i < ARRAY_SIZE(buffer); i++) {
++ msg.buf = &buffer[i][0];
++ msg.len = ARRAY_SIZE(buffer[0]);
++ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
++ printk(KERN_WARNING
++ "%s: Unable to enable tuner(%i).\n",
++ dev->name, i);
++ }
++ break;
++ }
++ } /* switch() */
++
++ /* initialize tuner */
++ if (TUNER_ABSENT != dev->tuner_type) {
++ int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
++
++ /* Note: radio tuner address is always filled in,
++ so we do not need to probe for a radio tuner device. */
++ if (dev->radio_type != UNSET)
++ v4l2_i2c_new_subdev(&dev->i2c_adap,
++ "tuner", "tuner", dev->radio_addr);
++ if (has_demod)
++ v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "tuner",
++ "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
++ if (dev->tuner_addr == ADDR_UNSET) {
++ enum v4l2_i2c_tuner_type type =
++ has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
++
++ v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "tuner",
++ "tuner", v4l2_i2c_tuner_addrs(type));
++ } else {
++ v4l2_i2c_new_subdev(&dev->i2c_adap,
++ "tuner", "tuner", dev->tuner_addr);
++ }
++ }
++
++ saa7134_tuner_setup(dev);
++
++ switch (dev->board) {
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ {
+ struct v4l2_priv_tun_config tea5767_cfg;
+@@ -6401,12 +6630,10 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
+ tea5767_cfg.tuner = TUNER_TEA5767;
+ tea5767_cfg.priv = &ctl;
+- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg);
++ saa_call_all(dev, tuner, s_config, &tea5767_cfg);
+ break;
+ }
+ } /* switch() */
+
+- saa7134_tuner_setup(dev);
+-
+ return 0;
+ }
+diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
+index 99221d7..dafa0d8 100644
+--- a/drivers/media/video/saa7134/saa7134-core.c
++++ b/drivers/media/video/saa7134/saa7134-core.c
+@@ -54,13 +54,9 @@ static unsigned int gpio_tracking;
+ module_param(gpio_tracking, int, 0644);
+ MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
+
+-static unsigned int alsa;
++static unsigned int alsa = 1;
+ module_param(alsa, int, 0644);
+-MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]");
+-
+-static unsigned int oss;
+-module_param(oss, int, 0644);
+-MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]");
++MODULE_PARM_DESC(alsa,"enable/disable ALSA DMA sound [dmasound]");
+
+ static unsigned int latency = UNSET;
+ module_param(latency, int, 0444);
+@@ -90,8 +86,10 @@ MODULE_PARM_DESC(radio_nr, "radio device number");
+ MODULE_PARM_DESC(tuner, "tuner type");
+ MODULE_PARM_DESC(card, "card type");
+
+-static DEFINE_MUTEX(devlist_lock);
++DEFINE_MUTEX(saa7134_devlist_lock);
++EXPORT_SYMBOL(saa7134_devlist_lock);
+ LIST_HEAD(saa7134_devlist);
++EXPORT_SYMBOL(saa7134_devlist);
+ static LIST_HEAD(mops_list);
+ static unsigned int saa7134_devcount;
+
+@@ -156,10 +154,10 @@ static void request_module_async(struct work_struct *work){
+ request_module("saa7134-empress");
+ if (card_is_dvb(dev))
+ request_module("saa7134-dvb");
+- if (alsa)
+- request_module("saa7134-alsa");
+- if (oss)
+- request_module("saa7134-oss");
++ if (alsa) {
++ if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130)
++ request_module("saa7134-alsa");
++ }
+ }
+
+ static void request_submodules(struct saa7134_dev *dev)
+@@ -778,7 +776,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
+ return NULL;
+ *vfd = *template;
+ vfd->minor = -1;
+- vfd->parent = &dev->pci->dev;
++ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+ vfd->debug = video_debug;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+@@ -851,6 +849,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
+ if (NULL == dev)
+ return -ENOMEM;
+
++ err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
++ if (err)
++ goto fail0;
++
+ /* pci init */
+ dev->pci = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+@@ -927,6 +929,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
+ dev->autodetected = card[dev->nr] != dev->board;
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ dev->tuner_addr = saa7134_boards[dev->board].tuner_addr;
++ dev->radio_type = saa7134_boards[dev->board].radio_type;
++ dev->radio_addr = saa7134_boards[dev->board].radio_addr;
+ dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
+ if (UNSET != tuner[dev->nr])
+ dev->tuner_type = tuner[dev->nr];
+@@ -971,23 +975,48 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
+ /* wait a bit, register i2c bus */
+ msleep(100);
+ saa7134_i2c_register(dev);
+-
+- /* initialize hardware #2 */
+- if (TUNER_ABSENT != dev->tuner_type)
+- request_module("tuner");
+ saa7134_board_init2(dev);
+
+ saa7134_hwinit2(dev);
+
+ /* load i2c helpers */
+ if (card_is_empress(dev)) {
+- request_module("saa6752hs");
++ struct v4l2_subdev *sd =
++ v4l2_i2c_new_subdev(&dev->i2c_adap,
++ "saa6752hs", "saa6752hs",
++ saa7134_boards[dev->board].empress_addr);
++
++ if (sd)
++ sd->grp_id = GRP_EMPRESS;
++ }
++
++ if (saa7134_boards[dev->board].rds_addr) {
++ unsigned short addrs[2] = { 0, I2C_CLIENT_END };
++ struct v4l2_subdev *sd;
++
++ addrs[0] = saa7134_boards[dev->board].rds_addr;
++ sd = v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "saa6588",
++ "saa6588", addrs);
++ if (sd)
++ printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
+ }
+
+ request_submodules(dev);
+
+ v4l2_prio_init(&dev->prio);
+
++ mutex_lock(&saa7134_devlist_lock);
++ list_for_each_entry(mops, &mops_list, next)
++ mpeg_ops_attach(mops, dev);
++ list_add_tail(&dev->devlist, &saa7134_devlist);
++ mutex_unlock(&saa7134_devlist_lock);
++
++ /* check for signal */
++ saa7134_irq_video_signalchange(dev);
++
++ if (TUNER_ABSENT != dev->tuner_type)
++ saa_call_all(dev, core, s_standby, 0);
++
+ /* register v4l devices */
+ if (saa7134_no_overlay > 0)
+ printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name);
+@@ -1023,24 +1052,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
+ }
+
+ /* everything worked */
+- pci_set_drvdata(pci_dev,dev);
+ saa7134_devcount++;
+
+- mutex_lock(&devlist_lock);
+- list_for_each_entry(mops, &mops_list, next)
+- mpeg_ops_attach(mops, dev);
+- list_add_tail(&dev->devlist,&saa7134_devlist);
+- mutex_unlock(&devlist_lock);
+-
+- /* check for signal */
+- saa7134_irq_video_signalchange(dev);
+-
+- if (saa7134_dmasound_init && !dev->dmasound.priv_data) {
++ if (saa7134_dmasound_init && !dev->dmasound.priv_data)
+ saa7134_dmasound_init(dev);
+- }
+-
+- if (TUNER_ABSENT != dev->tuner_type)
+- saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
+ return 0;
+
+@@ -1055,13 +1070,16 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
+ release_mem_region(pci_resource_start(pci_dev,0),
+ pci_resource_len(pci_dev,0));
+ fail1:
++ v4l2_device_unregister(&dev->v4l2_dev);
++ fail0:
+ kfree(dev);
+ return err;
+ }
+
+ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
+ {
+- struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
++ struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
+ struct saa7134_mpeg_ops *mops;
+
+ /* Release DMA sound modules if present */
+@@ -1088,11 +1106,11 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
+ saa7134_hwfini(dev);
+
+ /* unregister */
+- mutex_lock(&devlist_lock);
++ mutex_lock(&saa7134_devlist_lock);
+ list_del(&dev->devlist);
+ list_for_each_entry(mops, &mops_list, next)
+ mpeg_ops_detach(mops, dev);
+- mutex_unlock(&devlist_lock);
++ mutex_unlock(&saa7134_devlist_lock);
+ saa7134_devcount--;
+
+ saa7134_i2c_unregister(dev);
+@@ -1113,7 +1131,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
+ release_mem_region(pci_resource_start(pci_dev,0),
+ pci_resource_len(pci_dev,0));
+
+- pci_set_drvdata(pci_dev, NULL);
++
++ v4l2_device_unregister(&dev->v4l2_dev);
+
+ /* free memory */
+ kfree(dev);
+@@ -1148,8 +1167,8 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev,
+
+ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
+ {
+-
+- struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
++ struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
+
+ /* disable overlay - apps should enable it explicitly on resume*/
+ dev->ovenable = 0;
+@@ -1185,7 +1204,8 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
+
+ static int saa7134_resume(struct pci_dev *pci_dev)
+ {
+- struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
++ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
++ struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
+ unsigned long flags;
+
+ pci_set_power_state(pci_dev, PCI_D0);
+@@ -1247,11 +1267,11 @@ int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
+ {
+ struct saa7134_dev *dev;
+
+- mutex_lock(&devlist_lock);
++ mutex_lock(&saa7134_devlist_lock);
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ mpeg_ops_attach(ops, dev);
+ list_add_tail(&ops->next,&mops_list);
+- mutex_unlock(&devlist_lock);
++ mutex_unlock(&saa7134_devlist_lock);
+ return 0;
+ }
+
+@@ -1259,11 +1279,11 @@ void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops)
+ {
+ struct saa7134_dev *dev;
+
+- mutex_lock(&devlist_lock);
++ mutex_lock(&saa7134_devlist_lock);
+ list_del(&ops->next);
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ mpeg_ops_detach(ops, dev);
+- mutex_unlock(&devlist_lock);
++ mutex_unlock(&saa7134_devlist_lock);
+ }
+
+ EXPORT_SYMBOL(saa7134_ts_register);
+@@ -1307,8 +1327,6 @@ module_exit(saa7134_fini);
+ /* ----------------------------------------------------------- */
+
+ EXPORT_SYMBOL(saa7134_set_gpio);
+-EXPORT_SYMBOL(saa7134_i2c_call_clients);
+-EXPORT_SYMBOL(saa7134_devlist);
+ EXPORT_SYMBOL(saa7134_boards);
+
+ /* ----------------- for the DMA sound modules --------------- */
+diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
+index b5370b3..4eff1ca 100644
+--- a/drivers/media/video/saa7134/saa7134-dvb.c
++++ b/drivers/media/video/saa7134/saa7134-dvb.c
+@@ -48,9 +48,15 @@
+ #include "isl6405.h"
+ #include "lnbp21.h"
+ #include "tuner-simple.h"
++#include "tda18271.h"
++#include "lgdt3305.h"
++#include "tda8290.h"
+
+ #include "zl10353.h"
+
++#include "zl10036.h"
++#include "mt312.h"
++
+ MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+ MODULE_LICENSE("GPL");
+
+@@ -189,7 +195,7 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+- saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
++ saa_call_all(dev, tuner, s_frequency, &f);
+ msg.buf = on;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+@@ -950,6 +956,45 @@ static struct nxt200x_config kworldatsc110 = {
+ .demod_address = 0x0a,
+ };
+
++/* ------------------------------------------------------------------ */
++
++static struct mt312_config avertv_a700_mt312 = {
++ .demod_address = 0x0e,
++ .voltage_inverted = 1,
++};
++
++static struct zl10036_config avertv_a700_tuner = {
++ .tuner_address = 0x60,
++};
++
++static struct lgdt3305_config hcw_lgdt3305_config = {
++ .i2c_addr = 0x0e,
++ .mpeg_mode = LGDT3305_MPEG_SERIAL,
++ .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE,
++ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
++ .deny_i2c_rptr = 1,
++ .spectral_inversion = 1,
++ .qam_if_khz = 4000,
++ .vsb_if_khz = 3250,
++};
++
++static struct tda18271_std_map hauppauge_tda18271_std_map = {
++ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
++ .if_lvl = 1, .rfagc_top = 0x58, },
++ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
++ .if_lvl = 1, .rfagc_top = 0x58, },
++};
++
++static struct tda18271_config hcw_tda18271_config = {
++ .std_map = &hauppauge_tda18271_std_map,
++ .gate = TDA18271_GATE_ANALOG,
++ .config = 3,
++};
++
++static struct tda829x_config tda829x_no_probe = {
++ .probe_tuner = TDA829X_DONT_PROBE,
++};
++
+ /* ==================================================================
+ * Core code
+ */
+@@ -1076,6 +1121,19 @@ static int dvb_init(struct saa7134_dev *dev)
+ &tda827x_cfg_1) < 0)
+ goto dettach_frontend;
+ break;
++ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
++ fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
++ &hcw_lgdt3305_config,
++ &dev->i2c_adap);
++ if (fe0->dvb.frontend) {
++ dvb_attach(tda829x_attach, fe0->dvb.frontend,
++ &dev->i2c_adap, 0x4b,
++ &tda829x_no_probe);
++ dvb_attach(tda18271_attach, fe0->dvb.frontend,
++ 0x60, &dev->i2c_adap,
++ &hcw_tda18271_config);
++ }
++ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
+ &tda827x_cfg_0) < 0)
+@@ -1376,6 +1434,19 @@ static int dvb_init(struct saa7134_dev *dev)
+ TUNER_PHILIPS_FMD1216ME_MK3);
+ }
+ break;
++ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
++ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
++ /* Zarlink ZL10313 */
++ fe0->dvb.frontend = dvb_attach(mt312_attach,
++ &avertv_a700_mt312, &dev->i2c_adap);
++ if (fe0->dvb.frontend) {
++ if (dvb_attach(zl10036_attach, fe0->dvb.frontend,
++ &avertv_a700_tuner, &dev->i2c_adap) == NULL) {
++ wprintk("%s: No zl10036 found!\n",
++ __func__);
++ }
++ }
++ break;
+ default:
+ wprintk("Huh? unknown DVB card?\n");
+ break;
+@@ -1449,7 +1520,7 @@ static int dvb_fini(struct saa7134_dev *dev)
+ tda9887_cfg.priv = &on;
+
+ /* otherwise we don't detect the tuner on next insmod */
+- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg);
++ saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+ } else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) {
+ if ((dev->eedata[2] == 0x07) && use_frontend) {
+ /* turn off the 2nd lnb supply */
+diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
+index c9d8beb..9db3472 100644
+--- a/drivers/media/video/saa7134/saa7134-empress.c
++++ b/drivers/media/video/saa7134/saa7134-empress.c
+@@ -76,7 +76,7 @@ static int ts_init_encoder(struct saa7134_dev* dev)
+ break;
+ }
+ ts_reset_encoder(dev);
+- saa7134_i2c_call_clients(dev, VIDIOC_INT_INIT, &leading_null_bytes);
++ saa_call_all(dev, core, init, leading_null_bytes);
+ dev->empress_started = 1;
+ return 0;
+ }
+@@ -234,7 +234,7 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
+ {
+ struct saa7134_dev *dev = file->private_data;
+
+- saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f);
++ saa_call_all(dev, video, g_fmt, f);
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
+@@ -247,7 +247,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
+ {
+ struct saa7134_dev *dev = file->private_data;
+
+- saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f);
++ saa_call_all(dev, video, s_fmt, f);
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
+@@ -317,7 +317,7 @@ static int empress_s_ext_ctrls(struct file *file, void *priv,
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+- err = saa7134_i2c_call_saa6752(dev, VIDIOC_S_EXT_CTRLS, ctrls);
++ err = saa_call_empress(dev, core, s_ext_ctrls, ctrls);
+ ts_init_encoder(dev);
+
+ return err;
+@@ -330,7 +330,7 @@ static int empress_g_ext_ctrls(struct file *file, void *priv,
+
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+- return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls);
++ return saa_call_empress(dev, core, g_ext_ctrls, ctrls);
+ }
+
+ static int empress_g_ctrl(struct file *file, void *priv,
+@@ -352,6 +352,7 @@ static int empress_s_ctrl(struct file *file, void *priv,
+ static int empress_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+ {
++ /* Must be sorted from low to high control ID! */
+ static const u32 user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+@@ -364,6 +365,7 @@ static int empress_queryctrl(struct file *file, void *priv,
+ 0
+ };
+
++ /* Must be sorted from low to high control ID! */
+ static const u32 mpeg_ctrls[] = {
+ V4L2_CID_MPEG_CLASS,
+ V4L2_CID_MPEG_STREAM_TYPE,
+@@ -388,10 +390,10 @@ static int empress_queryctrl(struct file *file, void *priv,
+ if (c->id == 0)
+ return -EINVAL;
+ if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS)
+- return v4l2_ctrl_query_fill_std(c);
++ return v4l2_ctrl_query_fill(c, 0, 0, 0, 0);
+ if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+ return saa7134_queryctrl(file, priv, c);
+- return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYCTRL, c);
++ return saa_call_empress(dev, core, queryctrl, c);
+ }
+
+ static int empress_querymenu(struct file *file, void *priv,
+@@ -401,7 +403,7 @@ static int empress_querymenu(struct file *file, void *priv,
+
+ if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+- return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c);
++ return saa_call_empress(dev, core, querymenu, c);
+ }
+
+ static int empress_g_chip_ident(struct file *file, void *fh,
+@@ -411,14 +413,11 @@ static int empress_g_chip_ident(struct file *file, void *fh,
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+- if (dev->mpeg_i2c_client == NULL)
+- return -EINVAL;
+ if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER &&
+ !strcmp(chip->match.name, "saa6752hs"))
+- return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip);
+- if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR &&
+- chip->match.addr == dev->mpeg_i2c_client->addr)
+- return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip);
++ return saa_call_empress(dev, core, g_chip_ident, chip);
++ if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR)
++ return saa_call_empress(dev, core, g_chip_ident, chip);
+ return -EINVAL;
+ }
+
+diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
+index 20c1b33..f3e285a 100644
+--- a/drivers/media/video/saa7134/saa7134-i2c.c
++++ b/drivers/media/video/saa7134/saa7134-i2c.c
+@@ -255,7 +255,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
+ addr = msgs[i].addr << 1;
+ if (msgs[i].flags & I2C_M_RD)
+ addr |= 1;
+- if (i > 0 && msgs[i].flags & I2C_M_RD) {
++ if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) {
+ /* workaround for a saa7134 i2c bug
+ * needed to talk to the mt352 demux
+ * thanks to pinnacle for the hint */
+@@ -327,8 +327,6 @@ static int attach_inform(struct i2c_client *client)
+
+ d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
+ client->driver->driver.name, client->addr, client->name);
+- if (client->addr == 0x20 && client->driver && client->driver->command)
+- dev->mpeg_i2c_client = client;
+
+ /* Am I an i2c remote control? */
+
+@@ -357,7 +355,6 @@ static struct i2c_algorithm saa7134_algo = {
+
+ static struct i2c_adapter saa7134_adap_template = {
+ .owner = THIS_MODULE,
+- .class = I2C_CLASS_TV_ANALOG,
+ .name = "saa7134",
+ .id = I2C_HW_SAA7134,
+ .algo = &saa7134_algo,
+@@ -421,29 +418,13 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
+ }
+ }
+
+-void saa7134_i2c_call_clients(struct saa7134_dev *dev,
+- unsigned int cmd, void *arg)
+-{
+- BUG_ON(NULL == dev->i2c_adap.algo_data);
+- i2c_clients_command(&dev->i2c_adap, cmd, arg);
+-}
+-
+-int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
+- unsigned int cmd, void *arg)
+-{
+- if (dev->mpeg_i2c_client == NULL)
+- return -EINVAL;
+- return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client,
+- cmd, arg);
+-}
+-EXPORT_SYMBOL_GPL(saa7134_i2c_call_saa6752);
+-
+ int saa7134_i2c_register(struct saa7134_dev *dev)
+ {
+ dev->i2c_adap = saa7134_adap_template;
+ dev->i2c_adap.dev.parent = &dev->pci->dev;
+ strcpy(dev->i2c_adap.name,dev->name);
+ dev->i2c_adap.algo_data = dev;
++ i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+ i2c_add_adapter(&dev->i2c_adap);
+
+ dev->i2c_client = saa7134_client_template;
+diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
+index ef55a59..cc8b923 100644
+--- a/drivers/media/video/saa7134/saa7134-ts.c
++++ b/drivers/media/video/saa7134/saa7134-ts.c
+@@ -79,8 +79,19 @@ static int buffer_activate(struct saa7134_dev *dev,
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+
+ /* Start TS stream */
+- saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+- saa_writeb(SAA7134_TS_PARALLEL, 0xEC);
++ switch (saa7134_boards[dev->board].ts_type) {
++ case SAA7134_MPEG_TS_PARALLEL:
++ saa_writeb(SAA7134_TS_SERIAL0, 0x40);
++ saa_writeb(SAA7134_TS_PARALLEL, 0xec);
++ break;
++ case SAA7134_MPEG_TS_SERIAL:
++ saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
++ saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
++ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
++ saa_writeb(SAA7134_TS_SERIAL1, 0x02);
++ break;
++ }
++
+ dev->ts_state = SAA7134_TS_STARTED;
+ }
+
+diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
+index a1f7e35..404f70e 100644
+--- a/drivers/media/video/saa7134/saa7134-video.c
++++ b/drivers/media/video/saa7134/saa7134-video.c
+@@ -30,11 +30,7 @@
+ #include "saa7134-reg.h"
+ #include "saa7134.h"
+ #include <media/v4l2-common.h>
+-
+-#ifdef CONFIG_VIDEO_V4L1_COMPAT
+-/* Include V4L1 specific functions. Should be removed soon */
+-#include <linux/videodev.h>
+-#endif
++#include <media/rds.h>
+
+ /* ------------------------------------------------------------------ */
+
+@@ -452,6 +448,7 @@ static const struct v4l2_queryctrl video_ctrls[] = {
+ .name = "y offset odd field",
+ .minimum = 0,
+ .maximum = 128,
++ .step = 1,
+ .default_value = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+@@ -459,6 +456,7 @@ static const struct v4l2_queryctrl video_ctrls[] = {
+ .name = "y offset even field",
+ .minimum = 0,
+ .maximum = 128,
++ .step = 1,
+ .default_value = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+@@ -627,10 +625,10 @@ void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
+ saa7134_set_decoder(dev);
+
+ if (card_in(dev, dev->ctl_input).tv)
+- saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
++ saa_call_all(dev, tuner, s_std, dev->tvnorm->id);
+ /* Set the correct norm for the saa6752hs. This function
+ does nothing if there is no saa6752hs. */
+- saa7134_i2c_call_saa6752(dev, VIDIOC_S_STD, &dev->tvnorm->id);
++ saa_call_empress(dev, tuner, s_std, dev->tvnorm->id);
+ }
+
+ static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
+@@ -1266,8 +1264,7 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str
+ else
+ dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
+
+- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
+- &tda9887_cfg);
++ saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+ }
+ break;
+ }
+@@ -1334,7 +1331,7 @@ static int video_open(struct file *file)
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ int radio = 0;
+
+- lock_kernel();
++ mutex_lock(&saa7134_devlist_lock);
+ list_for_each_entry(dev, &saa7134_devlist, devlist) {
+ if (dev->video_dev && (dev->video_dev->minor == minor))
+ goto found;
+@@ -1347,19 +1344,20 @@ static int video_open(struct file *file)
+ goto found;
+ }
+ }
+- unlock_kernel();
++ mutex_unlock(&saa7134_devlist_lock);
+ return -ENODEV;
+- found:
++
++found:
++ mutex_unlock(&saa7134_devlist_lock);
+
+ dprintk("open minor=%d radio=%d type=%s\n",minor,radio,
+ v4l2_type_names[type]);
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+- if (NULL == fh) {
+- unlock_kernel();
++ if (NULL == fh)
+ return -ENOMEM;
+- }
++
+ file->private_data = fh;
+ fh->dev = dev;
+ fh->radio = radio;
+@@ -1387,12 +1385,11 @@ static int video_open(struct file *file)
+ if (fh->radio) {
+ /* switch to radio mode */
+ saa7134_tvaudio_setinput(dev,&card(dev).radio);
+- saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL);
++ saa_call_all(dev, tuner, s_radio);
+ } else {
+ /* switch to video/vbi mode */
+ video_mux(dev,dev->ctl_input);
+ }
+- unlock_kernel();
+ return 0;
+ }
+
+@@ -1466,6 +1463,7 @@ static int video_release(struct file *file)
+ {
+ struct saa7134_fh *fh = file->private_data;
+ struct saa7134_dev *dev = fh->dev;
++ struct rds_command cmd;
+ unsigned long flags;
+
+ /* turn off overlay */
+@@ -1498,7 +1496,9 @@ static int video_release(struct file *file)
+ saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0);
+ saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
+
+- saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
++ saa_call_all(dev, core, s_standby, 0);
++ if (fh->radio)
++ saa_call_all(dev, core, ioctl, RDS_CMD_CLOSE, &cmd);
+
+ /* free stuff */
+ videobuf_mmap_free(&fh->cap);
+@@ -1519,6 +1519,37 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma)
+ return videobuf_mmap_mapper(saa7134_queue(fh), vma);
+ }
+
++static ssize_t radio_read(struct file *file, char __user *data,
++ size_t count, loff_t *ppos)
++{
++ struct saa7134_fh *fh = file->private_data;
++ struct saa7134_dev *dev = fh->dev;
++ struct rds_command cmd;
++
++ cmd.block_count = count/3;
++ cmd.buffer = data;
++ cmd.instance = file;
++ cmd.result = -ENODEV;
++
++ saa_call_all(dev, core, ioctl, RDS_CMD_READ, &cmd);
++
++ return cmd.result;
++}
++
++static unsigned int radio_poll(struct file *file, poll_table *wait)
++{
++ struct saa7134_fh *fh = file->private_data;
++ struct saa7134_dev *dev = fh->dev;
++ struct rds_command cmd;
++
++ cmd.instance = file;
++ cmd.event_list = wait;
++ cmd.result = -ENODEV;
++ saa_call_all(dev, core, ioctl, RDS_CMD_POLL, &cmd);
++
++ return cmd.result;
++}
++
+ /* ------------------------------------------------------------------ */
+
+ static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
+@@ -2041,7 +2072,7 @@ static int saa7134_s_frequency(struct file *file, void *priv,
+ mutex_lock(&dev->lock);
+ dev->ctl_freq = f->frequency;
+
+- saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
++ saa_call_all(dev, tuner, s_frequency, f);
+
+ saa7134_tvaudio_do_scan(dev);
+ mutex_unlock(&dev->lock);
+@@ -2299,7 +2330,7 @@ static int radio_g_tuner(struct file *file, void *priv,
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
+
+- saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
++ saa_call_all(dev, tuner, g_tuner, t);
+ if (dev->input->amux == TV) {
+ t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
+ t->rxsubchans = (saa_readb(0x529) & 0x08) ?
+@@ -2316,7 +2347,7 @@ static int radio_s_tuner(struct file *file, void *priv,
+ if (0 != t->index)
+ return -EINVAL;
+
+- saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
++ saa_call_all(dev, tuner, s_tuner, t);
+ return 0;
+ }
+
+@@ -2443,8 +2474,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
+ static const struct v4l2_file_operations radio_fops = {
+ .owner = THIS_MODULE,
+ .open = video_open,
++ .read = radio_read,
+ .release = video_release,
+ .ioctl = video_ioctl2,
++ .poll = radio_poll,
+ };
+
+ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
+index 14ee265..a2dd326 100644
+--- a/drivers/media/video/saa7134/saa7134.h
++++ b/drivers/media/video/saa7134/saa7134.h
+@@ -35,6 +35,7 @@
+
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-ioctl.h>
++#include <media/v4l2-device.h>
+ #include <media/tuner.h>
+ #include <media/ir-common.h>
+ #include <media/ir-kbd-i2c.h>
+@@ -277,6 +278,8 @@ struct saa7134_format {
+ #define SAA7134_BOARD_ASUSTeK_TIGER 152
+ #define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
+ #define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
++#define SAA7134_BOARD_HAUPPAUGE_HVR1120 155
++#define SAA7134_BOARD_HAUPPAUGE_HVR1110R3 156
+
+ #define SAA7134_MAXBOARDS 32
+ #define SAA7134_INPUT_MAX 8
+@@ -309,6 +312,11 @@ enum saa7134_mpeg_type {
+ SAA7134_MPEG_DVB,
+ };
+
++enum saa7134_mpeg_ts_type {
++ SAA7134_MPEG_TS_PARALLEL = 0,
++ SAA7134_MPEG_TS_SERIAL,
++};
++
+ struct saa7134_board {
+ char *name;
+ unsigned int audio_clock;
+@@ -324,6 +332,8 @@ struct saa7134_board {
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
++ unsigned char empress_addr;
++ unsigned char rds_addr;
+
+ unsigned int tda9887_conf;
+ unsigned int tuner_config;
+@@ -331,6 +341,7 @@ struct saa7134_board {
+ /* peripheral I/O */
+ enum saa7134_video_out video_out;
+ enum saa7134_mpeg_type mpeg;
++ enum saa7134_mpeg_ts_type ts_type;
+ unsigned int vid_port_opts;
+ };
+
+@@ -445,7 +456,6 @@ struct saa7134_dmasound {
+ unsigned int bufsize;
+ struct saa7134_pgtable pt;
+ struct videobuf_dmabuf dma;
+- wait_queue_head_t wq;
+ unsigned int dma_blk;
+ unsigned int read_offset;
+ unsigned int read_count;
+@@ -482,6 +492,7 @@ struct saa7134_dev {
+ struct mutex lock;
+ spinlock_t slock;
+ struct v4l2_prio_state prio;
++ struct v4l2_device v4l2_dev;
+ /* workstruct for loading modules */
+ struct work_struct request_module_wk;
+
+@@ -572,7 +583,6 @@ struct saa7134_dev {
+ enum saa7134_ts_status ts_state;
+ unsigned int buff_cnt;
+ struct saa7134_mpeg_ops *mops;
+- struct i2c_client *mpeg_i2c_client;
+
+ /* SAA7134_MPEG_EMPRESS only */
+ struct video_device *empress_dev;
+@@ -588,6 +598,7 @@ struct saa7134_dev {
+ int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+ int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
+ #endif
++ void (*gate_ctrl)(struct saa7134_dev *dev, int open);
+ };
+
+ /* ----------------------------------------------------------- */
+@@ -616,10 +627,31 @@ struct saa7134_dev {
+ V4L2_STD_NTSC | V4L2_STD_PAL_M | \
+ V4L2_STD_PAL_60)
+
++#define GRP_EMPRESS (1)
++#define saa_call_all(dev, o, f, args...) do { \
++ if (dev->gate_ctrl) \
++ dev->gate_ctrl(dev, 1); \
++ v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \
++ if (dev->gate_ctrl) \
++ dev->gate_ctrl(dev, 0); \
++} while (0)
++
++#define saa_call_empress(dev, o, f, args...) ({ \
++ long _rc; \
++ if (dev->gate_ctrl) \
++ dev->gate_ctrl(dev, 1); \
++ _rc = v4l2_device_call_until_err(&(dev)->v4l2_dev, \
++ GRP_EMPRESS, o, f , ##args); \
++ if (dev->gate_ctrl) \
++ dev->gate_ctrl(dev, 0); \
++ _rc; \
++})
++
+ /* ----------------------------------------------------------- */
+ /* saa7134-core.c */
+
+ extern struct list_head saa7134_devlist;
++extern struct mutex saa7134_devlist_lock;
+ extern int saa7134_no_overlay;
+
+ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
+@@ -668,10 +700,6 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg);
+
+ int saa7134_i2c_register(struct saa7134_dev *dev);
+ int saa7134_i2c_unregister(struct saa7134_dev *dev);
+-void saa7134_i2c_call_clients(struct saa7134_dev *dev,
+- unsigned int cmd, void *arg);
+-int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
+- unsigned int cmd, void *arg);
+
+
+ /* ----------------------------------------------------------- */
+diff --git a/drivers/media/video/saa7146.h b/drivers/media/video/saa7146.h
+index 2830b5e..9fadb33 100644
+--- a/drivers/media/video/saa7146.h
++++ b/drivers/media/video/saa7146.h
+@@ -25,8 +25,6 @@
+ #include <linux/types.h>
+ #include <linux/wait.h>
+
+-#include <linux/videodev.h>
+-
+ #ifndef O_NONCAP
+ #define O_NONCAP O_TRUNC
+ #endif
+diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
+index 88c5e94..25bf230 100644
+--- a/drivers/media/video/saa717x.c
++++ b/drivers/media/video/saa717x.c
+@@ -931,7 +931,7 @@ static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ break;
+
+ case V4L2_CID_HUE:
+- if (ctrl->value < -127 || ctrl->value > 127) {
++ if (ctrl->value < -128 || ctrl->value > 127) {
+ v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+@@ -1380,11 +1380,6 @@ static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+ return 0;
+ }
+
+-static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops saa717x_core_ops = {
+@@ -1528,10 +1523,7 @@ MODULE_DEVICE_TABLE(i2c, saa717x_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa717x",
+- .driverid = I2C_DRIVERID_SAA717X,
+- .command = saa717x_command,
+ .probe = saa717x_probe,
+ .remove = saa717x_remove,
+- .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+ .id_table = saa717x_id,
+ };
+diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
+index 6debb65..75747b1 100644
+--- a/drivers/media/video/saa7185.c
++++ b/drivers/media/video/saa7185.c
+@@ -30,52 +30,58 @@
+ #include <asm/uaccess.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-id.h>
+-#include <linux/videodev.h>
+-#include <linux/video_encoder.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
+ MODULE_AUTHOR("Dave Perks");
+ MODULE_LICENSE("GPL");
+
+-
+ static int debug;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
++
+ /* ----------------------------------------------------------------------- */
+
+ struct saa7185 {
++ struct v4l2_subdev sd;
+ unsigned char reg[128];
+
+- int norm;
+- int enable;
+- int bright;
+- int contrast;
+- int hue;
+- int sat;
++ v4l2_std_id norm;
+ };
+
++static inline struct saa7185 *to_saa7185(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct saa7185, sd);
++}
++
+ /* ----------------------------------------------------------------------- */
+
+-static inline int saa7185_read(struct i2c_client *client)
++static inline int saa7185_read(struct v4l2_subdev *sd)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
+ return i2c_smbus_read_byte(client);
+ }
+
+-static int saa7185_write(struct i2c_client *client, u8 reg, u8 value)
++static int saa7185_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+ {
+- struct saa7185 *encoder = i2c_get_clientdata(client);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct saa7185 *encoder = to_saa7185(sd);
+
+- v4l_dbg(1, debug, client, "%02x set to %02x\n", reg, value);
++ v4l2_dbg(1, debug, sd, "%02x set to %02x\n", reg, value);
+ encoder->reg[reg] = value;
+ return i2c_smbus_write_byte_data(client, reg, value);
+ }
+
+-static int saa7185_write_block(struct i2c_client *client,
++static int saa7185_write_block(struct v4l2_subdev *sd,
+ const u8 *data, unsigned int len)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct saa7185 *encoder = to_saa7185(sd);
+ int ret = -1;
+ u8 reg;
+
+@@ -83,7 +89,6 @@ static int saa7185_write_block(struct i2c_client *client,
+ * 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);
+ u8 block_data[32];
+ int block_len;
+
+@@ -104,7 +109,7 @@ static int saa7185_write_block(struct i2c_client *client,
+ /* do some slow I2C emulation kind of thing */
+ while (len >= 2) {
+ reg = *data++;
+- ret = saa7185_write(client, reg, *data++);
++ ret = saa7185_write(sd, reg, *data++);
+ if (ret < 0)
+ break;
+ len -= 2;
+@@ -213,133 +218,106 @@ static const unsigned char init_ntsc[] = {
+ 0x66, 0x21, /* FSC3 */
+ };
+
+-static int saa7185_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- struct saa7185 *encoder = i2c_get_clientdata(client);
+-
+- switch (cmd) {
+- case 0:
+- saa7185_write_block(client, init_common,
+- sizeof(init_common));
+- switch (encoder->norm) {
+-
+- case VIDEO_MODE_NTSC:
+- saa7185_write_block(client, init_ntsc,
+- sizeof(init_ntsc));
+- break;
+-
+- case VIDEO_MODE_PAL:
+- saa7185_write_block(client, init_pal,
+- sizeof(init_pal));
+- break;
+- }
+- break;
+
+- case ENCODER_GET_CAPABILITIES:
+- {
+- struct video_encoder_capability *cap = arg;
++static int saa7185_init(struct v4l2_subdev *sd, u32 val)
++{
++ struct saa7185 *encoder = to_saa7185(sd);
+
+- cap->flags =
+- VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC |
+- VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR;
+- cap->inputs = 1;
+- cap->outputs = 1;
+- break;
+- }
++ saa7185_write_block(sd, init_common, sizeof(init_common));
++ if (encoder->norm & V4L2_STD_NTSC)
++ saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
++ else
++ saa7185_write_block(sd, init_pal, sizeof(init_pal));
++ return 0;
++}
+
+- case ENCODER_SET_NORM:
+- {
+- int *iarg = arg;
++static int saa7185_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
++{
++ struct saa7185 *encoder = to_saa7185(sd);
+
+- //saa7185_write_block(client, init_common, sizeof(init_common));
++ if (std & V4L2_STD_NTSC)
++ saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
++ else if (std & V4L2_STD_PAL)
++ saa7185_write_block(sd, init_pal, sizeof(init_pal));
++ else
++ return -EINVAL;
++ encoder->norm = std;
++ return 0;
++}
+
+- switch (*iarg) {
+- case VIDEO_MODE_NTSC:
+- saa7185_write_block(client, init_ntsc,
+- sizeof(init_ntsc));
+- break;
++static int saa7185_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
++{
++ struct saa7185 *encoder = to_saa7185(sd);
+
+- case VIDEO_MODE_PAL:
+- saa7185_write_block(client, init_pal,
+- sizeof(init_pal));
+- break;
++ /* RJ: route->input = 0: input is from SA7111
++ route->input = 1: input is from ZR36060 */
+
+- case VIDEO_MODE_SECAM:
+- default:
+- return -EINVAL;
+- }
+- encoder->norm = *iarg;
+- break;
+- }
+-
+- case ENCODER_SET_INPUT:
+- {
+- int *iarg = arg;
+-
+- /* RJ: *iarg = 0: input is from SA7111
+- *iarg = 1: input is from ZR36060 */
+-
+- switch (*iarg) {
+- 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 */
+- saa7185_write(client, 0x61,
+- (encoder->reg[0x61] & 0xf7) | 0x00);
+- /* SW: a slight sync problem... */
+- saa7185_write(client, 0x6e, 0x00);
+- break;
+-
+- default:
+- return -EINVAL;
+- }
++ switch (route->input) {
++ case 0:
++ /* turn off colorbar */
++ saa7185_write(sd, 0x3a, 0x0f);
++ /* Switch RTCE to 1 */
++ saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
++ saa7185_write(sd, 0x6e, 0x01);
+ break;
+- }
+
+- case ENCODER_SET_OUTPUT:
+- {
+- int *iarg = arg;
+-
+- /* not much choice of outputs */
+- if (*iarg != 0)
+- return -EINVAL;
++ case 1:
++ /* turn off colorbar */
++ saa7185_write(sd, 0x3a, 0x0f);
++ /* Switch RTCE to 0 */
++ saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00);
++ /* SW: a slight sync problem... */
++ saa7185_write(sd, 0x6e, 0x00);
+ break;
+- }
+-
+- case ENCODER_ENABLE_OUTPUT:
+- {
+- int *iarg = arg;
+
+- encoder->enable = !!*iarg;
+- saa7185_write(client, 0x61,
+- (encoder->reg[0x61] & 0xbf) |
+- (encoder->enable ? 0x00 : 0x40));
++ case 2:
++ /* turn on colorbar */
++ saa7185_write(sd, 0x3a, 0x8f);
++ /* Switch RTCE to 0 */
++ saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
++ /* SW: a slight sync problem... */
++ saa7185_write(sd, 0x6e, 0x01);
+ break;
+- }
+
+ default:
+ return -EINVAL;
+ }
+-
+ return 0;
+ }
+
++static int saa7185_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7185, 0);
++}
++
+ /* ----------------------------------------------------------------------- */
+
+-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
++static const struct v4l2_subdev_core_ops saa7185_core_ops = {
++ .g_chip_ident = saa7185_g_chip_ident,
++ .init = saa7185_init,
++};
+
+-I2C_CLIENT_INSMOD;
++static const struct v4l2_subdev_video_ops saa7185_video_ops = {
++ .s_std_output = saa7185_s_std_output,
++ .s_routing = saa7185_s_routing,
++};
++
++static const struct v4l2_subdev_ops saa7185_ops = {
++ .core = &saa7185_core_ops,
++ .video = &saa7185_video_ops,
++};
++
++
++/* ----------------------------------------------------------------------- */
+
+ static int saa7185_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ int i;
+ struct saa7185 *encoder;
++ struct v4l2_subdev *sd;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+@@ -351,28 +329,29 @@ static int saa7185_probe(struct i2c_client *client,
+ encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
+ if (encoder == NULL)
+ return -ENOMEM;
+- encoder->norm = VIDEO_MODE_NTSC;
+- encoder->enable = 1;
+- i2c_set_clientdata(client, encoder);
++ encoder->norm = V4L2_STD_NTSC;
++ sd = &encoder->sd;
++ v4l2_i2c_subdev_init(sd, client, &saa7185_ops);
+
+- i = saa7185_write_block(client, init_common, sizeof(init_common));
++ i = saa7185_write_block(sd, init_common, sizeof(init_common));
+ if (i >= 0)
+- i = saa7185_write_block(client, init_ntsc, sizeof(init_ntsc));
++ i = saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
+ if (i < 0)
+- v4l_dbg(1, debug, client, "init error %d\n", i);
++ v4l2_dbg(1, debug, sd, "init error %d\n", i);
+ else
+- v4l_dbg(1, debug, client, "revision 0x%x\n",
+- saa7185_read(client) >> 5);
++ v4l2_dbg(1, debug, sd, "revision 0x%x\n",
++ saa7185_read(sd) >> 5);
+ return 0;
+ }
+
+ static int saa7185_remove(struct i2c_client *client)
+ {
+- struct saa7185 *encoder = i2c_get_clientdata(client);
+-
+- saa7185_write(client, 0x61, (encoder->reg[0x61]) | 0x40); /* SW: output off is active */
+- //saa7185_write(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct saa7185 *encoder = to_saa7185(sd);
+
++ v4l2_device_unregister_subdev(sd);
++ /* SW: output off is active */
++ saa7185_write(sd, 0x61, (encoder->reg[0x61]) | 0x40);
+ kfree(encoder);
+ return 0;
+ }
+@@ -387,8 +366,6 @@ MODULE_DEVICE_TABLE(i2c, saa7185_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa7185",
+- .driverid = I2C_DRIVERID_SAA7185B,
+- .command = saa7185_command,
+ .probe = saa7185_probe,
+ .remove = saa7185_remove,
+ .id_table = saa7185_id,
+diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
+index b4018cc..3f523ae 100644
+--- a/drivers/media/video/saa7191.c
++++ b/drivers/media/video/saa7191.c
+@@ -19,9 +19,11 @@
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+
+-#include <linux/videodev.h>
+-#include <linux/video_decoder.h>
++#include <linux/videodev2.h>
+ #include <linux/i2c.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ #include "saa7191.h"
+
+@@ -32,6 +34,7 @@ MODULE_VERSION(SAA7191_MODULE_VERSION);
+ MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
+ MODULE_LICENSE("GPL");
+
++
+ // #define SAA7191_DEBUG
+
+ #ifdef SAA7191_DEBUG
+@@ -44,17 +47,20 @@ MODULE_LICENSE("GPL");
+ #define SAA7191_SYNC_DELAY 100 /* milliseconds */
+
+ struct saa7191 {
+- struct i2c_client *client;
++ struct v4l2_subdev sd;
+
+ /* the register values are stored here as the actual
+ * I2C-registers are write-only */
+ u8 reg[25];
+
+ int input;
+- int norm;
++ v4l2_std_id norm;
+ };
+
+-static struct i2c_driver i2c_driver_saa7191;
++static inline struct saa7191 *to_saa7191(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct saa7191, sd);
++}
+
+ static const u8 initseq[] = {
+ 0, /* Subaddress */
+@@ -100,15 +106,14 @@ static const u8 initseq[] = {
+
+ /* SAA7191 register handling */
+
+-static u8 saa7191_read_reg(struct i2c_client *client,
+- u8 reg)
++static u8 saa7191_read_reg(struct v4l2_subdev *sd, u8 reg)
+ {
+- return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg];
++ return to_saa7191(sd)->reg[reg];
+ }
+
+-static int saa7191_read_status(struct i2c_client *client,
+- u8 *value)
++static int saa7191_read_status(struct v4l2_subdev *sd, u8 *value)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ ret = i2c_master_recv(client, value, 1);
+@@ -121,21 +126,23 @@ static int saa7191_read_status(struct i2c_client *client,
+ }
+
+
+-static int saa7191_write_reg(struct i2c_client *client, u8 reg,
+- u8 value)
++static int saa7191_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
+ {
+- ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ to_saa7191(sd)->reg[reg] = value;
+ return i2c_smbus_write_byte_data(client, reg, value);
+ }
+
+ /* the first byte of data must be the first subaddress number (register) */
+-static int saa7191_write_block(struct i2c_client *client,
++static int saa7191_write_block(struct v4l2_subdev *sd,
+ u8 length, const u8 *data)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct saa7191 *decoder = to_saa7191(sd);
+ int i;
+ int ret;
+
+- struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client);
+ for (i = 0; i < (length - 1); i++) {
+ decoder->reg[data[0] + i] = data[i + 1];
+ }
+@@ -152,14 +159,15 @@ static int saa7191_write_block(struct i2c_client *client,
+
+ /* Helper functions */
+
+-static int saa7191_set_input(struct i2c_client *client, int input)
++static int saa7191_s_routing(struct v4l2_subdev *sd,
++ const struct v4l2_routing *route)
+ {
+- struct saa7191 *decoder = i2c_get_clientdata(client);
+- u8 luma = saa7191_read_reg(client, SAA7191_REG_LUMA);
+- u8 iock = saa7191_read_reg(client, SAA7191_REG_IOCK);
++ struct saa7191 *decoder = to_saa7191(sd);
++ u8 luma = saa7191_read_reg(sd, SAA7191_REG_LUMA);
++ u8 iock = saa7191_read_reg(sd, SAA7191_REG_IOCK);
+ int err;
+
+- switch (input) {
++ switch (route->input) {
+ case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
+ iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
+ | SAA7191_IOCK_GPSW2);
+@@ -175,54 +183,50 @@ static int saa7191_set_input(struct i2c_client *client, int input)
+ return -EINVAL;
+ }
+
+- err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma);
++ err = saa7191_write_reg(sd, SAA7191_REG_LUMA, luma);
+ if (err)
+ return -EIO;
+- err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock);
++ err = saa7191_write_reg(sd, SAA7191_REG_IOCK, iock);
+ if (err)
+ return -EIO;
+
+- decoder->input = input;
++ decoder->input = route->input;
+
+ return 0;
+ }
+
+-static int saa7191_set_norm(struct i2c_client *client, int norm)
++static int saa7191_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+ {
+- struct saa7191 *decoder = i2c_get_clientdata(client);
+- u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+- u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+- u8 chcv = saa7191_read_reg(client, SAA7191_REG_CHCV);
++ struct saa7191 *decoder = to_saa7191(sd);
++ u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
++ u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
++ u8 chcv = saa7191_read_reg(sd, SAA7191_REG_CHCV);
+ int err;
+
+- switch(norm) {
+- case SAA7191_NORM_PAL:
++ if (norm & V4L2_STD_PAL) {
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+ chcv = SAA7191_CHCV_PAL;
+- break;
+- case SAA7191_NORM_NTSC:
++ } else if (norm & V4L2_STD_NTSC) {
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~SAA7191_CTL3_AUFD;
+ ctl3 |= SAA7191_CTL3_FSEL;
+ chcv = SAA7191_CHCV_NTSC;
+- break;
+- case SAA7191_NORM_SECAM:
++ } else if (norm & V4L2_STD_SECAM) {
+ stdc |= SAA7191_STDC_SECS;
+ ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
+ chcv = SAA7191_CHCV_PAL;
+- break;
+- default:
++ } else {
+ return -EINVAL;
+ }
+
+- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
++ err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
+ if (err)
+ return -EIO;
+- err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
++ err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
+ if (err)
+ return -EIO;
+- err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv);
++ err = saa7191_write_reg(sd, SAA7191_REG_CHCV, chcv);
+ if (err)
+ return -EIO;
+
+@@ -230,19 +234,19 @@ static int saa7191_set_norm(struct i2c_client *client, int norm)
+
+ dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3,
+ stdc, chcv);
+- dprintk("norm: %d\n", norm);
++ dprintk("norm: %llx\n", norm);
+
+ return 0;
+ }
+
+-static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status)
++static int saa7191_wait_for_signal(struct v4l2_subdev *sd, u8 *status)
+ {
+ int i = 0;
+
+ dprintk("Checking for signal...\n");
+
+ for (i = 0; i < SAA7191_SYNC_COUNT; i++) {
+- if (saa7191_read_status(client, status))
++ if (saa7191_read_status(sd, status))
+ return -EIO;
+
+ if (((*status) & SAA7191_STATUS_HLCK) == 0) {
+@@ -258,31 +262,34 @@ static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status)
+ return -EBUSY;
+ }
+
+-static int saa7191_autodetect_norm_extended(struct i2c_client *client)
++static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
+ {
+- u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC);
+- u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
++ struct saa7191 *decoder = to_saa7191(sd);
++ u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
++ u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+ u8 status;
++ v4l2_std_id old_norm = decoder->norm;
+ int err = 0;
+
+ dprintk("SAA7191 extended signal auto-detection...\n");
+
++ *norm = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+ stdc &= ~SAA7191_STDC_SECS;
+ ctl3 &= ~(SAA7191_CTL3_FSEL);
+
+- err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc);
++ err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
+ if (err) {
+ err = -EIO;
+ goto out;
+ }
+- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
++ err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
+ if (err) {
+ err = -EIO;
+ goto out;
+ }
+
+ ctl3 |= SAA7191_CTL3_AUFD;
+- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
++ err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
+ if (err) {
+ err = -EIO;
+ goto out;
+@@ -290,53 +297,54 @@ static int saa7191_autodetect_norm_extended(struct i2c_client *client)
+
+ msleep(SAA7191_SYNC_DELAY);
+
+- err = saa7191_wait_for_signal(client, &status);
++ err = saa7191_wait_for_signal(sd, &status);
+ if (err)
+ goto out;
+
+ if (status & SAA7191_STATUS_FIDT) {
+ /* 60Hz signal -> NTSC */
+ dprintk("60Hz signal: NTSC\n");
+- return saa7191_set_norm(client, SAA7191_NORM_NTSC);
++ *norm = V4L2_STD_NTSC;
++ return 0;
+ }
+
+ /* 50Hz signal */
+ dprintk("50Hz signal: Trying PAL...\n");
+
+ /* try PAL first */
+- err = saa7191_set_norm(client, SAA7191_NORM_PAL);
++ err = saa7191_s_std(sd, V4L2_STD_PAL);
+ if (err)
+ goto out;
+
+ msleep(SAA7191_SYNC_DELAY);
+
+- err = saa7191_wait_for_signal(client, &status);
++ err = saa7191_wait_for_signal(sd, &status);
+ if (err)
+ goto out;
+
+ /* not 50Hz ? */
+ if (status & SAA7191_STATUS_FIDT) {
+ dprintk("No 50Hz signal\n");
+- err = -EAGAIN;
+- goto out;
++ saa7191_s_std(sd, old_norm);
++ return -EAGAIN;
+ }
+
+ if (status & SAA7191_STATUS_CODE) {
+ dprintk("PAL\n");
+- return 0;
++ *norm = V4L2_STD_PAL;
++ return saa7191_s_std(sd, old_norm);
+ }
+
+ dprintk("No color detected with PAL - Trying SECAM...\n");
+
+ /* no color detected ? -> try SECAM */
+- err = saa7191_set_norm(client,
+- SAA7191_NORM_SECAM);
++ err = saa7191_s_std(sd, V4L2_STD_SECAM);
+ if (err)
+ goto out;
+
+ msleep(SAA7191_SYNC_DELAY);
+
+- err = saa7191_wait_for_signal(client, &status);
++ err = saa7191_wait_for_signal(sd, &status);
+ if (err)
+ goto out;
+
+@@ -350,32 +358,17 @@ static int saa7191_autodetect_norm_extended(struct i2c_client *client)
+ if (status & SAA7191_STATUS_CODE) {
+ /* Color detected -> SECAM */
+ dprintk("SECAM\n");
+- return 0;
++ *norm = V4L2_STD_SECAM;
++ return saa7191_s_std(sd, old_norm);
+ }
+
+ dprintk("No color detected with SECAM - Going back to PAL.\n");
+
+- /* still no color detected ?
+- * -> set norm back to PAL */
+- err = saa7191_set_norm(client,
+- SAA7191_NORM_PAL);
+- if (err)
+- goto out;
+-
+ out:
+- ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3);
+- if (ctl3 & SAA7191_CTL3_AUFD) {
+- ctl3 &= ~(SAA7191_CTL3_AUFD);
+- err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3);
+- if (err) {
+- err = -EIO;
+- }
+- }
+-
+- return err;
++ return saa7191_s_std(sd, old_norm);
+ }
+
+-static int saa7191_autodetect_norm(struct i2c_client *client)
++static int saa7191_autodetect_norm(struct v4l2_subdev *sd)
+ {
+ u8 status;
+
+@@ -383,7 +376,7 @@ static int saa7191_autodetect_norm(struct i2c_client *client)
+
+ dprintk("Reading status...\n");
+
+- if (saa7191_read_status(client, &status))
++ if (saa7191_read_status(sd, &status))
+ return -EIO;
+
+ dprintk("Checking for signal...\n");
+@@ -399,26 +392,25 @@ static int saa7191_autodetect_norm(struct i2c_client *client)
+ if (status & SAA7191_STATUS_FIDT) {
+ /* 60hz signal -> NTSC */
+ dprintk("NTSC\n");
+- return saa7191_set_norm(client, SAA7191_NORM_NTSC);
++ return saa7191_s_std(sd, V4L2_STD_NTSC);
+ } else {
+ /* 50hz signal -> PAL */
+ dprintk("PAL\n");
+- return saa7191_set_norm(client, SAA7191_NORM_PAL);
++ return saa7191_s_std(sd, V4L2_STD_PAL);
+ }
+ }
+
+-static int saa7191_get_control(struct i2c_client *client,
+- struct saa7191_control *ctrl)
++static int saa7191_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ {
+ u8 reg;
+ int ret = 0;
+
+- switch (ctrl->type) {
++ switch (ctrl->id) {
+ case SAA7191_CONTROL_BANDPASS:
+ case SAA7191_CONTROL_BANDPASS_WEIGHT:
+ case SAA7191_CONTROL_CORING:
+- reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
+- switch (ctrl->type) {
++ reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
++ switch (ctrl->id) {
+ case SAA7191_CONTROL_BANDPASS:
+ ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK)
+ >> SAA7191_LUMA_BPSS_SHIFT;
+@@ -435,15 +427,15 @@ static int saa7191_get_control(struct i2c_client *client,
+ break;
+ case SAA7191_CONTROL_FORCE_COLOUR:
+ case SAA7191_CONTROL_CHROMA_GAIN:
+- reg = saa7191_read_reg(client, SAA7191_REG_GAIN);
+- if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR)
++ reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
++ if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR)
+ ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0;
+ else
+ ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK)
+ >> SAA7191_GAIN_LFIS_SHIFT;
+ break;
+- case SAA7191_CONTROL_HUE:
+- reg = saa7191_read_reg(client, SAA7191_REG_HUEC);
++ case V4L2_CID_HUE:
++ reg = saa7191_read_reg(sd, SAA7191_REG_HUEC);
+ if (reg < 0x80)
+ reg += 0x80;
+ else
+@@ -451,18 +443,18 @@ static int saa7191_get_control(struct i2c_client *client,
+ ctrl->value = (s32)reg;
+ break;
+ case SAA7191_CONTROL_VTRC:
+- reg = saa7191_read_reg(client, SAA7191_REG_STDC);
++ reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
+ ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0;
+ break;
+ case SAA7191_CONTROL_LUMA_DELAY:
+- reg = saa7191_read_reg(client, SAA7191_REG_CTL3);
++ reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+ ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK)
+ >> SAA7191_CTL3_YDEL_SHIFT;
+ if (ctrl->value >= 4)
+ ctrl->value -= 8;
+ break;
+ case SAA7191_CONTROL_VNR:
+- reg = saa7191_read_reg(client, SAA7191_REG_CTL4);
++ reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
+ ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK)
+ >> SAA7191_CTL4_VNOI_SHIFT;
+ break;
+@@ -473,18 +465,17 @@ static int saa7191_get_control(struct i2c_client *client,
+ return ret;
+ }
+
+-static int saa7191_set_control(struct i2c_client *client,
+- struct saa7191_control *ctrl)
++static int saa7191_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ {
+ u8 reg;
+ int ret = 0;
+
+- switch (ctrl->type) {
++ switch (ctrl->id) {
+ case SAA7191_CONTROL_BANDPASS:
+ case SAA7191_CONTROL_BANDPASS_WEIGHT:
+ case SAA7191_CONTROL_CORING:
+- reg = saa7191_read_reg(client, SAA7191_REG_LUMA);
+- switch (ctrl->type) {
++ reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
++ switch (ctrl->id) {
+ case SAA7191_CONTROL_BANDPASS:
+ reg &= ~SAA7191_LUMA_BPSS_MASK;
+ reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT)
+@@ -501,12 +492,12 @@ static int saa7191_set_control(struct i2c_client *client,
+ & SAA7191_LUMA_CORI_MASK;
+ break;
+ }
+- ret = saa7191_write_reg(client, SAA7191_REG_LUMA, reg);
++ ret = saa7191_write_reg(sd, SAA7191_REG_LUMA, reg);
+ break;
+ case SAA7191_CONTROL_FORCE_COLOUR:
+ case SAA7191_CONTROL_CHROMA_GAIN:
+- reg = saa7191_read_reg(client, SAA7191_REG_GAIN);
+- if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR) {
++ reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
++ if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) {
+ if (ctrl->value)
+ reg |= SAA7191_GAIN_COLO;
+ else
+@@ -516,41 +507,41 @@ static int saa7191_set_control(struct i2c_client *client,
+ reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT)
+ & SAA7191_GAIN_LFIS_MASK;
+ }
+- ret = saa7191_write_reg(client, SAA7191_REG_GAIN, reg);
++ ret = saa7191_write_reg(sd, SAA7191_REG_GAIN, reg);
+ break;
+- case SAA7191_CONTROL_HUE:
++ case V4L2_CID_HUE:
+ reg = ctrl->value & 0xff;
+ if (reg < 0x80)
+ reg += 0x80;
+ else
+ reg -= 0x80;
+- ret = saa7191_write_reg(client, SAA7191_REG_HUEC, reg);
++ ret = saa7191_write_reg(sd, SAA7191_REG_HUEC, reg);
+ break;
+ case SAA7191_CONTROL_VTRC:
+- reg = saa7191_read_reg(client, SAA7191_REG_STDC);
++ reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
+ if (ctrl->value)
+ reg |= SAA7191_STDC_VTRC;
+ else
+ reg &= ~SAA7191_STDC_VTRC;
+- ret = saa7191_write_reg(client, SAA7191_REG_STDC, reg);
++ ret = saa7191_write_reg(sd, SAA7191_REG_STDC, reg);
+ break;
+ case SAA7191_CONTROL_LUMA_DELAY: {
+ s32 value = ctrl->value;
+ if (value < 0)
+ value += 8;
+- reg = saa7191_read_reg(client, SAA7191_REG_CTL3);
++ reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
+ reg &= ~SAA7191_CTL3_YDEL_MASK;
+ reg |= (value << SAA7191_CTL3_YDEL_SHIFT)
+ & SAA7191_CTL3_YDEL_MASK;
+- ret = saa7191_write_reg(client, SAA7191_REG_CTL3, reg);
++ ret = saa7191_write_reg(sd, SAA7191_REG_CTL3, reg);
+ break;
+ }
+ case SAA7191_CONTROL_VNR:
+- reg = saa7191_read_reg(client, SAA7191_REG_CTL4);
++ reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
+ reg &= ~SAA7191_CTL4_VNOI_MASK;
+ reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT)
+ & SAA7191_CTL4_VNOI_MASK;
+- ret = saa7191_write_reg(client, SAA7191_REG_CTL4, reg);
++ ret = saa7191_write_reg(sd, SAA7191_REG_CTL4, reg);
+ break;
+ default:
+ ret = -EINVAL;
+@@ -561,247 +552,108 @@ static int saa7191_set_control(struct i2c_client *client,
+
+ /* I2C-interface */
+
+-static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
++static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
+ {
+- int err = 0;
+- struct saa7191 *decoder;
+- struct i2c_client *client;
+-
+- printk(KERN_INFO "Philips SAA7191 driver version %s\n",
+- SAA7191_MODULE_VERSION);
+-
+- client = kzalloc(sizeof(*client), GFP_KERNEL);
+- if (!client)
+- return -ENOMEM;
+- decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+- if (!decoder) {
+- err = -ENOMEM;
+- goto out_free_client;
+- }
+-
+- client->addr = addr;
+- client->adapter = adap;
+- client->driver = &i2c_driver_saa7191;
+- client->flags = 0;
+- strcpy(client->name, "saa7191 client");
+- i2c_set_clientdata(client, decoder);
+-
+- decoder->client = client;
+-
+- err = i2c_attach_client(client);
+- if (err)
+- goto out_free_decoder;
+-
+- err = saa7191_write_block(client, sizeof(initseq), initseq);
+- if (err) {
+- printk(KERN_ERR "SAA7191 initialization failed\n");
+- goto out_detach_client;
+- }
+-
+- printk(KERN_INFO "SAA7191 initialized\n");
+-
+- decoder->input = SAA7191_INPUT_COMPOSITE;
+- decoder->norm = SAA7191_NORM_PAL;
+-
+- err = saa7191_autodetect_norm(client);
+- if (err && (err != -EBUSY)) {
+- printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
+- }
++ u8 status_reg;
++ int res = V4L2_IN_ST_NO_SIGNAL;
+
++ if (saa7191_read_status(sd, &status_reg))
++ return -EIO;
++ if ((status_reg & SAA7191_STATUS_HLCK) == 0)
++ res = 0;
++ if (!(status_reg & SAA7191_STATUS_CODE))
++ res |= V4L2_IN_ST_NO_COLOR;
++ *status = res;
+ return 0;
+-
+-out_detach_client:
+- i2c_detach_client(client);
+-out_free_decoder:
+- kfree(decoder);
+-out_free_client:
+- kfree(client);
+- return err;
+ }
+
+-static int saa7191_probe(struct i2c_adapter *adap)
+-{
+- /* Always connected to VINO */
+- if (adap->id == I2C_HW_SGI_VINO)
+- return saa7191_attach(adap, SAA7191_ADDR, 0);
+- /* Feel free to add probe here :-) */
+- return -ENODEV;
+-}
+
+-static int saa7191_detach(struct i2c_client *client)
++static int saa7191_g_chip_ident(struct v4l2_subdev *sd,
++ struct v4l2_dbg_chip_ident *chip)
+ {
+- struct saa7191 *decoder = i2c_get_clientdata(client);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- i2c_detach_client(client);
+- kfree(decoder);
+- kfree(client);
+- return 0;
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7191, 0);
+ }
+
+-static int saa7191_command(struct i2c_client *client, unsigned int cmd,
+- void *arg)
+-{
+- struct saa7191 *decoder = i2c_get_clientdata(client);
++/* ----------------------------------------------------------------------- */
+
+- switch (cmd) {
+- case DECODER_GET_CAPABILITIES: {
+- struct video_decoder_capability *cap = arg;
++static const struct v4l2_subdev_core_ops saa7191_core_ops = {
++ .g_chip_ident = saa7191_g_chip_ident,
++ .g_ctrl = saa7191_g_ctrl,
++ .s_ctrl = saa7191_s_ctrl,
++};
+
+- cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
+- VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
+- cap->inputs = (client->adapter->id == I2C_HW_SGI_VINO) ? 2 : 1;
+- cap->outputs = 1;
+- break;
+- }
+- case DECODER_GET_STATUS: {
+- int *iarg = arg;
+- u8 status;
+- int res = 0;
++static const struct v4l2_subdev_tuner_ops saa7191_tuner_ops = {
++ .s_std = saa7191_s_std,
++};
+
+- if (saa7191_read_status(client, &status)) {
+- return -EIO;
+- }
+- if ((status & SAA7191_STATUS_HLCK) == 0)
+- res |= DECODER_STATUS_GOOD;
+- if (status & SAA7191_STATUS_CODE)
+- res |= DECODER_STATUS_COLOR;
+- switch (decoder->norm) {
+- case SAA7191_NORM_NTSC:
+- res |= DECODER_STATUS_NTSC;
+- break;
+- case SAA7191_NORM_PAL:
+- res |= DECODER_STATUS_PAL;
+- break;
+- case SAA7191_NORM_SECAM:
+- res |= DECODER_STATUS_SECAM;
+- break;
+- case SAA7191_NORM_AUTO:
+- default:
+- if (status & SAA7191_STATUS_FIDT)
+- res |= DECODER_STATUS_NTSC;
+- else
+- res |= DECODER_STATUS_PAL;
+- break;
+- }
+- *iarg = res;
+- break;
+- }
+- case DECODER_SET_NORM: {
+- int *iarg = arg;
+-
+- switch (*iarg) {
+- case VIDEO_MODE_AUTO:
+- return saa7191_autodetect_norm(client);
+- case VIDEO_MODE_PAL:
+- return saa7191_set_norm(client, SAA7191_NORM_PAL);
+- case VIDEO_MODE_NTSC:
+- return saa7191_set_norm(client, SAA7191_NORM_NTSC);
+- case VIDEO_MODE_SECAM:
+- return saa7191_set_norm(client, SAA7191_NORM_SECAM);
+- default:
+- return -EINVAL;
+- }
+- break;
+- }
+- case DECODER_SET_INPUT: {
+- int *iarg = arg;
+-
+- switch (client->adapter->id) {
+- case I2C_HW_SGI_VINO:
+- return saa7191_set_input(client, *iarg);
+- default:
+- if (*iarg != 0)
+- return -EINVAL;
+- }
+- break;
+- }
+- case DECODER_SET_OUTPUT: {
+- int *iarg = arg;
++static const struct v4l2_subdev_video_ops saa7191_video_ops = {
++ .s_routing = saa7191_s_routing,
++ .querystd = saa7191_querystd,
++ .g_input_status = saa7191_g_input_status,
++};
+
+- /* not much choice of outputs */
+- if (*iarg != 0)
+- return -EINVAL;
+- break;
+- }
+- case DECODER_ENABLE_OUTPUT: {
+- /* Always enabled */
+- break;
+- }
+- case DECODER_SET_PICTURE: {
+- struct video_picture *pic = arg;
+- unsigned val;
+- int err;
++static const struct v4l2_subdev_ops saa7191_ops = {
++ .core = &saa7191_core_ops,
++ .video = &saa7191_video_ops,
++ .tuner = &saa7191_tuner_ops,
++};
+
+- val = (pic->hue >> 8) - 0x80;
++static int saa7191_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ int err = 0;
++ struct saa7191 *decoder;
++ struct v4l2_subdev *sd;
+
+- err = saa7191_write_reg(client, SAA7191_REG_HUEC, val);
+- if (err)
+- return -EIO;
++ v4l_info(client, "chip found @ 0x%x (%s)\n",
++ client->addr << 1, client->adapter->name);
+
+- break;
+- }
+- case DECODER_SAA7191_GET_STATUS: {
+- struct saa7191_status *status = arg;
+- u8 status_reg;
++ decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
++ if (!decoder)
++ return -ENOMEM;
+
+- if (saa7191_read_status(client, &status_reg))
+- return -EIO;
++ sd = &decoder->sd;
++ v4l2_i2c_subdev_init(sd, client, &saa7191_ops);
+
+- status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0)
+- ? 1 : 0;
+- status->signal_60hz = (status_reg & SAA7191_STATUS_FIDT)
+- ? 1 : 0;
+- status->color = (status_reg & SAA7191_STATUS_CODE) ? 1 : 0;
++ err = saa7191_write_block(sd, sizeof(initseq), initseq);
++ if (err) {
++ printk(KERN_ERR "SAA7191 initialization failed\n");
++ kfree(decoder);
++ return err;
++ }
+
+- status->input = decoder->input;
+- status->norm = decoder->norm;
++ printk(KERN_INFO "SAA7191 initialized\n");
+
+- break;
+- }
+- case DECODER_SAA7191_SET_NORM: {
+- int *norm = arg;
+-
+- switch (*norm) {
+- case SAA7191_NORM_AUTO:
+- return saa7191_autodetect_norm(client);
+- case SAA7191_NORM_AUTO_EXT:
+- return saa7191_autodetect_norm_extended(client);
+- default:
+- return saa7191_set_norm(client, *norm);
+- }
+- }
+- case DECODER_SAA7191_GET_CONTROL: {
+- return saa7191_get_control(client, arg);
+- }
+- case DECODER_SAA7191_SET_CONTROL: {
+- return saa7191_set_control(client, arg);
+- }
+- default:
+- return -EINVAL;
+- }
++ decoder->input = SAA7191_INPUT_COMPOSITE;
++ decoder->norm = V4L2_STD_PAL;
++
++ err = saa7191_autodetect_norm(sd);
++ if (err && (err != -EBUSY))
++ printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
+
+ return 0;
+ }
+
+-static struct i2c_driver i2c_driver_saa7191 = {
+- .driver = {
+- .name = "saa7191",
+- },
+- .id = I2C_DRIVERID_SAA7191,
+- .attach_adapter = saa7191_probe,
+- .detach_client = saa7191_detach,
+- .command = saa7191_command
+-};
+-
+-static int saa7191_init(void)
++static int saa7191_remove(struct i2c_client *client)
+ {
+- return i2c_add_driver(&i2c_driver_saa7191);
+-}
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+-static void saa7191_exit(void)
+-{
+- i2c_del_driver(&i2c_driver_saa7191);
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_saa7191(sd));
++ return 0;
+ }
+
+-module_init(saa7191_init);
+-module_exit(saa7191_exit);
++static const struct i2c_device_id saa7191_id[] = {
++ { "saa7191", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, saa7191_id);
++
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++ .name = "saa7191",
++ .probe = saa7191_probe,
++ .remove = saa7191_remove,
++ .id_table = saa7191_id,
++};
+diff --git a/drivers/media/video/saa7191.h b/drivers/media/video/saa7191.h
+index a2310da..803c74d 100644
+--- a/drivers/media/video/saa7191.h
++++ b/drivers/media/video/saa7191.h
+@@ -176,11 +176,9 @@
+ #define SAA7191_INPUT_COMPOSITE 0
+ #define SAA7191_INPUT_SVIDEO 1
+
+-#define SAA7191_NORM_AUTO 0
+ #define SAA7191_NORM_PAL 1
+ #define SAA7191_NORM_NTSC 2
+ #define SAA7191_NORM_SECAM 3
+-#define SAA7191_NORM_AUTO_EXT 4 /* extended auto-detection */
+
+ struct saa7191_status {
+ /* 0=no signal, 1=signal detected */
+@@ -232,24 +230,16 @@ struct saa7191_status {
+ #define SAA7191_VNR_MAX 0x03
+ #define SAA7191_VNR_DEFAULT 0x00
+
+-#define SAA7191_CONTROL_BANDPASS 0
+-#define SAA7191_CONTROL_BANDPASS_WEIGHT 1
+-#define SAA7191_CONTROL_CORING 2
+-#define SAA7191_CONTROL_FORCE_COLOUR 3 /* boolean */
+-#define SAA7191_CONTROL_CHROMA_GAIN 4
+-#define SAA7191_CONTROL_HUE 5
+-#define SAA7191_CONTROL_VTRC 6 /* boolean */
+-#define SAA7191_CONTROL_LUMA_DELAY 7
+-#define SAA7191_CONTROL_VNR 8
+-
+-struct saa7191_control {
+- u8 type;
+- s32 value;
+-};
++#define SAA7191_CONTROL_BANDPASS (V4L2_CID_PRIVATE_BASE + 0)
++#define SAA7191_CONTROL_BANDPASS_WEIGHT (V4L2_CID_PRIVATE_BASE + 1)
++#define SAA7191_CONTROL_CORING (V4L2_CID_PRIVATE_BASE + 2)
++#define SAA7191_CONTROL_FORCE_COLOUR (V4L2_CID_PRIVATE_BASE + 3)
++#define SAA7191_CONTROL_CHROMA_GAIN (V4L2_CID_PRIVATE_BASE + 4)
++#define SAA7191_CONTROL_VTRC (V4L2_CID_PRIVATE_BASE + 5)
++#define SAA7191_CONTROL_LUMA_DELAY (V4L2_CID_PRIVATE_BASE + 6)
++#define SAA7191_CONTROL_VNR (V4L2_CID_PRIVATE_BASE + 7)
+
+ #define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status)
+ #define DECODER_SAA7191_SET_NORM _IOW('d', 196, int)
+-#define DECODER_SAA7191_GET_CONTROL _IOR('d', 197, struct saa7191_control)
+-#define DECODER_SAA7191_SET_CONTROL _IOW('d', 198, struct saa7191_control)
+
+ #endif
+diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
+index ddcb81d..b5e37a5 100644
+--- a/drivers/media/video/sh_mobile_ceu_camera.c
++++ b/drivers/media/video/sh_mobile_ceu_camera.c
+@@ -94,13 +94,37 @@ struct sh_mobile_ceu_dev {
+ spinlock_t lock;
+ struct list_head capture;
+ struct videobuf_buffer *active;
+- int is_interlace;
++ int is_interlaced;
+
+ struct sh_mobile_ceu_info *pdata;
+
+ const struct soc_camera_data_format *camera_fmt;
+ };
+
++static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev)
++{
++ unsigned long flags;
++
++ flags = SOCAM_MASTER |
++ SOCAM_PCLK_SAMPLE_RISING |
++ SOCAM_HSYNC_ACTIVE_HIGH |
++ SOCAM_HSYNC_ACTIVE_LOW |
++ SOCAM_VSYNC_ACTIVE_HIGH |
++ SOCAM_VSYNC_ACTIVE_LOW |
++ SOCAM_DATA_ACTIVE_HIGH;
++
++ if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS)
++ flags |= SOCAM_DATAWIDTH_8;
++
++ if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS)
++ flags |= SOCAM_DATAWIDTH_16;
++
++ if (flags & SOCAM_DATAWIDTH_MASK)
++ return flags;
++
++ return 0;
++}
++
+ static void ceu_write(struct sh_mobile_ceu_dev *priv,
+ unsigned long reg_offs, u32 data)
+ {
+@@ -150,6 +174,7 @@ static void free_buffer(struct videobuf_queue *vq,
+ if (in_interrupt())
+ BUG();
+
++ videobuf_waiton(&buf->vb, 0, 0);
+ videobuf_dma_contig_free(vq, &buf->vb);
+ dev_dbg(&icd->dev, "%s freed\n", __func__);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+@@ -181,7 +206,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
+
+ phys_addr_top = videobuf_to_dma_contig(pcdev->active);
+ ceu_write(pcdev, CDAYR, phys_addr_top);
+- if (pcdev->is_interlace) {
++ if (pcdev->is_interlaced) {
+ phys_addr_bottom = phys_addr_top + icd->width;
+ ceu_write(pcdev, CDBYR, phys_addr_bottom);
+ }
+@@ -193,7 +218,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
+ case V4L2_PIX_FMT_NV61:
+ phys_addr_top += icd->width * icd->height;
+ ceu_write(pcdev, CDACR, phys_addr_top);
+- if (pcdev->is_interlace) {
++ if (pcdev->is_interlaced) {
+ phys_addr_bottom = phys_addr_top + icd->width;
+ ceu_write(pcdev, CDBCR, phys_addr_bottom);
+ }
+@@ -396,7 +421,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
+
+ camera_flags = icd->ops->query_bus_param(icd);
+ common_flags = soc_camera_bus_param_compatible(camera_flags,
+- pcdev->pdata->flags);
++ make_bus_param(pcdev));
+ if (!common_flags)
+ return -EINVAL;
+
+@@ -457,7 +482,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
+ ceu_write(pcdev, CAMCR, value);
+
+ ceu_write(pcdev, CAPCR, 0x00300000);
+- ceu_write(pcdev, CAIFR, (pcdev->is_interlace) ? 0x101 : 0);
++ ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0);
+
+ mdelay(1);
+
+@@ -473,7 +498,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
+ }
+
+ height = icd->height;
+- if (pcdev->is_interlace) {
++ if (pcdev->is_interlaced) {
+ height /= 2;
+ cdwdr_width *= 2;
+ }
+@@ -517,7 +542,7 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd)
+
+ camera_flags = icd->ops->query_bus_param(icd);
+ common_flags = soc_camera_bus_param_compatible(camera_flags,
+- pcdev->pdata->flags);
++ make_bus_param(pcdev));
+ if (!common_flags)
+ return -EINVAL;
+
+@@ -562,11 +587,29 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
+ if (ret < 0)
+ return 0;
+
++ /* Beginning of a pass */
++ if (!idx)
++ icd->host_priv = NULL;
++
+ switch (icd->formats[idx].fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
++ if (icd->host_priv)
++ goto add_single_format;
++
++ /*
++ * Our case is simple so far: for any of the above four camera
++ * formats we add all our four synthesized NV* formats, so,
++ * just marking the device with a single flag suffices. If
++ * the format generation rules are more complex, you would have
++ * to actually hang your already added / counted formats onto
++ * the host_priv pointer and check whether the format you're
++ * going to add now is already there.
++ */
++ icd->host_priv = (void *)sh_mobile_ceu_formats;
++
+ n = ARRAY_SIZE(sh_mobile_ceu_formats);
+ formats += n;
+ for (k = 0; xlate && k < n; k++) {
+@@ -579,6 +622,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
+ icd->formats[idx].name);
+ }
+ default:
++add_single_format:
+ /* Generic pass-through */
+ formats++;
+ if (xlate) {
+@@ -595,24 +639,30 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
+ return formats;
+ }
+
++static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
++{
++ return icd->ops->set_crop(icd, rect);
++}
++
+ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
+- __u32 pixfmt, struct v4l2_rect *rect)
++ struct v4l2_format *f)
+ {
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
++ __u32 pixfmt = f->fmt.pix.pixelformat;
+ const struct soc_camera_format_xlate *xlate;
++ struct v4l2_format cam_f = *f;
+ int ret;
+
+- if (!pixfmt)
+- return icd->ops->set_fmt(icd, pixfmt, rect);
+-
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+- ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
++ cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
++ ret = icd->ops->set_fmt(icd, &cam_f);
+
+ if (!ret) {
+ icd->buswidth = xlate->buswidth;
+@@ -662,13 +712,13 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
+
+ switch (f->fmt.pix.field) {
+ case V4L2_FIELD_INTERLACED:
+- pcdev->is_interlace = 1;
++ pcdev->is_interlaced = 1;
+ break;
+ case V4L2_FIELD_ANY:
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ /* fall-through */
+ case V4L2_FIELD_NONE:
+- pcdev->is_interlace = 0;
++ pcdev->is_interlaced = 0;
+ break;
+ default:
+ ret = -EINVAL;
+@@ -734,7 +784,8 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
+ &sh_mobile_ceu_videobuf_ops,
+ &ici->dev, &pcdev->lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+- V4L2_FIELD_ANY,
++ pcdev->is_interlaced ?
++ V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE,
+ sizeof(struct sh_mobile_ceu_buffer),
+ icd);
+ }
+@@ -744,6 +795,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
+ .add = sh_mobile_ceu_add_device,
+ .remove = sh_mobile_ceu_remove_device,
+ .get_formats = sh_mobile_ceu_get_formats,
++ .set_crop = sh_mobile_ceu_set_crop,
+ .set_fmt = sh_mobile_ceu_set_fmt,
+ .try_fmt = sh_mobile_ceu_try_fmt,
+ .reqbufs = sh_mobile_ceu_reqbufs,
+diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
+index 8cb3457..38a7160 100644
+--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
++++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
+@@ -96,9 +96,7 @@ static const struct usb_device_id sn9c102_id_table[] = {
+ #if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+ { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
+-#endif
+ { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
+-#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+ { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
+ #endif
+ { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
+@@ -123,7 +121,9 @@ static const struct usb_device_id sn9c102_id_table[] = {
+ { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
+ #endif
+ { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
++#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+ { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
++#endif
+ { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
+ { }
+ };
+diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
+index fcb05f0..6d8bfd4 100644
+--- a/drivers/media/video/soc_camera.c
++++ b/drivers/media/video/soc_camera.c
+@@ -30,6 +30,10 @@
+ #include <media/videobuf-core.h>
+ #include <media/soc_camera.h>
+
++/* Default to VGA resolution */
++#define DEFAULT_WIDTH 640
++#define DEFAULT_HEIGHT 480
++
+ static LIST_HEAD(hosts);
+ static LIST_HEAD(devices);
+ static DEFINE_MUTEX(list_lock);
+@@ -256,6 +260,46 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
+ vfree(icd->user_formats);
+ }
+
++/* Called with .vb_lock held */
++static int soc_camera_set_fmt(struct soc_camera_file *icf,
++ struct v4l2_format *f)
++{
++ struct soc_camera_device *icd = icf->icd;
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ int ret;
++
++ /* We always call try_fmt() before set_fmt() or set_crop() */
++ ret = ici->ops->try_fmt(icd, f);
++ if (ret < 0)
++ return ret;
++
++ ret = ici->ops->set_fmt(icd, f);
++ if (ret < 0) {
++ return ret;
++ } else if (!icd->current_fmt ||
++ icd->current_fmt->fourcc != pix->pixelformat) {
++ dev_err(&ici->dev,
++ "Host driver hasn't set up current format correctly!\n");
++ return -EINVAL;
++ }
++
++ icd->width = pix->width;
++ icd->height = pix->height;
++ icf->vb_vidq.field =
++ icd->field = pix->field;
++
++ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
++ f->type);
++
++ dev_dbg(&icd->dev, "set width: %d height: %d\n",
++ icd->width, icd->height);
++
++ /* set physical bus parameters */
++ return ici->ops->set_bus_param(icd, pix->pixelformat);
++}
++
+ static int soc_camera_open(struct file *file)
+ {
+ struct video_device *vdev;
+@@ -297,14 +341,28 @@ static int soc_camera_open(struct file *file)
+
+ /* Now we really have to activate the camera */
+ if (icd->use_count == 1) {
+- ret = soc_camera_init_user_formats(icd);
+- if (ret < 0)
+- goto eiufmt;
++ /* Restore parameters before the last close() per V4L2 API */
++ struct v4l2_format f = {
++ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
++ .fmt.pix = {
++ .width = icd->width,
++ .height = icd->height,
++ .field = icd->field,
++ .pixelformat = icd->current_fmt->fourcc,
++ .colorspace = icd->current_fmt->colorspace,
++ },
++ };
++
+ ret = ici->ops->add(icd);
+ if (ret < 0) {
+ dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
+ goto eiciadd;
+ }
++
++ /* Try to configure with default parameters */
++ ret = soc_camera_set_fmt(icf, &f);
++ if (ret < 0)
++ goto esfmt;
+ }
+
+ mutex_unlock(&icd->video_lock);
+@@ -316,10 +374,13 @@ static int soc_camera_open(struct file *file)
+
+ return 0;
+
+- /* First two errors are entered with the .video_lock held */
++ /*
++ * First three errors are entered with the .video_lock held
++ * and use_count == 1
++ */
++esfmt:
++ ici->ops->remove(icd);
+ eiciadd:
+- soc_camera_free_user_formats(icd);
+-eiufmt:
+ icd->use_count--;
+ mutex_unlock(&icd->video_lock);
+ module_put(ici->ops->owner);
+@@ -339,10 +400,9 @@ static int soc_camera_close(struct file *file)
+
+ mutex_lock(&icd->video_lock);
+ icd->use_count--;
+- if (!icd->use_count) {
++ if (!icd->use_count)
+ ici->ops->remove(icd);
+- soc_camera_free_user_formats(icd);
+- }
++
+ mutex_unlock(&icd->video_lock);
+
+ module_put(icd->ops->owner);
+@@ -415,18 +475,10 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
+ {
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+- struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+- struct v4l2_pix_format *pix = &f->fmt.pix;
+- __u32 pixfmt = pix->pixelformat;
+ int ret;
+- struct v4l2_rect rect;
+
+ WARN_ON(priv != file->private_data);
+
+- ret = soc_camera_try_fmt_vid_cap(file, priv, f);
+- if (ret < 0)
+- return ret;
+-
+ mutex_lock(&icf->vb_vidq.vb_lock);
+
+ if (videobuf_queue_is_busy(&icf->vb_vidq)) {
+@@ -435,33 +487,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
+ goto unlock;
+ }
+
+- rect.left = icd->x_current;
+- rect.top = icd->y_current;
+- rect.width = pix->width;
+- rect.height = pix->height;
+- ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect);
+- if (ret < 0) {
+- goto unlock;
+- } else if (!icd->current_fmt ||
+- icd->current_fmt->fourcc != pixfmt) {
+- dev_err(&ici->dev,
+- "Host driver hasn't set up current format correctly!\n");
+- ret = -EINVAL;
+- goto unlock;
+- }
+-
+- icd->width = rect.width;
+- icd->height = rect.height;
+- icf->vb_vidq.field = pix->field;
+- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
+- f->type);
+-
+- dev_dbg(&icd->dev, "set width: %d height: %d\n",
+- icd->width, icd->height);
+-
+- /* set physical bus parameters */
+- ret = ici->ops->set_bus_param(icd, pixfmt);
++ ret = soc_camera_set_fmt(icf, f);
+
+ unlock:
+ mutex_unlock(&icf->vb_vidq.vb_lock);
+@@ -648,8 +674,8 @@ static int soc_camera_cropcap(struct file *file, void *fh,
+ a->bounds.height = icd->height_max;
+ a->defrect.left = icd->x_min;
+ a->defrect.top = icd->y_min;
+- a->defrect.width = 640;
+- a->defrect.height = 480;
++ a->defrect.width = DEFAULT_WIDTH;
++ a->defrect.height = DEFAULT_HEIGHT;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+@@ -685,7 +711,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
+ /* Cropping is allowed during a running capture, guard consistency */
+ mutex_lock(&icf->vb_vidq.vb_lock);
+
+- ret = ici->ops->set_fmt(icd, 0, &a->c);
++ ret = ici->ops->set_crop(icd, &a->c);
+ if (!ret) {
+ icd->width = a->c.width;
+ icd->height = a->c.height;
+@@ -844,9 +870,18 @@ static int soc_camera_probe(struct device *dev)
+ qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
+ icd->exposure = qctrl ? qctrl->default_value :
+ (unsigned short)~0;
++
++ ret = soc_camera_init_user_formats(icd);
++ if (ret < 0)
++ goto eiufmt;
++
++ icd->height = DEFAULT_HEIGHT;
++ icd->width = DEFAULT_WIDTH;
++ icd->field = V4L2_FIELD_ANY;
+ }
+- ici->ops->remove(icd);
+
++eiufmt:
++ ici->ops->remove(icd);
+ eiadd:
+ mutex_unlock(&icd->video_lock);
+ module_put(ici->ops->owner);
+@@ -865,6 +900,8 @@ static int soc_camera_remove(struct device *dev)
+ if (icd->ops->remove)
+ icd->ops->remove(icd);
+
++ soc_camera_free_user_formats(icd);
++
+ return 0;
+ }
+
+@@ -918,6 +955,7 @@ int soc_camera_host_register(struct soc_camera_host *ici)
+ if (!ici || !ici->ops ||
+ !ici->ops->try_fmt ||
+ !ici->ops->set_fmt ||
++ !ici->ops->set_crop ||
+ !ici->ops->set_bus_param ||
+ !ici->ops->querycap ||
+ !ici->ops->init_videobuf ||
+@@ -998,6 +1036,7 @@ int soc_camera_device_register(struct soc_camera_device *icd)
+ !icd->ops->release ||
+ !icd->ops->start_capture ||
+ !icd->ops->stop_capture ||
++ !icd->ops->set_crop ||
+ !icd->ops->set_fmt ||
+ !icd->ops->try_fmt ||
+ !icd->ops->query_bus_param ||
+diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
+index 013ab06..c486763 100644
+--- a/drivers/media/video/soc_camera_platform.c
++++ b/drivers/media/video/soc_camera_platform.c
+@@ -79,8 +79,14 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
+ return p->bus_param;
+ }
+
++static int soc_camera_platform_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
++{
++ return 0;
++}
++
+ static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
+- __u32 pixfmt, struct v4l2_rect *rect)
++ struct v4l2_format *f)
+ {
+ return 0;
+ }
+@@ -125,6 +131,7 @@ static struct soc_camera_ops soc_camera_platform_ops = {
+ .release = soc_camera_platform_release,
+ .start_capture = soc_camera_platform_start_capture,
+ .stop_capture = soc_camera_platform_stop_capture,
++ .set_crop = soc_camera_platform_set_crop,
+ .set_fmt = soc_camera_platform_set_fmt,
+ .try_fmt = soc_camera_platform_try_fmt,
+ .set_bus_param = soc_camera_platform_set_bus_param,
+diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
+index 26378cf..1a6d39c 100644
+--- a/drivers/media/video/stk-webcam.c
++++ b/drivers/media/video/stk-webcam.c
+@@ -933,8 +933,6 @@ static int stk_vidioc_s_ctrl(struct file *filp,
+ static int stk_vidioc_enum_fmt_vid_cap(struct file *filp,
+ void *priv, struct v4l2_fmtdesc *fmtd)
+ {
+- fmtd->flags = 0;
+-
+ switch (fmtd->index) {
+ case 0:
+ fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
+@@ -992,7 +990,6 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
+ pix_format->height = stk_sizes[i].h;
+ pix_format->field = V4L2_FIELD_NONE;
+ pix_format->colorspace = V4L2_COLORSPACE_SRGB;
+- pix_format->priv = 0;
+ pix_format->pixelformat = dev->vsettings.palette;
+ if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
+ pix_format->bytesperline = pix_format->width;
+@@ -1115,8 +1112,6 @@ static int stk_vidioc_reqbufs(struct file *filp,
+
+ if (dev == NULL)
+ return -ENODEV;
+- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+ if (rb->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+ if (is_streaming(dev)
+@@ -1139,16 +1134,10 @@ static int stk_vidioc_reqbufs(struct file *filp,
+ static int stk_vidioc_querybuf(struct file *filp,
+ void *priv, struct v4l2_buffer *buf)
+ {
+- int index;
+ struct stk_camera *dev = priv;
+ struct stk_sio_buffer *sbuf;
+
+- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+- index = buf->index;
+-
+- if (index < 0 || index >= dev->n_sbufs)
++ if (buf->index < 0 || buf->index >= dev->n_sbufs)
+ return -EINVAL;
+ sbuf = dev->sio_bufs + buf->index;
+ *buf = sbuf->v4lbuf;
+@@ -1161,8 +1150,6 @@ static int stk_vidioc_qbuf(struct file *filp,
+ struct stk_camera *dev = priv;
+ struct stk_sio_buffer *sbuf;
+ unsigned long flags;
+- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+@@ -1189,8 +1176,7 @@ static int stk_vidioc_dqbuf(struct file *filp,
+ unsigned long flags;
+ int ret;
+
+- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+- || !is_streaming(dev))
++ if (!is_streaming(dev))
+ return -EINVAL;
+
+ if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
+@@ -1249,16 +1235,10 @@ static int stk_vidioc_streamoff(struct file *filp,
+ static int stk_vidioc_g_parm(struct file *filp,
+ void *priv, struct v4l2_streamparm *sp)
+ {
+- if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+- sp->parm.capture.capability = 0;
+- sp->parm.capture.capturemode = 0;
+ /*FIXME This is not correct */
+ sp->parm.capture.timeperframe.numerator = 1;
+ sp->parm.capture.timeperframe.denominator = 30;
+ sp->parm.capture.readbuffers = 2;
+- sp->parm.capture.extendedmode = 0;
+ return 0;
+ }
+
+diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
+index 29991d1..b30c492 100644
+--- a/drivers/media/video/tcm825x.c
++++ b/drivers/media/video/tcm825x.c
+@@ -50,7 +50,7 @@ struct tcm825x_sensor {
+ };
+
+ /* list of image formats supported by TCM825X sensor */
+-const static struct v4l2_fmtdesc tcm825x_formats[] = {
++static const struct v4l2_fmtdesc tcm825x_formats[] = {
+ {
+ .description = "YUYV (YUV 4:2:2), packed",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+@@ -76,15 +76,15 @@ const static struct v4l2_fmtdesc tcm825x_formats[] = {
+ * TCM825X register configuration for all combinations of pixel format and
+ * image size
+ */
+-const static struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ };
+-const static struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ };
+-const static struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ };
+-const static struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ };
+-const static struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ };
+-const static struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ };
++static const struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ };
++static const struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ };
++static const struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ };
++static const struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ };
++static const struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ };
++static const struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ };
+
+-const static struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT };
+-const static struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT };
++static const struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT };
++static const struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT };
+
+ /* Our own specific controls */
+ #define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE
+@@ -248,10 +248,10 @@ static struct vcontrol {
+ };
+
+
+-const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
++static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
+ { &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
+
+-const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
++static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
+ { &yuv422, &rgb565 };
+
+ /*
+diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h
+index 770ebac..5b7e696 100644
+--- a/drivers/media/video/tcm825x.h
++++ b/drivers/media/video/tcm825x.h
+@@ -188,7 +188,7 @@ struct tcm825x_platform_data {
+ /* Array of image sizes supported by TCM825X. These must be ordered from
+ * smallest image size to largest.
+ */
+-const static struct capture_size tcm825x_sizes[] = {
++static const struct capture_size tcm825x_sizes[] = {
+ { 128, 96 }, /* subQCIF */
+ { 160, 120 }, /* QQVGA */
+ { 176, 144 }, /* QCIF */
+diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
+index 0c02058..005f8a4 100644
+--- a/drivers/media/video/tda7432.c
++++ b/drivers/media/video/tda7432.c
+@@ -50,7 +50,7 @@
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+ #include <media/i2c-addr.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
+
+ #ifndef VIDEO_AUDIO_BALANCE
+ # define VIDEO_AUDIO_BALANCE 32
+@@ -69,13 +69,6 @@ MODULE_PARM_DESC(maxvol,"Set maximium volume to +20db (0), default is 0db(1)");
+ module_param(maxvol, int, S_IRUGO | S_IWUSR);
+
+
+-/* Address to scan (I2C address of this chip) */
+-static unsigned short normal_i2c[] = {
+- I2C_ADDR_TDA7432 >> 1,
+- I2C_CLIENT_END,
+-};
+-
+-I2C_CLIENT_INSMOD;
+
+ /* Structure of address and subaddresses for the tda7432 */
+
+@@ -421,21 +414,18 @@ static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+ {
+ switch (qc->id) {
+- case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
++ case V4L2_CID_AUDIO_MUTE:
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+- return v4l2_ctrl_query_fill_std(qc);
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+ }
+ return -EINVAL;
+ }
+
+-static int tda7432_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops tda7432_core_ops = {
+@@ -498,8 +488,6 @@ MODULE_DEVICE_TABLE(i2c, tda7432_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tda7432",
+- .driverid = I2C_DRIVERID_TDA7432,
+- .command = tda7432_command,
+ .probe = tda7432_probe,
+ .remove = tda7432_remove,
+ .id_table = tda7432_id,
+diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
+index 6afb705..fe11580 100644
+--- a/drivers/media/video/tda9840.c
++++ b/drivers/media/video/tda9840.c
+@@ -30,8 +30,8 @@
+ #include <linux/ioctl.h>
+ #include <linux/i2c.h>
+ #include <media/v4l2-device.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
+-#include "tda9840.h"
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+ MODULE_DESCRIPTION("tda9840 driver");
+@@ -56,11 +56,6 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ #define TDA9840_SET_BOTH_R 0x16
+ #define TDA9840_SET_EXTERNAL 0x7a
+
+-/* addresses to scan, found only at 0x42 (7-Bit) */
+-static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
+-
+-/* magic definition of all other variables and things */
+-I2C_CLIENT_INSMOD;
+
+ static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+ {
+@@ -137,60 +132,17 @@ static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
+ return 0;
+ }
+
+-static long tda9840_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
++static int tda9840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+ {
+- int byte;
+-
+- switch (cmd) {
+- case TDA9840_LEVEL_ADJUST:
+- byte = *(int *)arg;
+- v4l2_dbg(1, debug, sd, "TDA9840_LEVEL_ADJUST: %d\n", byte);
+-
+- /* check for correct range */
+- if (byte > 25 || byte < -20)
+- return -EINVAL;
+-
+- /* calculate actual value to set, see specs, page 18 */
+- byte /= 5;
+- if (0 < byte)
+- byte += 0x8;
+- else
+- byte = -byte;
+- tda9840_write(sd, LEVEL_ADJUST, byte);
+- break;
+-
+- case TDA9840_STEREO_ADJUST:
+- byte = *(int *)arg;
+- v4l2_dbg(1, debug, sd, "TDA9840_STEREO_ADJUST: %d\n", byte);
+-
+- /* check for correct range */
+- if (byte > 25 || byte < -24)
+- return -EINVAL;
+-
+- /* calculate actual value to set */
+- byte /= 5;
+- if (0 < byte)
+- byte += 0x20;
+- else
+- byte = -byte;
+-
+- tda9840_write(sd, STEREO_ADJUST, byte);
+- break;
+- default:
+- return -ENOIOCTLCMD;
+- }
+- return 0;
+-}
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+-static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TDA9840, 0);
+ }
+
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops tda9840_core_ops = {
+- .ioctl = tda9840_ioctl,
++ .g_chip_ident = tda9840_g_chip_ident,
+ };
+
+ static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = {
+@@ -209,8 +161,6 @@ static int tda9840_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ struct v4l2_subdev *sd;
+- int result;
+- int byte;
+
+ /* let's see whether this adapter can support what we need */
+ if (!i2c_check_functionality(client->adapter,
+@@ -227,15 +177,9 @@ static int tda9840_probe(struct i2c_client *client,
+ v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
+
+ /* set initial values for level & stereo - adjustment, mode */
+- byte = 0;
+- result = tda9840_ioctl(sd, TDA9840_LEVEL_ADJUST, &byte);
+- result |= tda9840_ioctl(sd, TDA9840_STEREO_ADJUST, &byte);
++ tda9840_write(sd, LEVEL_ADJUST, 0);
++ tda9840_write(sd, STEREO_ADJUST, 0);
+ tda9840_write(sd, SWITCH, TDA9840_SET_STEREO);
+- if (result) {
+- v4l2_dbg(1, debug, sd, "could not initialize tda9840\n");
+- kfree(sd);
+- return -ENODEV;
+- }
+ return 0;
+ }
+
+@@ -248,12 +192,7 @@ static int tda9840_remove(struct i2c_client *client)
+ return 0;
+ }
+
+-static int tda9840_legacy_probe(struct i2c_adapter *adapter)
+-{
+- /* Let's see whether this is a known adapter we can attach to.
+- Prevents conflicts with tvaudio.c. */
+- return adapter->id == I2C_HW_SAA7146;
+-}
++
+ static const struct i2c_device_id tda9840_id[] = {
+ { "tda9840", 0 },
+ { }
+@@ -262,10 +201,7 @@ MODULE_DEVICE_TABLE(i2c, tda9840_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tda9840",
+- .driverid = I2C_DRIVERID_TDA9840,
+- .command = tda9840_command,
+ .probe = tda9840_probe,
+ .remove = tda9840_remove,
+- .legacy_probe = tda9840_legacy_probe,
+ .id_table = tda9840_id,
+ };
+diff --git a/drivers/media/video/tda9840.h b/drivers/media/video/tda9840.h
+deleted file mode 100644
+index dc12ae7..0000000
+--- a/drivers/media/video/tda9840.h
++++ /dev/null
+@@ -1,14 +0,0 @@
+-#ifndef __INCLUDED_TDA9840__
+-#define __INCLUDED_TDA9840__
+-
+-#define I2C_ADDR_TDA9840 0x42
+-
+-/* values may range between +2.5 and -2.0;
+- the value has to be multiplied with 10 */
+-#define TDA9840_LEVEL_ADJUST _IOW('v',3,int)
+-
+-/* values may range between +2.5 and -2.4;
+- the value has to be multiplied with 10 */
+-#define TDA9840_STEREO_ADJUST _IOW('v',4,int)
+-
+-#endif
+diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
+index 00c6cbe..24e2b7d 100644
+--- a/drivers/media/video/tda9875.c
++++ b/drivers/media/video/tda9875.c
+@@ -28,20 +28,13 @@
+ #include <linux/i2c.h>
+ #include <linux/videodev2.h>
+ #include <media/v4l2-device.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
+ #include <media/i2c-addr.h>
+
+ static int debug; /* insmod parameter */
+ module_param(debug, int, S_IRUGO | S_IWUSR);
+ MODULE_LICENSE("GPL");
+
+-/* Addresses to scan */
+-static unsigned short normal_i2c[] = {
+- I2C_ADDR_TDA9875 >> 1,
+- I2C_CLIENT_END
+-};
+-
+-I2C_CLIENT_INSMOD;
+
+ /* This is a superset of the TDA9875 */
+ struct tda9875 {
+@@ -313,18 +306,14 @@ static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+ {
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+- return v4l2_ctrl_query_fill_std(qc);
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+ }
+ return -EINVAL;
+ }
+
+-static int tda9875_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops tda9875_core_ops = {
+@@ -401,8 +390,6 @@ MODULE_DEVICE_TABLE(i2c, tda9875_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tda9875",
+- .driverid = I2C_DRIVERID_TDA9875,
+- .command = tda9875_command,
+ .probe = tda9875_probe,
+ .remove = tda9875_remove,
+ .id_table = tda9875_id,
+diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
+index 7519fd1..d61c56f 100644
+--- a/drivers/media/video/tea6415c.c
++++ b/drivers/media/video/tea6415c.c
+@@ -32,7 +32,8 @@
+ #include <linux/ioctl.h>
+ #include <linux/i2c.h>
+ #include <media/v4l2-device.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+ #include "tea6415c.h"
+
+ MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+@@ -44,25 +45,22 @@ module_param(debug, int, 0644);
+
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+-/* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */
+-static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END };
+
+-/* magic definition of all other variables and things */
+-I2C_CLIENT_INSMOD;
+-
+-/* makes a connection between the input-pin 'i' and the output-pin 'o'
+- for the tea6415c-client 'client' */
+-static int switch_matrix(struct i2c_client *client, int i, int o)
++/* makes a connection between the input-pin 'i' and the output-pin 'o' */
++static int tea6415c_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 byte = 0;
++ u32 i = route->input;
++ u32 o = route->output;
+ int ret;
+
+- v4l_dbg(1, debug, client, "i=%d, o=%d\n", i, o);
++ v4l2_dbg(1, debug, sd, "i=%d, o=%d\n", i, o);
+
+ /* check if the pins are valid */
+ if (0 == ((1 == i || 3 == i || 5 == i || 6 == i || 8 == i || 10 == i || 20 == i || 11 == i)
+ && (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o)))
+- return -1;
++ return -EINVAL;
+
+ /* to understand this, have a look at the tea6415c-specs (p.5) */
+ switch (o) {
+@@ -115,37 +113,33 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
+
+ ret = i2c_smbus_write_byte(client, byte);
+ if (ret) {
+- v4l_dbg(1, debug, client,
++ v4l2_dbg(1, debug, sd,
+ "i2c_smbus_write_byte() failed, ret:%d\n", ret);
+ return -EIO;
+ }
+ return ret;
+ }
+
+-static long tea6415c_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
++static int tea6415c_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+ {
+- if (cmd == TEA6415C_SWITCH) {
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- return switch_matrix(client, v->in, v->out);
+- }
+- return -ENOIOCTLCMD;
+-}
+-
+-static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6415C, 0);
+ }
+
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops tea6415c_core_ops = {
+- .ioctl = tea6415c_ioctl,
++ .g_chip_ident = tea6415c_g_chip_ident,
++};
++
++static const struct v4l2_subdev_video_ops tea6415c_video_ops = {
++ .s_routing = tea6415c_s_routing,
+ };
+
+ static const struct v4l2_subdev_ops tea6415c_ops = {
+ .core = &tea6415c_core_ops,
++ .video = &tea6415c_video_ops,
+ };
+
+ /* this function is called by i2c_probe */
+@@ -176,12 +170,6 @@ static int tea6415c_remove(struct i2c_client *client)
+ return 0;
+ }
+
+-static int tea6415c_legacy_probe(struct i2c_adapter *adapter)
+-{
+- /* Let's see whether this is a known adapter we can attach to.
+- Prevents conflicts with tvaudio.c. */
+- return adapter->id == I2C_HW_SAA7146;
+-}
+
+ static const struct i2c_device_id tea6415c_id[] = {
+ { "tea6415c", 0 },
+@@ -191,10 +179,7 @@ MODULE_DEVICE_TABLE(i2c, tea6415c_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tea6415c",
+- .driverid = I2C_DRIVERID_TEA6415C,
+- .command = tea6415c_command,
+ .probe = tea6415c_probe,
+ .remove = tea6415c_remove,
+- .legacy_probe = tea6415c_legacy_probe,
+ .id_table = tea6415c_id,
+ };
+diff --git a/drivers/media/video/tea6415c.h b/drivers/media/video/tea6415c.h
+index f84ed80..3a47d69 100644
+--- a/drivers/media/video/tea6415c.h
++++ b/drivers/media/video/tea6415c.h
+@@ -1,10 +1,6 @@
+ #ifndef __INCLUDED_TEA6415C__
+ #define __INCLUDED_TEA6415C__
+
+-/* possible i2c-addresses */
+-#define I2C_TEA6415C_1 0x03
+-#define I2C_TEA6415C_2 0x43
+-
+ /* the tea6415c's design is quite brain-dead. although there are
+ 8 inputs and 6 outputs, these aren't enumerated in any way. because
+ I don't want to say "connect input pin 20 to output pin 17", I define
+@@ -28,12 +24,4 @@
+ #define TEA6415C_INPUT7 1
+ #define TEA6415C_INPUT8 11
+
+-struct tea6415c_multiplex
+-{
+- int in; /* input-pin */
+- int out; /* output-pin */
+-};
+-
+-#define TEA6415C_SWITCH _IOW('v',1,struct tea6415c_multiplex)
+-
+ #endif
+diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
+index 081e74f..3492223 100644
+--- a/drivers/media/video/tea6420.c
++++ b/drivers/media/video/tea6420.c
+@@ -32,7 +32,8 @@
+ #include <linux/ioctl.h>
+ #include <linux/i2c.h>
+ #include <media/v4l2-device.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+ #include "tea6420.h"
+
+ MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
+@@ -44,24 +45,23 @@ module_param(debug, int, 0644);
+
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+-/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
+-static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
+-
+-/* magic definition of all other variables and things */
+-I2C_CLIENT_INSMOD;
+
+ /* make a connection between the input 'i' and the output 'o'
+- with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */
+-static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
++ with gain 'g' (note: i = 6 means 'mute') */
++static int tea6420_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int i = route->input;
++ int o = route->output & 0xf;
++ int g = (route->output >> 4) & 0xf;
+ u8 byte;
+ int ret;
+
+- v4l_dbg(1, debug, client, "i=%d, o=%d, g=%d\n", i, o, g);
++ v4l2_dbg(1, debug, sd, "i=%d, o=%d, g=%d\n", i, o, g);
+
+ /* check if the parameters are valid */
+ if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0)
+- return -1;
++ return -EINVAL;
+
+ byte = ((o - 1) << 5);
+ byte |= (i - 1);
+@@ -83,37 +83,33 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
+
+ ret = i2c_smbus_write_byte(client, byte);
+ if (ret) {
+- v4l_dbg(1, debug, client,
++ v4l2_dbg(1, debug, sd,
+ "i2c_smbus_write_byte() failed, ret:%d\n", ret);
+ return -EIO;
+ }
+ return 0;
+ }
+
+-static long tea6420_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
++static int tea6420_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+ {
+- if (cmd == TEA6420_SWITCH) {
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- return tea6420_switch(client, a->in, a->out, a->gain);
+- }
+- return -ENOIOCTLCMD;
+-}
+-
+-static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6420, 0);
+ }
+
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops tea6420_core_ops = {
+- .ioctl = tea6420_ioctl,
++ .g_chip_ident = tea6420_g_chip_ident,
++};
++
++static const struct v4l2_subdev_audio_ops tea6420_audio_ops = {
++ .s_routing = tea6420_s_routing,
+ };
+
+ static const struct v4l2_subdev_ops tea6420_ops = {
+ .core = &tea6420_core_ops,
++ .audio = &tea6420_audio_ops,
+ };
+
+ /* this function is called by i2c_probe */
+@@ -130,20 +126,24 @@ static int tea6420_probe(struct i2c_client *client,
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
++ sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
++ if (sd == NULL)
++ return -ENOMEM;
++ v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
++
+ /* set initial values: set "mute"-input to all outputs at gain 0 */
+ err = 0;
+ for (i = 1; i < 5; i++) {
+- err += tea6420_switch(client, 6, i, 0);
++ struct v4l2_routing route;
++
++ route.input = 6;
++ route.output = i;
++ err += tea6420_s_routing(sd, &route);
+ }
+ if (err) {
+ v4l_dbg(1, debug, client, "could not initialize tea6420\n");
+ return -ENODEV;
+ }
+-
+- sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+- if (sd == NULL)
+- return -ENOMEM;
+- v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
+ return 0;
+ }
+
+@@ -156,12 +156,6 @@ static int tea6420_remove(struct i2c_client *client)
+ return 0;
+ }
+
+-static int tea6420_legacy_probe(struct i2c_adapter *adapter)
+-{
+- /* Let's see whether this is a known adapter we can attach to.
+- Prevents conflicts with tvaudio.c. */
+- return adapter->id == I2C_HW_SAA7146;
+-}
+
+ static const struct i2c_device_id tea6420_id[] = {
+ { "tea6420", 0 },
+@@ -171,10 +165,7 @@ MODULE_DEVICE_TABLE(i2c, tea6420_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tea6420",
+- .driverid = I2C_DRIVERID_TEA6420,
+- .command = tea6420_command,
+ .probe = tea6420_probe,
+ .remove = tea6420_remove,
+- .legacy_probe = tea6420_legacy_probe,
+ .id_table = tea6420_id,
+ };
+diff --git a/drivers/media/video/tea6420.h b/drivers/media/video/tea6420.h
+index 5ef7c18..4aa3edb 100644
+--- a/drivers/media/video/tea6420.h
++++ b/drivers/media/video/tea6420.h
+@@ -1,17 +1,24 @@
+ #ifndef __INCLUDED_TEA6420__
+ #define __INCLUDED_TEA6420__
+
+-/* possible addresses */
+-#define I2C_ADDR_TEA6420_1 0x4c
+-#define I2C_ADDR_TEA6420_2 0x4d
++/* input pins */
++#define TEA6420_OUTPUT1 1
++#define TEA6420_OUTPUT2 2
++#define TEA6420_OUTPUT3 3
++#define TEA6420_OUTPUT4 4
+
+-struct tea6420_multiplex
+-{
+- int in; /* input of audio switch */
+- int out; /* output of audio switch */
+- int gain; /* gain of connection */
+-};
++/* output pins */
++#define TEA6420_INPUT1 1
++#define TEA6420_INPUT2 2
++#define TEA6420_INPUT3 3
++#define TEA6420_INPUT4 4
++#define TEA6420_INPUT5 5
++#define TEA6420_INPUT6 6
+
+-#define TEA6420_SWITCH _IOW('v',1,struct tea6420_multiplex)
++/* gain on the output pins, ORed with the output pin */
++#define TEA6420_GAIN0 0x00
++#define TEA6420_GAIN2 0x20
++#define TEA6420_GAIN4 0x40
++#define TEA6420_GAIN6 0x60
+
+ #endif
+diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
+index 5c95ecd..07789c6 100644
+--- a/drivers/media/video/tlv320aic23b.c
++++ b/drivers/media/video/tlv320aic23b.c
+@@ -31,15 +31,12 @@
+ #include <linux/i2c-id.h>
+ #include <linux/videodev2.h>
+ #include <media/v4l2-device.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("tlv320aic23b driver");
+ MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
+ MODULE_LICENSE("GPL");
+
+-static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
+-
+-I2C_CLIENT_INSMOD;
+
+ /* ----------------------------------------------------------------------- */
+
+@@ -121,11 +118,6 @@ static int tlv320aic23b_log_status(struct v4l2_subdev *sd)
+ return 0;
+ }
+
+-static int tlv320aic23b_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
+@@ -208,8 +200,6 @@ MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tlv320aic23b",
+- .driverid = I2C_DRIVERID_TLV320AIC23B,
+- .command = tlv320aic23b_command,
+ .probe = tlv320aic23b_probe,
+ .remove = tlv320aic23b_remove,
+ .id_table = tlv320aic23b_id,
+diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
+index 30640fb..72d4103 100644
+--- a/drivers/media/video/tuner-core.c
++++ b/drivers/media/video/tuner-core.c
+@@ -364,7 +364,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
+ }
+
+ t->type = type;
+- t->config = new_config;
++ /* prevent invalid config values */
++ t->config = ((new_config >= 0) && (new_config < 256)) ? new_config : 0;
+ if (tuner_callback != NULL) {
+ tuner_dbg("defining GPIO callback\n");
+ t->fe.callback = tuner_callback;
+@@ -452,7 +453,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
+ struct dvb_tuner_ops *xc_tuner_ops;
+
+ xc5000_cfg.i2c_address = t->i2c->addr;
+- xc5000_cfg.if_khz = 5380;
++ /* if_khz will be set when the digital dvb_attach() occurs */
++ xc5000_cfg.if_khz = 0;
+ if (!dvb_attach(xc5000_attach,
+ &t->fe, t->i2c->adapter, &xc5000_cfg))
+ goto attach_failed;
+@@ -776,8 +778,7 @@ static int tuner_s_radio(struct v4l2_subdev *sd)
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
+- == -EINVAL)
++ if (set_mode(client, t, V4L2_TUNER_RADIO, "s_radio") == -EINVAL)
+ return 0;
+ if (t->radio_freq)
+ set_freq(client, t->radio_freq);
+@@ -791,7 +792,7 @@ static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby)
+
+ tuner_dbg("Putting tuner to sleep\n");
+
+- if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
++ if (check_mode(t, "s_standby") == -EINVAL)
+ return 0;
+ t->mode = T_STANDBY;
+ if (analog_ops->standby)
+@@ -799,132 +800,6 @@ static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby)
+ return 0;
+ }
+
+-#ifdef CONFIG_VIDEO_ALLOW_V4L1
+-static long tuner_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+-{
+- struct tuner *t = to_tuner(sd);
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+- struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+-
+- switch (cmd) {
+- case VIDIOCSAUDIO:
+- if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL)
+- return 0;
+- if (check_v4l2(t) == -EINVAL)
+- return 0;
+-
+- /* Should be implemented, since bttv calls it */
+- tuner_dbg("VIDIOCSAUDIO not implemented.\n");
+- break;
+- case VIDIOCSCHAN:
+- {
+- static const v4l2_std_id map[] = {
+- [VIDEO_MODE_PAL] = V4L2_STD_PAL,
+- [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
+- [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
+- [4 /* bttv */ ] = V4L2_STD_PAL_M,
+- [5 /* bttv */ ] = V4L2_STD_PAL_N,
+- [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
+- };
+- struct video_channel *vc = arg;
+-
+- if (check_v4l2(t) == -EINVAL)
+- return 0;
+-
+- if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==-EINVAL)
+- return 0;
+-
+- if (vc->norm < ARRAY_SIZE(map))
+- t->std = map[vc->norm];
+- tuner_fixup_std(t);
+- if (t->tv_freq)
+- set_tv_freq(client, t->tv_freq);
+- return 0;
+- }
+- case VIDIOCSFREQ:
+- {
+- unsigned long *v = arg;
+-
+- if (check_mode(t, "VIDIOCSFREQ") == -EINVAL)
+- return 0;
+- if (check_v4l2(t) == -EINVAL)
+- return 0;
+-
+- set_freq(client, *v);
+- return 0;
+- }
+- case VIDIOCGTUNER:
+- {
+- struct video_tuner *vt = arg;
+-
+- if (check_mode(t, "VIDIOCGTUNER") == -EINVAL)
+- return 0;
+- if (check_v4l2(t) == -EINVAL)
+- return 0;
+-
+- if (V4L2_TUNER_RADIO == t->mode) {
+- if (fe_tuner_ops->get_status) {
+- u32 tuner_status;
+-
+- fe_tuner_ops->get_status(&t->fe, &tuner_status);
+- if (tuner_status & TUNER_STATUS_STEREO)
+- vt->flags |= VIDEO_TUNER_STEREO_ON;
+- else
+- vt->flags &= ~VIDEO_TUNER_STEREO_ON;
+- } else {
+- if (analog_ops->is_stereo) {
+- if (analog_ops->is_stereo(&t->fe))
+- vt->flags |=
+- VIDEO_TUNER_STEREO_ON;
+- else
+- vt->flags &=
+- ~VIDEO_TUNER_STEREO_ON;
+- }
+- }
+- if (analog_ops->has_signal)
+- vt->signal =
+- analog_ops->has_signal(&t->fe);
+-
+- vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
+-
+- vt->rangelow = radio_range[0] * 16000;
+- vt->rangehigh = radio_range[1] * 16000;
+-
+- } else {
+- vt->rangelow = tv_range[0] * 16;
+- vt->rangehigh = tv_range[1] * 16;
+- }
+-
+- return 0;
+- }
+- case VIDIOCGAUDIO:
+- {
+- struct video_audio *va = arg;
+-
+- if (check_mode(t, "VIDIOCGAUDIO") == -EINVAL)
+- return 0;
+- if (check_v4l2(t) == -EINVAL)
+- return 0;
+-
+- if (V4L2_TUNER_RADIO == t->mode) {
+- if (fe_tuner_ops->get_status) {
+- u32 tuner_status;
+-
+- fe_tuner_ops->get_status(&t->fe, &tuner_status);
+- va->mode = (tuner_status & TUNER_STATUS_STEREO)
+- ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+- } else if (analog_ops->is_stereo)
+- va->mode = analog_ops->is_stereo(&t->fe)
+- ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+- }
+- return 0;
+- }
+- }
+- return -ENOIOCTLCMD;
+-}
+-#endif
+-
+ static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg)
+ {
+ struct tuner *t = to_tuner(sd);
+@@ -950,8 +825,7 @@ static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
+- == -EINVAL)
++ if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "s_std") == -EINVAL)
+ return 0;
+
+ switch_v4l2();
+@@ -968,8 +842,7 @@ static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- if (set_mode(client, t, f->type, "VIDIOC_S_FREQUENCY")
+- == -EINVAL)
++ if (set_mode(client, t, f->type, "s_frequency") == -EINVAL)
+ return 0;
+ switch_v4l2();
+ set_freq(client, f->frequency);
+@@ -982,7 +855,7 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+ struct tuner *t = to_tuner(sd);
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+- if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
++ if (check_mode(t, "g_frequency") == -EINVAL)
+ return 0;
+ switch_v4l2();
+ f->type = t->mode;
+@@ -1006,7 +879,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+ struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+- if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
++ if (check_mode(t, "g_tuner") == -EINVAL)
+ return 0;
+ switch_v4l2();
+
+@@ -1055,7 +928,7 @@ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+ struct tuner *t = to_tuner(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
++ if (check_mode(t, "s_tuner") == -EINVAL)
+ return 0;
+
+ switch_v4l2();
+@@ -1112,9 +985,6 @@ static int tuner_resume(struct i2c_client *c)
+ static const struct v4l2_subdev_core_ops tuner_core_ops = {
+ .log_status = tuner_log_status,
+ .s_standby = tuner_s_standby,
+-#ifdef CONFIG_VIDEO_ALLOW_V4L1
+- .ioctl = tuner_ioctl,
+-#endif
+ };
+
+ static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
+diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
+index 076ed5b..226bf35 100644
+--- a/drivers/media/video/tvaudio.c
++++ b/drivers/media/video/tvaudio.c
+@@ -26,7 +26,7 @@
+ #include <linux/delay.h>
+ #include <linux/errno.h>
+ #include <linux/slab.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <linux/i2c.h>
+ #include <linux/init.h>
+ #include <linux/kthread.h>
+@@ -1047,6 +1047,116 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
+ return 0;
+ }
+
++/* ---------------------------------------------------------------------- */
++/* audio chip description - defines+functions for tda9875 */
++/* The TDA9875 is made by Philips Semiconductor
++ * http://www.semiconductors.philips.com
++ * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator
++ *
++ */
++
++/* subaddresses for TDA9875 */
++#define TDA9875_MUT 0x12 /*General mute (value --> 0b11001100*/
++#define TDA9875_CFG 0x01 /* Config register (value --> 0b00000000 */
++#define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/
++#define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/
++
++#define TDA9875_CH1V 0x0c /*Channel 1 volume (mute)*/
++#define TDA9875_CH2V 0x0d /*Channel 2 volume (mute)*/
++#define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/
++#define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/
++
++#define TDA9875_ADCIS 0x17 /*ADC input select (mono) 0b0110 000*/
++#define TDA9875_AER 0x19 /*Audio effect (AVL+Pseudo) 0b0000 0110*/
++#define TDA9875_MCS 0x18 /*Main channel select (DAC) 0b0000100*/
++#define TDA9875_MVL 0x1a /* Main volume gauche */
++#define TDA9875_MVR 0x1b /* Main volume droite */
++#define TDA9875_MBA 0x1d /* Main Basse */
++#define TDA9875_MTR 0x1e /* Main treble */
++#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/
++#define TDA9875_AVL 0x20 /* Auxilary volume gauche */
++#define TDA9875_AVR 0x21 /* Auxilary volume droite */
++#define TDA9875_ABA 0x22 /* Auxilary Basse */
++#define TDA9875_ATR 0x23 /* Auxilary treble */
++
++#define TDA9875_MSR 0x02 /* Monitor select register */
++#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */
++#define TDA9875_C1MIB 0x04 /* Carrier 1 (FM) frequency register (16-8]b */
++#define TDA9875_C1LSB 0x05 /* Carrier 1 (FM) frequency register LSB */
++#define TDA9875_C2MSB 0x06 /* Carrier 2 (nicam) frequency register MSB */
++#define TDA9875_C2MIB 0x07 /* Carrier 2 (nicam) frequency register (16-8]b */
++#define TDA9875_C2LSB 0x08 /* Carrier 2 (nicam) frequency register LSB */
++#define TDA9875_DCR 0x09 /* Demodulateur configuration regirter*/
++#define TDA9875_DEEM 0x0a /* FM de-emphasis regirter*/
++#define TDA9875_FMAT 0x0b /* FM Matrix regirter*/
++
++/* values */
++#define TDA9875_MUTE_ON 0xff /* general mute */
++#define TDA9875_MUTE_OFF 0xcc /* general no mute */
++
++static int tda9875_initialize(struct CHIPSTATE *chip)
++{
++ chip_write(chip, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
++ chip_write(chip, TDA9875_MSR, 0x03); /* Monitor 0b00000XXX*/
++ chip_write(chip, TDA9875_C1MSB, 0x00); /*Car1(FM) MSB XMHz*/
++ chip_write(chip, TDA9875_C1MIB, 0x00); /*Car1(FM) MIB XMHz*/
++ chip_write(chip, TDA9875_C1LSB, 0x00); /*Car1(FM) LSB XMHz*/
++ chip_write(chip, TDA9875_C2MSB, 0x00); /*Car2(NICAM) MSB XMHz*/
++ chip_write(chip, TDA9875_C2MIB, 0x00); /*Car2(NICAM) MIB XMHz*/
++ chip_write(chip, TDA9875_C2LSB, 0x00); /*Car2(NICAM) LSB XMHz*/
++ chip_write(chip, TDA9875_DCR, 0x00); /*Demod config 0x00*/
++ chip_write(chip, TDA9875_DEEM, 0x44); /*DE-Emph 0b0100 0100*/
++ chip_write(chip, TDA9875_FMAT, 0x00); /*FM Matrix reg 0x00*/
++ chip_write(chip, TDA9875_SC1, 0x00); /* SCART 1 (SC1)*/
++ chip_write(chip, TDA9875_SC2, 0x01); /* SCART 2 (sc2)*/
++
++ chip_write(chip, TDA9875_CH1V, 0x10); /* Channel volume 1 mute*/
++ chip_write(chip, TDA9875_CH2V, 0x10); /* Channel volume 2 mute */
++ chip_write(chip, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/
++ chip_write(chip, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/
++ chip_write(chip, TDA9875_LOSR, 0x00); /* line out (in:mono)*/
++ chip_write(chip, TDA9875_AER, 0x00); /*06 Effect (AVL+PSEUDO) */
++ chip_write(chip, TDA9875_MCS, 0x44); /* Main ch select (DAC) */
++ chip_write(chip, TDA9875_MVL, 0x03); /* Vol Main left 10dB */
++ chip_write(chip, TDA9875_MVR, 0x03); /* Vol Main right 10dB*/
++ chip_write(chip, TDA9875_MBA, 0x00); /* Main Bass Main 0dB*/
++ chip_write(chip, TDA9875_MTR, 0x00); /* Main Treble Main 0dB*/
++ chip_write(chip, TDA9875_ACS, 0x44); /* Aux chan select (dac)*/
++ chip_write(chip, TDA9875_AVL, 0x00); /* Vol Aux left 0dB*/
++ chip_write(chip, TDA9875_AVR, 0x00); /* Vol Aux right 0dB*/
++ chip_write(chip, TDA9875_ABA, 0x00); /* Aux Bass Main 0dB*/
++ chip_write(chip, TDA9875_ATR, 0x00); /* Aux Aigus Main 0dB*/
++
++ chip_write(chip, TDA9875_MUT, 0xcc); /* General mute */
++ return 0;
++}
++
++static int tda9875_volume(int val) { return (unsigned char)(val / 602 - 84); }
++static int tda9875_bass(int val) { return (unsigned char)(max(-12, val / 2115 - 15)); }
++static int tda9875_treble(int val) { return (unsigned char)(val / 2622 - 12); }
++
++/* ----------------------------------------------------------------------- */
++
++
++/* *********************** *
++ * i2c interface functions *
++ * *********************** */
++
++static int tda9875_checkit(struct CHIPSTATE *chip)
++{
++ struct v4l2_subdev *sd = &chip->sd;
++ int dic, rev;
++
++ dic = chip_read2(chip, 254);
++ rev = chip_read2(chip, 255);
++
++ if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
++ v4l2_info(sd, "found tda9875%s rev. %d.\n",
++ dic == 0 ? "" : "A", rev);
++ return 1;
++ }
++ return 0;
++}
+
+ /* ---------------------------------------------------------------------- */
+ /* audio chip descriptions - defines+functions for tea6420 */
+@@ -1280,6 +1390,7 @@ static int tda9850 = 1;
+ static int tda9855 = 1;
+ static int tda9873 = 1;
+ static int tda9874a = 1;
++static int tda9875 = 1;
+ static int tea6300; /* default 0 - address clash with msp34xx */
+ static int tea6320; /* default 0 - address clash with msp34xx */
+ static int tea6420 = 1;
+@@ -1292,6 +1403,7 @@ module_param(tda9850, int, 0444);
+ module_param(tda9855, int, 0444);
+ module_param(tda9873, int, 0444);
+ module_param(tda9874a, int, 0444);
++module_param(tda9875, int, 0444);
+ module_param(tea6300, int, 0444);
+ module_param(tea6320, int, 0444);
+ module_param(tea6420, int, 0444);
+@@ -1349,6 +1461,26 @@ static struct CHIPDESC chiplist[] = {
+ .setmode = tda9874a_setmode,
+ },
+ {
++ .name = "tda9875",
++ .insmodopt = &tda9875,
++ .addr_lo = I2C_ADDR_TDA9875 >> 1,
++ .addr_hi = I2C_ADDR_TDA9875 >> 1,
++ .flags = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
++
++ /* callbacks */
++ .initialize = tda9875_initialize,
++ .checkit = tda9875_checkit,
++ .volfunc = tda9875_volume,
++ .bassfunc = tda9875_bass,
++ .treblefunc = tda9875_treble,
++ .leftreg = TDA9875_MVL,
++ .rightreg = TDA9875_MVR,
++ .bassreg = TDA9875_MBA,
++ .treblereg = TDA9875_MTR,
++ .leftinit = 58880,
++ .rightinit = 58880,
++ },
++ {
+ .name = "tda9850",
+ .insmodopt = &tda9850,
+ .addr_lo = I2C_ADDR_TDA985x_L >> 1,
+@@ -1511,6 +1643,8 @@ static int tvaudio_g_ctrl(struct v4l2_subdev *sd,
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
++ if (!(desc->flags & CHIP_HAS_INPUTSEL))
++ break;
+ ctrl->value=chip->muted;
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+@@ -1552,6 +1686,9 @@ static int tvaudio_s_ctrl(struct v4l2_subdev *sd,
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
++ if (!(desc->flags & CHIP_HAS_INPUTSEL))
++ break;
++
+ if (ctrl->value < 0 || ctrl->value >= 2)
+ return -ERANGE;
+ chip->muted = ctrl->value;
+@@ -1636,21 +1773,26 @@ static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_MUTE:
++ if (desc->flags & CHIP_HAS_INPUTSEL)
++ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
++ if (desc->flags & CHIP_HAS_VOLUME)
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
++ break;
+ case V4L2_CID_AUDIO_BALANCE:
+- if (!(desc->flags & CHIP_HAS_VOLUME))
+- return -EINVAL;
++ if (desc->flags & CHIP_HAS_VOLUME)
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+- if (!(desc->flags & CHIP_HAS_BASSTREBLE))
+- return -EINVAL;
++ if (desc->flags & CHIP_HAS_BASSTREBLE)
++ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+ break;
+ default:
+- return -EINVAL;
++ break;
+ }
+- return v4l2_ctrl_query_fill_std(qc);
++ return -EINVAL;
+ }
+
+ static int tvaudio_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt)
+@@ -1658,7 +1800,9 @@ static int tvaudio_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *
+ struct CHIPSTATE *chip = to_state(sd);
+ struct CHIPDESC *desc = chip->desc;
+
+- if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
++ if (!(desc->flags & CHIP_HAS_INPUTSEL))
++ return 0;
++ if (rt->input >= 4)
+ return -EINVAL;
+ /* There are four inputs: tuner, radio, extern and intern. */
+ chip->input = rt->input;
+@@ -1675,8 +1819,11 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+ struct CHIPDESC *desc = chip->desc;
+ int mode = 0;
+
++ if (!desc->setmode)
++ return 0;
+ if (chip->radio)
+ return 0;
++
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_STEREO:
+@@ -1692,7 +1839,7 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+ }
+ chip->audmode = vt->audmode;
+
+- if (desc->setmode && mode) {
++ if (mode) {
+ chip->watch_stereo = 0;
+ /* del_timer(&chip->wt); */
+ chip->mode = mode;
+@@ -1707,15 +1854,17 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+ struct CHIPDESC *desc = chip->desc;
+ int mode = V4L2_TUNER_MODE_MONO;
+
++ if (!desc->getmode)
++ return 0;
+ if (chip->radio)
+ return 0;
++
+ vt->audmode = chip->audmode;
+ vt->rxsubchans = 0;
+ vt->capability = V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+
+- if (desc->getmode)
+- mode = desc->getmode(chip);
++ mode = desc->getmode(chip);
+
+ if (mode & V4L2_TUNER_MODE_MONO)
+ vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
+@@ -1901,6 +2050,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
+ }
+
+ chip->thread = NULL;
++ init_timer(&chip->wt);
+ if (desc->flags & CHIP_NEED_CHECKMODE) {
+ if (!desc->getmode || !desc->setmode) {
+ /* This shouldn't be happen. Warn user, but keep working
+@@ -1910,7 +2060,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
+ return 0;
+ }
+ /* start async thread */
+- init_timer(&chip->wt);
+ chip->wt.function = chip_thread_wake;
+ chip->wt.data = (unsigned long)chip;
+ chip->thread = kthread_run(chip_thread, chip, client->name);
+diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
+index 78277ab..e24a38c 100644
+--- a/drivers/media/video/tveeprom.c
++++ b/drivers/media/video/tveeprom.c
+@@ -261,7 +261,12 @@ hauppauge_tuner[] =
+ { TUNER_ABSENT, "MaxLinear MXL5005_v2"},
+ { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"},
+ /* 150-159 */
+- { TUNER_ABSENT, "Xceive XC5000"},
++ { TUNER_XC5000, "Xceive XC5000"},
++ { TUNER_ABSENT, "Xceive XC3028L"},
++ { TUNER_ABSENT, "NXP 18271C2_716x"},
++ { TUNER_ABSENT, "Xceive XC4000"},
++ { TUNER_ABSENT, "Dibcom 7070"},
++ { TUNER_PHILIPS_TDA8290, "NXP 18271C2"},
+ };
+
+ /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
+diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
+index 8e23aa5..4262e60 100644
+--- a/drivers/media/video/tvp514x.c
++++ b/drivers/media/video/tvp514x.c
+@@ -86,9 +86,12 @@ struct tvp514x_std_info {
+ struct v4l2_standard standard;
+ };
+
++static struct tvp514x_reg tvp514x_reg_list_default[0x40];
+ /**
+- * struct tvp514x_decoded - TVP5146/47 decoder object
++ * struct tvp514x_decoder - TVP5146/47 decoder object
+ * @v4l2_int_device: Slave handle
++ * @tvp514x_slave: Slave pointer which is used by @v4l2_int_device
++ * @tvp514x_regs: copy of hw's regs with preset values.
+ * @pdata: Board specific
+ * @client: I2C client data
+ * @id: Entry from I2C table
+@@ -103,7 +106,9 @@ struct tvp514x_std_info {
+ * @route: input and output routing at chip level
+ */
+ struct tvp514x_decoder {
+- struct v4l2_int_device *v4l2_int_device;
++ struct v4l2_int_device v4l2_int_device;
++ struct v4l2_int_slave tvp514x_slave;
++ struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
+ const struct tvp514x_platform_data *pdata;
+ struct i2c_client *client;
+
+@@ -124,7 +129,7 @@ struct tvp514x_decoder {
+ };
+
+ /* TVP514x default register values */
+-static struct tvp514x_reg tvp514x_reg_list[] = {
++static struct tvp514x_reg tvp514x_reg_list_default[] = {
+ {TOK_WRITE, REG_INPUT_SEL, 0x05}, /* Composite selected */
+ {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
+ {TOK_WRITE, REG_VIDEO_STD, 0x00}, /* Auto mode */
+@@ -422,7 +427,7 @@ static int tvp514x_configure(struct tvp514x_decoder *decoder)
+
+ /* common register initialization */
+ err =
+- tvp514x_write_regs(decoder->client, tvp514x_reg_list);
++ tvp514x_write_regs(decoder->client, decoder->tvp514x_regs);
+ if (err)
+ return err;
+
+@@ -580,7 +585,8 @@ static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
+ return err;
+
+ decoder->current_std = i;
+- tvp514x_reg_list[REG_VIDEO_STD].val = decoder->std_list[i].video_std;
++ decoder->tvp514x_regs[REG_VIDEO_STD].val =
++ decoder->std_list[i].video_std;
+
+ v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
+ decoder->std_list[i].standard.name);
+@@ -625,8 +631,8 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
+ if (err)
+ return err;
+
+- tvp514x_reg_list[REG_INPUT_SEL].val = input_sel;
+- tvp514x_reg_list[REG_OUTPUT_FORMATTER1].val = output_sel;
++ decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel;
++ decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel;
+
+ /* Clear status */
+ msleep(LOCK_RETRY_DELAY);
+@@ -686,7 +692,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
+ break; /* Input detected */
+ }
+
+- if ((current_std == STD_INVALID) || (try_count < 0))
++ if ((current_std == STD_INVALID) || (try_count <= 0))
+ return -EINVAL;
+
+ decoder->current_std = current_std;
+@@ -719,10 +725,9 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
+
+ switch (qctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+- /* Brightness supported is same as standard one (0-255),
+- * so make use of standard API provided.
++ /* Brightness supported is (0-255),
+ */
+- err = v4l2_ctrl_query_fill_std(qctrl);
++ err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+ break;
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+@@ -779,16 +784,16 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+- ctrl->value = tvp514x_reg_list[REG_BRIGHTNESS].val;
++ ctrl->value = decoder->tvp514x_regs[REG_BRIGHTNESS].val;
+ break;
+ case V4L2_CID_CONTRAST:
+- ctrl->value = tvp514x_reg_list[REG_CONTRAST].val;
++ ctrl->value = decoder->tvp514x_regs[REG_CONTRAST].val;
+ break;
+ case V4L2_CID_SATURATION:
+- ctrl->value = tvp514x_reg_list[REG_SATURATION].val;
++ ctrl->value = decoder->tvp514x_regs[REG_SATURATION].val;
+ break;
+ case V4L2_CID_HUE:
+- ctrl->value = tvp514x_reg_list[REG_HUE].val;
++ ctrl->value = decoder->tvp514x_regs[REG_HUE].val;
+ if (ctrl->value == 0x7F)
+ ctrl->value = 180;
+ else if (ctrl->value == 0x80)
+@@ -798,7 +803,7 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+
+ break;
+ case V4L2_CID_AUTOGAIN:
+- ctrl->value = tvp514x_reg_list[REG_AFE_GAIN_CTRL].val;
++ ctrl->value = decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val;
+ if ((ctrl->value & 0x3) == 3)
+ ctrl->value = 1;
+ else
+@@ -848,7 +853,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+ value);
+ if (err)
+ return err;
+- tvp514x_reg_list[REG_BRIGHTNESS].val = value;
++ decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
+ break;
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+@@ -861,7 +866,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+ value);
+ if (err)
+ return err;
+- tvp514x_reg_list[REG_CONTRAST].val = value;
++ decoder->tvp514x_regs[REG_CONTRAST].val = value;
+ break;
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+@@ -874,7 +879,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+ value);
+ if (err)
+ return err;
+- tvp514x_reg_list[REG_SATURATION].val = value;
++ decoder->tvp514x_regs[REG_SATURATION].val = value;
+ break;
+ case V4L2_CID_HUE:
+ if (value == 180)
+@@ -893,7 +898,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+ value);
+ if (err)
+ return err;
+- tvp514x_reg_list[REG_HUE].val = value;
++ decoder->tvp514x_regs[REG_HUE].val = value;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if (value == 1)
+@@ -910,7 +915,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+ value);
+ if (err)
+ return err;
+- tvp514x_reg_list[REG_AFE_GAIN_CTRL].val = value;
++ decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
+ break;
+ default:
+ v4l_err(decoder->client,
+@@ -1275,7 +1280,7 @@ static int ioctl_init(struct v4l2_int_device *s)
+ struct tvp514x_decoder *decoder = s->priv;
+
+ /* Set default standard to auto */
+- tvp514x_reg_list[REG_VIDEO_STD].val =
++ decoder->tvp514x_regs[REG_VIDEO_STD].val =
+ VIDEO_STD_AUTO_SWITCH_BIT;
+
+ return tvp514x_configure(decoder);
+@@ -1344,11 +1349,6 @@ static struct v4l2_int_ioctl_desc tvp514x_ioctl_desc[] = {
+ (v4l2_int_ioctl_func *) ioctl_s_routing},
+ };
+
+-static struct v4l2_int_slave tvp514x_slave = {
+- .ioctls = tvp514x_ioctl_desc,
+- .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
+-};
+-
+ static struct tvp514x_decoder tvp514x_dev = {
+ .state = STATE_NOT_DETECTED,
+
+@@ -1369,17 +1369,15 @@ static struct tvp514x_decoder tvp514x_dev = {
+ .current_std = STD_NTSC_MJ,
+ .std_list = tvp514x_std_list,
+ .num_stds = ARRAY_SIZE(tvp514x_std_list),
+-
+-};
+-
+-static struct v4l2_int_device tvp514x_int_device = {
+- .module = THIS_MODULE,
+- .name = TVP514X_MODULE_NAME,
+- .priv = &tvp514x_dev,
+- .type = v4l2_int_type_slave,
+- .u = {
+- .slave = &tvp514x_slave,
+- },
++ .v4l2_int_device = {
++ .module = THIS_MODULE,
++ .name = TVP514X_MODULE_NAME,
++ .type = v4l2_int_type_slave,
++ },
++ .tvp514x_slave = {
++ .ioctls = tvp514x_ioctl_desc,
++ .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
++ },
+ };
+
+ /**
+@@ -1392,26 +1390,37 @@ static struct v4l2_int_device tvp514x_int_device = {
+ static int
+ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ {
+- struct tvp514x_decoder *decoder = &tvp514x_dev;
++ struct tvp514x_decoder *decoder;
+ int err;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+- decoder->pdata = client->dev.platform_data;
+- if (!decoder->pdata) {
++ decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
++ if (!decoder)
++ return -ENOMEM;
++
++ if (!client->dev.platform_data) {
+ v4l_err(client, "No platform data!!\n");
+- return -ENODEV;
++ err = -ENODEV;
++ goto out_free;
+ }
++
++ *decoder = tvp514x_dev;
++ decoder->v4l2_int_device.priv = decoder;
++ decoder->pdata = client->dev.platform_data;
++ decoder->v4l2_int_device.u.slave = &decoder->tvp514x_slave;
++ memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
++ sizeof(tvp514x_reg_list_default));
+ /*
+ * Fetch platform specific data, and configure the
+ * tvp514x_reg_list[] accordingly. Since this is one
+ * time configuration, no need to preserve.
+ */
+- tvp514x_reg_list[REG_OUTPUT_FORMATTER2].val |=
++ decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
+ (decoder->pdata->clk_polarity << 1);
+- tvp514x_reg_list[REG_SYNC_CONTROL].val |=
++ decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
+ ((decoder->pdata->hs_polarity << 2) |
+ (decoder->pdata->vs_polarity << 3));
+ /*
+@@ -1419,23 +1428,27 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ */
+ decoder->id = (struct i2c_device_id *)id;
+ /* Attach to Master */
+- strcpy(tvp514x_int_device.u.slave->attach_to, decoder->pdata->master);
+- decoder->v4l2_int_device = &tvp514x_int_device;
++ strcpy(decoder->v4l2_int_device.u.slave->attach_to,
++ decoder->pdata->master);
+ decoder->client = client;
+ i2c_set_clientdata(client, decoder);
+
+ /* Register with V4L2 layer as slave device */
+- err = v4l2_int_device_register(decoder->v4l2_int_device);
++ err = v4l2_int_device_register(&decoder->v4l2_int_device);
+ if (err) {
+ i2c_set_clientdata(client, NULL);
+ v4l_err(client,
+ "Unable to register to v4l2. Err[%d]\n", err);
++ goto out_free;
+
+ } else
+ v4l_info(client, "Registered to v4l2 master %s!!\n",
+ decoder->pdata->master);
+-
+ return 0;
++
++out_free:
++ kfree(decoder);
++ return err;
+ }
+
+ /**
+@@ -1452,9 +1465,9 @@ static int __exit tvp514x_remove(struct i2c_client *client)
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+- v4l2_int_device_unregister(decoder->v4l2_int_device);
++ v4l2_int_device_unregister(&decoder->v4l2_int_device);
+ i2c_set_clientdata(client, NULL);
+-
++ kfree(decoder);
+ return 0;
+ }
+ /*
+diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
+index 2cd64ef..3a5a95f 100644
+--- a/drivers/media/video/tvp5150.c
++++ b/drivers/media/video/tvp5150.c
+@@ -8,7 +8,6 @@
+ #include <linux/i2c.h>
+ #include <linux/videodev2.h>
+ #include <linux/delay.h>
+-#include <linux/video_decoder.h>
+ #include <media/v4l2-device.h>
+ #include <media/tvp5150.h>
+ #include <media/v4l2-i2c-drv-legacy.h>
+@@ -632,7 +631,7 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
+ const struct i2c_vbi_ram_value *regs = vbi_ram_default;
+ int line;
+
+- v4l2_dbg(1, debug, sd, "VIDIOC_G_SLICED_VBI_CAP\n");
++ v4l2_dbg(1, debug, sd, "g_sliced_vbi_cap\n");
+ memset(cap, 0, sizeof *cap);
+
+ while (regs->reg != (u16)-1 ) {
+@@ -831,7 +830,7 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
+
+ static int tvp5150_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ {
+- v4l2_dbg(1, debug, sd, "VIDIOC_G_CTRL called\n");
++ v4l2_dbg(1, debug, sd, "g_ctrl called\n");
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+@@ -861,7 +860,7 @@ static int tvp5150_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+ if (ctrl->value < tvp5150_qctrl[i].minimum ||
+ ctrl->value > tvp5150_qctrl[i].maximum)
+ return -ERANGE;
+- v4l2_dbg(1, debug, sd, "VIDIOC_S_CTRL: id=%d, value=%d\n",
++ v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n",
+ ctrl->id, ctrl->value);
+ break;
+ }
+@@ -1015,7 +1014,7 @@ static int tvp5150_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+ {
+ int i;
+
+- v4l2_dbg(1, debug, sd, "VIDIOC_QUERYCTRL called\n");
++ v4l2_dbg(1, debug, sd, "queryctrl called\n");
+
+ for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
+ if (qc->id && qc->id == tvp5150_qctrl[i].id) {
+@@ -1126,7 +1125,6 @@ MODULE_DEVICE_TABLE(i2c, tvp5150_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "tvp5150",
+- .driverid = I2C_DRIVERID_TVP5150,
+ .command = tvp5150_command,
+ .probe = tvp5150_probe,
+ .remove = tvp5150_remove,
+diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
+index 52c0357..a399476 100644
+--- a/drivers/media/video/tw9910.c
++++ b/drivers/media/video/tw9910.c
+@@ -460,9 +460,11 @@ static int tw9910_mask_set(struct i2c_client *client, u8 command,
+ u8 mask, u8 set)
+ {
+ s32 val = i2c_smbus_read_byte_data(client, command);
++ if (val < 0)
++ return val;
+
+ val &= ~mask;
+- val |= set;
++ val |= set & mask;
+
+ return i2c_smbus_write_byte_data(client, command, val);
+ }
+@@ -639,8 +641,8 @@ static int tw9910_set_register(struct soc_camera_device *icd,
+ }
+ #endif
+
+-static int tw9910_set_fmt(struct soc_camera_device *icd, __u32 pixfmt,
+- struct v4l2_rect *rect)
++static int tw9910_set_crop(struct soc_camera_device *icd,
++ struct v4l2_rect *rect)
+ {
+ struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+ int ret = -EINVAL;
+@@ -731,8 +733,33 @@ tw9910_set_fmt_error:
+ return ret;
+ }
+
++static int tw9910_set_fmt(struct soc_camera_device *icd,
++ struct v4l2_format *f)
++{
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ struct v4l2_rect rect = {
++ .left = icd->x_current,
++ .top = icd->y_current,
++ .width = pix->width,
++ .height = pix->height,
++ };
++ int i;
++
++ /*
++ * check color format
++ */
++ for (i = 0; i < ARRAY_SIZE(tw9910_color_fmt); i++)
++ if (pix->pixelformat == tw9910_color_fmt[i].fourcc)
++ break;
++
++ if (i == ARRAY_SIZE(tw9910_color_fmt))
++ return -EINVAL;
++
++ return tw9910_set_crop(icd, &rect);
++}
++
+ static int tw9910_try_fmt(struct soc_camera_device *icd,
+- struct v4l2_format *f)
++ struct v4l2_format *f)
+ {
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ const struct tw9910_scale_ctrl *scale;
+@@ -820,6 +847,7 @@ static struct soc_camera_ops tw9910_ops = {
+ .release = tw9910_release,
+ .start_capture = tw9910_start_capture,
+ .stop_capture = tw9910_stop_capture,
++ .set_crop = tw9910_set_crop,
+ .set_fmt = tw9910_set_fmt,
+ .try_fmt = tw9910_try_fmt,
+ .set_bus_param = tw9910_set_bus_param,
+diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
+index f4522bb..c0ac651 100644
+--- a/drivers/media/video/upd64031a.c
++++ b/drivers/media/video/upd64031a.c
+@@ -187,11 +187,6 @@ static int upd64031a_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
+ }
+ #endif
+
+-static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops upd64031a_core_ops = {
+@@ -267,8 +262,6 @@ MODULE_DEVICE_TABLE(i2c, upd64031a_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "upd64031a",
+- .driverid = I2C_DRIVERID_UPD64031A,
+- .command = upd64031a_command,
+ .probe = upd64031a_probe,
+ .remove = upd64031a_remove,
+ .id_table = upd64031a_id,
+diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
+index a5fb74b..410c915 100644
+--- a/drivers/media/video/upd64083.c
++++ b/drivers/media/video/upd64083.c
+@@ -164,11 +164,6 @@ static int upd64083_log_status(struct v4l2_subdev *sd)
+ return 0;
+ }
+
+-static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops upd64083_core_ops = {
+@@ -239,8 +234,6 @@ MODULE_DEVICE_TABLE(i2c, upd64083_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "upd64083",
+- .driverid = I2C_DRIVERID_UPD64083,
+- .command = upd64083_command,
+ .probe = upd64083_probe,
+ .remove = upd64083_remove,
+ .id_table = upd64083_id,
+diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
+index 2f11063..8d73979 100644
+--- a/drivers/media/video/usbvideo/vicam.c
++++ b/drivers/media/video/usbvideo/vicam.c
+@@ -191,7 +191,7 @@ initialize_camera(struct vicam_camera *cam)
+ {
+ int err;
+ const struct ihex_binrec *rec;
+- const struct firmware *fw;
++ const struct firmware *uninitialized_var(fw);
+
+ err = request_ihex_firmware(&fw, "vicam/firmware.fw", &cam->udev->dev);
+ if (err) {
+diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
+index 9e4f506..a0feb1c 100644
+--- a/drivers/media/video/usbvision/usbvision-core.c
++++ b/drivers/media/video/usbvision/usbvision-core.c
+@@ -36,7 +36,6 @@
+ #include <linux/spinlock.h>
+ #include <asm/io.h>
+ #include <linux/videodev2.h>
+-#include <linux/video_decoder.h>
+ #include <linux/i2c.h>
+
+ #include <media/saa7115.h>
+@@ -381,8 +380,9 @@ int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
+ usbvision->scratch = vmalloc_32(scratch_buf_size);
+ scratch_reset(usbvision);
+ if(usbvision->scratch == NULL) {
+- err("%s: unable to allocate %d bytes for scratch",
+- __func__, scratch_buf_size);
++ dev_err(&usbvision->dev->dev,
++ "%s: unable to allocate %d bytes for scratch\n",
++ __func__, scratch_buf_size);
+ return -ENOMEM;
+ }
+ return 0;
+@@ -491,8 +491,9 @@ int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
+ int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2;
+ usbvision->IntraFrameBuffer = vmalloc_32(IFB_size);
+ if (usbvision->IntraFrameBuffer == NULL) {
+- err("%s: unable to allocate %d for compr. frame buffer",
+- __func__, IFB_size);
++ dev_err(&usbvision->dev->dev,
++ "%s: unable to allocate %d for compr. frame buffer\n",
++ __func__, IFB_size);
+ return -ENOMEM;
+ }
+ return 0;
+@@ -1514,8 +1515,9 @@ static void usbvision_isocIrq(struct urb *urb)
+ errCode = usb_submit_urb (urb, GFP_ATOMIC);
+
+ if(errCode) {
+- err("%s: usb_submit_urb failed: error %d",
+- __func__, errCode);
++ dev_err(&usbvision->dev->dev,
++ "%s: usb_submit_urb failed: error %d\n",
++ __func__, errCode);
+ }
+
+ return;
+@@ -1546,7 +1548,8 @@ int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg)
+ 0, (__u16) reg, buffer, 1, HZ);
+
+ if (errCode < 0) {
+- err("%s: failed: error %d", __func__, errCode);
++ dev_err(&usbvision->dev->dev,
++ "%s: failed: error %d\n", __func__, errCode);
+ return errCode;
+ }
+ return buffer[0];
+@@ -1574,7 +1577,8 @@ int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
+ USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ);
+
+ if (errCode < 0) {
+- err("%s: failed: error %d", __func__, errCode);
++ dev_err(&usbvision->dev->dev,
++ "%s: failed: error %d\n", __func__, errCode);
+ }
+ return errCode;
+ }
+@@ -1850,7 +1854,8 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
+ 0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ);
+
+ if (errCode < 0) {
+- err("%s failed: error %d", __func__, errCode);
++ dev_err(&usbvision->dev->dev,
++ "%s failed: error %d\n", __func__, errCode);
+ return errCode;
+ }
+ usbvision->curwidth = usbvision->stretch_width * UsbWidth;
+@@ -2236,7 +2241,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
+ (__u16) USBVISION_DRM_PRM1, value, 8, HZ);
+
+ if (rc < 0) {
+- err("%sERROR=%d", __func__, rc);
++ dev_err(&usbvision->dev->dev, "%sERROR=%d\n", __func__, rc);
+ return rc;
+ }
+
+@@ -2432,8 +2437,9 @@ int usbvision_set_alternate(struct usb_usbvision *dev)
+ PDEBUG(DBG_FUNC,"setting alternate %d with wMaxPacketSize=%u", dev->ifaceAlt,dev->isocPacketSize);
+ errCode = usb_set_interface(dev->dev, dev->iface, dev->ifaceAlt);
+ if (errCode < 0) {
+- err ("cannot change alternate number to %d (error=%i)",
+- dev->ifaceAlt, errCode);
++ dev_err(&dev->dev->dev,
++ "cannot change alternate number to %d (error=%i)\n",
++ dev->ifaceAlt, errCode);
+ return errCode;
+ }
+ }
+@@ -2484,7 +2490,8 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
+
+ urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
+ if (urb == NULL) {
+- err("%s: usb_alloc_urb() failed", __func__);
++ dev_err(&usbvision->dev->dev,
++ "%s: usb_alloc_urb() failed\n", __func__);
+ return -ENOMEM;
+ }
+ usbvision->sbuf[bufIdx].urb = urb;
+@@ -2496,7 +2503,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
+ urb->dev = dev;
+ urb->context = usbvision;
+ urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
+- urb->transfer_flags = URB_ISO_ASAP;
++ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = 1;
+ urb->transfer_buffer = usbvision->sbuf[bufIdx].data;
+ urb->complete = usbvision_isocIrq;
+@@ -2516,8 +2523,9 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
+ errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb,
+ GFP_KERNEL);
+ if (errCode) {
+- err("%s: usb_submit_urb(%d) failed: error %d",
+- __func__, bufIdx, errCode);
++ dev_err(&usbvision->dev->dev,
++ "%s: usb_submit_urb(%d) failed: error %d\n",
++ __func__, bufIdx, errCode);
+ }
+ }
+
+@@ -2566,8 +2574,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
+ errCode = usb_set_interface(usbvision->dev, usbvision->iface,
+ usbvision->ifaceAlt);
+ if (errCode < 0) {
+- err("%s: usb_set_interface() failed: error %d",
+- __func__, errCode);
++ dev_err(&usbvision->dev->dev,
++ "%s: usb_set_interface() failed: error %d\n",
++ __func__, errCode);
+ usbvision->last_error = errCode;
+ }
+ regValue = (16-usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
+@@ -2623,7 +2632,7 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
+ }
+ route.input = mode[channel];
+ route.output = 0;
+- call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
++ call_all(usbvision, video, s_routing, &route);
+ usbvision_set_audio(usbvision, audio[channel]);
+ return 0;
+ }
+diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
+index 6b66ae4..dd2f8f2 100644
+--- a/drivers/media/video/usbvision/usbvision-i2c.c
++++ b/drivers/media/video/usbvision/usbvision-i2c.c
+@@ -119,7 +119,8 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
+ /* try extended address code... */
+ ret = try_write_address(i2c_adap, addr, retries);
+ if (ret != 1) {
+- err("died at extended address code, while writing");
++ dev_err(&i2c_adap->dev,
++ "died at extended address code, while writing\n");
+ return -EREMOTEIO;
+ }
+ add[0] = addr;
+@@ -128,7 +129,8 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
+ addr |= 0x01;
+ ret = try_read_address(i2c_adap, addr, retries);
+ if (ret != 1) {
+- err("died at extended address code, while reading");
++ dev_err(&i2c_adap->dev,
++ "died at extended address code, while reading\n");
+ return -EREMOTEIO;
+ }
+ }
+@@ -200,72 +202,78 @@ static struct i2c_algorithm usbvision_algo = {
+ };
+
+
+-/*
+- * registering functions to load algorithms at runtime
+- */
+-static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap)
+-{
+- PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]");
+- PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]");
+-
+- /* register new adapter to i2c module... */
+-
+- adap->algo = &usbvision_algo;
+-
+- adap->timeout = 100; /* default values, should */
+- adap->retries = 3; /* be replaced by defines */
+-
+- i2c_add_adapter(adap);
+-
+- PDEBUG(DBG_I2C,"i2c bus for %s registered", adap->name);
+-
+- return 0;
+-}
+-
+ /* ----------------------------------------------------------------------- */
+ /* usbvision specific I2C functions */
+ /* ----------------------------------------------------------------------- */
+ static struct i2c_adapter i2c_adap_template;
+-static struct i2c_client i2c_client_template;
+
+ int usbvision_i2c_register(struct usb_usbvision *usbvision)
+ {
++ static unsigned short saa711x_addrs[] = {
++ 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
++ 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
++ I2C_CLIENT_END };
++
+ memcpy(&usbvision->i2c_adap, &i2c_adap_template,
+ sizeof(struct i2c_adapter));
+- memcpy(&usbvision->i2c_client, &i2c_client_template,
+- sizeof(struct i2c_client));
+
+ sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name),
+ " #%d", usbvision->vdev->num);
+ PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
+ usbvision->i2c_adap.dev.parent = &usbvision->dev->dev;
+
+- i2c_set_adapdata(&usbvision->i2c_adap, usbvision);
+- i2c_set_clientdata(&usbvision->i2c_client, usbvision);
+-
+- usbvision->i2c_client.adapter = &usbvision->i2c_adap;
++ i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
+
+ if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
+ printk(KERN_ERR "usbvision_register: can't write reg\n");
+ return -EBUSY;
+ }
+
+-#ifdef CONFIG_MODULES
++ PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]");
++ PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]");
++
++ /* register new adapter to i2c module... */
++
++ usbvision->i2c_adap.algo = &usbvision_algo;
++
++ usbvision->i2c_adap.timeout = 100; /* default values, should */
++ usbvision->i2c_adap.retries = 3; /* be replaced by defines */
++
++ i2c_add_adapter(&usbvision->i2c_adap);
++
++ PDEBUG(DBG_I2C, "i2c bus for %s registered", usbvision->i2c_adap.name);
++
+ /* Request the load of the i2c modules we need */
+ switch (usbvision_device_data[usbvision->DevModel].Codec) {
+ case CODEC_SAA7113:
+- request_module("saa7115");
+- break;
+ case CODEC_SAA7111:
+- request_module("saa7115");
++ v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "saa7115",
++ "saa7115_auto", saa711x_addrs);
+ break;
+ }
+ if (usbvision_device_data[usbvision->DevModel].Tuner == 1) {
+- request_module("tuner");
++ struct v4l2_subdev *sd;
++ enum v4l2_i2c_tuner_type type;
++ struct tuner_setup tun_setup;
++
++ sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner",
++ "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
++ /* depending on whether we found a demod or not, select
++ the tuner type. */
++ type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
++
++ sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner",
++ "tuner", v4l2_i2c_tuner_addrs(type));
++
++ if (usbvision->tuner_type != -1) {
++ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
++ tun_setup.type = usbvision->tuner_type;
++ tun_setup.addr = v4l2_i2c_subdev_addr(sd);
++ call_all(usbvision, tuner, s_type_addr, &tun_setup);
++ }
+ }
+-#endif
+
+- return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap);
++ return 0;
+ }
+
+ int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
+@@ -278,67 +286,6 @@ int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
+ return 0;
+ }
+
+-void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,
+- void *arg)
+-{
+- i2c_clients_command(&usbvision->i2c_adap, cmd, arg);
+-}
+-
+-static int attach_inform(struct i2c_client *client)
+-{
+- struct usb_usbvision *usbvision;
+-
+- usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
+-
+- switch (client->addr << 1) {
+- case 0x42 << 1:
+- case 0x43 << 1:
+- case 0x4a << 1:
+- case 0x4b << 1:
+- PDEBUG(DBG_I2C,"attach_inform: tda9887 detected.");
+- break;
+- case 0x42:
+- PDEBUG(DBG_I2C,"attach_inform: saa7114 detected.");
+- break;
+- case 0x4a:
+- PDEBUG(DBG_I2C,"attach_inform: saa7113 detected.");
+- break;
+- case 0x48:
+- PDEBUG(DBG_I2C,"attach_inform: saa7111 detected.");
+- break;
+- case 0xa0:
+- PDEBUG(DBG_I2C,"attach_inform: eeprom detected.");
+- break;
+-
+- default:
+- {
+- struct tuner_setup tun_setup;
+-
+- PDEBUG(DBG_I2C,"attach inform: detected I2C address %x", client->addr << 1);
+- usbvision->tuner_addr = client->addr;
+-
+- if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) {
+- tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+- tun_setup.type = usbvision->tuner_type;
+- tun_setup.addr = usbvision->tuner_addr;
+- call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup);
+- }
+- }
+- break;
+- }
+- return 0;
+-}
+-
+-static int detach_inform(struct i2c_client *client)
+-{
+- struct usb_usbvision *usbvision;
+-
+- usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
+-
+- PDEBUG(DBG_I2C,"usbvision[%d] detaches %s", usbvision->nr, client->name);
+- return 0;
+-}
+-
+ static int
+ usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr,
+ char *buf, short len)
+@@ -511,14 +458,6 @@ static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char add
+ static struct i2c_adapter i2c_adap_template = {
+ .owner = THIS_MODULE,
+ .name = "usbvision",
+- .id = I2C_HW_B_BT848, /* FIXME */
+- .client_register = attach_inform,
+- .client_unregister = detach_inform,
+- .class = I2C_CLASS_TV_ANALOG,
+-};
+-
+-static struct i2c_client i2c_client_template = {
+- .name = "usbvision internal",
+ };
+
+ /*
+diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
+index 2622de0..fa62a2f 100644
+--- a/drivers/media/video/usbvision/usbvision-video.c
++++ b/drivers/media/video/usbvision/usbvision-video.c
+@@ -59,7 +59,6 @@
+ #include <linux/spinlock.h>
+ #include <asm/io.h>
+ #include <linux/videodev2.h>
+-#include <linux/video_decoder.h>
+ #include <linux/i2c.h>
+
+ #include <media/saa7115.h>
+@@ -212,7 +211,7 @@ static ssize_t show_hue(struct device *cd,
+ ctrl.id = V4L2_CID_HUE;
+ ctrl.value = 0;
+ if(usbvision->user)
+- call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
++ call_all(usbvision, core, g_ctrl, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value);
+ }
+ static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+@@ -227,7 +226,7 @@ static ssize_t show_contrast(struct device *cd,
+ ctrl.id = V4L2_CID_CONTRAST;
+ ctrl.value = 0;
+ if(usbvision->user)
+- call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
++ call_all(usbvision, core, g_ctrl, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value);
+ }
+ static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+@@ -242,7 +241,7 @@ static ssize_t show_brightness(struct device *cd,
+ ctrl.id = V4L2_CID_BRIGHTNESS;
+ ctrl.value = 0;
+ if(usbvision->user)
+- call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
++ call_all(usbvision, core, g_ctrl, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value);
+ }
+ static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+@@ -257,7 +256,7 @@ static ssize_t show_saturation(struct device *cd,
+ ctrl.id = V4L2_CID_SATURATION;
+ ctrl.value = 0;
+ if(usbvision->user)
+- call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
++ call_all(usbvision, core, g_ctrl, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value);
+ }
+ static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+@@ -329,7 +328,7 @@ static void usbvision_create_sysfs(struct video_device *vdev)
+ return;
+ } while (0);
+
+- err("%s error: %d\n", __func__, res);
++ dev_err(&vdev->dev, "%s error: %d\n", __func__, res);
+ }
+
+ static void usbvision_remove_sysfs(struct video_device *vdev)
+@@ -487,8 +486,9 @@ static int vidioc_g_register (struct file *file, void *priv,
+ /* NT100x has a 8-bit register space */
+ errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+ if (errCode < 0) {
+- err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
+- __func__, errCode);
++ dev_err(&usbvision->vdev->dev,
++ "%s: VIDIOC_DBG_G_REGISTER failed: error %d\n",
++ __func__, errCode);
+ return errCode;
+ }
+ reg->val = errCode;
+@@ -507,8 +507,9 @@ static int vidioc_s_register (struct file *file, void *priv,
+ /* NT100x has a 8-bit register space */
+ errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+ if (errCode < 0) {
+- err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
+- __func__, errCode);
++ dev_err(&usbvision->vdev->dev,
++ "%s: VIDIOC_DBG_S_REGISTER failed: error %d\n",
++ __func__, errCode);
+ return errCode;
+ }
+ return 0;
+@@ -524,8 +525,7 @@ static int vidioc_querycap (struct file *file, void *priv,
+ strlcpy(vc->card,
+ usbvision_device_data[usbvision->DevModel].ModelString,
+ sizeof(vc->card));
+- strlcpy(vc->bus_info, dev_name(&usbvision->dev->dev),
+- sizeof(vc->bus_info));
++ usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
+ vc->version = USBVISION_DRIVER_VERSION;
+ vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+@@ -621,8 +621,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+ usbvision->tvnormId=*id;
+
+ mutex_lock(&usbvision->lock);
+- call_i2c_clients(usbvision, VIDIOC_S_STD,
+- &usbvision->tvnormId);
++ call_all(usbvision, tuner, s_std, usbvision->tvnormId);
+ mutex_unlock(&usbvision->lock);
+ /* propagate the change to the decoder */
+ usbvision_muxsel(usbvision, usbvision->ctl_input);
+@@ -644,7 +643,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
+ strcpy(vt->name, "Television");
+ }
+ /* Let clients fill in the remainder of this struct */
+- call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
++ call_all(usbvision, tuner, g_tuner, vt);
+
+ return 0;
+ }
+@@ -658,7 +657,7 @@ static int vidioc_s_tuner (struct file *file, void *priv,
+ if (!usbvision->have_tuner || vt->index)
+ return -EINVAL;
+ /* let clients handle this */
+- call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
++ call_all(usbvision, tuner, s_tuner, vt);
+
+ return 0;
+ }
+@@ -689,7 +688,7 @@ static int vidioc_s_frequency (struct file *file, void *priv,
+ return -EINVAL;
+
+ usbvision->freq = freq->frequency;
+- call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
++ call_all(usbvision, tuner, s_frequency, freq);
+
+ return 0;
+ }
+@@ -698,7 +697,6 @@ static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+ {
+ struct usb_usbvision *usbvision = video_drvdata(file);
+
+- memset(a,0,sizeof(*a));
+ if(usbvision->radio) {
+ strcpy(a->name,"Radio");
+ } else {
+@@ -722,12 +720,8 @@ static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *ctrl)
+ {
+ struct usb_usbvision *usbvision = video_drvdata(file);
+- int id=ctrl->id;
+
+- memset(ctrl,0,sizeof(*ctrl));
+- ctrl->id=id;
+-
+- call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
++ call_all(usbvision, core, queryctrl, ctrl);
+
+ if (!ctrl->type)
+ return -EINVAL;
+@@ -739,7 +733,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+ struct usb_usbvision *usbvision = video_drvdata(file);
+- call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
++ call_all(usbvision, core, g_ctrl, ctrl);
+
+ return 0;
+ }
+@@ -748,7 +742,7 @@ static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
+ struct usb_usbvision *usbvision = video_drvdata(file);
+- call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
++ call_all(usbvision, core, s_ctrl, ctrl);
+
+ return 0;
+ }
+@@ -763,8 +757,7 @@ static int vidioc_reqbufs (struct file *file,
+
+ /* Check input validity:
+ the user must do a VIDEO CAPTURE and MMAP method. */
+- if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+- (vr->memory != V4L2_MEMORY_MMAP))
++ if (vr->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ if(usbvision->streaming == Stream_On) {
+@@ -789,9 +782,6 @@ static int vidioc_querybuf (struct file *file,
+
+ /* FIXME : must control
+ that buffers are mapped (VIDIOC_REQBUFS has been called) */
+- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+- return -EINVAL;
+- }
+ if(vb->index>=usbvision->num_frames) {
+ return -EINVAL;
+ }
+@@ -825,9 +815,6 @@ static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+ unsigned long lock_flags;
+
+ /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
+- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+- return -EINVAL;
+- }
+ if(vb->index>=usbvision->num_frames) {
+ return -EINVAL;
+ }
+@@ -862,9 +849,6 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+ struct usbvision_frame *f;
+ unsigned long lock_flags;
+
+- if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+-
+ if (list_empty(&(usbvision->outqueue))) {
+ if (usbvision->streaming == Stream_Idle)
+ return -EINVAL;
+@@ -899,10 +883,9 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+ {
+ struct usb_usbvision *usbvision = video_drvdata(file);
+- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ usbvision->streaming = Stream_On;
+- call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
++ call_all(usbvision, video, s_stream, 1);
+
+ return 0;
+ }
+@@ -911,7 +894,6 @@ static int vidioc_streamoff(struct file *file,
+ void *priv, enum v4l2_buf_type type)
+ {
+ struct usb_usbvision *usbvision = video_drvdata(file);
+- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+@@ -919,7 +901,7 @@ static int vidioc_streamoff(struct file *file,
+ if(usbvision->streaming == Stream_On) {
+ usbvision_stream_interrupt(usbvision);
+ /* Stop all video streamings */
+- call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
++ call_all(usbvision, video, s_stream, 0);
+ }
+ usbvision_empty_framequeues(usbvision);
+
+@@ -932,11 +914,8 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
+ if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+ return -EINVAL;
+ }
+- vfd->flags = 0;
+- vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+ vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
+- memset(vfd->reserved, 0, sizeof(vfd->reserved));
+ return 0;
+ }
+
+@@ -1042,7 +1021,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
+ if(usbvision->streaming != Stream_On) {
+ /* no stream is running, make it running ! */
+ usbvision->streaming = Stream_On;
+- call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
++ call_all(usbvision, video, s_stream, 1);
+ }
+
+ /* Then, enqueue as many frames as possible
+@@ -1189,7 +1168,9 @@ static int usbvision_radio_open(struct file *file)
+ mutex_lock(&usbvision->lock);
+
+ if (usbvision->user) {
+- err("%s: Someone tried to open an already opened USBVision Radio!", __func__);
++ dev_err(&usbvision->rdev->dev,
++ "%s: Someone tried to open an already opened USBVision Radio!\n",
++ __func__);
+ errCode = -EBUSY;
+ }
+ else {
+@@ -1211,7 +1192,7 @@ static int usbvision_radio_open(struct file *file)
+
+ // If so far no errors then we shall start the radio
+ usbvision->radio = 1;
+- call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
++ call_all(usbvision, tuner, s_radio);
+ usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
+ usbvision->user++;
+ }
+@@ -1413,7 +1394,8 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
+ struct video_device *vdev;
+
+ if (usb_dev == NULL) {
+- err("%s: usbvision->dev is not set", __func__);
++ dev_err(&usbvision->dev->dev,
++ "%s: usbvision->dev is not set\n", __func__);
+ return NULL;
+ }
+
+@@ -1423,7 +1405,7 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
+ }
+ *vdev = *vdev_template;
+ // vdev->minor = -1;
+- vdev->parent = &usb_dev->dev;
++ vdev->v4l2_dev = &usbvision->v4l2_dev;
+ snprintf(vdev->name, sizeof(vdev->name), "%s", name);
+ video_set_drvdata(vdev, usbvision);
+ return vdev;
+@@ -1524,7 +1506,9 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
+ return 0;
+
+ err_exit:
+- err("USBVision[%d]: video_register_device() failed", usbvision->nr);
++ dev_err(&usbvision->dev->dev,
++ "USBVision[%d]: video_register_device() failed\n",
++ usbvision->nr);
+ usbvision_unregister_video(usbvision);
+ return -1;
+ }
+@@ -1542,33 +1526,30 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
+ {
+ struct usb_usbvision *usbvision;
+
+- if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
+- NULL) {
+- goto err_exit;
+- }
++ usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL);
++ if (usbvision == NULL)
++ return NULL;
+
+ usbvision->dev = dev;
++ if (v4l2_device_register(&dev->dev, &usbvision->v4l2_dev))
++ goto err_free;
+
+ mutex_init(&usbvision->lock); /* available */
+
+ // prepare control urb for control messages during interrupts
+ usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
+- if (usbvision->ctrlUrb == NULL) {
+- goto err_exit;
+- }
++ if (usbvision->ctrlUrb == NULL)
++ goto err_unreg;
+ init_waitqueue_head(&usbvision->ctrlUrb_wq);
+
+ usbvision_init_powerOffTimer(usbvision);
+
+ return usbvision;
+
+-err_exit:
+- if (usbvision && usbvision->ctrlUrb) {
+- usb_free_urb(usbvision->ctrlUrb);
+- }
+- if (usbvision) {
+- kfree(usbvision);
+- }
++err_unreg:
++ v4l2_device_unregister(&usbvision->v4l2_dev);
++err_free:
++ kfree(usbvision);
+ return NULL;
+ }
+
+@@ -1598,6 +1579,7 @@ static void usbvision_release(struct usb_usbvision *usbvision)
+ usb_free_urb(usbvision->ctrlUrb);
+ }
+
++ v4l2_device_unregister(&usbvision->v4l2_dev);
+ kfree(usbvision);
+
+ PDEBUG(DBG_PROBE, "success");
+@@ -1675,20 +1657,20 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
+ }
+ endpoint = &interface->endpoint[1].desc;
+ if (!usb_endpoint_xfer_isoc(endpoint)) {
+- err("%s: interface %d. has non-ISO endpoint!",
++ dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
+ __func__, ifnum);
+- err("%s: Endpoint attributes %d",
++ dev_err(&intf->dev, "%s: Endpoint attributes %d",
+ __func__, endpoint->bmAttributes);
+ return -ENODEV;
+ }
+ if (usb_endpoint_dir_out(endpoint)) {
+- err("%s: interface %d. has ISO OUT endpoint!",
++ dev_err(&intf->dev, "%s: interface %d. has ISO OUT endpoint!\n",
+ __func__, ifnum);
+ return -ENODEV;
+ }
+
+ if ((usbvision = usbvision_alloc(dev)) == NULL) {
+- err("%s: couldn't allocate USBVision struct", __func__);
++ dev_err(&intf->dev, "%s: couldn't allocate USBVision struct\n", __func__);
+ return -ENOMEM;
+ }
+
+@@ -1711,7 +1693,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
+ usbvision->alt_max_pkt_size = kmalloc(32*
+ usbvision->num_alt,GFP_KERNEL);
+ if (usbvision->alt_max_pkt_size == NULL) {
+- err("usbvision: out of memory!\n");
++ dev_err(&intf->dev, "usbvision: out of memory!\n");
+ mutex_unlock(&usbvision->lock);
+ return -ENOMEM;
+ }
+@@ -1733,8 +1715,6 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
+ usbvision->tuner_type = usbvision_device_data[model].TunerType;
+ }
+
+- usbvision->tuner_addr = ADDR_UNSET;
+-
+ usbvision->DevModel = model;
+ usbvision->remove_pending = 0;
+ usbvision->iface = ifnum;
+@@ -1772,7 +1752,8 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
+ PDEBUG(DBG_PROBE, "");
+
+ if (usbvision == NULL) {
+- err("%s: usb_get_intfdata() failed", __func__);
++ dev_err(&usbvision->dev->dev,
++ "%s: usb_get_intfdata() failed\n", __func__);
+ return;
+ }
+ usb_set_intfdata (intf, NULL);
+@@ -1782,6 +1763,8 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
+ // At this time we ask to cancel outstanding URBs
+ usbvision_stop_isoc(usbvision);
+
++ v4l2_device_disconnect(&usbvision->v4l2_dev);
++
+ if (usbvision->power) {
+ usbvision_i2c_unregister(usbvision);
+ usbvision_power_off(usbvision);
+diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
+index 20d7ec6..f8d7458 100644
+--- a/drivers/media/video/usbvision/usbvision.h
++++ b/drivers/media/video/usbvision/usbvision.h
+@@ -6,7 +6,7 @@
+ * Dwaine Garden <dwainegarden@rogers.com>
+ *
+ *
+- * Report problems to v4l MailingList : http://www.redhat.com/mailman/listinfo/video4linux-list
++ * Report problems to v4l MailingList: linux-media@vger.kernel.org
+ *
+ * This module is part of usbvision driver project.
+ * Updates to driver completed by Dwaine P. Garden
+@@ -35,7 +35,7 @@
+ #include <linux/usb.h>
+ #include <linux/i2c.h>
+ #include <linux/mutex.h>
+-#include <media/v4l2-common.h>
++#include <media/v4l2-device.h>
+ #include <media/tuner.h>
+ #include <linux/videodev2.h>
+
+@@ -357,13 +357,13 @@ extern struct usbvision_device_data_st usbvision_device_data[];
+ extern struct usb_device_id usbvision_table[];
+
+ struct usb_usbvision {
++ struct v4l2_device v4l2_dev;
+ struct video_device *vdev; /* Video Device */
+ struct video_device *rdev; /* Radio Device */
+ struct video_device *vbi; /* VBI Device */
+
+ /* i2c Declaration Section*/
+ struct i2c_adapter i2c_adap;
+- struct i2c_client i2c_client;
+
+ struct urb *ctrlUrb;
+ unsigned char ctrlUrbBuffer[8];
+@@ -374,7 +374,6 @@ struct usb_usbvision {
+ /* configuration part */
+ int have_tuner;
+ int tuner_type;
+- int tuner_addr;
+ int bridgeType; // NT1003, NT1004, NT1005
+ int radio;
+ int video_inputs; // # of inputs
+@@ -464,6 +463,8 @@ struct usb_usbvision {
+ int ComprBlockTypes[4];
+ };
+
++#define call_all(usbvision, o, f, args...) \
++ v4l2_device_call_all(&usbvision->v4l2_dev, 0, o, f, ##args)
+
+ /* --------------------------------------------------------------- */
+ /* defined in usbvision-i2c.c */
+@@ -475,7 +476,6 @@ struct usb_usbvision {
+ /* ----------------------------------------------------------------------- */
+ int usbvision_i2c_register(struct usb_usbvision *usbvision);
+ int usbvision_i2c_unregister(struct usb_usbvision *usbvision);
+-void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg);
+
+ /* defined in usbvision-core.c */
+ int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
+diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
+index d2576f6..0d7e38d 100644
+--- a/drivers/media/video/uvc/uvc_ctrl.c
++++ b/drivers/media/video/uvc/uvc_ctrl.c
+@@ -786,7 +786,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+ memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
+ v4l2_ctrl->id = mapping->id;
+ v4l2_ctrl->type = mapping->v4l2_type;
+- strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
++ strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
+ v4l2_ctrl->flags = 0;
+
+ if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
+diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
+index b128732..399412d 100644
+--- a/drivers/media/video/uvc/uvc_driver.c
++++ b/drivers/media/video/uvc/uvc_driver.c
+@@ -314,7 +314,7 @@ static int uvc_parse_format(struct uvc_device *dev,
+ fmtdesc = uvc_format_by_guid(&buffer[5]);
+
+ if (fmtdesc != NULL) {
+- strncpy(format->name, fmtdesc->name,
++ strlcpy(format->name, fmtdesc->name,
+ sizeof format->name);
+ format->fcc = fmtdesc->fcc;
+ } else {
+@@ -345,7 +345,7 @@ static int uvc_parse_format(struct uvc_device *dev,
+ return -EINVAL;
+ }
+
+- strncpy(format->name, "MJPEG", sizeof format->name);
++ strlcpy(format->name, "MJPEG", sizeof format->name);
+ format->fcc = V4L2_PIX_FMT_MJPEG;
+ format->flags = UVC_FMT_FLAG_COMPRESSED;
+ format->bpp = 0;
+@@ -363,13 +363,13 @@ static int uvc_parse_format(struct uvc_device *dev,
+
+ switch (buffer[8] & 0x7f) {
+ case 0:
+- strncpy(format->name, "SD-DV", sizeof format->name);
++ strlcpy(format->name, "SD-DV", sizeof format->name);
+ break;
+ case 1:
+- strncpy(format->name, "SDL-DV", sizeof format->name);
++ strlcpy(format->name, "SDL-DV", sizeof format->name);
+ break;
+ case 2:
+- strncpy(format->name, "HD-DV", sizeof format->name);
++ strlcpy(format->name, "HD-DV", sizeof format->name);
+ break;
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+@@ -379,7 +379,7 @@ static int uvc_parse_format(struct uvc_device *dev,
+ return -EINVAL;
+ }
+
+- strncat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
++ strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
+ sizeof format->name);
+
+ format->fcc = V4L2_PIX_FMT_DV;
+@@ -1526,7 +1526,7 @@ static int uvc_register_video(struct uvc_device *dev)
+ vdev->minor = -1;
+ vdev->fops = &uvc_fops;
+ vdev->release = video_device_release;
+- strncpy(vdev->name, dev->name, sizeof vdev->name);
++ strlcpy(vdev->name, dev->name, sizeof vdev->name);
+
+ /* Set the driver data before calling video_register_device, otherwise
+ * uvc_v4l2_open might race us.
+@@ -1621,7 +1621,7 @@ static int uvc_probe(struct usb_interface *intf,
+ dev->quirks = id->driver_info | uvc_quirks_param;
+
+ if (udev->product != NULL)
+- strncpy(dev->name, udev->product, sizeof dev->name);
++ strlcpy(dev->name, udev->product, sizeof dev->name);
+ else
+ snprintf(dev->name, sizeof dev->name,
+ "UVC Camera (%04x:%04x)",
+@@ -1833,6 +1833,15 @@ static struct usb_device_id uvc_ids[] = {
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
++ /* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
++ | USB_DEVICE_ID_MATCH_INT_INFO,
++ .idVendor = 0x058f,
++ .idProduct = 0x3820,
++ .bInterfaceClass = USB_CLASS_VIDEO,
++ .bInterfaceSubClass = 1,
++ .bInterfaceProtocol = 0,
++ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Apple Built-In iSight */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+@@ -1852,6 +1861,15 @@ static struct usb_device_id uvc_ids[] = {
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
++ /* ViMicro */
++ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
++ | USB_DEVICE_ID_MATCH_INT_INFO,
++ .idVendor = 0x0ac8,
++ .idProduct = 0x0000,
++ .bInterfaceClass = USB_CLASS_VIDEO,
++ .bInterfaceSubClass = 1,
++ .bInterfaceProtocol = 0,
++ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
+ /* MT6227 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+@@ -1879,7 +1897,7 @@ static struct usb_device_id uvc_ids[] = {
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+- /* Asus F9SG */
++ /* Syntek (Asus F9SG) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+@@ -1897,6 +1915,15 @@ static struct usb_device_id uvc_ids[] = {
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
++ /* Syntek (JAOtech Smart Terminal) */
++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
++ | USB_DEVICE_ID_MATCH_INT_INFO,
++ .idVendor = 0x174f,
++ .idProduct = 0x8a34,
++ .bInterfaceClass = USB_CLASS_VIDEO,
++ .bInterfaceSubClass = 1,
++ .bInterfaceProtocol = 0,
++ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Lenovo Thinkpad SL500 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
+index c705f24..21d8712 100644
+--- a/drivers/media/video/uvc/uvc_status.c
++++ b/drivers/media/video/uvc/uvc_status.c
+@@ -24,26 +24,19 @@
+ #ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
+ static int uvc_input_init(struct uvc_device *dev)
+ {
+- struct usb_device *udev = dev->udev;
+ struct input_dev *input;
+- char *phys = NULL;
+ int ret;
+
+ input = input_allocate_device();
+ if (input == NULL)
+ return -ENOMEM;
+
+- phys = kmalloc(6 + strlen(udev->bus->bus_name) + strlen(udev->devpath),
+- GFP_KERNEL);
+- if (phys == NULL) {
+- ret = -ENOMEM;
+- goto error;
+- }
+- sprintf(phys, "usb-%s-%s", udev->bus->bus_name, udev->devpath);
++ usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys));
++ strlcat(dev->input_phys, "/button", sizeof(dev->input_phys));
+
+ input->name = dev->name;
+- input->phys = phys;
+- usb_to_input_id(udev, &input->id);
++ input->phys = dev->input_phys;
++ usb_to_input_id(dev->udev, &input->id);
+ input->dev.parent = &dev->intf->dev;
+
+ __set_bit(EV_KEY, input->evbit);
+@@ -57,7 +50,6 @@ static int uvc_input_init(struct uvc_device *dev)
+
+ error:
+ input_free_device(input);
+- kfree(phys);
+ return ret;
+ }
+
+diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
+index d681519..2a80caa 100644
+--- a/drivers/media/video/uvc/uvc_v4l2.c
++++ b/drivers/media/video/uvc/uvc_v4l2.c
+@@ -55,7 +55,7 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video,
+ return -EINVAL;
+
+ menu_info = &mapping->menu_info[query_menu->index];
+- strncpy(query_menu->name, menu_info->name, 32);
++ strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
+ return 0;
+ }
+
+@@ -486,10 +486,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ struct v4l2_capability *cap = arg;
+
+ memset(cap, 0, sizeof *cap);
+- strncpy(cap->driver, "uvcvideo", sizeof cap->driver);
+- strncpy(cap->card, vdev->name, 32);
+- strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
+- sizeof cap->bus_info);
++ strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
++ strlcpy(cap->card, vdev->name, sizeof cap->card);
++ usb_make_path(video->dev->udev,
++ cap->bus_info, sizeof(cap->bus_info));
+ cap->version = DRIVER_VERSION_NUMBER;
+ if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+@@ -620,7 +620,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+
+ memset(input, 0, sizeof *input);
+ input->index = index;
+- strncpy(input->name, iterm->name, sizeof input->name);
++ strlcpy(input->name, iterm->name, sizeof input->name);
+ if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ break;
+@@ -673,16 +673,22 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ {
+ struct v4l2_fmtdesc *fmt = arg;
+ struct uvc_format *format;
++ enum v4l2_buf_type type = fmt->type;
++ __u32 index = fmt->index;
+
+ if (fmt->type != video->streaming->type ||
+ fmt->index >= video->streaming->nformats)
+ return -EINVAL;
+
++ memset(fmt, 0, sizeof(*fmt));
++ fmt->index = index;
++ fmt->type = type;
++
+ format = &video->streaming->format[fmt->index];
+ fmt->flags = 0;
+ if (format->flags & UVC_FMT_FLAG_COMPRESSED)
+ fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+- strncpy(fmt->description, format->name,
++ strlcpy(fmt->description, format->name,
+ sizeof fmt->description);
+ fmt->description[sizeof fmt->description - 1] = 0;
+ fmt->pixelformat = format->fcc;
+diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
+index 9bc4705..a95e173 100644
+--- a/drivers/media/video/uvc/uvc_video.c
++++ b/drivers/media/video/uvc/uvc_video.c
+@@ -61,7 +61,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ return 0;
+ }
+
+-static void uvc_fixup_buffer_size(struct uvc_video_device *video,
++static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl)
+ {
+ struct uvc_format *format;
+@@ -84,6 +84,31 @@ static void uvc_fixup_buffer_size(struct uvc_video_device *video,
+ video->dev->uvc_version < 0x0110))
+ ctrl->dwMaxVideoFrameSize =
+ frame->dwMaxVideoFrameBufferSize;
++
++ if (video->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
++ video->streaming->intf->num_altsetting > 1) {
++ u32 interval;
++ u32 bandwidth;
++
++ interval = (ctrl->dwFrameInterval > 100000)
++ ? ctrl->dwFrameInterval
++ : frame->dwFrameInterval[0];
++
++ /* Compute a bandwidth estimation by multiplying the frame
++ * size by the number of video frames per second, divide the
++ * result by the number of USB frames (or micro-frames for
++ * high-speed devices) per second and add the UVC header size
++ * (assumed to be 12 bytes long).
++ */
++ bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
++ bandwidth *= 10000000 / interval + 1;
++ bandwidth /= 1000;
++ if (video->dev->udev->speed == USB_SPEED_HIGH)
++ bandwidth /= 8;
++ bandwidth += 12;
++
++ ctrl->dwMaxPayloadTransferSize = bandwidth;
++ }
+ }
+
+ static int uvc_get_video_ctrl(struct uvc_video_device *video,
+@@ -158,10 +183,11 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
+ ctrl->bMaxVersion = 0;
+ }
+
+- /* Some broken devices return a null or wrong dwMaxVideoFrameSize.
+- * Try to get the value from the format and frame descriptors.
++ /* Some broken devices return null or wrong dwMaxVideoFrameSize and
++ * dwMaxPayloadTransferSize fields. Try to get the value from the
++ * format and frame descriptors.
+ */
+- uvc_fixup_buffer_size(video, ctrl);
++ uvc_fixup_video_ctrl(video, ctrl);
+ ret = 0;
+
+ out:
+@@ -540,6 +566,9 @@ static void uvc_video_decode_bulk(struct urb *urb,
+ u8 *mem;
+ int len, ret;
+
++ if (urb->actual_length == 0)
++ return;
++
+ mem = urb->transfer_buffer;
+ len = urb->actual_length;
+ video->bulk.payload_size += len;
+@@ -699,27 +728,47 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video)
+ * already allocated when resuming from suspend, in which case it will
+ * return without touching the buffers.
+ *
+- * Return 0 on success or -ENOMEM when out of memory.
++ * Limit the buffer size to UVC_MAX_PACKETS bulk/isochronous packets. If the
++ * system is too low on memory try successively smaller numbers of packets
++ * until allocation succeeds.
++ *
++ * Return the number of allocated packets on success or 0 when out of memory.
+ */
+ static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
+- unsigned int size)
++ unsigned int size, unsigned int psize, gfp_t gfp_flags)
+ {
++ unsigned int npackets;
+ unsigned int i;
+
+ /* Buffers are already allocated, bail out. */
+ if (video->urb_size)
+ return 0;
+
+- for (i = 0; i < UVC_URBS; ++i) {
+- video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
+- size, GFP_KERNEL, &video->urb_dma[i]);
+- if (video->urb_buffer[i] == NULL) {
+- uvc_free_urb_buffers(video);
+- return -ENOMEM;
++ /* Compute the number of packets. Bulk endpoints might transfer UVC
++ * payloads accross multiple URBs.
++ */
++ npackets = DIV_ROUND_UP(size, psize);
++ if (npackets > UVC_MAX_PACKETS)
++ npackets = UVC_MAX_PACKETS;
++
++ /* Retry allocations until one succeed. */
++ for (; npackets > 1; npackets /= 2) {
++ for (i = 0; i < UVC_URBS; ++i) {
++ video->urb_buffer[i] = usb_buffer_alloc(
++ video->dev->udev, psize * npackets,
++ gfp_flags | __GFP_NOWARN, &video->urb_dma[i]);
++ if (!video->urb_buffer[i]) {
++ uvc_free_urb_buffers(video);
++ break;
++ }
++ }
++
++ if (i == UVC_URBS) {
++ video->urb_size = psize * npackets;
++ return npackets;
+ }
+ }
+
+- video->urb_size = size;
+ return 0;
+ }
+
+@@ -753,29 +802,19 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
+ {
+ struct urb *urb;
+ unsigned int npackets, i, j;
+- __u16 psize;
+- __u32 size;
++ u16 psize;
++ u32 size;
+
+- /* Compute the number of isochronous packets to allocate by dividing
+- * the maximum video frame size by the packet size. Limit the result
+- * to UVC_MAX_ISO_PACKETS.
+- */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+-
+ size = video->streaming->ctrl.dwMaxVideoFrameSize;
+- if (size > UVC_MAX_FRAME_SIZE)
+- return -EINVAL;
+
+- npackets = DIV_ROUND_UP(size, psize);
+- if (npackets > UVC_MAX_ISO_PACKETS)
+- npackets = UVC_MAX_ISO_PACKETS;
++ npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
++ if (npackets == 0)
++ return -ENOMEM;
+
+ size = npackets * psize;
+
+- if (uvc_alloc_urb_buffers(video, size) < 0)
+- return -ENOMEM;
+-
+ for (i = 0; i < UVC_URBS; ++i) {
+ urb = usb_alloc_urb(npackets, gfp_flags);
+ if (urb == NULL) {
+@@ -814,25 +853,20 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
+ struct usb_host_endpoint *ep, gfp_t gfp_flags)
+ {
+ struct urb *urb;
+- unsigned int pipe, i;
+- __u16 psize;
+- __u32 size;
+-
+- /* Compute the bulk URB size. Some devices set the maximum payload
+- * size to a value too high for memory-constrained devices. We must
+- * then transfer the payload accross multiple URBs. To be consistant
+- * with isochronous mode, allocate maximum UVC_MAX_ISO_PACKETS per bulk
+- * URB.
+- */
++ unsigned int npackets, pipe, i;
++ u16 psize;
++ u32 size;
++
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
+ size = video->streaming->ctrl.dwMaxPayloadTransferSize;
+ video->bulk.max_payload_size = size;
+- if (size > psize * UVC_MAX_ISO_PACKETS)
+- size = psize * UVC_MAX_ISO_PACKETS;
+
+- if (uvc_alloc_urb_buffers(video, size) < 0)
++ npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
++ if (npackets == 0)
+ return -ENOMEM;
+
++ size = npackets * psize;
++
+ if (usb_endpoint_dir_in(&ep->desc))
+ pipe = usb_rcvbulkpipe(video->dev->udev,
+ ep->desc.bEndpointAddress);
+@@ -1021,11 +1055,20 @@ int uvc_video_init(struct uvc_video_device *video)
+ */
+ usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+
+- /* Some webcams don't suport GET_DEF requests on the probe control. We
+- * fall back to GET_CUR if GET_DEF fails.
++ /* Set the streaming probe control with default streaming parameters
++ * retrieved from the device. Webcams that don't suport GET_DEF
++ * requests on the probe control will just keep their current streaming
++ * parameters.
++ */
++ if (uvc_get_video_ctrl(video, probe, 1, GET_DEF) == 0)
++ uvc_set_video_ctrl(video, probe, 1);
++
++ /* Initialize the streaming parameters with the probe control current
++ * value. This makes sure SET_CUR requests on the streaming commit
++ * control will always use values retrieved from a successful GET_CUR
++ * request on the probe control, as required by the UVC specification.
+ */
+- if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 &&
+- (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
++ if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ return ret;
+
+ /* Check if the default format descriptor exists. Use the first
+diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
+index 027947e..e5014e6 100644
+--- a/drivers/media/video/uvc/uvcvideo.h
++++ b/drivers/media/video/uvc/uvcvideo.h
+@@ -296,10 +296,8 @@ struct uvc_xu_control {
+
+ /* Number of isochronous URBs. */
+ #define UVC_URBS 5
+-/* Maximum number of packets per isochronous URB. */
+-#define UVC_MAX_ISO_PACKETS 40
+-/* Maximum frame size in bytes, for sanity checking. */
+-#define UVC_MAX_FRAME_SIZE (16*1024*1024)
++/* Maximum number of packets per URB. */
++#define UVC_MAX_PACKETS 32
+ /* Maximum number of video buffers. */
+ #define UVC_MAX_VIDEO_BUFFERS 32
+ /* Maximum status buffer size in bytes of interrupt URB. */
+@@ -316,6 +314,7 @@ struct uvc_xu_control {
+ #define UVC_QUIRK_STREAM_NO_FID 0x00000010
+ #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
+ #define UVC_QUIRK_PRUNE_CONTROLS 0x00000040
++#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
+
+ /* Format flags */
+ #define UVC_FMT_FLAG_COMPRESSED 0x00000001
+@@ -649,6 +648,7 @@ struct uvc_device {
+ struct urb *int_urb;
+ __u8 *status;
+ struct input_dev *input;
++ char input_phys[64];
+
+ /* Video Streaming interfaces */
+ struct list_head streaming;
+diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
+index b8f2be8..1da8cb8 100644
+--- a/drivers/media/video/v4l2-common.c
++++ b/drivers/media/video/v4l2-common.c
+@@ -334,6 +334,12 @@ const char **v4l2_ctrl_get_menu(u32 id)
+ "Aperture Priority Mode",
+ NULL
+ };
++ static const char *colorfx[] = {
++ "None",
++ "Black & White",
++ "Sepia",
++ NULL
++ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+@@ -370,6 +376,8 @@ const char **v4l2_ctrl_get_menu(u32 id)
+ return camera_power_line_frequency;
+ case V4L2_CID_EXPOSURE_AUTO:
+ return camera_exposure_auto;
++ case V4L2_CID_COLORFX:
++ return colorfx;
+ default:
+ return NULL;
+ }
+@@ -382,16 +390,16 @@ const char *v4l2_ctrl_get_name(u32 id)
+ switch (id) {
+ /* USER controls */
+ case V4L2_CID_USER_CLASS: return "User Controls";
++ case V4L2_CID_BRIGHTNESS: return "Brightness";
++ case V4L2_CID_CONTRAST: return "Contrast";
++ case V4L2_CID_SATURATION: return "Saturation";
++ case V4L2_CID_HUE: return "Hue";
+ case V4L2_CID_AUDIO_VOLUME: return "Volume";
+- case V4L2_CID_AUDIO_MUTE: return "Mute";
+ case V4L2_CID_AUDIO_BALANCE: return "Balance";
+ case V4L2_CID_AUDIO_BASS: return "Bass";
+ case V4L2_CID_AUDIO_TREBLE: return "Treble";
++ case V4L2_CID_AUDIO_MUTE: return "Mute";
+ case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
+- case V4L2_CID_BRIGHTNESS: return "Brightness";
+- case V4L2_CID_CONTRAST: return "Contrast";
+- case V4L2_CID_SATURATION: return "Saturation";
+- case V4L2_CID_HUE: return "Hue";
+ case V4L2_CID_BLACK_LEVEL: return "Black Level";
+ case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic";
+ case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance";
+@@ -412,6 +420,7 @@ const char *v4l2_ctrl_get_name(u32 id)
+ case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation";
+ case V4L2_CID_CHROMA_AGC: return "Chroma AGC";
+ case V4L2_CID_COLOR_KILLER: return "Color Killer";
++ case V4L2_CID_COLORFX: return "Color Effects";
+
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
+@@ -490,16 +499,25 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HUE_AUTO:
++ case V4L2_CID_CHROMA_AGC:
++ case V4L2_CID_COLOR_KILLER:
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
++ case V4L2_CID_FOCUS_AUTO:
+ case V4L2_CID_PRIVACY:
+ qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+ min = 0;
+ max = step = 1;
+ break;
++ case V4L2_CID_PAN_RESET:
++ case V4L2_CID_TILT_RESET:
++ qctrl->type = V4L2_CTRL_TYPE_BUTTON;
++ qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
++ min = max = step = def = 0;
++ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+@@ -517,6 +535,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ case V4L2_CID_EXPOSURE_AUTO:
++ case V4L2_CID_COLORFX:
+ qctrl->type = V4L2_CTRL_TYPE_MENU;
+ step = 1;
+ break;
+@@ -547,161 +566,29 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
++ case V4L2_CID_RED_BALANCE:
++ case V4L2_CID_BLUE_BALANCE:
++ case V4L2_CID_GAMMA:
++ case V4L2_CID_SHARPNESS:
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ break;
++ case V4L2_CID_PAN_RELATIVE:
++ case V4L2_CID_TILT_RELATIVE:
++ case V4L2_CID_FOCUS_RELATIVE:
++ case V4L2_CID_ZOOM_RELATIVE:
++ qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
++ break;
+ }
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+- snprintf(qctrl->name, sizeof(qctrl->name), name);
++ strlcpy(qctrl->name, name, sizeof(qctrl->name));
+ return 0;
+ }
+ EXPORT_SYMBOL(v4l2_ctrl_query_fill);
+
+-/* Fill in a struct v4l2_queryctrl with standard values based on
+- the control ID. */
+-int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
+-{
+- switch (qctrl->id) {
+- /* USER controls */
+- case V4L2_CID_USER_CLASS:
+- case V4L2_CID_MPEG_CLASS:
+- return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
+- case V4L2_CID_AUDIO_VOLUME:
+- return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880);
+- case V4L2_CID_AUDIO_MUTE:
+- case V4L2_CID_AUDIO_LOUDNESS:
+- return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+- case V4L2_CID_AUDIO_BALANCE:
+- case V4L2_CID_AUDIO_BASS:
+- case V4L2_CID_AUDIO_TREBLE:
+- return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 32768);
+- case V4L2_CID_BRIGHTNESS:
+- return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+- case V4L2_CID_CONTRAST:
+- case V4L2_CID_SATURATION:
+- return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64);
+- case V4L2_CID_HUE:
+- return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0);
+-
+- /* MPEG controls */
+- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+- V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+- V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+- case V4L2_CID_MPEG_AUDIO_ENCODING:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
+- V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
+- V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+- case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_L1_BITRATE_32K,
+- V4L2_MPEG_AUDIO_L1_BITRATE_448K, 1,
+- V4L2_MPEG_AUDIO_L1_BITRATE_256K);
+- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_L2_BITRATE_32K,
+- V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+- V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_L3_BITRATE_32K,
+- V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
+- V4L2_MPEG_AUDIO_L3_BITRATE_192K);
+- case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:
+- return v4l2_ctrl_query_fill(qctrl, 0, 6400, 1, 3200000);
+- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_AC3_BITRATE_32K,
+- V4L2_MPEG_AUDIO_AC3_BITRATE_640K, 1,
+- V4L2_MPEG_AUDIO_AC3_BITRATE_384K);
+- case V4L2_CID_MPEG_AUDIO_MODE:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_MODE_STEREO,
+- V4L2_MPEG_AUDIO_MODE_MONO, 1,
+- V4L2_MPEG_AUDIO_MODE_STEREO);
+- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+- case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+- V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+- V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+- case V4L2_CID_MPEG_AUDIO_CRC:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_AUDIO_CRC_NONE,
+- V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+- V4L2_MPEG_AUDIO_CRC_NONE);
+- case V4L2_CID_MPEG_AUDIO_MUTE:
+- return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+- case V4L2_CID_MPEG_VIDEO_ENCODING:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+- V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
+- V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+- case V4L2_CID_MPEG_VIDEO_ASPECT:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_VIDEO_ASPECT_1x1,
+- V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+- V4L2_MPEG_VIDEO_ASPECT_4x3);
+- case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+- return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+- return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, 12);
+- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+- return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+- return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+- V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+- case V4L2_CID_MPEG_VIDEO_BITRATE:
+- return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+- return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+- case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+- return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+- case V4L2_CID_MPEG_VIDEO_MUTE:
+- return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+- case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */
+- return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080);
+- case V4L2_CID_MPEG_STREAM_TYPE:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+- V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+- V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+- case V4L2_CID_MPEG_STREAM_PID_PMT:
+- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
+- case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
+- case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
+- case V4L2_CID_MPEG_STREAM_PID_PCR:
+- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
+- case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO:
+- return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+- case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO:
+- return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+- case V4L2_CID_MPEG_STREAM_VBI_FMT:
+- return v4l2_ctrl_query_fill(qctrl,
+- V4L2_MPEG_STREAM_VBI_FMT_NONE,
+- V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
+- V4L2_MPEG_STREAM_VBI_FMT_NONE);
+- default:
+- return -EINVAL;
+- }
+-}
+-EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
+-
+ /* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
+ the menu. The qctrl pointer may be NULL, in which case it is ignored.
+ If menu_items is NULL, then the menu items are retrieved using
+@@ -720,7 +607,7 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
+ for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
+ if (menu_items[i] == NULL || menu_items[i][0] == '\0')
+ return -EINVAL;
+- snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
++ strlcpy(qmenu->name, menu_items[qmenu->index], sizeof(qmenu->name));
+ return 0;
+ }
+ EXPORT_SYMBOL(v4l2_ctrl_query_menu);
+@@ -737,8 +624,8 @@ int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *id
+ return -EINVAL;
+ while (*ids != V4L2_CTRL_MENU_IDS_END) {
+ if (*ids++ == qmenu->index) {
+- snprintf(qmenu->name, sizeof(qmenu->name),
+- menu_items[qmenu->index]);
++ strlcpy(qmenu->name, menu_items[qmenu->index],
++ sizeof(qmenu->name));
+ return 0;
+ }
+ }
+@@ -749,7 +636,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items);
+ /* ctrl_classes points to an array of u32 pointers, the last element is
+ a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
+ Each array must be sorted low to high and belong to the same control
+- class. The array of u32 pointer must also be sorted, from low class IDs
++ class. The array of u32 pointers must also be sorted, from low class IDs
+ to high class IDs.
+
+ This function returns the first ID that follows after the given ID.
+@@ -910,10 +797,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
+ struct i2c_board_info info;
+
+ BUG_ON(!dev);
+-#ifdef MODULE
++
+ if (module_name)
+ request_module(module_name);
+-#endif
++
+ /* Setup the i2c board info with the device type and
+ the device address. */
+ memset(&info, 0, sizeof(info));
+@@ -927,11 +814,11 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
+ We need better support from the kernel so that we
+ can easily wait for the load to finish. */
+ if (client == NULL || client->driver == NULL)
+- return NULL;
++ goto error;
+
+ /* Lock the module so we can safely get the v4l2_subdev pointer */
+ if (!try_module_get(client->driver->driver.owner))
+- return NULL;
++ goto error;
+ sd = i2c_get_clientdata(client);
+
+ /* Register with the v4l2_device which increases the module's
+@@ -940,8 +827,13 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
+ sd = NULL;
+ /* Decrease the module use count to match the first try_module_get. */
+ module_put(client->driver->driver.owner);
+- return sd;
+
++error:
++ /* If we have a client but no subdev, then something went wrong and
++ we must unregister the client. */
++ if (client && sd == NULL)
++ i2c_unregister_device(client);
++ return sd;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
+
+@@ -958,10 +850,10 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
+ struct i2c_board_info info;
+
+ BUG_ON(!dev);
+-#ifdef MODULE
++
+ if (module_name)
+ request_module(module_name);
+-#endif
++
+ /* Setup the i2c board info with the device type and
+ the device address. */
+ memset(&info, 0, sizeof(info));
+@@ -974,11 +866,11 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
+ We need better support from the kernel so that we
+ can easily wait for the load to finish. */
+ if (client == NULL || client->driver == NULL)
+- return NULL;
++ goto error;
+
+ /* Lock the module so we can safely get the v4l2_subdev pointer */
+ if (!try_module_get(client->driver->driver.owner))
+- return NULL;
++ goto error;
+ sd = i2c_get_clientdata(client);
+
+ /* Register with the v4l2_device which increases the module's
+@@ -987,8 +879,59 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
+ sd = NULL;
+ /* Decrease the module use count to match the first try_module_get. */
+ module_put(client->driver->driver.owner);
++
++error:
++ /* If we have a client but no subdev, then something went wrong and
++ we must unregister the client. */
++ if (client && sd == NULL)
++ i2c_unregister_device(client);
+ return sd;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev);
+
++/* Return i2c client address of v4l2_subdev. */
++unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return client ? client->addr : I2C_CLIENT_END;
++}
++EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr);
++
++/* Return a list of I2C tuner addresses to probe. Use only if the tuner
++ addresses are unknown. */
++const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
++{
++ static const unsigned short radio_addrs[] = {
++#if defined(CONFIG_MEDIA_TUNER_TEA5761) || defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE)
++ 0x10,
++#endif
++ 0x60,
++ I2C_CLIENT_END
++ };
++ static const unsigned short demod_addrs[] = {
++ 0x42, 0x43, 0x4a, 0x4b,
++ I2C_CLIENT_END
++ };
++ static const unsigned short tv_addrs[] = {
++ 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
++ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
++ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
++ I2C_CLIENT_END
++ };
++
++ switch (type) {
++ case ADDRS_RADIO:
++ return radio_addrs;
++ case ADDRS_DEMOD:
++ return demod_addrs;
++ case ADDRS_TV:
++ return tv_addrs;
++ case ADDRS_TV_WITH_DEMOD:
++ return tv_addrs + 4;
++ }
++ return NULL;
++}
++EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);
++
+ #endif
+diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
+index 110376b..0056b11 100644
+--- a/drivers/media/video/v4l2-compat-ioctl32.c
++++ b/drivers/media/video/v4l2-compat-ioctl32.c
+@@ -1047,7 +1047,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+ case VIDIOC_DBG_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_G_CHIP_IDENT:
+- case VIDIOC_G_CHIP_IDENT_OLD:
+ case VIDIOC_S_HW_FREQ_SEEK:
+ ret = do_video_ioctl(file, cmd, arg);
+ break;
+diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
+index 13f87c2..91228b3 100644
+--- a/drivers/media/video/v4l2-dev.c
++++ b/drivers/media/video/v4l2-dev.c
+@@ -198,6 +198,23 @@ static long v4l2_unlocked_ioctl(struct file *filp,
+ return vdev->fops->unlocked_ioctl(filp, cmd, arg);
+ }
+
++#ifdef CONFIG_MMU
++#define v4l2_get_unmapped_area NULL
++#else
++static unsigned long v4l2_get_unmapped_area(struct file *filp,
++ unsigned long addr, unsigned long len, unsigned long pgoff,
++ unsigned long flags)
++{
++ struct video_device *vdev = video_devdata(filp);
++
++ if (!vdev->fops->get_unmapped_area)
++ return -ENOSYS;
++ if (video_is_unregistered(vdev))
++ return -ENODEV;
++ return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
++}
++#endif
++
+ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
+ {
+ struct video_device *vdev = video_devdata(filp);
+@@ -250,6 +267,7 @@ static const struct file_operations v4l2_unlocked_fops = {
+ .read = v4l2_read,
+ .write = v4l2_write,
+ .open = v4l2_open,
++ .get_unmapped_area = v4l2_get_unmapped_area,
+ .mmap = v4l2_mmap,
+ .unlocked_ioctl = v4l2_unlocked_ioctl,
+ #ifdef CONFIG_COMPAT
+@@ -265,6 +283,7 @@ static const struct file_operations v4l2_fops = {
+ .read = v4l2_read,
+ .write = v4l2_write,
+ .open = v4l2_open,
++ .get_unmapped_area = v4l2_get_unmapped_area,
+ .mmap = v4l2_mmap,
+ .ioctl = v4l2_ioctl,
+ #ifdef CONFIG_COMPAT
+@@ -288,37 +307,38 @@ static const struct file_operations v4l2_fops = {
+ */
+ static int get_index(struct video_device *vdev, int num)
+ {
+- u32 used = 0;
+- const int max_index = sizeof(used) * 8 - 1;
++ /* This can be static since this function is called with the global
++ videodev_lock held. */
++ static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
+ int i;
+
+- /* Currently a single v4l driver instance cannot create more than
+- 32 devices.
+- Increase to u64 or an array of u32 if more are needed. */
+- if (num > max_index) {
++ if (num >= VIDEO_NUM_DEVICES) {
+ printk(KERN_ERR "videodev: %s num is too large\n", __func__);
+ return -EINVAL;
+ }
+
+- /* Some drivers do not set the parent. In that case always return 0. */
++ /* Some drivers do not set the parent. In that case always return
++ num or 0. */
+ if (vdev->parent == NULL)
+- return 0;
++ return num >= 0 ? num : 0;
++
++ bitmap_zero(used, VIDEO_NUM_DEVICES);
+
+ for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
+ if (video_device[i] != NULL &&
+ video_device[i]->parent == vdev->parent) {
+- used |= 1 << video_device[i]->index;
++ set_bit(video_device[i]->index, used);
+ }
+ }
+
+ if (num >= 0) {
+- if (used & (1 << num))
++ if (test_bit(num, used))
+ return -ENFILE;
+ return num;
+ }
+
+- i = ffz(used);
+- return i > max_index ? -ENFILE : i;
++ i = find_first_zero_bit(used, VIDEO_NUM_DEVICES);
++ return i == VIDEO_NUM_DEVICES ? -ENFILE : i;
+ }
+
+ int video_register_device(struct video_device *vdev, int type, int nr)
+@@ -365,12 +385,11 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
+
+ /* A minor value of -1 marks this video device as never
+ having been registered */
+- if (vdev)
+- vdev->minor = -1;
++ vdev->minor = -1;
+
+ /* the release callback MUST be present */
+- WARN_ON(!vdev || !vdev->release);
+- if (!vdev || !vdev->release)
++ WARN_ON(!vdev->release);
++ if (!vdev->release)
+ return -EINVAL;
+
+ /* Part 1: check device type */
+@@ -395,7 +414,7 @@ int video_register_device_index(struct video_device *vdev, int type, int nr,
+
+ vdev->vfl_type = type;
+ vdev->cdev = NULL;
+- if (vdev->v4l2_dev)
++ if (vdev->v4l2_dev && vdev->v4l2_dev->dev)
+ vdev->parent = vdev->v4l2_dev->dev;
+
+ /* Part 2: find a free minor, kernel number and device index. */
+@@ -582,6 +601,7 @@ module_exit(videodev_exit)
+ MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
+ MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
+ MODULE_LICENSE("GPL");
++MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR);
+
+
+ /*
+diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
+index cf9d4c7..94aa485 100644
+--- a/drivers/media/video/v4l2-device.c
++++ b/drivers/media/video/v4l2-device.c
+@@ -26,48 +26,66 @@
+
+ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
+ {
+- if (dev == NULL || v4l2_dev == NULL)
++ if (v4l2_dev == NULL)
+ return -EINVAL;
+- /* Warn if we apparently re-register a device */
+- WARN_ON(dev_get_drvdata(dev) != NULL);
++
+ INIT_LIST_HEAD(&v4l2_dev->subdevs);
+ spin_lock_init(&v4l2_dev->lock);
+ v4l2_dev->dev = dev;
+- snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
+- dev->driver->name, dev->bus_id);
++ if (dev == NULL) {
++ /* If dev == NULL, then name must be filled in by the caller */
++ WARN_ON(!v4l2_dev->name[0]);
++ return 0;
++ }
++
++ /* Set name to driver name + device name if it is empty. */
++ if (!v4l2_dev->name[0])
++ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
++ dev->driver->name, dev_name(dev));
++ if (dev_get_drvdata(dev))
++ v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n");
+ dev_set_drvdata(dev, v4l2_dev);
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_register);
+
++void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
++{
++ if (v4l2_dev->dev) {
++ dev_set_drvdata(v4l2_dev->dev, NULL);
++ v4l2_dev->dev = NULL;
++ }
++}
++EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
++
+ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
+ {
+ struct v4l2_subdev *sd, *next;
+
+- if (v4l2_dev == NULL || v4l2_dev->dev == NULL)
++ if (v4l2_dev == NULL)
+ return;
+- dev_set_drvdata(v4l2_dev->dev, NULL);
+- /* unregister subdevs */
++ v4l2_device_disconnect(v4l2_dev);
++
++ /* Unregister subdevs */
+ list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
+ v4l2_device_unregister_subdev(sd);
+-
+- v4l2_dev->dev = NULL;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_unregister);
+
+-int v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd)
++int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
++ struct v4l2_subdev *sd)
+ {
+ /* Check for valid input */
+- if (dev == NULL || sd == NULL || !sd->name[0])
++ if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
+ return -EINVAL;
+ /* Warn if we apparently re-register a subdev */
+- WARN_ON(sd->dev != NULL);
++ WARN_ON(sd->v4l2_dev != NULL);
+ if (!try_module_get(sd->owner))
+ return -ENODEV;
+- sd->dev = dev;
+- spin_lock(&dev->lock);
+- list_add_tail(&sd->list, &dev->subdevs);
+- spin_unlock(&dev->lock);
++ sd->v4l2_dev = v4l2_dev;
++ spin_lock(&v4l2_dev->lock);
++ list_add_tail(&sd->list, &v4l2_dev->subdevs);
++ spin_unlock(&v4l2_dev->lock);
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
+@@ -75,12 +93,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
+ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
+ {
+ /* return if it isn't registered */
+- if (sd == NULL || sd->dev == NULL)
++ if (sd == NULL || sd->v4l2_dev == NULL)
+ return;
+- spin_lock(&sd->dev->lock);
++ spin_lock(&sd->v4l2_dev->lock);
+ list_del(&sd->list);
+- spin_unlock(&sd->dev->lock);
+- sd->dev = NULL;
++ spin_unlock(&sd->v4l2_dev->lock);
++ sd->v4l2_dev = NULL;
+ module_put(sd->owner);
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
+diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
+index 52d687b..f41c6f5 100644
+--- a/drivers/media/video/v4l2-ioctl.c
++++ b/drivers/media/video/v4l2-ioctl.c
+@@ -17,6 +17,7 @@
+ #include <linux/kernel.h>
+
+ #define __OLD_VIDIOC_ /* To allow fixing old calls */
++#include <linux/videodev.h>
+ #include <linux/videodev2.h>
+
+ #ifdef CONFIG_VIDEO_V4L1
+@@ -24,7 +25,7 @@
+ #endif
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-ioctl.h>
+-#include <linux/video_decoder.h>
++#include <media/v4l2-chip-ident.h>
+
+ #define dbgarg(cmd, fmt, arg...) \
+ do { \
+@@ -100,25 +101,27 @@ const char *v4l2_norm_to_name(v4l2_std_id id)
+ }
+ EXPORT_SYMBOL(v4l2_norm_to_name);
+
++/* Returns frame period for the given standard */
++void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod)
++{
++ if (id & V4L2_STD_525_60) {
++ frameperiod->numerator = 1001;
++ frameperiod->denominator = 30000;
++ } else {
++ frameperiod->numerator = 1;
++ frameperiod->denominator = 25;
++ }
++}
++EXPORT_SYMBOL(v4l2_video_std_frame_period);
++
+ /* Fill in the fields of a v4l2_standard structure according to the
+ 'id' and 'transmission' parameters. Returns negative on error. */
+ int v4l2_video_std_construct(struct v4l2_standard *vs,
+ int id, const char *name)
+ {
+- u32 index = vs->index;
+-
+- memset(vs, 0, sizeof(struct v4l2_standard));
+- vs->index = index;
+- vs->id = id;
+- if (id & V4L2_STD_525_60) {
+- vs->frameperiod.numerator = 1001;
+- vs->frameperiod.denominator = 30000;
+- vs->framelines = 525;
+- } else {
+- vs->frameperiod.numerator = 1;
+- vs->frameperiod.denominator = 25;
+- vs->framelines = 625;
+- }
++ vs->id = id;
++ v4l2_video_std_frame_period(id, &vs->frameperiod);
++ vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625;
+ strlcpy(vs->name, name, sizeof(vs->name));
+ return 0;
+ }
+@@ -273,19 +276,6 @@ static const char *v4l2_ioctls[] = {
+ #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+ static const char *v4l2_int_ioctls[] = {
+-#ifdef CONFIG_VIDEO_V4L1_COMPAT
+- [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES",
+- [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS",
+- [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM",
+- [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT",
+- [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT",
+- [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT",
+- [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE",
+- [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO",
+- [_IOC_NR(DECODER_INIT)] = "DECODER_INIT",
+- [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS",
+- [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP",
+-#endif
+ [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
+
+ [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
+@@ -654,8 +644,6 @@ static long __video_do_ioctl(struct file *file,
+ if (cmd == VIDIOCGMBUF) {
+ struct video_mbuf *p = arg;
+
+- memset(p, 0, sizeof(*p));
+-
+ if (!ops->vidiocgmbuf)
+ return ret;
+ ret = ops->vidiocgmbuf(file, fh, p);
+@@ -682,7 +670,6 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = (struct v4l2_capability *)arg;
+- memset(cap, 0, sizeof(*cap));
+
+ if (!ops->vidioc_querycap)
+ break;
+@@ -725,16 +712,8 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+- enum v4l2_buf_type type;
+- unsigned int index;
+-
+- index = f->index;
+- type = f->type;
+- memset(f, 0, sizeof(*f));
+- f->index = index;
+- f->type = type;
+
+- switch (type) {
++ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (ops->vidioc_enum_fmt_vid_cap)
+ ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
+@@ -771,8 +750,6 @@ static long __video_do_ioctl(struct file *file,
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+- memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));
+-
+ /* FIXME: Should be one dump per type */
+ dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
+
+@@ -1088,7 +1065,6 @@ static long __video_do_ioctl(struct file *file,
+ return -EINVAL;
+
+ v4l2_video_std_construct(p, curr_id, descr);
+- p->index = index;
+
+ dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, "
+ "framelines=%d\n", p->index,
+@@ -1153,12 +1129,9 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *p = arg;
+- int i = p->index;
+
+ if (!ops->vidioc_enum_input)
+ break;
+- memset(p, 0, sizeof(*p));
+- p->index = i;
+
+ ret = ops->vidioc_enum_input(file, fh, p);
+ if (!ret)
+@@ -1197,12 +1170,9 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_ENUMOUTPUT:
+ {
+ struct v4l2_output *p = arg;
+- int i = p->index;
+
+ if (!ops->vidioc_enum_output)
+ break;
+- memset(p, 0, sizeof(*p));
+- p->index = i;
+
+ ret = ops->vidioc_enum_output(file, fh, p);
+ if (!ret)
+@@ -1378,13 +1348,10 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *p = arg;
+- __u32 index = p->index;
+
+ if (!ops->vidioc_g_audio)
+ break;
+
+- memset(p, 0, sizeof(*p));
+- p->index = index;
+ ret = ops->vidioc_g_audio(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
+@@ -1426,7 +1393,7 @@ static long __video_do_ioctl(struct file *file,
+
+ if (!ops->vidioc_g_audout)
+ break;
+- dbgarg(cmd, "Enum for index=%d\n", p->index);
++
+ ret = ops->vidioc_g_audout(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+@@ -1479,15 +1446,10 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop *p = arg;
+- __u32 type;
+
+ if (!ops->vidioc_g_crop)
+ break;
+
+- type = p->type;
+- memset(p, 0, sizeof(*p));
+- p->type = type;
+-
+ dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+ ret = ops->vidioc_g_crop(file, fh, p);
+ if (!ret)
+@@ -1508,16 +1470,11 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *p = arg;
+- __u32 type;
+
+ /*FIXME: Should also show v4l2_fract pixelaspect */
+ if (!ops->vidioc_cropcap)
+ break;
+
+- type = p->type;
+- memset(p, 0, sizeof(*p));
+- p->type = type;
+-
+ dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+ ret = ops->vidioc_cropcap(file, fh, p);
+ if (!ret) {
+@@ -1533,8 +1490,6 @@ static long __video_do_ioctl(struct file *file,
+ if (!ops->vidioc_g_jpegcomp)
+ break;
+
+- memset(p, 0, sizeof(*p));
+-
+ ret = ops->vidioc_g_jpegcomp(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "quality=%d, APPn=%d, "
+@@ -1575,7 +1530,6 @@ static long __video_do_ioctl(struct file *file,
+
+ if (!ops->vidioc_encoder_cmd)
+ break;
+- memset(&p->raw, 0, sizeof(p->raw));
+ ret = ops->vidioc_encoder_cmd(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+@@ -1587,7 +1541,6 @@ static long __video_do_ioctl(struct file *file,
+
+ if (!ops->vidioc_try_encoder_cmd)
+ break;
+- memset(&p->raw, 0, sizeof(p->raw));
+ ret = ops->vidioc_try_encoder_cmd(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+@@ -1596,23 +1549,18 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm *p = arg;
+- __u32 type = p->type;
+-
+- memset(p, 0, sizeof(*p));
+- p->type = type;
+
+ if (ops->vidioc_g_parm) {
++ ret = check_fmt(ops, p->type);
++ if (ret)
++ break;
+ ret = ops->vidioc_g_parm(file, fh, p);
+ } else {
+- struct v4l2_standard s;
+-
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+- v4l2_video_std_construct(&s, vfd->current_norm,
+- v4l2_norm_to_name(vfd->current_norm));
+-
+- p->parm.capture.timeperframe = s.frameperiod;
++ v4l2_video_std_frame_period(vfd->current_norm,
++ &p->parm.capture.timeperframe);
+ ret = 0;
+ }
+
+@@ -1625,6 +1573,10 @@ static long __video_do_ioctl(struct file *file,
+
+ if (!ops->vidioc_s_parm)
+ break;
++ ret = check_fmt(ops, p->type);
++ if (ret)
++ break;
++
+ dbgarg(cmd, "type=%d\n", p->type);
+ ret = ops->vidioc_s_parm(file, fh, p);
+ break;
+@@ -1632,14 +1584,10 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *p = arg;
+- __u32 index = p->index;
+
+ if (!ops->vidioc_g_tuner)
+ break;
+
+- memset(p, 0, sizeof(*p));
+- p->index = index;
+-
+ ret = ops->vidioc_g_tuner(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "index=%d, name=%s, type=%d, "
+@@ -1676,8 +1624,6 @@ static long __video_do_ioctl(struct file *file,
+ if (!ops->vidioc_g_frequency)
+ break;
+
+- memset(p->reserved, 0, sizeof(p->reserved));
+-
+ ret = ops->vidioc_g_frequency(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
+@@ -1698,12 +1644,13 @@ static long __video_do_ioctl(struct file *file,
+ case VIDIOC_G_SLICED_VBI_CAP:
+ {
+ struct v4l2_sliced_vbi_cap *p = arg;
+- __u32 type = p->type;
+
+ if (!ops->vidioc_g_sliced_vbi_cap)
+ break;
+- memset(p, 0, sizeof(*p));
+- p->type = type;
++
++ /* Clear up to type, everything after type is zerod already */
++ memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
++
+ dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+ ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p);
+ if (!ret)
+@@ -1745,16 +1692,13 @@ static long __video_do_ioctl(struct file *file,
+
+ if (!ops->vidioc_g_chip_ident)
+ break;
++ p->ident = V4L2_IDENT_NONE;
++ p->revision = 0;
+ ret = ops->vidioc_g_chip_ident(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
+ break;
+ }
+- case VIDIOC_G_CHIP_IDENT_OLD:
+- printk(KERN_ERR "VIDIOC_G_CHIP_IDENT has been deprecated and will disappear in 2.6.30.\n");
+- printk(KERN_ERR "It is a debugging ioctl and must not be used in applications!\n");
+- return -EINVAL;
+-
+ case VIDIOC_S_HW_FREQ_SEEK:
+ {
+ struct v4l2_hw_freq_seek *p = arg;
+@@ -1774,8 +1718,6 @@ static long __video_do_ioctl(struct file *file,
+ if (!ops->vidioc_enum_framesizes)
+ break;
+
+- memset(p, 0, sizeof(*p));
+-
+ ret = ops->vidioc_enum_framesizes(file, fh, p);
+ dbgarg(cmd,
+ "index=%d, pixelformat=%d, type=%d ",
+@@ -1807,8 +1749,6 @@ static long __video_do_ioctl(struct file *file,
+ if (!ops->vidioc_enum_frameintervals)
+ break;
+
+- memset(p, 0, sizeof(*p));
+-
+ ret = ops->vidioc_enum_frameintervals(file, fh, p);
+ dbgarg(cmd,
+ "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
+@@ -1857,6 +1797,45 @@ static long __video_do_ioctl(struct file *file,
+ return ret;
+ }
+
++/* In some cases, only a few fields are used as input, i.e. when the app sets
++ * "index" and then the driver fills in the rest of the structure for the thing
++ * with that index. We only need to copy up the first non-input field. */
++static unsigned long cmd_input_size(unsigned int cmd)
++{
++ /* Size of structure up to and including 'field' */
++#define CMDINSIZE(cmd, type, field) \
++ case VIDIOC_##cmd: \
++ return offsetof(struct v4l2_##type, field) + \
++ sizeof(((struct v4l2_##type *)0)->field);
++
++ switch (cmd) {
++ CMDINSIZE(ENUM_FMT, fmtdesc, type);
++ CMDINSIZE(G_FMT, format, type);
++ CMDINSIZE(QUERYBUF, buffer, type);
++ CMDINSIZE(G_PARM, streamparm, type);
++ CMDINSIZE(ENUMSTD, standard, index);
++ CMDINSIZE(ENUMINPUT, input, index);
++ CMDINSIZE(G_CTRL, control, id);
++ CMDINSIZE(G_TUNER, tuner, index);
++ CMDINSIZE(QUERYCTRL, queryctrl, id);
++ CMDINSIZE(QUERYMENU, querymenu, index);
++ CMDINSIZE(ENUMOUTPUT, output, index);
++ CMDINSIZE(G_MODULATOR, modulator, index);
++ CMDINSIZE(G_FREQUENCY, frequency, tuner);
++ CMDINSIZE(CROPCAP, cropcap, type);
++ CMDINSIZE(G_CROP, crop, type);
++ CMDINSIZE(ENUMAUDIO, audio, index);
++ CMDINSIZE(ENUMAUDOUT, audioout, index);
++ CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
++ CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
++ CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
++ CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
++ CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
++ default:
++ return _IOC_SIZE(cmd);
++ }
++}
++
+ long video_ioctl2(struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+@@ -1875,13 +1854,7 @@ long video_ioctl2(struct file *file,
+ cmd == VIDIOC_TRY_EXT_CTRLS);
+
+ /* Copy arguments into temp kernel buffer */
+- switch (_IOC_DIR(cmd)) {
+- case _IOC_NONE:
+- parg = NULL;
+- break;
+- case _IOC_READ:
+- case _IOC_WRITE:
+- case (_IOC_WRITE | _IOC_READ):
++ if (_IOC_DIR(cmd) != _IOC_NONE) {
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+@@ -1893,10 +1866,19 @@ long video_ioctl2(struct file *file,
+ }
+
+ err = -EFAULT;
+- if (_IOC_DIR(cmd) & _IOC_WRITE)
+- if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
++ if (_IOC_DIR(cmd) & _IOC_WRITE) {
++ unsigned long n = cmd_input_size(cmd);
++
++ if (copy_from_user(parg, (void __user *)arg, n))
+ goto out;
+- break;
++
++ /* zero out anything we don't copy from userspace */
++ if (n < _IOC_SIZE(cmd))
++ memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
++ } else {
++ /* read-only ioctl */
++ memset(parg, 0, _IOC_SIZE(cmd));
++ }
+ }
+
+ if (is_ext_ctrl) {
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 2120880..dc88167 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -33,6 +33,12 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg)
+ return v4l2_subdev_call(sd, core, g_ctrl, arg);
+ case VIDIOC_S_CTRL:
+ return v4l2_subdev_call(sd, core, s_ctrl, arg);
++ case VIDIOC_G_EXT_CTRLS:
++ return v4l2_subdev_call(sd, core, g_ext_ctrls, arg);
++ case VIDIOC_S_EXT_CTRLS:
++ return v4l2_subdev_call(sd, core, s_ext_ctrls, arg);
++ case VIDIOC_TRY_EXT_CTRLS:
++ return v4l2_subdev_call(sd, core, try_ext_ctrls, arg);
+ case VIDIOC_QUERYMENU:
+ return v4l2_subdev_call(sd, core, querymenu, arg);
+ case VIDIOC_LOG_STATUS:
+@@ -92,16 +98,28 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg)
+ return v4l2_subdev_call(sd, video, g_vbi_data, arg);
+ case VIDIOC_G_SLICED_VBI_CAP:
+ return v4l2_subdev_call(sd, video, g_sliced_vbi_cap, arg);
++ case VIDIOC_ENUM_FMT:
++ return v4l2_subdev_call(sd, video, enum_fmt, arg);
++ case VIDIOC_TRY_FMT:
++ return v4l2_subdev_call(sd, video, try_fmt, arg);
+ case VIDIOC_S_FMT:
+ return v4l2_subdev_call(sd, video, s_fmt, arg);
+ case VIDIOC_G_FMT:
+ return v4l2_subdev_call(sd, video, g_fmt, arg);
+ case VIDIOC_INT_S_STD_OUTPUT:
+ return v4l2_subdev_call(sd, video, s_std_output, *(v4l2_std_id *)arg);
++ case VIDIOC_QUERYSTD:
++ return v4l2_subdev_call(sd, video, querystd, arg);
++ case VIDIOC_INT_G_INPUT_STATUS:
++ return v4l2_subdev_call(sd, video, g_input_status, arg);
+ case VIDIOC_STREAMON:
+ return v4l2_subdev_call(sd, video, s_stream, 1);
+ case VIDIOC_STREAMOFF:
+ return v4l2_subdev_call(sd, video, s_stream, 0);
++ case VIDIOC_S_PARM:
++ return v4l2_subdev_call(sd, video, s_parm, arg);
++ case VIDIOC_G_PARM:
++ return v4l2_subdev_call(sd, video, g_parm, arg);
+
+ default:
+ return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
+index 31944b1..6109fb5 100644
+--- a/drivers/media/video/videobuf-dma-contig.c
++++ b/drivers/media/video/videobuf-dma-contig.c
+@@ -400,7 +400,7 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
+ So, it should free memory only if the memory were allocated for
+ read() operation.
+ */
+- if ((buf->memory != V4L2_MEMORY_USERPTR) || !buf->baddr)
++ if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
+ return;
+
+ if (!mem)
+diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
+index be65a2f..30ae30f 100644
+--- a/drivers/media/video/videobuf-vmalloc.c
++++ b/drivers/media/video/videobuf-vmalloc.c
+@@ -425,7 +425,7 @@ void videobuf_vmalloc_free (struct videobuf_buffer *buf)
+ So, it should free memory only if the memory were allocated for
+ read() operation.
+ */
+- if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0))
++ if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
+ return;
+
+ if (!mem)
+diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
+index 88bf845..8da4dd1 100644
+--- a/drivers/media/video/vino.c
++++ b/drivers/media/video/vino.c
+@@ -8,6 +8,12 @@
+ *
+ * Based on the previous version of the driver for 2.4 kernels by:
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
++ *
++ * v4l2_device/v4l2_subdev conversion by:
++ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
++ *
++ * Note: this conversion is untested! Please contact the linux-media
++ * mailinglist if you can test this, together with the test results.
+ */
+
+ /*
+@@ -33,12 +39,10 @@
+ #include <linux/kmod.h>
+
+ #include <linux/i2c.h>
+-#include <linux/i2c-algo-sgi.h>
+
+ #include <linux/videodev2.h>
+-#include <media/v4l2-common.h>
++#include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+-#include <linux/video_decoder.h>
+ #include <linux/mutex.h>
+
+ #include <asm/paccess.h>
+@@ -139,13 +143,23 @@ MODULE_LICENSE("GPL");
+ #define VINO_DATA_NORM_PAL 1
+ #define VINO_DATA_NORM_SECAM 2
+ #define VINO_DATA_NORM_D1 3
+-/* The following are special entries that can be used to
+- * autodetect the norm. */
+-#define VINO_DATA_NORM_AUTO 0xfe
+-#define VINO_DATA_NORM_AUTO_EXT 0xff
+
+ #define VINO_DATA_NORM_COUNT 4
+
++/* I2C controller flags */
++#define SGI_I2C_FORCE_IDLE (0 << 0)
++#define SGI_I2C_NOT_IDLE (1 << 0)
++#define SGI_I2C_WRITE (0 << 1)
++#define SGI_I2C_READ (1 << 1)
++#define SGI_I2C_RELEASE_BUS (0 << 2)
++#define SGI_I2C_HOLD_BUS (1 << 2)
++#define SGI_I2C_XFER_DONE (0 << 4)
++#define SGI_I2C_XFER_BUSY (1 << 4)
++#define SGI_I2C_ACK (0 << 5)
++#define SGI_I2C_NACK (1 << 5)
++#define SGI_I2C_BUS_OK (0 << 7)
++#define SGI_I2C_BUS_ERR (1 << 7)
++
+ /* Internal data structure definitions */
+
+ struct vino_input {
+@@ -289,22 +303,20 @@ struct vino_channel_settings {
+ struct vino_interrupt_data int_data;
+
+ /* V4L support */
+- struct video_device *v4l_device;
+-};
+-
+-struct vino_client {
+- /* the channel which owns this client:
+- * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
+- unsigned int owner;
+- struct i2c_client *driver;
++ struct video_device *vdev;
+ };
+
+ struct vino_settings {
++ struct v4l2_device v4l2_dev;
+ struct vino_channel_settings a;
+ struct vino_channel_settings b;
+
+- struct vino_client decoder;
+- struct vino_client camera;
++ /* the channel which owns this client:
++ * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
++ unsigned int decoder_owner;
++ struct v4l2_subdev *decoder;
++ unsigned int camera_owner;
++ struct v4l2_subdev *camera;
+
+ /* a lock for vino register access */
+ spinlock_t vino_lock;
+@@ -344,11 +356,16 @@ static struct sgi_vino *vino;
+
+ static struct vino_settings *vino_drvdata;
+
++#define camera_call(o, f, args...) \
++ v4l2_subdev_call(vino_drvdata->camera, o, f, ##args)
++#define decoder_call(o, f, args...) \
++ v4l2_subdev_call(vino_drvdata->decoder, o, f, ##args)
++
+ static const char *vino_driver_name = "vino";
+ static const char *vino_driver_description = "SGI VINO";
+ static const char *vino_bus_name = "GIO64 bus";
+-static const char *vino_v4l_device_name_a = "SGI VINO Channel A";
+-static const char *vino_v4l_device_name_b = "SGI VINO Channel B";
++static const char *vino_vdev_name_a = "SGI VINO Channel A";
++static const char *vino_vdev_name_b = "SGI VINO Channel B";
+
+ static void vino_capture_tasklet(unsigned long channel);
+
+@@ -360,11 +377,11 @@ static const struct vino_input vino_inputs[] = {
+ .name = "Composite",
+ .std = V4L2_STD_NTSC | V4L2_STD_PAL
+ | V4L2_STD_SECAM,
+- },{
++ }, {
+ .name = "S-Video",
+ .std = V4L2_STD_NTSC | V4L2_STD_PAL
+ | V4L2_STD_SECAM,
+- },{
++ }, {
+ .name = "D1/IndyCam",
+ .std = V4L2_STD_NTSC,
+ }
+@@ -376,17 +393,17 @@ static const struct vino_data_format vino_data_formats[] = {
+ .bpp = 1,
+ .pixelformat = V4L2_PIX_FMT_GREY,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+- },{
++ }, {
+ .description = "8-bit dithered RGB 3-3-2",
+ .bpp = 1,
+ .pixelformat = V4L2_PIX_FMT_RGB332,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+- },{
++ }, {
+ .description = "32-bit RGB",
+ .bpp = 4,
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+- },{
++ }, {
+ .description = "YUV 4:2:2",
+ .bpp = 2,
+ .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped?
+@@ -417,7 +434,7 @@ static const struct vino_data_norm vino_data_norms[] = {
+ + VINO_NTSC_HEIGHT / 2 - 1,
+ .right = VINO_NTSC_WIDTH,
+ },
+- },{
++ }, {
+ .description = "PAL",
+ .std = V4L2_STD_PAL,
+ .fps_min = 5,
+@@ -439,7 +456,7 @@ static const struct vino_data_norm vino_data_norms[] = {
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+- },{
++ }, {
+ .description = "SECAM",
+ .std = V4L2_STD_SECAM,
+ .fps_min = 5,
+@@ -461,7 +478,7 @@ static const struct vino_data_norm vino_data_norms[] = {
+ + VINO_PAL_HEIGHT / 2 - 1,
+ .right = VINO_PAL_WIDTH,
+ },
+- },{
++ }, {
+ .description = "NTSC/D1",
+ .std = V4L2_STD_NTSC,
+ .fps_min = 6,
+@@ -497,9 +514,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+ .maximum = 1,
+ .step = 1,
+ .default_value = INDYCAM_AGC_DEFAULT,
+- .flags = 0,
+- .reserved = { INDYCAM_CONTROL_AGC, 0 },
+- },{
++ }, {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic White Balance",
+@@ -507,9 +522,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+ .maximum = 1,
+ .step = 1,
+ .default_value = INDYCAM_AWB_DEFAULT,
+- .flags = 0,
+- .reserved = { INDYCAM_CONTROL_AWB, 0 },
+- },{
++ }, {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+@@ -517,29 +530,23 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+ .maximum = INDYCAM_GAIN_MAX,
+ .step = 1,
+ .default_value = INDYCAM_GAIN_DEFAULT,
+- .flags = 0,
+- .reserved = { INDYCAM_CONTROL_GAIN, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE,
++ }, {
++ .id = INDYCAM_CONTROL_RED_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Saturation",
+ .minimum = INDYCAM_RED_SATURATION_MIN,
+ .maximum = INDYCAM_RED_SATURATION_MAX,
+ .step = 1,
+ .default_value = INDYCAM_RED_SATURATION_DEFAULT,
+- .flags = 0,
+- .reserved = { INDYCAM_CONTROL_RED_SATURATION, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE + 1,
++ }, {
++ .id = INDYCAM_CONTROL_BLUE_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Saturation",
+ .minimum = INDYCAM_BLUE_SATURATION_MIN,
+ .maximum = INDYCAM_BLUE_SATURATION_MAX,
+ .step = 1,
+ .default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
+- .flags = 0,
+- .reserved = { INDYCAM_CONTROL_BLUE_SATURATION, 0 },
+- },{
++ }, {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+@@ -547,9 +554,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+ .maximum = INDYCAM_RED_BALANCE_MAX,
+ .step = 1,
+ .default_value = INDYCAM_RED_BALANCE_DEFAULT,
+- .flags = 0,
+- .reserved = { INDYCAM_CONTROL_RED_BALANCE, 0 },
+- },{
++ }, {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+@@ -557,9 +562,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+ .maximum = INDYCAM_BLUE_BALANCE_MAX,
+ .step = 1,
+ .default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
+- .flags = 0,
+- .reserved = { INDYCAM_CONTROL_BLUE_BALANCE, 0 },
+- },{
++ }, {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Shutter Control",
+@@ -567,9 +570,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+ .maximum = INDYCAM_SHUTTER_MAX,
+ .step = 1,
+ .default_value = INDYCAM_SHUTTER_DEFAULT,
+- .flags = 0,
+- .reserved = { INDYCAM_CONTROL_SHUTTER, 0 },
+- },{
++ }, {
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+@@ -577,8 +578,6 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
+ .maximum = INDYCAM_GAMMA_MAX,
+ .step = 1,
+ .default_value = INDYCAM_GAMMA_DEFAULT,
+- .flags = 0,
+- .reserved = { INDYCAM_CONTROL_GAMMA, 0 },
+ }
+ };
+
+@@ -593,209 +592,73 @@ struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
+ .maximum = SAA7191_HUE_MAX,
+ .step = 1,
+ .default_value = SAA7191_HUE_DEFAULT,
+- .flags = 0,
+- .reserved = { SAA7191_CONTROL_HUE, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE,
++ }, {
++ .id = SAA7191_CONTROL_BANDPASS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Luminance Bandpass",
+ .minimum = SAA7191_BANDPASS_MIN,
+ .maximum = SAA7191_BANDPASS_MAX,
+ .step = 1,
+ .default_value = SAA7191_BANDPASS_DEFAULT,
+- .flags = 0,
+- .reserved = { SAA7191_CONTROL_BANDPASS, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE + 1,
++ }, {
++ .id = SAA7191_CONTROL_BANDPASS_WEIGHT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Luminance Bandpass Weight",
+ .minimum = SAA7191_BANDPASS_WEIGHT_MIN,
+ .maximum = SAA7191_BANDPASS_WEIGHT_MAX,
+ .step = 1,
+ .default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT,
+- .flags = 0,
+- .reserved = { SAA7191_CONTROL_BANDPASS_WEIGHT, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE + 2,
++ }, {
++ .id = SAA7191_CONTROL_CORING,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HF Luminance Coring",
+ .minimum = SAA7191_CORING_MIN,
+ .maximum = SAA7191_CORING_MAX,
+ .step = 1,
+ .default_value = SAA7191_CORING_DEFAULT,
+- .flags = 0,
+- .reserved = { SAA7191_CONTROL_CORING, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE + 3,
++ }, {
++ .id = SAA7191_CONTROL_FORCE_COLOUR,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Force Colour",
+ .minimum = SAA7191_FORCE_COLOUR_MIN,
+ .maximum = SAA7191_FORCE_COLOUR_MAX,
+ .step = 1,
+ .default_value = SAA7191_FORCE_COLOUR_DEFAULT,
+- .flags = 0,
+- .reserved = { SAA7191_CONTROL_FORCE_COLOUR, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE + 4,
++ }, {
++ .id = SAA7191_CONTROL_CHROMA_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Chrominance Gain Control",
+ .minimum = SAA7191_CHROMA_GAIN_MIN,
+ .maximum = SAA7191_CHROMA_GAIN_MAX,
+ .step = 1,
+ .default_value = SAA7191_CHROMA_GAIN_DEFAULT,
+- .flags = 0,
+- .reserved = { SAA7191_CONTROL_CHROMA_GAIN, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE + 5,
++ }, {
++ .id = SAA7191_CONTROL_VTRC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VTR Time Constant",
+ .minimum = SAA7191_VTRC_MIN,
+ .maximum = SAA7191_VTRC_MAX,
+ .step = 1,
+ .default_value = SAA7191_VTRC_DEFAULT,
+- .flags = 0,
+- .reserved = { SAA7191_CONTROL_VTRC, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE + 6,
++ }, {
++ .id = SAA7191_CONTROL_LUMA_DELAY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Luminance Delay Compensation",
+ .minimum = SAA7191_LUMA_DELAY_MIN,
+ .maximum = SAA7191_LUMA_DELAY_MAX,
+ .step = 1,
+ .default_value = SAA7191_LUMA_DELAY_DEFAULT,
+- .flags = 0,
+- .reserved = { SAA7191_CONTROL_LUMA_DELAY, 0 },
+- },{
+- .id = V4L2_CID_PRIVATE_BASE + 7,
++ }, {
++ .id = SAA7191_CONTROL_VNR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Vertical Noise Reduction",
+ .minimum = SAA7191_VNR_MIN,
+ .maximum = SAA7191_VNR_MAX,
+ .step = 1,
+ .default_value = SAA7191_VNR_DEFAULT,
+- .flags = 0,
+- .reserved = { SAA7191_CONTROL_VNR, 0 },
+ }
+ };
+
+-/* VINO I2C bus functions */
+-
+-unsigned i2c_vino_getctrl(void *data)
+-{
+- return vino->i2c_control;
+-}
+-
+-void i2c_vino_setctrl(void *data, unsigned val)
+-{
+- vino->i2c_control = val;
+-}
+-
+-unsigned i2c_vino_rdata(void *data)
+-{
+- return vino->i2c_data;
+-}
+-
+-void i2c_vino_wdata(void *data, unsigned val)
+-{
+- vino->i2c_data = val;
+-}
+-
+-static struct i2c_algo_sgi_data i2c_sgi_vino_data =
+-{
+- .getctrl = &i2c_vino_getctrl,
+- .setctrl = &i2c_vino_setctrl,
+- .rdata = &i2c_vino_rdata,
+- .wdata = &i2c_vino_wdata,
+- .xfer_timeout = 200,
+- .ack_timeout = 1000,
+-};
+-
+-/*
+- * There are two possible clients on VINO I2C bus, so we limit usage only
+- * to them.
+- */
+-static int i2c_vino_client_reg(struct i2c_client *client)
+-{
+- unsigned long flags;
+- int ret = 0;
+-
+- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+- switch (client->driver->id) {
+- case I2C_DRIVERID_SAA7191:
+- if (vino_drvdata->decoder.driver)
+- ret = -EBUSY;
+- else
+- vino_drvdata->decoder.driver = client;
+- break;
+- case I2C_DRIVERID_INDYCAM:
+- if (vino_drvdata->camera.driver)
+- ret = -EBUSY;
+- else
+- vino_drvdata->camera.driver = client;
+- break;
+- default:
+- ret = -ENODEV;
+- }
+- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+-
+- return ret;
+-}
+-
+-static int i2c_vino_client_unreg(struct i2c_client *client)
+-{
+- unsigned long flags;
+- int ret = 0;
+-
+- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+- if (client == vino_drvdata->decoder.driver) {
+- if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL)
+- ret = -EBUSY;
+- else
+- vino_drvdata->decoder.driver = NULL;
+- } else if (client == vino_drvdata->camera.driver) {
+- if (vino_drvdata->camera.owner != VINO_NO_CHANNEL)
+- ret = -EBUSY;
+- else
+- vino_drvdata->camera.driver = NULL;
+- }
+- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+-
+- return ret;
+-}
+-
+-static struct i2c_adapter vino_i2c_adapter =
+-{
+- .name = "VINO I2C bus",
+- .id = I2C_HW_SGI_VINO,
+- .algo_data = &i2c_sgi_vino_data,
+- .client_register = &i2c_vino_client_reg,
+- .client_unregister = &i2c_vino_client_unreg,
+-};
+-
+-static int vino_i2c_add_bus(void)
+-{
+- return i2c_sgi_add_bus(&vino_i2c_adapter);
+-}
+-
+-static int vino_i2c_del_bus(void)
+-{
+- return i2c_del_adapter(&vino_i2c_adapter);
+-}
+-
+-static int i2c_camera_command(unsigned int cmd, void *arg)
+-{
+- return vino_drvdata->camera.driver->
+- driver->command(vino_drvdata->camera.driver,
+- cmd, arg);
+-}
+-
+-static int i2c_decoder_command(unsigned int cmd, void *arg)
+-{
+- return vino_drvdata->decoder.driver->
+- driver->command(vino_drvdata->decoder.driver,
+- cmd, arg);
+-}
+-
+ /* VINO framebuffer/DMA descriptor management */
+
+ static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
+@@ -1741,6 +1604,184 @@ static inline void vino_set_default_framerate(struct
+ vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
+ }
+
++/* VINO I2C bus functions */
++
++struct i2c_algo_sgi_data {
++ void *data; /* private data for lowlevel routines */
++ unsigned (*getctrl)(void *data);
++ void (*setctrl)(void *data, unsigned val);
++ unsigned (*rdata)(void *data);
++ void (*wdata)(void *data, unsigned val);
++
++ int xfer_timeout;
++ int ack_timeout;
++};
++
++static int wait_xfer_done(struct i2c_algo_sgi_data *adap)
++{
++ int i;
++
++ for (i = 0; i < adap->xfer_timeout; i++) {
++ if ((adap->getctrl(adap->data) & SGI_I2C_XFER_BUSY) == 0)
++ return 0;
++ udelay(1);
++ }
++
++ return -ETIMEDOUT;
++}
++
++static int wait_ack(struct i2c_algo_sgi_data *adap)
++{
++ int i;
++
++ if (wait_xfer_done(adap))
++ return -ETIMEDOUT;
++ for (i = 0; i < adap->ack_timeout; i++) {
++ if ((adap->getctrl(adap->data) & SGI_I2C_NACK) == 0)
++ return 0;
++ udelay(1);
++ }
++
++ return -ETIMEDOUT;
++}
++
++static int force_idle(struct i2c_algo_sgi_data *adap)
++{
++ int i;
++
++ adap->setctrl(adap->data, SGI_I2C_FORCE_IDLE);
++ for (i = 0; i < adap->xfer_timeout; i++) {
++ if ((adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) == 0)
++ goto out;
++ udelay(1);
++ }
++ return -ETIMEDOUT;
++out:
++ if (adap->getctrl(adap->data) & SGI_I2C_BUS_ERR)
++ return -EIO;
++ return 0;
++}
++
++static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr,
++ int rd)
++{
++ if (rd)
++ adap->setctrl(adap->data, SGI_I2C_NOT_IDLE);
++ /* Check if bus is idle, eventually force it to do so */
++ if (adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE)
++ if (force_idle(adap))
++ return -EIO;
++ /* Write out the i2c chip address and specify operation */
++ adap->setctrl(adap->data,
++ SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE);
++ if (rd)
++ addr |= 1;
++ adap->wdata(adap->data, addr);
++ if (wait_ack(adap))
++ return -EIO;
++ return 0;
++}
++
++static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf,
++ unsigned int len)
++{
++ int i;
++
++ adap->setctrl(adap->data,
++ SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE);
++ for (i = 0; i < len; i++) {
++ if (wait_xfer_done(adap))
++ return -EIO;
++ buf[i] = adap->rdata(adap->data);
++ }
++ adap->setctrl(adap->data, SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE);
++
++ return 0;
++
++}
++
++static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf,
++ unsigned int len)
++{
++ int i;
++
++ /* We are already in write state */
++ for (i = 0; i < len; i++) {
++ adap->wdata(adap->data, buf[i]);
++ if (wait_ack(adap))
++ return -EIO;
++ }
++ return 0;
++}
++
++static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
++ int num)
++{
++ struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
++ struct i2c_msg *p;
++ int i, err = 0;
++
++ for (i = 0; !err && i < num; i++) {
++ p = &msgs[i];
++ err = do_address(adap, p->addr, p->flags & I2C_M_RD);
++ if (err || !p->len)
++ continue;
++ if (p->flags & I2C_M_RD)
++ err = i2c_read(adap, p->buf, p->len);
++ else
++ err = i2c_write(adap, p->buf, p->len);
++ }
++
++ return (err < 0) ? err : i;
++}
++
++static u32 sgi_func(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_SMBUS_EMUL;
++}
++
++static const struct i2c_algorithm sgi_algo = {
++ .master_xfer = sgi_xfer,
++ .functionality = sgi_func,
++};
++
++static unsigned i2c_vino_getctrl(void *data)
++{
++ return vino->i2c_control;
++}
++
++static void i2c_vino_setctrl(void *data, unsigned val)
++{
++ vino->i2c_control = val;
++}
++
++static unsigned i2c_vino_rdata(void *data)
++{
++ return vino->i2c_data;
++}
++
++static void i2c_vino_wdata(void *data, unsigned val)
++{
++ vino->i2c_data = val;
++}
++
++static struct i2c_algo_sgi_data i2c_sgi_vino_data = {
++ .getctrl = &i2c_vino_getctrl,
++ .setctrl = &i2c_vino_setctrl,
++ .rdata = &i2c_vino_rdata,
++ .wdata = &i2c_vino_wdata,
++ .xfer_timeout = 200,
++ .ack_timeout = 1000,
++};
++
++static struct i2c_adapter vino_i2c_adapter = {
++ .name = "VINO I2C bus",
++ .id = I2C_HW_SGI_VINO,
++ .algo = &sgi_algo,
++ .algo_data = &i2c_sgi_vino_data,
++ .owner = THIS_MODULE,
++};
++
+ /*
+ * Prepare VINO for DMA transfer...
+ * (execute only with vino_lock and input_lock locked)
+@@ -2490,86 +2531,15 @@ static int vino_get_saa7191_input(int input)
+ }
+ }
+
+-static int vino_get_saa7191_norm(unsigned int data_norm)
+-{
+- switch (data_norm) {
+- case VINO_DATA_NORM_AUTO:
+- return SAA7191_NORM_AUTO;
+- case VINO_DATA_NORM_AUTO_EXT:
+- return SAA7191_NORM_AUTO_EXT;
+- case VINO_DATA_NORM_PAL:
+- return SAA7191_NORM_PAL;
+- case VINO_DATA_NORM_NTSC:
+- return SAA7191_NORM_NTSC;
+- case VINO_DATA_NORM_SECAM:
+- return SAA7191_NORM_SECAM;
+- default:
+- printk(KERN_ERR "VINO: vino_get_saa7191_norm(): "
+- "invalid norm!\n");
+- return -1;
+- }
+-}
+-
+-static int vino_get_from_saa7191_norm(int saa7191_norm)
+-{
+- switch (saa7191_norm) {
+- case SAA7191_NORM_PAL:
+- return VINO_DATA_NORM_PAL;
+- case SAA7191_NORM_NTSC:
+- return VINO_DATA_NORM_NTSC;
+- case SAA7191_NORM_SECAM:
+- return VINO_DATA_NORM_SECAM;
+- default:
+- printk(KERN_ERR "VINO: vino_get_from_saa7191_norm(): "
+- "invalid norm!\n");
+- return VINO_DATA_NORM_NONE;
+- }
+-}
+-
+-static int vino_saa7191_set_norm(unsigned int *data_norm)
+-{
+- int saa7191_norm, new_data_norm;
+- int err = 0;
+-
+- saa7191_norm = vino_get_saa7191_norm(*data_norm);
+-
+- err = i2c_decoder_command(DECODER_SAA7191_SET_NORM,
+- &saa7191_norm);
+- if (err)
+- goto out;
+-
+- if ((*data_norm == VINO_DATA_NORM_AUTO)
+- || (*data_norm == VINO_DATA_NORM_AUTO_EXT)) {
+- struct saa7191_status status;
+-
+- err = i2c_decoder_command(DECODER_SAA7191_GET_STATUS,
+- &status);
+- if (err)
+- goto out;
+-
+- new_data_norm =
+- vino_get_from_saa7191_norm(status.norm);
+- if (new_data_norm == VINO_DATA_NORM_NONE) {
+- err = -EINVAL;
+- goto out;
+- }
+-
+- *data_norm = (unsigned int)new_data_norm;
+- }
+-
+-out:
+- return err;
+-}
+-
+ /* execute with input_lock locked */
+ static int vino_is_input_owner(struct vino_channel_settings *vcs)
+ {
+ switch(vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+- return (vino_drvdata->decoder.owner == vcs->channel);
++ return vino_drvdata->decoder_owner == vcs->channel;
+ case VINO_INPUT_D1:
+- return (vino_drvdata->camera.owner == vcs->channel);
++ return vino_drvdata->camera_owner == vcs->channel;
+ default:
+ return 0;
+ }
+@@ -2585,23 +2555,22 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+ /* First try D1 and then SAA7191 */
+- if (vino_drvdata->camera.driver
+- && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
+- i2c_use_client(vino_drvdata->camera.driver);
+- vino_drvdata->camera.owner = vcs->channel;
++ if (vino_drvdata->camera
++ && (vino_drvdata->camera_owner == VINO_NO_CHANNEL)) {
++ vino_drvdata->camera_owner = vcs->channel;
+ vcs->input = VINO_INPUT_D1;
+ vcs->data_norm = VINO_DATA_NORM_D1;
+- } else if (vino_drvdata->decoder.driver
+- && (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) {
+- int input, data_norm;
+- int saa7191_input;
++ } else if (vino_drvdata->decoder
++ && (vino_drvdata->decoder_owner == VINO_NO_CHANNEL)) {
++ int input;
++ int data_norm;
++ v4l2_std_id norm;
++ struct v4l2_routing route = { 0, 0 };
+
+- i2c_use_client(vino_drvdata->decoder.driver);
+ input = VINO_INPUT_COMPOSITE;
+
+- saa7191_input = vino_get_saa7191_input(input);
+- ret = i2c_decoder_command(DECODER_SET_INPUT,
+- &saa7191_input);
++ route.input = vino_get_saa7191_input(input);
++ ret = decoder_call(video, s_routing, &route);
+ if (ret) {
+ ret = -EINVAL;
+ goto out;
+@@ -2612,12 +2581,15 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
+ /* Don't hold spinlocks while auto-detecting norm
+ * as it may take a while... */
+
+- data_norm = VINO_DATA_NORM_AUTO_EXT;
+-
+- ret = vino_saa7191_set_norm(&data_norm);
+- if ((ret == -EBUSY) || (ret == -EAGAIN)) {
+- data_norm = VINO_DATA_NORM_PAL;
+- ret = vino_saa7191_set_norm(&data_norm);
++ ret = decoder_call(video, querystd, &norm);
++ if (!ret) {
++ for (data_norm = 0; data_norm < 3; data_norm++) {
++ if (vino_data_norms[data_norm].std & norm)
++ break;
++ }
++ if (data_norm == 3)
++ data_norm = VINO_DATA_NORM_PAL;
++ ret = decoder_call(tuner, s_std, norm);
+ }
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+@@ -2627,7 +2599,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
+ goto out;
+ }
+
+- vino_drvdata->decoder.owner = vcs->channel;
++ vino_drvdata->decoder_owner = vcs->channel;
+
+ vcs->input = input;
+ vcs->data_norm = data_norm;
+@@ -2672,25 +2644,24 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
+ switch (input) {
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO:
+- if (!vino_drvdata->decoder.driver) {
++ if (!vino_drvdata->decoder) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+- if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
+- i2c_use_client(vino_drvdata->decoder.driver);
+- vino_drvdata->decoder.owner = vcs->channel;
++ if (vino_drvdata->decoder_owner == VINO_NO_CHANNEL) {
++ vino_drvdata->decoder_owner = vcs->channel;
+ }
+
+- if (vino_drvdata->decoder.owner == vcs->channel) {
++ if (vino_drvdata->decoder_owner == vcs->channel) {
+ int data_norm;
+- int saa7191_input;
++ v4l2_std_id norm;
++ struct v4l2_routing route = { 0, 0 };
+
+- saa7191_input = vino_get_saa7191_input(input);
+- ret = i2c_decoder_command(DECODER_SET_INPUT,
+- &saa7191_input);
++ route.input = vino_get_saa7191_input(input);
++ ret = decoder_call(video, s_routing, &route);
+ if (ret) {
+- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
++ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
+ ret = -EINVAL;
+ goto out;
+ }
+@@ -2700,18 +2671,21 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
+ /* Don't hold spinlocks while auto-detecting norm
+ * as it may take a while... */
+
+- data_norm = VINO_DATA_NORM_AUTO_EXT;
+-
+- ret = vino_saa7191_set_norm(&data_norm);
+- if ((ret == -EBUSY) || (ret == -EAGAIN)) {
+- data_norm = VINO_DATA_NORM_PAL;
+- ret = vino_saa7191_set_norm(&data_norm);
++ ret = decoder_call(video, querystd, &norm);
++ if (!ret) {
++ for (data_norm = 0; data_norm < 3; data_norm++) {
++ if (vino_data_norms[data_norm].std & norm)
++ break;
++ }
++ if (data_norm == 3)
++ data_norm = VINO_DATA_NORM_PAL;
++ ret = decoder_call(tuner, s_std, norm);
+ }
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+ if (ret) {
+- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
++ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
+ ret = -EINVAL;
+ goto out;
+ }
+@@ -2728,37 +2702,31 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
+ vcs->data_norm = vcs2->data_norm;
+ }
+
+- if (vino_drvdata->camera.owner == vcs->channel) {
++ if (vino_drvdata->camera_owner == vcs->channel) {
+ /* Transfer the ownership or release the input */
+ if (vcs2->input == VINO_INPUT_D1) {
+- vino_drvdata->camera.owner = vcs2->channel;
++ vino_drvdata->camera_owner = vcs2->channel;
+ } else {
+- i2c_release_client(vino_drvdata->
+- camera.driver);
+- vino_drvdata->camera.owner = VINO_NO_CHANNEL;
++ vino_drvdata->camera_owner = VINO_NO_CHANNEL;
+ }
+ }
+ break;
+ case VINO_INPUT_D1:
+- if (!vino_drvdata->camera.driver) {
++ if (!vino_drvdata->camera) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+- if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
+- i2c_use_client(vino_drvdata->camera.driver);
+- vino_drvdata->camera.owner = vcs->channel;
+- }
++ if (vino_drvdata->camera_owner == VINO_NO_CHANNEL)
++ vino_drvdata->camera_owner = vcs->channel;
+
+- if (vino_drvdata->decoder.owner == vcs->channel) {
++ if (vino_drvdata->decoder_owner == vcs->channel) {
+ /* Transfer the ownership or release the input */
+ if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+ (vcs2->input == VINO_INPUT_SVIDEO)) {
+- vino_drvdata->decoder.owner = vcs2->channel;
++ vino_drvdata->decoder_owner = vcs2->channel;
+ } else {
+- i2c_release_client(vino_drvdata->
+- decoder.driver);
+- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
++ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
+ }
+ }
+
+@@ -2795,20 +2763,18 @@ static void vino_release_input(struct vino_channel_settings *vcs)
+ /* Release ownership of the channel
+ * and if the other channel takes input from
+ * the same source, transfer the ownership */
+- if (vino_drvdata->camera.owner == vcs->channel) {
++ if (vino_drvdata->camera_owner == vcs->channel) {
+ if (vcs2->input == VINO_INPUT_D1) {
+- vino_drvdata->camera.owner = vcs2->channel;
++ vino_drvdata->camera_owner = vcs2->channel;
+ } else {
+- i2c_release_client(vino_drvdata->camera.driver);
+- vino_drvdata->camera.owner = VINO_NO_CHANNEL;
++ vino_drvdata->camera_owner = VINO_NO_CHANNEL;
+ }
+- } else if (vino_drvdata->decoder.owner == vcs->channel) {
++ } else if (vino_drvdata->decoder_owner == vcs->channel) {
+ if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
+ (vcs2->input == VINO_INPUT_SVIDEO)) {
+- vino_drvdata->decoder.owner = vcs2->channel;
++ vino_drvdata->decoder_owner = vcs2->channel;
+ } else {
+- i2c_release_client(vino_drvdata->decoder.driver);
+- vino_drvdata->decoder.owner = VINO_NO_CHANNEL;
++ vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
+ }
+ }
+ vcs->input = VINO_INPUT_NONE;
+@@ -2829,18 +2795,16 @@ static int vino_set_data_norm(struct vino_channel_settings *vcs,
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ /* only one "norm" supported */
+- if ((data_norm != VINO_DATA_NORM_D1)
+- && (data_norm != VINO_DATA_NORM_AUTO)
+- && (data_norm != VINO_DATA_NORM_AUTO_EXT))
++ if (data_norm != VINO_DATA_NORM_D1)
+ return -EINVAL;
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO: {
++ v4l2_std_id norm;
++
+ if ((data_norm != VINO_DATA_NORM_PAL)
+ && (data_norm != VINO_DATA_NORM_NTSC)
+- && (data_norm != VINO_DATA_NORM_SECAM)
+- && (data_norm != VINO_DATA_NORM_AUTO)
+- && (data_norm != VINO_DATA_NORM_AUTO_EXT))
++ && (data_norm != VINO_DATA_NORM_SECAM))
+ return -EINVAL;
+
+ spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags);
+@@ -2848,7 +2812,8 @@ static int vino_set_data_norm(struct vino_channel_settings *vcs,
+ /* Don't hold spinlocks while setting norm
+ * as it may take a while... */
+
+- err = vino_saa7191_set_norm(&data_norm);
++ norm = vino_data_norms[data_norm].std;
++ err = decoder_call(tuner, s_std, norm);
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, *flags);
+
+@@ -2884,41 +2849,13 @@ static int vino_find_data_format(__u32 pixelformat)
+ return VINO_DATA_FMT_NONE;
+ }
+
+-static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index)
+-{
+- int data_norm = VINO_DATA_NORM_NONE;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+- switch(vcs->input) {
+- case VINO_INPUT_COMPOSITE:
+- case VINO_INPUT_SVIDEO:
+- if (index == 0) {
+- data_norm = VINO_DATA_NORM_PAL;
+- } else if (index == 1) {
+- data_norm = VINO_DATA_NORM_NTSC;
+- } else if (index == 2) {
+- data_norm = VINO_DATA_NORM_SECAM;
+- }
+- break;
+- case VINO_INPUT_D1:
+- if (index == 0) {
+- data_norm = VINO_DATA_NORM_D1;
+- }
+- break;
+- }
+- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+-
+- return data_norm;
+-}
+-
+-static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
++static int vino_int_enum_input(struct vino_channel_settings *vcs, __u32 index)
+ {
+ int input = VINO_INPUT_NONE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+- if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
++ if (vino_drvdata->decoder && vino_drvdata->camera) {
+ switch (index) {
+ case 0:
+ input = VINO_INPUT_COMPOSITE;
+@@ -2930,7 +2867,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
+ input = VINO_INPUT_D1;
+ break;
+ }
+- } else if (vino_drvdata->decoder.driver) {
++ } else if (vino_drvdata->decoder) {
+ switch (index) {
+ case 0:
+ input = VINO_INPUT_COMPOSITE;
+@@ -2939,7 +2876,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index)
+ input = VINO_INPUT_SVIDEO;
+ break;
+ }
+- } else if (vino_drvdata->camera.driver) {
++ } else if (vino_drvdata->camera) {
+ switch (index) {
+ case 0:
+ input = VINO_INPUT_D1;
+@@ -2957,7 +2894,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
+ __u32 index = 0;
+ // FIXME: detect when no inputs available
+
+- if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) {
++ if (vino_drvdata->decoder && vino_drvdata->camera) {
+ switch (vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ index = 0;
+@@ -2969,7 +2906,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
+ index = 2;
+ break;
+ }
+- } else if (vino_drvdata->decoder.driver) {
++ } else if (vino_drvdata->decoder) {
+ switch (vcs->input) {
+ case VINO_INPUT_COMPOSITE:
+ index = 0;
+@@ -2978,7 +2915,7 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
+ index = 1;
+ break;
+ }
+- } else if (vino_drvdata->camera.driver) {
++ } else if (vino_drvdata->camera) {
+ switch (vcs->input) {
+ case VINO_INPUT_D1:
+ index = 0;
+@@ -2991,7 +2928,8 @@ static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
+
+ /* V4L2 ioctls */
+
+-static void vino_v4l2_querycap(struct v4l2_capability *cap)
++static int vino_querycap(struct file *file, void *__fh,
++ struct v4l2_capability *cap)
+ {
+ memset(cap, 0, sizeof(struct v4l2_capability));
+
+@@ -3003,16 +2941,18 @@ static void vino_v4l2_querycap(struct v4l2_capability *cap)
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING;
+ // V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE
++ return 0;
+ }
+
+-static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
++static int vino_enum_input(struct file *file, void *__fh,
+ struct v4l2_input *i)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ __u32 index = i->index;
+ int input;
+ dprintk("requested index = %d\n", index);
+
+- input = vino_enum_input(vcs, index);
++ input = vino_int_enum_input(vcs, index);
+ if (input == VINO_INPUT_NONE)
+ return -EINVAL;
+
+@@ -3023,20 +2963,15 @@ static int vino_v4l2_enuminput(struct vino_channel_settings *vcs,
+ i->std = vino_inputs[input].std;
+ strcpy(i->name, vino_inputs[input].name);
+
+- if ((input == VINO_INPUT_COMPOSITE)
+- || (input == VINO_INPUT_SVIDEO)) {
+- struct saa7191_status status;
+- i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
+- i->status |= status.signal ? 0 : V4L2_IN_ST_NO_SIGNAL;
+- i->status |= status.color ? 0 : V4L2_IN_ST_NO_COLOR;
+- }
+-
++ if (input == VINO_INPUT_COMPOSITE || input == VINO_INPUT_SVIDEO)
++ decoder_call(video, g_input_status, &i->status);
+ return 0;
+ }
+
+-static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
++static int vino_g_input(struct file *file, void *__fh,
+ unsigned int *i)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ __u32 index;
+ int input;
+ unsigned long flags;
+@@ -3057,52 +2992,24 @@ static int vino_v4l2_g_input(struct vino_channel_settings *vcs,
+ return 0;
+ }
+
+-static int vino_v4l2_s_input(struct vino_channel_settings *vcs,
+- unsigned int *i)
++static int vino_s_input(struct file *file, void *__fh,
++ unsigned int i)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ int input;
+- dprintk("requested input = %d\n", *i);
++ dprintk("requested input = %d\n", i);
+
+- input = vino_enum_input(vcs, *i);
++ input = vino_int_enum_input(vcs, i);
+ if (input == VINO_INPUT_NONE)
+ return -EINVAL;
+
+ return vino_set_input(vcs, input);
+ }
+
+-static int vino_v4l2_enumstd(struct vino_channel_settings *vcs,
+- struct v4l2_standard *s)
+-{
+- int index = s->index;
+- int data_norm;
+-
+- data_norm = vino_enum_data_norm(vcs, index);
+- dprintk("standard index = %d\n", index);
+-
+- if (data_norm == VINO_DATA_NORM_NONE)
+- return -EINVAL;
+-
+- dprintk("standard name = %s\n",
+- vino_data_norms[data_norm].description);
+-
+- memset(s, 0, sizeof(struct v4l2_standard));
+- s->index = index;
+-
+- s->id = vino_data_norms[data_norm].std;
+- s->frameperiod.numerator = 1;
+- s->frameperiod.denominator =
+- vino_data_norms[data_norm].fps_max;
+- s->framelines =
+- vino_data_norms[data_norm].framelines;
+- strcpy(s->name,
+- vino_data_norms[data_norm].description);
+-
+- return 0;
+-}
+-
+-static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
++static int vino_querystd(struct file *file, void *__fh,
+ v4l2_std_id *std)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
+ int err = 0;
+
+@@ -3114,19 +3021,7 @@ static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
+ break;
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO: {
+- struct saa7191_status status;
+-
+- i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status);
+-
+- if (status.signal) {
+- if (status.signal_60hz) {
+- *std = V4L2_STD_NTSC;
+- } else {
+- *std = V4L2_STD_PAL | V4L2_STD_SECAM;
+- }
+- } else {
+- *std = vino_inputs[vcs->input].std;
+- }
++ decoder_call(video, querystd, std);
+ break;
+ }
+ default:
+@@ -3138,9 +3033,10 @@ static int vino_v4l2_querystd(struct vino_channel_settings *vcs,
+ return err;
+ }
+
+-static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
++static int vino_g_std(struct file *file, void *__fh,
+ v4l2_std_id *std)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+@@ -3153,9 +3049,10 @@ static int vino_v4l2_g_std(struct vino_channel_settings *vcs,
+ return 0;
+ }
+
+-static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
++static int vino_s_std(struct file *file, void *__fh,
+ v4l2_std_id *std)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
+ int ret = 0;
+
+@@ -3176,12 +3073,7 @@ static int vino_v4l2_s_std(struct vino_channel_settings *vcs,
+ if (vcs->input == VINO_INPUT_D1)
+ goto out;
+
+- if (((*std) & V4L2_STD_PAL)
+- && ((*std) & V4L2_STD_NTSC)
+- && ((*std) & V4L2_STD_SECAM)) {
+- ret = vino_set_data_norm(vcs, VINO_DATA_NORM_AUTO_EXT,
+- &flags);
+- } else if ((*std) & V4L2_STD_PAL) {
++ if ((*std) & V4L2_STD_PAL) {
+ ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL,
+ &flags);
+ } else if ((*std) & V4L2_STD_NTSC) {
+@@ -3207,185 +3099,144 @@ out:
+ return ret;
+ }
+
+-static int vino_v4l2_enum_fmt(struct vino_channel_settings *vcs,
++static int vino_enum_fmt_vid_cap(struct file *file, void *__fh,
+ struct v4l2_fmtdesc *fd)
+ {
+- enum v4l2_buf_type type = fd->type;
+- int index = fd->index;
+- dprintk("format index = %d\n", index);
++ dprintk("format index = %d\n", fd->index);
+
+- switch (fd->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- if ((fd->index < 0) ||
+- (fd->index >= VINO_DATA_FMT_COUNT))
+- return -EINVAL;
+- dprintk("format name = %s\n",
+- vino_data_formats[index].description);
+-
+- memset(fd, 0, sizeof(struct v4l2_fmtdesc));
+- fd->index = index;
+- fd->type = type;
+- fd->pixelformat = vino_data_formats[index].pixelformat;
+- strcpy(fd->description, vino_data_formats[index].description);
+- break;
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
++ if (fd->index >= VINO_DATA_FMT_COUNT)
+ return -EINVAL;
+- }
++ dprintk("format name = %s\n", vino_data_formats[fd->index].description);
+
++ fd->pixelformat = vino_data_formats[fd->index].pixelformat;
++ strcpy(fd->description, vino_data_formats[fd->index].description);
+ return 0;
+ }
+
+-static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs,
++static int vino_try_fmt_vid_cap(struct file *file, void *__fh,
+ struct v4l2_format *f)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ struct vino_channel_settings tempvcs;
+ unsigned long flags;
++ struct v4l2_pix_format *pf = &f->fmt.pix;
+
+- switch (f->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- struct v4l2_pix_format *pf = &f->fmt.pix;
+-
+- dprintk("requested: w = %d, h = %d\n",
+- pf->width, pf->height);
+-
+- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+- memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
+- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
++ dprintk("requested: w = %d, h = %d\n",
++ pf->width, pf->height);
+
+- tempvcs.data_format = vino_find_data_format(pf->pixelformat);
+- if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
+- tempvcs.data_format = VINO_DATA_FMT_GREY;
+- pf->pixelformat =
+- vino_data_formats[tempvcs.data_format].
+- pixelformat;
+- }
++ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
++ memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
++ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+- /* data format must be set before clipping/scaling */
+- vino_set_scaling(&tempvcs, pf->width, pf->height);
++ tempvcs.data_format = vino_find_data_format(pf->pixelformat);
++ if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
++ tempvcs.data_format = VINO_DATA_FMT_GREY;
++ pf->pixelformat =
++ vino_data_formats[tempvcs.data_format].
++ pixelformat;
++ }
+
+- dprintk("data format = %s\n",
+- vino_data_formats[tempvcs.data_format].description);
++ /* data format must be set before clipping/scaling */
++ vino_set_scaling(&tempvcs, pf->width, pf->height);
+
+- pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
+- tempvcs.decimation;
+- pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+- tempvcs.decimation;
++ dprintk("data format = %s\n",
++ vino_data_formats[tempvcs.data_format].description);
+
+- pf->field = V4L2_FIELD_INTERLACED;
+- pf->bytesperline = tempvcs.line_size;
+- pf->sizeimage = tempvcs.line_size *
+- (tempvcs.clipping.bottom - tempvcs.clipping.top) /
+- tempvcs.decimation;
+- pf->colorspace =
+- vino_data_formats[tempvcs.data_format].colorspace;
++ pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
++ tempvcs.decimation;
++ pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
++ tempvcs.decimation;
+
+- pf->priv = 0;
+- break;
+- }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
+- return -EINVAL;
+- }
++ pf->field = V4L2_FIELD_INTERLACED;
++ pf->bytesperline = tempvcs.line_size;
++ pf->sizeimage = tempvcs.line_size *
++ (tempvcs.clipping.bottom - tempvcs.clipping.top) /
++ tempvcs.decimation;
++ pf->colorspace =
++ vino_data_formats[tempvcs.data_format].colorspace;
+
++ pf->priv = 0;
+ return 0;
+ }
+
+-static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs,
++static int vino_g_fmt_vid_cap(struct file *file, void *__fh,
+ struct v4l2_format *f)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
++ struct v4l2_pix_format *pf = &f->fmt.pix;
+
+- switch (f->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- struct v4l2_pix_format *pf = &f->fmt.pix;
+-
+- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+-
+- pf->width = (vcs->clipping.right - vcs->clipping.left) /
+- vcs->decimation;
+- pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
+- vcs->decimation;
+- pf->pixelformat =
+- vino_data_formats[vcs->data_format].pixelformat;
++ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+- pf->field = V4L2_FIELD_INTERLACED;
+- pf->bytesperline = vcs->line_size;
+- pf->sizeimage = vcs->line_size *
+- (vcs->clipping.bottom - vcs->clipping.top) /
+- vcs->decimation;
+- pf->colorspace =
+- vino_data_formats[vcs->data_format].colorspace;
++ pf->width = (vcs->clipping.right - vcs->clipping.left) /
++ vcs->decimation;
++ pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
++ vcs->decimation;
++ pf->pixelformat =
++ vino_data_formats[vcs->data_format].pixelformat;
+
+- pf->priv = 0;
++ pf->field = V4L2_FIELD_INTERLACED;
++ pf->bytesperline = vcs->line_size;
++ pf->sizeimage = vcs->line_size *
++ (vcs->clipping.bottom - vcs->clipping.top) /
++ vcs->decimation;
++ pf->colorspace =
++ vino_data_formats[vcs->data_format].colorspace;
+
+- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+- break;
+- }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
+- return -EINVAL;
+- }
++ pf->priv = 0;
+
++ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+ return 0;
+ }
+
+-static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs,
++static int vino_s_fmt_vid_cap(struct file *file, void *__fh,
+ struct v4l2_format *f)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ int data_format;
+ unsigned long flags;
++ struct v4l2_pix_format *pf = &f->fmt.pix;
+
+- switch (f->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- struct v4l2_pix_format *pf = &f->fmt.pix;
+-
+- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
++ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+- data_format = vino_find_data_format(pf->pixelformat);
++ data_format = vino_find_data_format(pf->pixelformat);
+
+- if (data_format == VINO_DATA_FMT_NONE) {
+- vcs->data_format = VINO_DATA_FMT_GREY;
+- pf->pixelformat =
+- vino_data_formats[vcs->data_format].
+- pixelformat;
+- } else {
+- vcs->data_format = data_format;
+- }
++ if (data_format == VINO_DATA_FMT_NONE) {
++ vcs->data_format = VINO_DATA_FMT_GREY;
++ pf->pixelformat =
++ vino_data_formats[vcs->data_format].
++ pixelformat;
++ } else {
++ vcs->data_format = data_format;
++ }
+
+- /* data format must be set before clipping/scaling */
+- vino_set_scaling(vcs, pf->width, pf->height);
++ /* data format must be set before clipping/scaling */
++ vino_set_scaling(vcs, pf->width, pf->height);
+
+- dprintk("data format = %s\n",
+- vino_data_formats[vcs->data_format].description);
++ dprintk("data format = %s\n",
++ vino_data_formats[vcs->data_format].description);
+
+- pf->width = vcs->clipping.right - vcs->clipping.left;
+- pf->height = vcs->clipping.bottom - vcs->clipping.top;
++ pf->width = vcs->clipping.right - vcs->clipping.left;
++ pf->height = vcs->clipping.bottom - vcs->clipping.top;
+
+- pf->field = V4L2_FIELD_INTERLACED;
+- pf->bytesperline = vcs->line_size;
+- pf->sizeimage = vcs->line_size *
+- (vcs->clipping.bottom - vcs->clipping.top) /
+- vcs->decimation;
+- pf->colorspace =
+- vino_data_formats[vcs->data_format].colorspace;
++ pf->field = V4L2_FIELD_INTERLACED;
++ pf->bytesperline = vcs->line_size;
++ pf->sizeimage = vcs->line_size *
++ (vcs->clipping.bottom - vcs->clipping.top) /
++ vcs->decimation;
++ pf->colorspace =
++ vino_data_formats[vcs->data_format].colorspace;
+
+- pf->priv = 0;
+-
+- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+- break;
+- }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
+- return -EINVAL;
+- }
++ pf->priv = 0;
+
++ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+ return 0;
+ }
+
+-static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
++static int vino_cropcap(struct file *file, void *__fh,
+ struct v4l2_cropcap *ccap)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ const struct vino_data_norm *norm;
+ unsigned long flags;
+
+@@ -3415,9 +3266,10 @@ static int vino_v4l2_cropcap(struct vino_channel_settings *vcs,
+ return 0;
+ }
+
+-static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
++static int vino_g_crop(struct file *file, void *__fh,
+ struct v4l2_crop *c)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
+
+ switch (c->type) {
+@@ -3439,9 +3291,10 @@ static int vino_v4l2_g_crop(struct vino_channel_settings *vcs,
+ return 0;
+ }
+
+-static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
++static int vino_s_crop(struct file *file, void *__fh,
+ struct v4l2_crop *c)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
+
+ switch (c->type) {
+@@ -3461,108 +3314,83 @@ static int vino_v4l2_s_crop(struct vino_channel_settings *vcs,
+ return 0;
+ }
+
+-static int vino_v4l2_g_parm(struct vino_channel_settings *vcs,
++static int vino_g_parm(struct file *file, void *__fh,
+ struct v4l2_streamparm *sp)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
++ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+- switch (sp->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- struct v4l2_captureparm *cp = &sp->parm.capture;
+- memset(cp, 0, sizeof(struct v4l2_captureparm));
++ cp->capability = V4L2_CAP_TIMEPERFRAME;
++ cp->timeperframe.numerator = 1;
+
+- cp->capability = V4L2_CAP_TIMEPERFRAME;
+- cp->timeperframe.numerator = 1;
++ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
++ cp->timeperframe.denominator = vcs->fps;
+
+- cp->timeperframe.denominator = vcs->fps;
++ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+
+- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
+-
+- // TODO: cp->readbuffers = xxx;
+- break;
+- }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
+- return -EINVAL;
+- }
++ /* TODO: cp->readbuffers = xxx; */
+
+ return 0;
+ }
+
+-static int vino_v4l2_s_parm(struct vino_channel_settings *vcs,
++static int vino_s_parm(struct file *file, void *__fh,
+ struct v4l2_streamparm *sp)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
++ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+- switch (sp->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- struct v4l2_captureparm *cp = &sp->parm.capture;
+-
+- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+-
+- if ((cp->timeperframe.numerator == 0) ||
+- (cp->timeperframe.denominator == 0)) {
+- /* reset framerate */
+- vino_set_default_framerate(vcs);
+- } else {
+- vino_set_framerate(vcs, cp->timeperframe.denominator /
+- cp->timeperframe.numerator);
+- }
+-
+- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
++ spin_lock_irqsave(&vino_drvdata->input_lock, flags);
+
+- // TODO: set buffers according to cp->readbuffers
+- break;
+- }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
+- return -EINVAL;
++ if ((cp->timeperframe.numerator == 0) ||
++ (cp->timeperframe.denominator == 0)) {
++ /* reset framerate */
++ vino_set_default_framerate(vcs);
++ } else {
++ vino_set_framerate(vcs, cp->timeperframe.denominator /
++ cp->timeperframe.numerator);
+ }
+
++ spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
++
+ return 0;
+ }
+
+-static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs,
++static int vino_reqbufs(struct file *file, void *__fh,
+ struct v4l2_requestbuffers *rb)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
++
+ if (vcs->reading)
+ return -EBUSY;
+
+- switch (rb->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- // TODO: check queue type
+- if (rb->memory != V4L2_MEMORY_MMAP) {
+- dprintk("type not mmap\n");
+- return -EINVAL;
+- }
++ /* TODO: check queue type */
++ if (rb->memory != V4L2_MEMORY_MMAP) {
++ dprintk("type not mmap\n");
++ return -EINVAL;
++ }
+
+- dprintk("count = %d\n", rb->count);
+- if (rb->count > 0) {
+- if (vino_is_capturing(vcs)) {
+- dprintk("busy, capturing\n");
+- return -EBUSY;
+- }
++ dprintk("count = %d\n", rb->count);
++ if (rb->count > 0) {
++ if (vino_is_capturing(vcs)) {
++ dprintk("busy, capturing\n");
++ return -EBUSY;
++ }
+
+- if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
+- dprintk("busy, buffers still mapped\n");
+- return -EBUSY;
+- } else {
+- vcs->streaming = 0;
+- vino_queue_free(&vcs->fb_queue);
+- vino_queue_init(&vcs->fb_queue, &rb->count);
+- }
++ if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
++ dprintk("busy, buffers still mapped\n");
++ return -EBUSY;
+ } else {
+ vcs->streaming = 0;
+- vino_capture_stop(vcs);
+ vino_queue_free(&vcs->fb_queue);
++ vino_queue_init(&vcs->fb_queue, &rb->count);
+ }
+- break;
+- }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
+- return -EINVAL;
++ } else {
++ vcs->streaming = 0;
++ vino_capture_stop(vcs);
++ vino_queue_free(&vcs->fb_queue);
+ }
+
+ return 0;
+@@ -3606,156 +3434,135 @@ static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
+ fb->id, fb->size, fb->data_size, fb->offset);
+ }
+
+-static int vino_v4l2_querybuf(struct vino_channel_settings *vcs,
++static int vino_querybuf(struct file *file, void *__fh,
+ struct v4l2_buffer *b)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
++ struct vino_framebuffer *fb;
++
+ if (vcs->reading)
+ return -EBUSY;
+
+- switch (b->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- struct vino_framebuffer *fb;
+-
+- // TODO: check queue type
+- if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
+- dprintk("invalid index = %d\n",
+- b->index);
+- return -EINVAL;
+- }
+-
+- fb = vino_queue_get_buffer(&vcs->fb_queue,
+- b->index);
+- if (fb == NULL) {
+- dprintk("vino_queue_get_buffer() failed");
+- return -EINVAL;
+- }
+-
+- vino_v4l2_get_buffer_status(vcs, fb, b);
+- break;
++ /* TODO: check queue type */
++ if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
++ dprintk("invalid index = %d\n",
++ b->index);
++ return -EINVAL;
+ }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
++
++ fb = vino_queue_get_buffer(&vcs->fb_queue,
++ b->index);
++ if (fb == NULL) {
++ dprintk("vino_queue_get_buffer() failed");
+ return -EINVAL;
+ }
+
++ vino_v4l2_get_buffer_status(vcs, fb, b);
++
+ return 0;
+ }
+
+-static int vino_v4l2_qbuf(struct vino_channel_settings *vcs,
++static int vino_qbuf(struct file *file, void *__fh,
+ struct v4l2_buffer *b)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
++ struct vino_framebuffer *fb;
++ int ret;
++
+ if (vcs->reading)
+ return -EBUSY;
+
+- switch (b->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- struct vino_framebuffer *fb;
+- int ret;
+-
+- // TODO: check queue type
+- if (b->memory != V4L2_MEMORY_MMAP) {
+- dprintk("type not mmap\n");
+- return -EINVAL;
+- }
++ /* TODO: check queue type */
++ if (b->memory != V4L2_MEMORY_MMAP) {
++ dprintk("type not mmap\n");
++ return -EINVAL;
++ }
+
+- fb = vino_capture_enqueue(vcs, b->index);
+- if (fb == NULL)
+- return -EINVAL;
++ fb = vino_capture_enqueue(vcs, b->index);
++ if (fb == NULL)
++ return -EINVAL;
+
+- vino_v4l2_get_buffer_status(vcs, fb, b);
++ vino_v4l2_get_buffer_status(vcs, fb, b);
+
+- if (vcs->streaming) {
+- ret = vino_capture_next(vcs, 1);
+- if (ret)
+- return ret;
+- }
+- break;
+- }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
+- return -EINVAL;
++ if (vcs->streaming) {
++ ret = vino_capture_next(vcs, 1);
++ if (ret)
++ return ret;
+ }
+
+ return 0;
+ }
+
+-static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs,
+- struct v4l2_buffer *b,
+- unsigned int nonblocking)
++static int vino_dqbuf(struct file *file, void *__fh,
++ struct v4l2_buffer *b)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
++ unsigned int nonblocking = file->f_flags & O_NONBLOCK;
++ struct vino_framebuffer *fb;
++ unsigned int incoming, outgoing;
++ int err;
++
+ if (vcs->reading)
+ return -EBUSY;
+
+- switch (b->type) {
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+- struct vino_framebuffer *fb;
+- unsigned int incoming, outgoing;
+- int err;
++ /* TODO: check queue type */
+
+- // TODO: check queue type
++ err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
++ if (err) {
++ dprintk("vino_queue_get_incoming() failed\n");
++ return -EINVAL;
++ }
++ err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
++ if (err) {
++ dprintk("vino_queue_get_outgoing() failed\n");
++ return -EINVAL;
++ }
+
+- err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
+- if (err) {
+- dprintk("vino_queue_get_incoming() failed\n");
++ dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
++
++ if (outgoing == 0) {
++ if (incoming == 0) {
++ dprintk("no incoming or outgoing buffers\n");
+ return -EINVAL;
+ }
+- err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
+- if (err) {
+- dprintk("vino_queue_get_outgoing() failed\n");
+- return -EINVAL;
++ if (nonblocking) {
++ dprintk("non-blocking I/O was selected and "
++ "there are no buffers to dequeue\n");
++ return -EAGAIN;
+ }
+
+- dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
+-
+- if (outgoing == 0) {
+- if (incoming == 0) {
+- dprintk("no incoming or outgoing buffers\n");
+- return -EINVAL;
+- }
+- if (nonblocking) {
+- dprintk("non-blocking I/O was selected and "
+- "there are no buffers to dequeue\n");
+- return -EAGAIN;
+- }
+-
++ err = vino_wait_for_frame(vcs);
++ if (err) {
+ err = vino_wait_for_frame(vcs);
+ if (err) {
+- err = vino_wait_for_frame(vcs);
+- if (err) {
+- /* interrupted or
+- * no frames captured because
+- * of frame skipping */
+- // vino_capture_failed(vcs);
+- return -EIO;
+- }
++ /* interrupted or no frames captured because of
++ * frame skipping */
++ /* vino_capture_failed(vcs); */
++ return -EIO;
+ }
+ }
++ }
+
+- fb = vino_queue_remove(&vcs->fb_queue, &b->index);
+- if (fb == NULL) {
+- dprintk("vino_queue_remove() failed\n");
+- return -EINVAL;
+- }
+-
+- err = vino_check_buffer(vcs, fb);
++ fb = vino_queue_remove(&vcs->fb_queue, &b->index);
++ if (fb == NULL) {
++ dprintk("vino_queue_remove() failed\n");
++ return -EINVAL;
++ }
+
+- vino_v4l2_get_buffer_status(vcs, fb, b);
++ err = vino_check_buffer(vcs, fb);
+
+- if (err)
+- return -EIO;
++ vino_v4l2_get_buffer_status(vcs, fb, b);
+
+- break;
+- }
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- default:
+- return -EINVAL;
+- }
++ if (err)
++ return -EIO;
+
+ return 0;
+ }
+
+-static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
++static int vino_streamon(struct file *file, void *__fh,
++ enum v4l2_buf_type i)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned int incoming;
+ int ret;
+ if (vcs->reading)
+@@ -3792,8 +3599,10 @@ static int vino_v4l2_streamon(struct vino_channel_settings *vcs)
+ return 0;
+ }
+
+-static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
++static int vino_streamoff(struct file *file, void *__fh,
++ enum v4l2_buf_type i)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ if (vcs->reading)
+ return -EBUSY;
+
+@@ -3806,9 +3615,10 @@ static int vino_v4l2_streamoff(struct vino_channel_settings *vcs)
+ return 0;
+ }
+
+-static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
++static int vino_queryctrl(struct file *file, void *__fh,
+ struct v4l2_queryctrl *queryctrl)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
+ int i;
+ int err = 0;
+@@ -3855,9 +3665,10 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs,
+ return err;
+ }
+
+-static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
++static int vino_g_ctrl(struct file *file, void *__fh,
+ struct v4l2_control *control)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
+ int i;
+ int err = 0;
+@@ -3866,56 +3677,38 @@ static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs,
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1: {
+- struct indycam_control indycam_ctrl;
+-
++ err = -EINVAL;
+ for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+- if (vino_indycam_v4l2_controls[i].id ==
+- control->id) {
+- goto found1;
++ if (vino_indycam_v4l2_controls[i].id == control->id) {
++ err = 0;
++ break;
+ }
+ }
+
+- err = -EINVAL;
+- goto out;
+-
+-found1:
+- indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0];
+-
+- err = i2c_camera_command(DECODER_INDYCAM_GET_CONTROL,
+- &indycam_ctrl);
+- if (err) {
+- err = -EINVAL;
++ if (err)
+ goto out;
+- }
+
+- control->value = indycam_ctrl.value;
++ err = camera_call(core, g_ctrl, control);
++ if (err)
++ err = -EINVAL;
+ break;
+ }
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO: {
+- struct saa7191_control saa7191_ctrl;
+-
++ err = -EINVAL;
+ for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+- if (vino_saa7191_v4l2_controls[i].id ==
+- control->id) {
+- goto found2;
++ if (vino_saa7191_v4l2_controls[i].id == control->id) {
++ err = 0;
++ break;
+ }
+ }
+
+- err = -EINVAL;
+- goto out;
+-
+-found2:
+- saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0];
+-
+- err = i2c_decoder_command(DECODER_SAA7191_GET_CONTROL,
+- &saa7191_ctrl);
+- if (err) {
+- err = -EINVAL;
++ if (err)
+ goto out;
+- }
+
+- control->value = saa7191_ctrl.value;
++ err = decoder_call(core, g_ctrl, control);
++ if (err)
++ err = -EINVAL;
+ break;
+ }
+ default:
+@@ -3928,9 +3721,10 @@ out:
+ return err;
+ }
+
+-static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
++static int vino_s_ctrl(struct file *file, void *__fh,
+ struct v4l2_control *control)
+ {
++ struct vino_channel_settings *vcs = video_drvdata(file);
+ unsigned long flags;
+ int i;
+ int err = 0;
+@@ -3944,65 +3738,43 @@ static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs,
+
+ switch (vcs->input) {
+ case VINO_INPUT_D1: {
+- struct indycam_control indycam_ctrl;
+-
++ err = -EINVAL;
+ for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
+- if (vino_indycam_v4l2_controls[i].id ==
+- control->id) {
+- if ((control->value >=
+- vino_indycam_v4l2_controls[i].minimum)
+- && (control->value <=
+- vino_indycam_v4l2_controls[i].
+- maximum)) {
+- goto found1;
+- } else {
+- err = -ERANGE;
+- goto out;
+- }
++ if (vino_indycam_v4l2_controls[i].id == control->id) {
++ err = 0;
++ break;
+ }
+ }
+-
+- err = -EINVAL;
+- goto out;
+-
+-found1:
+- indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0];
+- indycam_ctrl.value = control->value;
+-
+- err = i2c_camera_command(DECODER_INDYCAM_SET_CONTROL,
+- &indycam_ctrl);
++ if (err)
++ goto out;
++ if (control->value < vino_indycam_v4l2_controls[i].minimum ||
++ control->value > vino_indycam_v4l2_controls[i].maximum) {
++ err = -ERANGE;
++ goto out;
++ }
++ err = camera_call(core, s_ctrl, control);
+ if (err)
+ err = -EINVAL;
+ break;
+ }
+ case VINO_INPUT_COMPOSITE:
+ case VINO_INPUT_SVIDEO: {
+- struct saa7191_control saa7191_ctrl;
+-
++ err = -EINVAL;
+ for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
+- if (vino_saa7191_v4l2_controls[i].id ==
+- control->id) {
+- if ((control->value >=
+- vino_saa7191_v4l2_controls[i].minimum)
+- && (control->value <=
+- vino_saa7191_v4l2_controls[i].
+- maximum)) {
+- goto found2;
+- } else {
+- err = -ERANGE;
+- goto out;
+- }
++ if (vino_saa7191_v4l2_controls[i].id == control->id) {
++ err = 0;
++ break;
+ }
+ }
+- err = -EINVAL;
+- goto out;
+-
+-found2:
+- saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0];
+- saa7191_ctrl.value = control->value;
++ if (err)
++ goto out;
++ if (control->value < vino_saa7191_v4l2_controls[i].minimum ||
++ control->value > vino_saa7191_v4l2_controls[i].maximum) {
++ err = -ERANGE;
++ goto out;
++ }
+
+- err = i2c_decoder_command(DECODER_SAA7191_SET_CONTROL,
+- &saa7191_ctrl);
++ err = decoder_call(core, s_ctrl, control);
+ if (err)
+ err = -EINVAL;
+ break;
+@@ -4233,116 +4005,9 @@ over:
+ ret = POLLIN | POLLRDNORM;
+
+ error:
+-
+ return ret;
+ }
+
+-static long vino_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+-{
+- struct vino_channel_settings *vcs = video_drvdata(file);
+-
+-#ifdef VINO_DEBUG
+- switch (_IOC_TYPE(cmd)) {
+- case 'v':
+- dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd);
+- break;
+- case 'V':
+- dprintk("ioctl(): V4L2 %s (0x%08x)\n",
+- v4l2_ioctl_names[_IOC_NR(cmd)], cmd);
+- break;
+- default:
+- dprintk("ioctl(): unsupported command 0x%08x\n", cmd);
+- }
+-#endif
+-
+- switch (cmd) {
+- /* V4L2 interface */
+- case VIDIOC_QUERYCAP: {
+- vino_v4l2_querycap(arg);
+- break;
+- }
+- case VIDIOC_ENUMINPUT: {
+- return vino_v4l2_enuminput(vcs, arg);
+- }
+- case VIDIOC_G_INPUT: {
+- return vino_v4l2_g_input(vcs, arg);
+- }
+- case VIDIOC_S_INPUT: {
+- return vino_v4l2_s_input(vcs, arg);
+- }
+- case VIDIOC_ENUMSTD: {
+- return vino_v4l2_enumstd(vcs, arg);
+- }
+- case VIDIOC_QUERYSTD: {
+- return vino_v4l2_querystd(vcs, arg);
+- }
+- case VIDIOC_G_STD: {
+- return vino_v4l2_g_std(vcs, arg);
+- }
+- case VIDIOC_S_STD: {
+- return vino_v4l2_s_std(vcs, arg);
+- }
+- case VIDIOC_ENUM_FMT: {
+- return vino_v4l2_enum_fmt(vcs, arg);
+- }
+- case VIDIOC_TRY_FMT: {
+- return vino_v4l2_try_fmt(vcs, arg);
+- }
+- case VIDIOC_G_FMT: {
+- return vino_v4l2_g_fmt(vcs, arg);
+- }
+- case VIDIOC_S_FMT: {
+- return vino_v4l2_s_fmt(vcs, arg);
+- }
+- case VIDIOC_CROPCAP: {
+- return vino_v4l2_cropcap(vcs, arg);
+- }
+- case VIDIOC_G_CROP: {
+- return vino_v4l2_g_crop(vcs, arg);
+- }
+- case VIDIOC_S_CROP: {
+- return vino_v4l2_s_crop(vcs, arg);
+- }
+- case VIDIOC_G_PARM: {
+- return vino_v4l2_g_parm(vcs, arg);
+- }
+- case VIDIOC_S_PARM: {
+- return vino_v4l2_s_parm(vcs, arg);
+- }
+- case VIDIOC_REQBUFS: {
+- return vino_v4l2_reqbufs(vcs, arg);
+- }
+- case VIDIOC_QUERYBUF: {
+- return vino_v4l2_querybuf(vcs, arg);
+- }
+- case VIDIOC_QBUF: {
+- return vino_v4l2_qbuf(vcs, arg);
+- }
+- case VIDIOC_DQBUF: {
+- return vino_v4l2_dqbuf(vcs, arg, file->f_flags & O_NONBLOCK);
+- }
+- case VIDIOC_STREAMON: {
+- return vino_v4l2_streamon(vcs);
+- }
+- case VIDIOC_STREAMOFF: {
+- return vino_v4l2_streamoff(vcs);
+- }
+- case VIDIOC_QUERYCTRL: {
+- return vino_v4l2_queryctrl(vcs, arg);
+- }
+- case VIDIOC_G_CTRL: {
+- return vino_v4l2_g_ctrl(vcs, arg);
+- }
+- case VIDIOC_S_CTRL: {
+- return vino_v4l2_s_ctrl(vcs, arg);
+- }
+- default:
+- return -ENOIOCTLCMD;
+- }
+-
+- return 0;
+-}
+-
+ static long vino_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+@@ -4352,7 +4017,7 @@ static long vino_ioctl(struct file *file,
+ if (mutex_lock_interruptible(&vcs->mutex))
+ return -EINTR;
+
+- ret = video_usercopy(file, cmd, arg, vino_do_ioctl);
++ ret = video_ioctl2(file, cmd, arg);
+
+ mutex_unlock(&vcs->mutex);
+
+@@ -4364,45 +4029,75 @@ static long vino_ioctl(struct file *file,
+ /* __initdata */
+ static int vino_init_stage;
+
++const struct v4l2_ioctl_ops vino_ioctl_ops = {
++ .vidioc_enum_fmt_vid_cap = vino_enum_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap = vino_g_fmt_vid_cap,
++ .vidioc_s_fmt_vid_cap = vino_s_fmt_vid_cap,
++ .vidioc_try_fmt_vid_cap = vino_try_fmt_vid_cap,
++ .vidioc_querycap = vino_querycap,
++ .vidioc_enum_input = vino_enum_input,
++ .vidioc_g_input = vino_g_input,
++ .vidioc_s_input = vino_s_input,
++ .vidioc_g_std = vino_g_std,
++ .vidioc_s_std = vino_s_std,
++ .vidioc_querystd = vino_querystd,
++ .vidioc_cropcap = vino_cropcap,
++ .vidioc_s_crop = vino_s_crop,
++ .vidioc_g_crop = vino_g_crop,
++ .vidioc_s_parm = vino_s_parm,
++ .vidioc_g_parm = vino_g_parm,
++ .vidioc_reqbufs = vino_reqbufs,
++ .vidioc_querybuf = vino_querybuf,
++ .vidioc_qbuf = vino_qbuf,
++ .vidioc_dqbuf = vino_dqbuf,
++ .vidioc_streamon = vino_streamon,
++ .vidioc_streamoff = vino_streamoff,
++ .vidioc_queryctrl = vino_queryctrl,
++ .vidioc_g_ctrl = vino_g_ctrl,
++ .vidioc_s_ctrl = vino_s_ctrl,
++};
++
+ static const struct v4l2_file_operations vino_fops = {
+ .owner = THIS_MODULE,
+ .open = vino_open,
+ .release = vino_close,
+- .ioctl = vino_ioctl,
++ .unlocked_ioctl = vino_ioctl,
+ .mmap = vino_mmap,
+ .poll = vino_poll,
+ };
+
+-static struct video_device v4l_device_template = {
++static struct video_device vdev_template = {
+ .name = "NOT SET",
+ .fops = &vino_fops,
++ .ioctl_ops = &vino_ioctl_ops,
++ .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+ .minor = -1,
+ };
+
+ static void vino_module_cleanup(int stage)
+ {
+ switch(stage) {
++ case 11:
++ video_unregister_device(vino_drvdata->b.vdev);
++ vino_drvdata->b.vdev = NULL;
+ case 10:
+- video_unregister_device(vino_drvdata->b.v4l_device);
+- vino_drvdata->b.v4l_device = NULL;
++ video_unregister_device(vino_drvdata->a.vdev);
++ vino_drvdata->a.vdev = NULL;
+ case 9:
+- video_unregister_device(vino_drvdata->a.v4l_device);
+- vino_drvdata->a.v4l_device = NULL;
++ i2c_del_adapter(&vino_i2c_adapter);
+ case 8:
+- vino_i2c_del_bus();
+- case 7:
+ free_irq(SGI_VINO_IRQ, NULL);
++ case 7:
++ if (vino_drvdata->b.vdev) {
++ video_device_release(vino_drvdata->b.vdev);
++ vino_drvdata->b.vdev = NULL;
++ }
+ case 6:
+- if (vino_drvdata->b.v4l_device) {
+- video_device_release(vino_drvdata->b.v4l_device);
+- vino_drvdata->b.v4l_device = NULL;
++ if (vino_drvdata->a.vdev) {
++ video_device_release(vino_drvdata->a.vdev);
++ vino_drvdata->a.vdev = NULL;
+ }
+ case 5:
+- if (vino_drvdata->a.v4l_device) {
+- video_device_release(vino_drvdata->a.v4l_device);
+- vino_drvdata->a.v4l_device = NULL;
+- }
+- case 4:
+ /* all entries in dma_cpu dummy table have the same address */
+ dma_unmap_single(NULL,
+ vino_drvdata->dummy_desc_table.dma_cpu[0],
+@@ -4412,8 +4107,10 @@ static void vino_module_cleanup(int stage)
+ (void *)vino_drvdata->
+ dummy_desc_table.dma_cpu,
+ vino_drvdata->dummy_desc_table.dma);
+- case 3:
++ case 4:
+ free_page(vino_drvdata->dummy_page);
++ case 3:
++ v4l2_device_unregister(&vino_drvdata->v4l2_dev);
+ case 2:
+ kfree(vino_drvdata);
+ case 1:
+@@ -4468,6 +4165,7 @@ static int vino_probe(void)
+ static int vino_init(void)
+ {
+ dma_addr_t dma_dummy_address;
++ int err;
+ int i;
+
+ vino_drvdata = kzalloc(sizeof(struct vino_settings), GFP_KERNEL);
+@@ -4476,6 +4174,12 @@ static int vino_init(void)
+ return -ENOMEM;
+ }
+ vino_init_stage++;
++ strlcpy(vino_drvdata->v4l2_dev.name, "vino",
++ sizeof(vino_drvdata->v4l2_dev.name));
++ err = v4l2_device_register(NULL, &vino_drvdata->v4l2_dev);
++ if (err)
++ return err;
++ vino_init_stage++;
+
+ /* create a dummy dma descriptor */
+ vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
+@@ -4542,25 +4246,27 @@ static int vino_init_channel_settings(struct vino_channel_settings *vcs,
+ spin_lock_init(&vcs->fb_queue.queue_lock);
+ init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
+
+- vcs->v4l_device = video_device_alloc();
+- if (!vcs->v4l_device) {
++ vcs->vdev = video_device_alloc();
++ if (!vcs->vdev) {
+ vino_module_cleanup(vino_init_stage);
+ return -ENOMEM;
+ }
+ vino_init_stage++;
+
+- memcpy(vcs->v4l_device, &v4l_device_template,
++ memcpy(vcs->vdev, &vdev_template,
+ sizeof(struct video_device));
+- strcpy(vcs->v4l_device->name, name);
+- vcs->v4l_device->release = video_device_release;
++ strcpy(vcs->vdev->name, name);
++ vcs->vdev->release = video_device_release;
++ vcs->vdev->v4l2_dev = &vino_drvdata->v4l2_dev;
+
+- video_set_drvdata(vcs->v4l_device, vcs);
++ video_set_drvdata(vcs->vdev, vcs);
+
+ return 0;
+ }
+
+ static int __init vino_module_init(void)
+ {
++ unsigned short addr[] = { 0, I2C_CLIENT_END };
+ int ret;
+
+ printk(KERN_INFO "SGI VINO driver version %s\n",
+@@ -4580,12 +4286,12 @@ static int __init vino_module_init(void)
+ spin_lock_init(&vino_drvdata->input_lock);
+
+ ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A,
+- vino_v4l_device_name_a);
++ vino_vdev_name_a);
+ if (ret)
+ return ret;
+
+ ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B,
+- vino_v4l_device_name_b);
++ vino_vdev_name_b);
+ if (ret)
+ return ret;
+
+@@ -4601,15 +4307,16 @@ static int __init vino_module_init(void)
+ }
+ vino_init_stage++;
+
+- ret = vino_i2c_add_bus();
++ ret = i2c_add_adapter(&vino_i2c_adapter);
+ if (ret) {
+ printk(KERN_ERR "VINO I2C bus registration failed\n");
+ vino_module_cleanup(vino_init_stage);
+ return ret;
+ }
++ i2c_set_adapdata(&vino_i2c_adapter, &vino_drvdata->v4l2_dev);
+ vino_init_stage++;
+
+- ret = video_register_device(vino_drvdata->a.v4l_device,
++ ret = video_register_device(vino_drvdata->a.vdev,
+ VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ printk(KERN_ERR "VINO channel A Video4Linux-device "
+@@ -4619,7 +4326,7 @@ static int __init vino_module_init(void)
+ }
+ vino_init_stage++;
+
+- ret = video_register_device(vino_drvdata->b.v4l_device,
++ ret = video_register_device(vino_drvdata->b.vdev,
+ VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ printk(KERN_ERR "VINO channel B Video4Linux-device "
+@@ -4629,10 +4336,12 @@ static int __init vino_module_init(void)
+ }
+ vino_init_stage++;
+
+-#ifdef MODULE
+- request_module("saa7191");
+- request_module("indycam");
+-#endif
++ addr[0] = 0x45;
++ vino_drvdata->decoder = v4l2_i2c_new_probed_subdev(&vino_i2c_adapter,
++ "saa7191", "saa7191", addr);
++ addr[0] = 0x2b;
++ vino_drvdata->camera = v4l2_i2c_new_probed_subdev(&vino_i2c_adapter,
++ "indycam", "indycam", addr);
+
+ dprintk("init complete!\n");
+
+diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
+index 81d5aa5..fbfefae 100644
+--- a/drivers/media/video/vivi.c
++++ b/drivers/media/video/vivi.c
+@@ -28,17 +28,14 @@
+ #include <linux/mutex.h>
+ #include <linux/videodev2.h>
+ #include <linux/dma-mapping.h>
+-#ifdef CONFIG_VIDEO_V4L1_COMPAT
+-/* Include V4L1 specific functions. Should be removed soon */
+-#include <linux/videodev.h>
+-#endif
+ #include <linux/interrupt.h>
+-#include <media/videobuf-vmalloc.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-ioctl.h>
+ #include <linux/kthread.h>
+ #include <linux/highmem.h>
+ #include <linux/freezer.h>
++#include <media/videobuf-vmalloc.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
++#include "font.h"
+
+ #define VIVI_MODULE_NAME "vivi"
+
+@@ -47,18 +44,32 @@
+ #define WAKE_DENOMINATOR 1001
+ #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+
+-#include "font.h"
+-
+ #define VIVI_MAJOR_VERSION 0
+-#define VIVI_MINOR_VERSION 5
++#define VIVI_MINOR_VERSION 6
+ #define VIVI_RELEASE 0
+ #define VIVI_VERSION \
+ KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
+
+-/* Declare static vars that will be used as parameters */
+-static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
+-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
+-static int n_devs = 1; /* Number of virtual devices */
++MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
++MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
++MODULE_LICENSE("Dual BSD/GPL");
++
++static unsigned video_nr = -1;
++module_param(video_nr, uint, 0644);
++MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
++
++static unsigned n_devs = 1;
++module_param(n_devs, uint, 0644);
++MODULE_PARM_DESC(n_devs, "number of video devices to create");
++
++static unsigned debug;
++module_param(debug, uint, 0644);
++MODULE_PARM_DESC(debug, "activates debug info");
++
++static unsigned int vid_limit = 16;
++module_param(vid_limit, uint, 0644);
++MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
++
+
+ /* supported controls */
+ static struct v4l2_queryctrl vivi_qctrl[] = {
+@@ -69,7 +80,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 65535,
+- .flags = 0,
++ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }, {
+ .id = V4L2_CID_BRIGHTNESS,
+@@ -79,7 +90,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+- .flags = 0,
++ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+@@ -88,7 +99,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 0x10,
+- .flags = 0,
++ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+@@ -97,7 +108,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 127,
+- .flags = 0,
++ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+@@ -106,17 +117,12 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
+ .maximum = 127,
+ .step = 0x1,
+ .default_value = 0,
+- .flags = 0,
++ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }
+ };
+
+-static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
+-
+-#define dprintk(dev, level, fmt, arg...) \
+- do { \
+- if (dev->vfd->debug >= (level)) \
+- printk(KERN_DEBUG "vivi: " fmt , ## arg); \
+- } while (0)
++#define dprintk(dev, level, fmt, arg...) \
++ v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
+
+ /* ------------------------------------------------------------------
+ Basic structures
+@@ -206,6 +212,7 @@ static LIST_HEAD(vivi_devlist);
+
+ struct vivi_dev {
+ struct list_head vivi_devlist;
++ struct v4l2_device v4l2_dev;
+
+ spinlock_t slock;
+ struct mutex mutex;
+@@ -223,6 +230,12 @@ struct vivi_dev {
+ char timestr[13];
+
+ int mv_count; /* Controls bars movement */
++
++ /* Input Number */
++ int input;
++
++ /* Control 'registers' */
++ int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
+ };
+
+ struct vivi_fh {
+@@ -235,6 +248,7 @@ struct vivi_fh {
+
+ enum v4l2_buf_type type;
+ unsigned char bars[8][3];
++ int input; /* Input Number on bars */
+ };
+
+ /* ------------------------------------------------------------------
+@@ -254,18 +268,72 @@ enum colors {
+ BLACK,
+ };
+
+-static u8 bars[8][3] = {
+ /* R G B */
+- {204, 204, 204}, /* white */
+- {208, 208, 0}, /* ambar */
+- { 0, 206, 206}, /* cyan */
+- { 0, 239, 0}, /* green */
+- {239, 0, 239}, /* magenta */
+- {205, 0, 0}, /* red */
+- { 0, 0, 255}, /* blue */
+- { 0, 0, 0}, /* black */
++#define COLOR_WHITE {204, 204, 204}
++#define COLOR_AMBAR {208, 208, 0}
++#define COLOR_CIAN { 0, 206, 206}
++#define COLOR_GREEN { 0, 239, 0}
++#define COLOR_MAGENTA {239, 0, 239}
++#define COLOR_RED {205, 0, 0}
++#define COLOR_BLUE { 0, 0, 255}
++#define COLOR_BLACK { 0, 0, 0}
++
++struct bar_std {
++ u8 bar[8][3];
+ };
+
++/* Maximum number of bars are 10 - otherwise, the input print code
++ should be modified */
++static struct bar_std bars[] = {
++ { /* Standard ITU-R color bar sequence */
++ {
++ COLOR_WHITE,
++ COLOR_AMBAR,
++ COLOR_CIAN,
++ COLOR_GREEN,
++ COLOR_MAGENTA,
++ COLOR_RED,
++ COLOR_BLUE,
++ COLOR_BLACK,
++ }
++ }, {
++ {
++ COLOR_WHITE,
++ COLOR_AMBAR,
++ COLOR_BLACK,
++ COLOR_WHITE,
++ COLOR_AMBAR,
++ COLOR_BLACK,
++ COLOR_WHITE,
++ COLOR_AMBAR,
++ }
++ }, {
++ {
++ COLOR_WHITE,
++ COLOR_CIAN,
++ COLOR_BLACK,
++ COLOR_WHITE,
++ COLOR_CIAN,
++ COLOR_BLACK,
++ COLOR_WHITE,
++ COLOR_CIAN,
++ }
++ }, {
++ {
++ COLOR_WHITE,
++ COLOR_GREEN,
++ COLOR_BLACK,
++ COLOR_WHITE,
++ COLOR_GREEN,
++ COLOR_BLACK,
++ COLOR_WHITE,
++ COLOR_GREEN,
++ }
++ },
++};
++
++#define NUM_INPUTS ARRAY_SIZE(bars)
++
+ #define TO_Y(r, g, b) \
+ (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
+ /* RGB to V(Cr) Color transform */
+@@ -275,9 +343,10 @@ static u8 bars[8][3] = {
+ #define TO_U(r, g, b) \
+ (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
+
+-#define TSTAMP_MIN_Y 24
+-#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
+-#define TSTAMP_MIN_X 64
++#define TSTAMP_MIN_Y 24
++#define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15)
++#define TSTAMP_INPUT_X 10
++#define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X)
+
+ static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
+ {
+@@ -392,9 +461,29 @@ static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
+ pos += 4; /* only 16 bpp supported for now */
+ }
+
+- /* Checks if it is possible to show timestamp */
++ /* Prints input entry number */
++
++ /* Checks if it is possible to input number */
+ if (TSTAMP_MAX_Y >= hmax)
+ goto end;
++
++ if (TSTAMP_INPUT_X + strlen(timestr) >= wmax)
++ goto end;
++
++ if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
++ chr = rom8x16_bits[fh->input * 16 + line - TSTAMP_MIN_Y];
++ pos = TSTAMP_INPUT_X;
++ for (i = 0; i < 7; i++) {
++ /* Draw white font on black background */
++ if (chr & 1 << (7 - i))
++ gen_twopix(fh, basep + pos, WHITE);
++ else
++ gen_twopix(fh, basep + pos, BLACK);
++ pos += 2;
++ }
++ }
++
++ /* Checks if it is possible to show timestamp */
+ if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
+ goto end;
+
+@@ -577,7 +666,7 @@ static int vivi_start_thread(struct vivi_fh *fh)
+ dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
+
+ if (IS_ERR(dma_q->kthread)) {
+- printk(KERN_ERR "vivi: kernel_thread() failed\n");
++ v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+ return PTR_ERR(dma_q->kthread);
+ }
+ /* Wakes thread */
+@@ -720,8 +809,12 @@ static struct videobuf_queue_ops vivi_video_qops = {
+ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+ {
++ struct vivi_fh *fh = priv;
++ struct vivi_dev *dev = fh->dev;
++
+ strcpy(cap->driver, "vivi");
+ strcpy(cap->card, "vivi");
++ strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+ cap->version = VIVI_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+@@ -807,38 +900,19 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ return 0;
+ }
+
+-/*FIXME: This seems to be generic enough to be at videodev2 */
+-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+- struct v4l2_format *f)
++/* precalculate color bar values to speed up rendering */
++static void precalculate_bars(struct vivi_fh *fh)
+ {
+- struct vivi_fh *fh = priv;
+- struct videobuf_queue *q = &fh->vb_vidq;
++ struct vivi_dev *dev = fh->dev;
+ unsigned char r, g, b;
+ int k, is_yuv;
+
+- int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+- if (ret < 0)
+- return (ret);
+-
+- mutex_lock(&q->vb_lock);
+-
+- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+- dprintk(fh->dev, 1, "%s queue busy\n", __func__);
+- ret = -EBUSY;
+- goto out;
+- }
+-
+- fh->fmt = get_format(f);
+- fh->width = f->fmt.pix.width;
+- fh->height = f->fmt.pix.height;
+- fh->vb_vidq.field = f->fmt.pix.field;
+- fh->type = f->type;
++ fh->input = dev->input;
+
+- /* precalculate color bar values to speed up rendering */
+ for (k = 0; k < 8; k++) {
+- r = bars[k][0];
+- g = bars[k][1];
+- b = bars[k][2];
++ r = bars[fh->input].bar[k][0];
++ g = bars[fh->input].bar[k][1];
++ b = bars[fh->input].bar[k][2];
+ is_yuv = 0;
+
+ switch (fh->fmt->fourcc) {
+@@ -871,11 +945,40 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ }
+ }
+
++}
++
++/*FIXME: This seems to be generic enough to be at videodev2 */
++static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct vivi_fh *fh = priv;
++ struct videobuf_queue *q = &fh->vb_vidq;
++
++ int ret = vidioc_try_fmt_vid_cap(file, fh, f);
++ if (ret < 0)
++ return ret;
++
++ mutex_lock(&q->vb_lock);
++
++ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
++ dprintk(fh->dev, 1, "%s queue busy\n", __func__);
++ ret = -EBUSY;
++ goto out;
++ }
++
++ fh->fmt = get_format(f);
++ fh->width = f->fmt.pix.width;
++ fh->height = f->fmt.pix.height;
++ fh->vb_vidq.field = f->fmt.pix.field;
++ fh->type = f->type;
++
++ precalculate_bars(fh);
++
+ ret = 0;
+ out:
+ mutex_unlock(&q->vb_lock);
+
+- return (ret);
++ return ret;
+ }
+
+ static int vidioc_reqbufs(struct file *file, void *priv,
+@@ -950,27 +1053,36 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+ static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+ {
+- if (inp->index != 0)
++ if (inp->index >= NUM_INPUTS)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = V4L2_STD_525_60;
+- strcpy(inp->name, "Camera");
++ sprintf(inp->name, "Camera %u", inp->index);
+
+ return (0);
+ }
+
+ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+ {
+- *i = 0;
++ struct vivi_fh *fh = priv;
++ struct vivi_dev *dev = fh->dev;
++
++ *i = dev->input;
+
+ return (0);
+ }
+ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+ {
+- if (i > 0)
++ struct vivi_fh *fh = priv;
++ struct vivi_dev *dev = fh->dev;
++
++ if (i >= NUM_INPUTS)
+ return -EINVAL;
+
++ dev->input = i;
++ precalculate_bars(fh);
++
+ return (0);
+ }
+
+@@ -993,12 +1105,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
+ static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
++ struct vivi_fh *fh = priv;
++ struct vivi_dev *dev = fh->dev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (ctrl->id == vivi_qctrl[i].id) {
+- ctrl->value = qctl_regs[i];
+- return (0);
++ ctrl->value = dev->qctl_regs[i];
++ return 0;
+ }
+
+ return -EINVAL;
+@@ -1006,16 +1120,18 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
+ static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+ {
++ struct vivi_fh *fh = priv;
++ struct vivi_dev *dev = fh->dev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (ctrl->id == vivi_qctrl[i].id) {
+- if (ctrl->value < vivi_qctrl[i].minimum
+- || ctrl->value > vivi_qctrl[i].maximum) {
+- return (-ERANGE);
+- }
+- qctl_regs[i] = ctrl->value;
+- return (0);
++ if (ctrl->value < vivi_qctrl[i].minimum ||
++ ctrl->value > vivi_qctrl[i].maximum) {
++ return -ERANGE;
++ }
++ dev->qctl_regs[i] = ctrl->value;
++ return 0;
+ }
+ return -EINVAL;
+ }
+@@ -1026,32 +1142,20 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
+
+ static int vivi_open(struct file *file)
+ {
+- int minor = video_devdata(file)->minor;
+- struct vivi_dev *dev;
++ struct vivi_dev *dev = video_drvdata(file);
+ struct vivi_fh *fh = NULL;
+- int i;
+ int retval = 0;
+
+- printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
+-
+- lock_kernel();
+- list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
+- if (dev->vfd->minor == minor)
+- goto found;
+- unlock_kernel();
+- return -ENODEV;
+-
+-found:
+ mutex_lock(&dev->mutex);
+ dev->users++;
+
+ if (dev->users > 1) {
+ dev->users--;
+- retval = -EBUSY;
+- goto unlock;
++ mutex_unlock(&dev->mutex);
++ return -EBUSY;
+ }
+
+- dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
++ dprintk(dev, 1, "open /dev/video%d type=%s users=%d\n", dev->vfd->num,
+ v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+
+ /* allocate + initialize per filehandle data */
+@@ -1059,14 +1163,11 @@ found:
+ if (NULL == fh) {
+ dev->users--;
+ retval = -ENOMEM;
+- goto unlock;
+ }
+-unlock:
+ mutex_unlock(&dev->mutex);
+- if (retval) {
+- unlock_kernel();
++
++ if (retval)
+ return retval;
+- }
+
+ file->private_data = fh;
+ fh->dev = dev;
+@@ -1076,10 +1177,6 @@ unlock:
+ fh->width = 640;
+ fh->height = 480;
+
+- /* Put all controls at a sane state */
+- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+- qctl_regs[i] = vivi_qctrl[i].default_value;
+-
+ /* Resets frame counters */
+ dev->h = 0;
+ dev->m = 0;
+@@ -1095,7 +1192,6 @@ unlock:
+ sizeof(struct vivi_buffer), fh);
+
+ vivi_start_thread(fh);
+- unlock_kernel();
+
+ return 0;
+ }
+@@ -1151,32 +1247,6 @@ static int vivi_close(struct file *file)
+ return 0;
+ }
+
+-static int vivi_release(void)
+-{
+- struct vivi_dev *dev;
+- struct list_head *list;
+-
+- while (!list_empty(&vivi_devlist)) {
+- list = vivi_devlist.next;
+- list_del(list);
+- dev = list_entry(list, struct vivi_dev, vivi_devlist);
+-
+- if (-1 != dev->vfd->minor) {
+- printk(KERN_INFO "%s: unregistering /dev/video%d\n",
+- VIVI_MODULE_NAME, dev->vfd->num);
+- video_unregister_device(dev->vfd);
+- } else {
+- printk(KERN_INFO "%s: releasing /dev/video%d\n",
+- VIVI_MODULE_NAME, dev->vfd->num);
+- video_device_release(dev->vfd);
+- }
+-
+- kfree(dev);
+- }
+-
+- return 0;
+-}
+-
+ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+ struct vivi_fh *fh = file->private_data;
+@@ -1239,87 +1309,130 @@ static struct video_device vivi_template = {
+ .tvnorms = V4L2_STD_525_60,
+ .current_norm = V4L2_STD_NTSC_M,
+ };
++
+ /* -----------------------------------------------------------------
+ Initialization and module stuff
+ ------------------------------------------------------------------*/
+
+-/* This routine allocates from 1 to n_devs virtual drivers.
++static int vivi_release(void)
++{
++ struct vivi_dev *dev;
++ struct list_head *list;
+
+- The real maximum number of virtual drivers will depend on how many drivers
+- will succeed. This is limited to the maximum number of devices that
+- videodev supports. Since there are 64 minors for video grabbers, this is
+- currently the theoretical maximum limit. However, a further limit does
+- exist at videodev that forbids any driver to register more than 32 video
+- grabbers.
+- */
+-static int __init vivi_init(void)
++ while (!list_empty(&vivi_devlist)) {
++ list = vivi_devlist.next;
++ list_del(list);
++ dev = list_entry(list, struct vivi_dev, vivi_devlist);
++
++ v4l2_info(&dev->v4l2_dev, "unregistering /dev/video%d\n",
++ dev->vfd->num);
++ video_unregister_device(dev->vfd);
++ v4l2_device_unregister(&dev->v4l2_dev);
++ kfree(dev);
++ }
++
++ return 0;
++}
++
++static int __init vivi_create_instance(int inst)
+ {
+- int ret = -ENOMEM, i;
+ struct vivi_dev *dev;
+ struct video_device *vfd;
++ int ret, i;
+
+- if (n_devs <= 0)
+- n_devs = 1;
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
+
+- for (i = 0; i < n_devs; i++) {
+- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+- if (!dev)
+- break;
++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
++ "%s-%03d", VIVI_MODULE_NAME, inst);
++ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
++ if (ret)
++ goto free_dev;
+
+- /* init video dma queues */
+- INIT_LIST_HEAD(&dev->vidq.active);
+- init_waitqueue_head(&dev->vidq.wq);
++ /* init video dma queues */
++ INIT_LIST_HEAD(&dev->vidq.active);
++ init_waitqueue_head(&dev->vidq.wq);
+
+- /* initialize locks */
+- spin_lock_init(&dev->slock);
+- mutex_init(&dev->mutex);
++ /* initialize locks */
++ spin_lock_init(&dev->slock);
++ mutex_init(&dev->mutex);
+
+- vfd = video_device_alloc();
+- if (!vfd) {
+- kfree(dev);
+- break;
+- }
++ ret = -ENOMEM;
++ vfd = video_device_alloc();
++ if (!vfd)
++ goto unreg_dev;
+
+- *vfd = vivi_template;
++ *vfd = vivi_template;
+
+- ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+- if (ret < 0) {
+- video_device_release(vfd);
+- kfree(dev);
++ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
++ if (ret < 0)
++ goto rel_vdev;
+
+- /* If some registers succeeded, keep driver */
+- if (i)
+- ret = 0;
++ video_set_drvdata(vfd, dev);
+
+- break;
+- }
++ /* Set all controls to their default value. */
++ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
++ dev->qctl_regs[i] = vivi_qctrl[i].default_value;
++
++ /* Now that everything is fine, let's add it to device list */
++ list_add_tail(&dev->vivi_devlist, &vivi_devlist);
++
++ snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
++ vivi_template.name, vfd->num);
++
++ if (video_nr >= 0)
++ video_nr++;
+
+- /* Now that everything is fine, let's add it to device list */
+- list_add_tail(&dev->vivi_devlist, &vivi_devlist);
++ dev->vfd = vfd;
++ v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n",
++ vfd->num);
++ return 0;
++
++rel_vdev:
++ video_device_release(vfd);
++unreg_dev:
++ v4l2_device_unregister(&dev->v4l2_dev);
++free_dev:
++ kfree(dev);
++ return ret;
++}
++
++/* This routine allocates from 1 to n_devs virtual drivers.
+
+- snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
+- vivi_template.name, vfd->minor);
++ The real maximum number of virtual drivers will depend on how many drivers
++ will succeed. This is limited to the maximum number of devices that
++ videodev supports, which is equal to VIDEO_NUM_DEVICES.
++ */
++static int __init vivi_init(void)
++{
++ int ret = 0, i;
+
+- if (video_nr >= 0)
+- video_nr++;
++ if (n_devs <= 0)
++ n_devs = 1;
+
+- dev->vfd = vfd;
+- printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
+- VIVI_MODULE_NAME, vfd->num);
++ for (i = 0; i < n_devs; i++) {
++ ret = vivi_create_instance(i);
++ if (ret) {
++ /* If some instantiations succeeded, keep driver */
++ if (i)
++ ret = 0;
++ break;
++ }
+ }
+
+ if (ret < 0) {
+- vivi_release();
+ printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
+- } else {
+- printk(KERN_INFO "Video Technology Magazine Virtual Video "
++ return ret;
++ }
++
++ printk(KERN_INFO "Video Technology Magazine Virtual Video "
+ "Capture Board ver %u.%u.%u successfully loaded.\n",
+ (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
+ VIVI_VERSION & 0xFF);
+
+- /* n_devs will reflect the actual number of allocated devices */
+- n_devs = i;
+- }
++ /* n_devs will reflect the actual number of allocated devices */
++ n_devs = i;
+
+ return ret;
+ }
+@@ -1331,19 +1444,3 @@ static void __exit vivi_exit(void)
+
+ module_init(vivi_init);
+ module_exit(vivi_exit);
+-
+-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+-MODULE_LICENSE("Dual BSD/GPL");
+-
+-module_param(video_nr, uint, 0444);
+-MODULE_PARM_DESC(video_nr, "video iminor start number");
+-
+-module_param(n_devs, uint, 0444);
+-MODULE_PARM_DESC(n_devs, "number of video devices to create");
+-
+-module_param_named(debug, vivi_template.debug, int, 0444);
+-MODULE_PARM_DESC(debug, "activates debug info");
+-
+-module_param(vid_limit, int, 0644);
+-MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
+index 5d73f66..42e23a4 100644
+--- a/drivers/media/video/vp27smpx.c
++++ b/drivers/media/video/vp27smpx.c
+@@ -129,11 +129,6 @@ static int vp27smpx_log_status(struct v4l2_subdev *sd)
+ return 0;
+ }
+
+-static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops vp27smpx_core_ops = {
+@@ -206,8 +201,6 @@ MODULE_DEVICE_TABLE(i2c, vp27smpx_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "vp27smpx",
+- .driverid = I2C_DRIVERID_VP27SMPX,
+- .command = vp27smpx_command,
+ .probe = vp27smpx_probe,
+ .remove = vp27smpx_remove,
+ .id_table = vp27smpx_id,
+diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
+index 67aa0db..2fa7e8b 100644
+--- a/drivers/media/video/vpx3220.c
++++ b/drivers/media/video/vpx3220.c
+@@ -24,10 +24,10 @@
+ #include <linux/types.h>
+ #include <asm/uaccess.h>
+ #include <linux/i2c.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
+-#include <linux/videodev.h>
+-#include <linux/video_decoder.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
+ MODULE_AUTHOR("Laurent Pinchart");
+@@ -37,14 +37,17 @@ static int debug;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
++
+ #define VPX_TIMEOUT_COUNT 10
+
+ /* ----------------------------------------------------------------------- */
+
+ struct vpx3220 {
++ struct v4l2_subdev sd;
+ unsigned char reg[255];
+
+- int norm;
++ v4l2_std_id norm;
++ int ident;
+ int input;
+ int enable;
+ int bright;
+@@ -53,30 +56,38 @@ struct vpx3220 {
+ int sat;
+ };
+
++static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct vpx3220, sd);
++}
++
+ static char *inputs[] = { "internal", "composite", "svideo" };
+
+ /* ----------------------------------------------------------------------- */
+
+-static inline int vpx3220_write(struct i2c_client *client, u8 reg, u8 value)
++static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ 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)
++static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
+ return i2c_smbus_read_byte_data(client, reg);
+ }
+
+-static int vpx3220_fp_status(struct i2c_client *client)
++static int vpx3220_fp_status(struct v4l2_subdev *sd)
+ {
+ unsigned char status;
+ unsigned int i;
+
+ for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
+- status = vpx3220_read(client, 0x29);
++ status = vpx3220_read(sd, 0x29);
+
+ if (!(status & 4))
+ return 0;
+@@ -90,57 +101,60 @@ static int vpx3220_fp_status(struct i2c_client *client)
+ return -1;
+ }
+
+-static int vpx3220_fp_write(struct i2c_client *client, u8 fpaddr, u16 data)
++static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
+ /* Write the 16-bit address to the FPWR register */
+ if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
+- v4l_dbg(1, debug, client, "%s: failed\n", __func__);
++ v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
+ return -1;
+ }
+
+- if (vpx3220_fp_status(client) < 0)
++ if (vpx3220_fp_status(sd) < 0)
+ return -1;
+
+ /* Write the 16-bit data to the FPDAT register */
+ if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
+- v4l_dbg(1, debug, client, "%s: failed\n", __func__);
++ v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+ }
+
+-static u16 vpx3220_fp_read(struct i2c_client *client, u16 fpaddr)
++static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ s16 data;
+
+ /* Write the 16-bit address to the FPRD register */
+ if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
+- v4l_dbg(1, debug, client, "%s: failed\n", __func__);
++ v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
+ return -1;
+ }
+
+- if (vpx3220_fp_status(client) < 0)
++ if (vpx3220_fp_status(sd) < 0)
+ return -1;
+
+ /* Read the 16-bit data from the FPDAT register */
+ data = i2c_smbus_read_word_data(client, 0x28);
+ if (data == -1) {
+- v4l_dbg(1, debug, client, "%s: failed\n", __func__);
++ v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
+ return -1;
+ }
+
+ return swab16(data);
+ }
+
+-static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
++static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
+ {
+ u8 reg;
+ int ret = -1;
+
+ while (len >= 2) {
+ reg = *data++;
+- ret = vpx3220_write(client, reg, *data++);
++ ret = vpx3220_write(sd, reg, *data++);
+ if (ret < 0)
+ break;
+ len -= 2;
+@@ -149,7 +163,7 @@ static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsign
+ return ret;
+ }
+
+-static int vpx3220_write_fp_block(struct i2c_client *client,
++static int vpx3220_write_fp_block(struct v4l2_subdev *sd,
+ const u16 *data, unsigned int len)
+ {
+ u8 reg;
+@@ -157,7 +171,7 @@ static int vpx3220_write_fp_block(struct i2c_client *client,
+
+ while (len > 1) {
+ reg = *data++;
+- ret |= vpx3220_fp_write(client, reg, *data++);
++ ret |= vpx3220_fp_write(sd, reg, *data++);
+ len -= 2;
+ }
+
+@@ -259,276 +273,277 @@ static const unsigned short init_fp[] = {
+ 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) {
+- v4l_dbg(1, debug, client, "i2c reg 0x%02x data 0x%02x\n",
+- *data, vpx3220_read(client, *data));
+- data += 2;
+- len -= 2;
+- }
++static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
++{
++ struct vpx3220 *decoder = to_vpx3220(sd);
++
++ vpx3220_write_block(sd, init_common, sizeof(init_common));
++ vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
++ if (decoder->norm & V4L2_STD_NTSC)
++ vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
++ else if (decoder->norm & V4L2_STD_PAL)
++ vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
++ else if (decoder->norm & V4L2_STD_SECAM)
++ vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
++ else
++ vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
++ return 0;
+ }
+
+-static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg)
++static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
+ {
+- struct vpx3220 *decoder = i2c_get_clientdata(client);
++ int res = V4L2_IN_ST_NO_SIGNAL, status;
++ v4l2_std_id std = 0;
+
+- 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;
++ status = vpx3220_fp_read(sd, 0x0f3);
++
++ v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status);
++
++ if (status < 0)
++ return status;
+
+- case VIDEO_MODE_PAL:
+- vpx3220_write_fp_block(client, init_pal,
+- sizeof(init_pal) >> 1);
++ if ((status & 0x20) == 0) {
++ res = 0;
++
++ switch (status & 0x18) {
++ case 0x00:
++ case 0x10:
++ case 0x14:
++ case 0x18:
++ std = V4L2_STD_PAL;
+ break;
+- case VIDEO_MODE_SECAM:
+- vpx3220_write_fp_block(client, init_secam,
+- sizeof(init_secam) >> 1);
++
++ case 0x08:
++ std = V4L2_STD_SECAM;
+ break;
+- default:
+- vpx3220_write_fp_block(client, init_pal,
+- sizeof(init_pal) >> 1);
++
++ case 0x04:
++ case 0x0c:
++ case 0x1c:
++ std = V4L2_STD_NTSC;
+ break;
+ }
+- break;
+- }
+-
+- case DECODER_DUMP:
+- {
+- vpx3220_dump_i2c(client);
+- break;
+ }
++ if (pstd)
++ *pstd = std;
++ if (pstatus)
++ *pstatus = status;
++ return 0;
++}
+
+- case DECODER_GET_CAPABILITIES:
+- {
+- struct video_decoder_capability *cap = arg;
++static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
++{
++ v4l2_dbg(1, debug, sd, "querystd\n");
++ return vpx3220_status(sd, NULL, std);
++}
+
+- v4l_dbg(1, debug, client, "DECODER_GET_CAPABILITIES\n");
++static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status)
++{
++ v4l2_dbg(1, debug, sd, "g_input_status\n");
++ return vpx3220_status(sd, status, NULL);
++}
+
+- cap->flags = VIDEO_DECODER_PAL |
+- VIDEO_DECODER_NTSC |
+- VIDEO_DECODER_SECAM |
+- VIDEO_DECODER_AUTO |
+- VIDEO_DECODER_CCIR;
+- cap->inputs = 3;
+- cap->outputs = 1;
+- break;
++static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
++{
++ struct vpx3220 *decoder = to_vpx3220(sd);
++ int temp_input;
++
++ /* Here we back up the input selection because it gets
++ overwritten when we fill the registers with the
++ choosen video norm */
++ temp_input = vpx3220_fp_read(sd, 0xf2);
++
++ v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std);
++ if (std & V4L2_STD_NTSC) {
++ vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
++ v4l2_dbg(1, debug, sd, "norm switched to NTSC\n");
++ } else if (std & V4L2_STD_PAL) {
++ vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
++ v4l2_dbg(1, debug, sd, "norm switched to PAL\n");
++ } else if (std & V4L2_STD_SECAM) {
++ vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
++ v4l2_dbg(1, debug, sd, "norm switched to SECAM\n");
++ } else {
++ return -EINVAL;
+ }
+
+- case DECODER_GET_STATUS:
+- {
+- int res = 0, status;
++ decoder->norm = std;
+
+- v4l_dbg(1, debug, client, "DECODER_GET_STATUS\n");
+-
+- status = vpx3220_fp_read(client, 0x0f3);
+-
+- v4l_dbg(1, debug, client, "status: 0x%04x\n", status);
+-
+- if (status < 0)
+- return status;
++ /* And here we set the backed up video input again */
++ vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010);
++ udelay(10);
++ return 0;
++}
+
+- if ((status & 0x20) == 0) {
+- res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR;
++static int vpx3220_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
++{
++ int data;
+
+- switch (status & 0x18) {
+- case 0x00:
+- case 0x10:
+- case 0x14:
+- case 0x18:
+- res |= DECODER_STATUS_PAL;
+- break;
++ /* RJ: route->input = 0: ST8 (PCTV) input
++ route->input = 1: COMPOSITE input
++ route->input = 2: SVHS input */
+
+- case 0x08:
+- res |= DECODER_STATUS_SECAM;
+- break;
++ const int input[3][2] = {
++ {0x0c, 0},
++ {0x0d, 0},
++ {0x0e, 1}
++ };
+
+- case 0x04:
+- case 0x0c:
+- case 0x1c:
+- res |= DECODER_STATUS_NTSC;
+- break;
+- }
+- }
++ if (route->input < 0 || route->input > 2)
++ return -EINVAL;
+
+- *(int *) arg = res;
+- break;
+- }
++ v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[route->input]);
+
+- case DECODER_SET_NORM:
+- {
+- int *iarg = arg, data;
+- int temp_input;
+-
+- /* Here we back up the input selection because it gets
+- overwritten when we fill the registers with the
+- choosen video norm */
+- temp_input = vpx3220_fp_read(client, 0xf2);
+-
+- v4l_dbg(1, debug, client, "DECODER_SET_NORM %d\n", *iarg);
+- switch (*iarg) {
+- case VIDEO_MODE_NTSC:
+- vpx3220_write_fp_block(client, init_ntsc,
+- sizeof(init_ntsc) >> 1);
+- v4l_dbg(1, debug, client, "norm switched to NTSC\n");
+- break;
++ vpx3220_write(sd, 0x33, input[route->input][0]);
+
+- case VIDEO_MODE_PAL:
+- vpx3220_write_fp_block(client, init_pal,
+- sizeof(init_pal) >> 1);
+- v4l_dbg(1, debug, client, "norm switched to PAL\n");
+- break;
++ data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020);
++ if (data < 0)
++ return data;
++ /* 0x0010 is required to latch the setting */
++ vpx3220_fp_write(sd, 0xf2,
++ data | (input[route->input][1] << 5) | 0x0010);
+
+- case VIDEO_MODE_SECAM:
+- vpx3220_write_fp_block(client, init_secam,
+- sizeof(init_secam) >> 1);
+- v4l_dbg(1, debug, client, "norm switched to SECAM\n");
+- break;
++ udelay(10);
++ return 0;
++}
+
+- case VIDEO_MODE_AUTO:
+- /* FIXME This is only preliminary support */
+- data = vpx3220_fp_read(client, 0xf2) & 0x20;
+- vpx3220_fp_write(client, 0xf2, 0x00c0 | data);
+- v4l_dbg(1, debug, client, "norm switched to AUTO\n");
+- break;
++static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ v4l2_dbg(1, debug, sd, "s_stream %s\n", enable ? "on" : "off");
+
+- default:
+- return -EINVAL;
+- }
+- decoder->norm = *iarg;
++ vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00));
++ return 0;
++}
+
+- /* And here we set the backed up video input again */
+- vpx3220_fp_write(client, 0xf2, temp_input | 0x0010);
+- udelay(10);
++static int vpx3220_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
++{
++ switch (qc->id) {
++ case V4L2_CID_BRIGHTNESS:
++ v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+ 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;
+-
+- v4l_dbg(1, debug, client, "input switched to %s\n", 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);
++ case V4L2_CID_CONTRAST:
++ v4l2_ctrl_query_fill(qc, 0, 63, 1, 32);
+ break;
+- }
+
+- case DECODER_SET_OUTPUT:
+- {
+- int *iarg = arg;
++ case V4L2_CID_SATURATION:
++ v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048);
++ break;
+
+- /* not much choice of outputs */
+- if (*iarg != 0) {
+- return -EINVAL;
+- }
++ case V4L2_CID_HUE:
++ v4l2_ctrl_query_fill(qc, -512, 511, 1, 0);
+ break;
+- }
+
+- case DECODER_ENABLE_OUTPUT:
+- {
+- int *iarg = arg;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
+
+- v4l_dbg(1, debug, client, "DECODER_ENABLE_OUTPUT %d\n", *iarg);
++static int vpx3220_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct vpx3220 *decoder = to_vpx3220(sd);
+
+- vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00));
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ ctrl->value = decoder->bright;
++ break;
++ case V4L2_CID_CONTRAST:
++ ctrl->value = decoder->contrast;
+ break;
++ case V4L2_CID_SATURATION:
++ ctrl->value = decoder->sat;
++ break;
++ case V4L2_CID_HUE:
++ ctrl->value = decoder->hue;
++ break;
++ default:
++ return -EINVAL;
+ }
++ return 0;
++}
+
+- case DECODER_SET_PICTURE:
+- {
+- struct video_picture *pic = arg;
++static int vpx3220_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
++{
++ struct vpx3220 *decoder = to_vpx3220(sd);
+
+- 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);
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ if (decoder->bright != ctrl->value) {
++ decoder->bright = ctrl->value;
++ vpx3220_write(sd, 0xe6, decoder->bright);
+ }
+- if (decoder->contrast != pic->contrast) {
+- /* We want 0 to 64 we get 0-65535 */
++ break;
++ case V4L2_CID_CONTRAST:
++ if (decoder->contrast != ctrl->value) {
+ /* Bit 7 and 8 is for noise shaping */
+- decoder->contrast = pic->contrast;
+- vpx3220_write(client, 0xe7,
+- (decoder->contrast >> 10) + 192);
++ decoder->contrast = ctrl->value;
++ vpx3220_write(sd, 0xe7, decoder->contrast + 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);
++ break;
++ case V4L2_CID_SATURATION:
++ if (decoder->sat != ctrl->value) {
++ decoder->sat = ctrl->value;
++ vpx3220_fp_write(sd, 0xa0, decoder->sat);
+ }
+- 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;
++ case V4L2_CID_HUE:
++ if (decoder->hue != ctrl->value) {
++ decoder->hue = ctrl->value;
++ vpx3220_fp_write(sd, 0x1c, decoder->hue);
+ }
+ break;
+- }
+-
+ default:
+ return -EINVAL;
+ }
+-
+ return 0;
+ }
+
+-static int vpx3220_init_client(struct i2c_client *client)
++static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+ {
+- 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);
++ struct vpx3220 *decoder = to_vpx3220(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+- return 0;
++ return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
+ }
+
++/* ----------------------------------------------------------------------- */
++
++static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
++ .g_chip_ident = vpx3220_g_chip_ident,
++ .init = vpx3220_init,
++ .g_ctrl = vpx3220_g_ctrl,
++ .s_ctrl = vpx3220_s_ctrl,
++ .queryctrl = vpx3220_queryctrl,
++};
++
++static const struct v4l2_subdev_tuner_ops vpx3220_tuner_ops = {
++ .s_std = vpx3220_s_std,
++};
++
++static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
++ .s_routing = vpx3220_s_routing,
++ .s_stream = vpx3220_s_stream,
++ .querystd = vpx3220_querystd,
++ .g_input_status = vpx3220_g_input_status,
++};
++
++static const struct v4l2_subdev_ops vpx3220_ops = {
++ .core = &vpx3220_core_ops,
++ .tuner = &vpx3220_tuner_ops,
++ .video = &vpx3220_video_ops,
++};
++
+ /* -----------------------------------------------------------------------
+ * Client management code
+ */
+
+-static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END };
+-
+-I2C_CLIENT_INSMOD;
+-
+ static int vpx3220_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ struct vpx3220 *decoder;
++ struct v4l2_subdev *sd;
+ const char *name = NULL;
+ u8 ver;
+ u16 pn;
+@@ -541,18 +556,20 @@ static int vpx3220_probe(struct i2c_client *client,
+ decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
+ if (decoder == NULL)
+ return -ENOMEM;
+- decoder->norm = VIDEO_MODE_PAL;
++ sd = &decoder->sd;
++ v4l2_i2c_subdev_init(sd, client, &vpx3220_ops);
++ decoder->norm = V4L2_STD_PAL;
+ decoder->input = 0;
+ decoder->enable = 1;
+ decoder->bright = 32768;
+ decoder->contrast = 32768;
+ decoder->hue = 32768;
+ decoder->sat = 32768;
+- i2c_set_clientdata(client, decoder);
+
+ ver = i2c_smbus_read_byte_data(client, 0x00);
+ pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
+ i2c_smbus_read_byte_data(client, 0x01);
++ decoder->ident = V4L2_IDENT_VPX3220A;
+ if (ver == 0xec) {
+ switch (pn) {
+ case 0x4680:
+@@ -560,26 +577,34 @@ static int vpx3220_probe(struct i2c_client *client,
+ break;
+ case 0x4260:
+ name = "vpx3216b";
++ decoder->ident = V4L2_IDENT_VPX3216B;
+ break;
+ case 0x4280:
+ name = "vpx3214c";
++ decoder->ident = V4L2_IDENT_VPX3214C;
+ break;
+ }
+ }
+ if (name)
+- v4l_info(client, "%s found @ 0x%x (%s)\n", name,
++ v4l2_info(sd, "%s found @ 0x%x (%s)\n", name,
+ client->addr << 1, client->adapter->name);
+ else
+- v4l_info(client, "chip (%02x:%04x) found @ 0x%x (%s)\n",
++ v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n",
+ ver, pn, client->addr << 1, client->adapter->name);
+
+- vpx3220_init_client(client);
++ vpx3220_write_block(sd, init_common, sizeof(init_common));
++ vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
++ /* Default to PAL */
++ vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
+ return 0;
+ }
+
+ static int vpx3220_remove(struct i2c_client *client)
+ {
+- kfree(i2c_get_clientdata(client));
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++
++ v4l2_device_unregister_subdev(sd);
++ kfree(to_vpx3220(sd));
+ return 0;
+ }
+
+@@ -593,8 +618,6 @@ MODULE_DEVICE_TABLE(i2c, vpx3220_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "vpx3220",
+- .driverid = I2C_DRIVERID_VPX3220,
+- .command = vpx3220_command,
+ .probe = vpx3220_probe,
+ .remove = vpx3220_remove,
+ .id_table = vpx3220_id,
+diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
+index 038ff32..dcade61 100644
+--- a/drivers/media/video/w9966.c
++++ b/drivers/media/video/w9966.c
+@@ -57,7 +57,7 @@
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+-#include <linux/videodev2.h>
++#include <linux/videodev.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-ioctl.h>
+ #include <linux/parport.h>
+diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
+index 105a832..3b08bc4 100644
+--- a/drivers/media/video/w9968cf.c
++++ b/drivers/media/video/w9968cf.c
+@@ -42,6 +42,7 @@
+ #include <asm/page.h>
+ #include <asm/uaccess.h>
+ #include <linux/page-flags.h>
++#include <linux/videodev.h>
+ #include <media/v4l2-ioctl.h>
+
+ #include "w9968cf.h"
+@@ -68,7 +69,6 @@ MODULE_VERSION(W9968CF_MODULE_VERSION);
+ MODULE_LICENSE(W9968CF_MODULE_LICENSE);
+ MODULE_SUPPORTED_DEVICE("Video");
+
+-static int ovmod_load = W9968CF_OVMOD_LOAD;
+ static unsigned short simcams = W9968CF_SIMCAMS;
+ static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
+ static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+@@ -111,9 +111,6 @@ static int specific_debug = W9968CF_SPECIFIC_DEBUG;
+
+ static unsigned int param_nv[24]; /* number of values per parameter */
+
+-#ifdef CONFIG_MODULES
+-module_param(ovmod_load, bool, 0644);
+-#endif
+ module_param(simcams, ushort, 0644);
+ module_param_array(video_nr, short, &param_nv[0], 0444);
+ module_param_array(packet_size, uint, &param_nv[1], 0444);
+@@ -144,18 +141,6 @@ module_param(debug, ushort, 0644);
+ module_param(specific_debug, bool, 0644);
+ #endif
+
+-#ifdef CONFIG_MODULES
+-MODULE_PARM_DESC(ovmod_load,
+- "\n<0|1> Automatic 'ovcamchip' module loading."
+- "\n0 disabled, 1 enabled."
+- "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
+- "\nmodule in the system, according to its configuration, and"
+- "\nattempts to load that module automatically. This action is"
+- "\nperformed once as soon as the 'w9968cf' module is loaded"
+- "\ninto memory."
+- "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
+- "\n");
+-#endif
+ MODULE_PARM_DESC(simcams,
+ "\n<n> Number of cameras allowed to stream simultaneously."
+ "\nn may vary from 0 to "
+@@ -443,8 +428,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data*);
+ static u32 w9968cf_i2c_func(struct i2c_adapter*);
+-static int w9968cf_i2c_attach_inform(struct i2c_client*);
+-static int w9968cf_i2c_detach_inform(struct i2c_client*);
+
+ /* Memory management */
+ static void* rvmalloc(unsigned long size);
+@@ -1443,19 +1426,11 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+ {
+- struct w9968cf_device* cam = i2c_get_adapdata(adapter);
++ struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
++ struct w9968cf_device *cam = to_cam(v4l2_dev);
+ u8 i;
+ int err = 0;
+
+- switch (addr) {
+- case OV6xx0_SID:
+- case OV7xx0_SID:
+- break;
+- default:
+- DBG(4, "Rejected slave ID 0x%04X", addr)
+- return -EINVAL;
+- }
+-
+ if (size == I2C_SMBUS_BYTE) {
+ /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
+ addr <<= 1;
+@@ -1463,8 +1438,17 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ if (read_write == I2C_SMBUS_WRITE)
+ err = w9968cf_i2c_adap_write_byte(cam, addr, command);
+ else if (read_write == I2C_SMBUS_READ)
+- err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
+-
++ for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
++ err = w9968cf_i2c_adap_read_byte(cam, addr,
++ &data->byte);
++ if (err) {
++ if (w9968cf_smbus_refresh_bus(cam)) {
++ err = -EIO;
++ break;
++ }
++ } else
++ break;
++ }
+ } else if (size == I2C_SMBUS_BYTE_DATA) {
+ addr <<= 1;
+
+@@ -1491,7 +1475,6 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ DBG(4, "Unsupported I2C transfer mode (%d)", size)
+ return -EINVAL;
+ }
+-
+ return err;
+ }
+
+@@ -1504,44 +1487,6 @@ static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
+ }
+
+
+-static int w9968cf_i2c_attach_inform(struct i2c_client* client)
+-{
+- struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
+- int id = client->driver->id, err = 0;
+-
+- if (id == I2C_DRIVERID_OVCAMCHIP) {
+- cam->sensor_client = client;
+- err = w9968cf_sensor_init(cam);
+- if (err) {
+- cam->sensor_client = NULL;
+- return err;
+- }
+- } else {
+- DBG(4, "Rejected client [%s] with driver [%s]",
+- client->name, client->driver->driver.name)
+- return -EINVAL;
+- }
+-
+- DBG(5, "I2C attach client [%s] with driver [%s]",
+- client->name, client->driver->driver.name)
+-
+- return 0;
+-}
+-
+-
+-static int w9968cf_i2c_detach_inform(struct i2c_client* client)
+-{
+- struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
+-
+- if (cam->sensor_client == client)
+- cam->sensor_client = NULL;
+-
+- DBG(5, "I2C detach client [%s]", client->name)
+-
+- return 0;
+-}
+-
+-
+ static int w9968cf_i2c_init(struct w9968cf_device* cam)
+ {
+ int err = 0;
+@@ -1554,15 +1499,13 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
+ static struct i2c_adapter adap = {
+ .id = I2C_HW_SMBUS_W9968CF,
+ .owner = THIS_MODULE,
+- .client_register = w9968cf_i2c_attach_inform,
+- .client_unregister = w9968cf_i2c_detach_inform,
+ .algo = &algo,
+ };
+
+ memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
+ strcpy(cam->i2c_adapter.name, "w9968cf");
+ cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
+- i2c_set_adapdata(&cam->i2c_adapter, cam);
++ i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
+
+ DBG(6, "Registering I2C adapter with kernel...")
+
+@@ -2165,13 +2108,9 @@ w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
+ static int
+ w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
+ {
+- struct i2c_client* c = cam->sensor_client;
+- int rc = 0;
+-
+- if (!c || !c->driver || !c->driver->command)
+- return -EINVAL;
++ int rc;
+
+- rc = c->driver->command(c, cmd, arg);
++ rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
+ /* The I2C driver returns -EPERM on non-supported controls */
+ return (rc < 0 && rc != -EPERM) ? rc : 0;
+ }
+@@ -2346,7 +2285,7 @@ static int w9968cf_sensor_init(struct w9968cf_device* cam)
+ goto error;
+
+ /* NOTE: Make sure width and height are a multiple of 16 */
+- switch (cam->sensor_client->addr) {
++ switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
+ case OV6xx0_SID:
+ cam->maxwidth = 352;
+ cam->maxheight = 288;
+@@ -2651,6 +2590,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
+ w9968cf_deallocate_memory(cam);
+ kfree(cam->control_buffer);
+ kfree(cam->data_buffer);
++ v4l2_device_unregister(&cam->v4l2_dev);
+
+ mutex_unlock(&w9968cf_devlist_mutex);
+ }
+@@ -3480,6 +3420,11 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+ struct list_head* ptr;
+ u8 sc = 0; /* number of simultaneous cameras */
+ static unsigned short dev_nr; /* 0 - we are handling device number n */
++ static unsigned short addrs[] = {
++ OV7xx0_SID,
++ OV6xx0_SID,
++ I2C_CLIENT_END
++ };
+
+ if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor &&
+ le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
+@@ -3495,12 +3440,14 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+ if (!cam)
+ return -ENOMEM;
+
++ err = v4l2_device_register(&udev->dev, &cam->v4l2_dev);
++ if (err)
++ goto fail0;
++
+ mutex_init(&cam->dev_mutex);
+ mutex_lock(&cam->dev_mutex);
+
+ cam->usbdev = udev;
+- /* NOTE: a local copy is used to avoid possible race conditions */
+- memcpy(&cam->dev, &udev->dev, sizeof(struct device));
+
+ DBG(2, "%s detected", symbolic(camlist, mod_id))
+
+@@ -3549,7 +3496,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+ cam->v4ldev->minor = video_nr[dev_nr];
+ cam->v4ldev->release = video_device_release;
+ video_set_drvdata(cam->v4ldev, cam);
+- cam->v4ldev->parent = &cam->dev;
++ cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
+
+ err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+ video_nr[dev_nr]);
+@@ -3576,9 +3523,13 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+ w9968cf_turn_on_led(cam);
+
+ w9968cf_i2c_init(cam);
++ cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->i2c_adapter,
++ "ovcamchip", "ovcamchip", addrs);
+
+ usb_set_intfdata(intf, cam);
+ mutex_unlock(&cam->dev_mutex);
++
++ err = w9968cf_sensor_init(cam);
+ return 0;
+
+ fail: /* Free unused memory */
+@@ -3587,6 +3538,8 @@ fail: /* Free unused memory */
+ if (cam->v4ldev)
+ video_device_release(cam->v4ldev);
+ mutex_unlock(&cam->dev_mutex);
++ v4l2_device_unregister(&cam->v4l2_dev);
++fail0:
+ kfree(cam);
+ return err;
+ }
+@@ -3597,15 +3550,16 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
+ struct w9968cf_device* cam =
+ (struct w9968cf_device*)usb_get_intfdata(intf);
+
+- down_write(&w9968cf_disconnect);
+-
+ if (cam) {
++ down_write(&w9968cf_disconnect);
+ /* Prevent concurrent accesses to data */
+ mutex_lock(&cam->dev_mutex);
+
+ cam->disconnected = 1;
+
+- DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id))
++ DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id));
++
++ v4l2_device_disconnect(&cam->v4l2_dev);
+
+ wake_up_interruptible_all(&cam->open);
+
+@@ -3621,12 +3575,12 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
+ w9968cf_release_resources(cam);
+
+ mutex_unlock(&cam->dev_mutex);
++ up_write(&w9968cf_disconnect);
+
+- if (!cam->users)
++ if (!cam->users) {
+ kfree(cam);
++ }
+ }
+-
+- up_write(&w9968cf_disconnect);
+ }
+
+
+@@ -3650,9 +3604,6 @@ static int __init w9968cf_module_init(void)
+ KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
+ KDBG(3, W9968CF_MODULE_AUTHOR)
+
+- if (ovmod_load)
+- request_module("ovcamchip");
+-
+ if ((err = usb_register(&w9968cf_usb_driver)))
+ return err;
+
+diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h
+index 30032e1..fdfc6a4 100644
+--- a/drivers/media/video/w9968cf.h
++++ b/drivers/media/video/w9968cf.h
+@@ -33,6 +33,7 @@
+ #include <linux/rwsem.h>
+ #include <linux/mutex.h>
+
++#include <media/v4l2-device.h>
+ #include <media/ovcamchip.h>
+
+ #include "w9968cf_vpp.h"
+@@ -42,7 +43,6 @@
+ * Default values *
+ ****************************************************************************/
+
+-#define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */
+ #define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */
+
+ /* Comment/uncomment the following line to enable/disable debugging messages */
+@@ -195,10 +195,9 @@ enum w9968cf_vpp_flag {
+
+ /* Main device driver structure */
+ struct w9968cf_device {
+- struct device dev; /* device structure */
+-
+ enum w9968cf_model_id id; /* private device identifier */
+
++ struct v4l2_device v4l2_dev;
+ struct video_device* v4ldev; /* -> V4L structure */
+ struct list_head v4llist; /* entry of the list of V4L cameras */
+
+@@ -265,7 +264,7 @@ struct w9968cf_device {
+
+ /* I2C interface to kernel */
+ struct i2c_adapter i2c_adapter;
+- struct i2c_client* sensor_client;
++ struct v4l2_subdev *sensor_sd;
+
+ /* Locks */
+ struct mutex dev_mutex, /* for probe, disconnect,open and close */
+@@ -277,6 +276,11 @@ struct w9968cf_device {
+ char command[16]; /* name of the program holding the device */
+ };
+
++static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev)
++{
++ return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev);
++}
++
+
+ /****************************************************************************
+ * Macros for debugging *
+@@ -291,14 +295,14 @@ struct w9968cf_device {
+ if ( ((specific_debug) && (debug == (level))) || \
+ ((!specific_debug) && (debug >= (level))) ) { \
+ if ((level) == 1) \
+- dev_err(&cam->dev, fmt "\n", ## args); \
++ v4l2_err(&cam->v4l2_dev, fmt "\n", ## args); \
+ else if ((level) == 2 || (level) == 3) \
+- dev_info(&cam->dev, fmt "\n", ## args); \
++ v4l2_info(&cam->v4l2_dev, fmt "\n", ## args); \
+ else if ((level) == 4) \
+- dev_warn(&cam->dev, fmt "\n", ## args); \
++ v4l2_warn(&cam->v4l2_dev, fmt "\n", ## args); \
+ else if ((level) >= 5) \
+- dev_info(&cam->dev, "[%s:%d] " fmt "\n", \
+- __func__, __LINE__ , ## args); \
++ v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", \
++ __func__, __LINE__ , ## args); \
+ } \
+ }
+ /* For generic kernel (not device specific) messages */
+@@ -321,7 +325,7 @@ struct w9968cf_device {
+
+ #undef PDBG
+ #define PDBG(fmt, args...) \
+-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
++v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
+
+ #undef PDBGG
+ #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
+diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
+index f2864d5..b572ce2 100644
+--- a/drivers/media/video/wm8739.c
++++ b/drivers/media/video/wm8739.c
+@@ -252,11 +252,6 @@ static int wm8739_log_status(struct v4l2_subdev *sd)
+ return 0;
+ }
+
+-static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops wm8739_core_ops = {
+@@ -343,8 +338,6 @@ MODULE_DEVICE_TABLE(i2c, wm8739_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "wm8739",
+- .driverid = I2C_DRIVERID_WM8739,
+- .command = wm8739_command,
+ .probe = wm8739_probe,
+ .remove = wm8739_remove,
+ .id_table = wm8739_id,
+diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
+index 53fcd42..eddf11a 100644
+--- a/drivers/media/video/wm8775.c
++++ b/drivers/media/video/wm8775.c
+@@ -34,15 +34,12 @@
+ #include <linux/videodev2.h>
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-chip-ident.h>
+-#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
+
+ MODULE_DESCRIPTION("wm8775 driver");
+ MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
+ MODULE_LICENSE("GPL");
+
+-static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
+-
+-I2C_CLIENT_INSMOD;
+
+
+ /* ----------------------------------------------------------------------- */
+@@ -161,11 +158,6 @@ static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fre
+ return 0;
+ }
+
+-static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
+-{
+- return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+-}
+-
+ /* ----------------------------------------------------------------------- */
+
+ static const struct v4l2_subdev_core_ops wm8775_core_ops = {
+@@ -268,8 +260,6 @@ MODULE_DEVICE_TABLE(i2c, wm8775_id);
+
+ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "wm8775",
+- .driverid = I2C_DRIVERID_WM8775,
+- .command = wm8775_command,
+ .probe = wm8775_probe,
+ .remove = wm8775_remove,
+ .id_table = wm8775_id,
+diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
+index b0cd49c..3a408de 100644
+--- a/drivers/media/video/zc0301/zc0301_sensor.h
++++ b/drivers/media/video/zc0301/zc0301_sensor.h
+@@ -58,12 +58,20 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
+ .idProduct = (prod), \
+ .bInterfaceClass = (intclass)
+
++#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
+ #define ZC0301_ID_TABLE \
+ static const struct usb_device_id zc0301_id_table[] = { \
+ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
+ { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
+ { } \
+ };
++#else
++#define ZC0301_ID_TABLE \
++static const struct usb_device_id zc0301_id_table[] = { \
++ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
++ { } \
++};
++#endif
+
+ /*****************************************************************************/
+
+diff --git a/drivers/media/video/zoran/Kconfig b/drivers/media/video/zoran/Kconfig
+index 8666e19..fd4120e 100644
+--- a/drivers/media/video/zoran/Kconfig
++++ b/drivers/media/video/zoran/Kconfig
+@@ -1,6 +1,6 @@
+ config VIDEO_ZORAN
+ tristate "Zoran ZR36057/36067 Video For Linux"
+- depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
++ depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 && VIRT_TO_BUS
+ help
+ Say Y for support for MJPEG capture cards based on the Zoran
+ 36057/36067 PCI controller chipset. This includes the Iomega
+@@ -32,7 +32,7 @@ config VIDEO_ZORAN_ZR36060
+ config VIDEO_ZORAN_BUZ
+ tristate "Iomega Buz support"
+ depends on VIDEO_ZORAN_ZR36060
+- select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
+ help
+ Support for the Iomega Buz MJPEG capture/playback card.
+@@ -58,7 +58,7 @@ config VIDEO_ZORAN_LML33
+ config VIDEO_ZORAN_LML33R10
+ tristate "Linux Media Labs LML33R10 support"
+ depends on VIDEO_ZORAN_ZR36060
+- select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
++ select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
+ help
+ support for the Linux Media Labs LML33R10 MJPEG capture/playback
+@@ -66,7 +66,7 @@ config VIDEO_ZORAN_LML33R10
+
+ config VIDEO_ZORAN_AVS6EYES
+ tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+- depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
++ depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL
+ select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_BT866 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
+diff --git a/drivers/media/video/zoran/videocodec.h b/drivers/media/video/zoran/videocodec.h
+index 97a3bbe..5c27b25 100644
+--- a/drivers/media/video/zoran/videocodec.h
++++ b/drivers/media/video/zoran/videocodec.h
+@@ -97,7 +97,7 @@
+ 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_*)
++ the norm param is defined in videodev2.h (V4L2_STD_*)
+
+ additional setup may be available, too - but the codec should work with
+ some default values even without this
+@@ -144,9 +144,8 @@ M zr36055[1] 0001 0000c001 00000000 (zr36050[1])
+ #ifndef __LINUX_VIDEOCODEC_H
+ #define __LINUX_VIDEOCODEC_H
+
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+
+-//should be in videodev.h ??? (VID_DO_....)
+ #define CODEC_DO_COMPRESSION 0
+ #define CODEC_DO_EXPANSION 1
+
+@@ -237,10 +236,6 @@ struct vfe_settings {
+ __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 */
+ };
+
+diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h
+index e873a91..afecf32 100644
+--- a/drivers/media/video/zoran/zoran.h
++++ b/drivers/media/video/zoran/zoran.h
+@@ -31,6 +31,8 @@
+ #ifndef _BUZ_H_
+ #define _BUZ_H_
+
++#include <media/v4l2-device.h>
++
+ struct zoran_requestbuffers {
+ unsigned long count; /* Number of buffers for MJPEG grabbing */
+ unsigned long size; /* Size PER BUFFER in bytes */
+@@ -170,7 +172,7 @@ Private IOCTL to set up for displaying MJPEG
+ #endif
+ #define V4L_MASK_FRAME (V4L_MAX_FRAME - 1)
+
+-#define MAX_KMALLOC_MEM (128*1024)
++#define MAX_FRAME (BUZ_MAX_FRAME > VIDEO_MAX_FRAME ? BUZ_MAX_FRAME : VIDEO_MAX_FRAME)
+
+ #include "zr36057.h"
+
+@@ -240,9 +242,6 @@ enum gpcs_type {
+
+ struct zoran_format {
+ char *name;
+-#ifdef CONFIG_VIDEO_V4L1_COMPAT
+- int palette;
+-#endif
+ __u32 fourcc;
+ int colorspace;
+ int depth;
+@@ -283,21 +282,21 @@ struct zoran_mapping {
+ int count;
+ };
+
+-struct zoran_jpg_buffer {
+- struct zoran_mapping *map;
+- __le32 *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 zoran_v4l_buffer {
++struct zoran_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_buffer_state state; /* state: unused/pending/dma/done */
++ struct zoran_sync bs; /* DONE: info to return to application */
++ union {
++ struct {
++ __le32 *frag_tab; /* addresses of frag table */
++ u32 frag_tab_bus; /* same value cached to save time in ISR */
++ } jpg;
++ struct {
++ 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 */
++ } v4l;
++ };
+ };
+
+ enum zoran_lock_activity {
+@@ -307,21 +306,13 @@ enum zoran_lock_activity {
+ };
+
+ /* buffer collections */
+-struct zoran_jpg_struct {
++struct zoran_buffer_col {
+ enum zoran_lock_activity active; /* feature currently in use? */
+- struct zoran_jpg_buffer buffer[BUZ_MAX_FRAME]; /* buffers */
+- int num_buffers, buffer_size;
++ unsigned int num_buffers, buffer_size;
++ struct zoran_buffer buffer[MAX_FRAME]; /* buffers */
+ 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 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 */
++ /* only applies to jpg buffers, raw buffers are always contiguous */
+ };
+
+ struct zoran;
+@@ -330,23 +321,27 @@ struct zoran;
+ struct zoran_fh {
+ struct zoran *zr;
+
+- enum zoran_map_mode map_mode; /* Flag which bufferset will map by next mmap() */
++ 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? */
++ 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_buffer_col buffers; /* buffers' info */
+
++ struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */
+ 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 */
++ const char *i2c_decoder; /* i2c decoder device */
++ const char *mod_decoder; /* i2c decoder module */
++ const unsigned short *addrs_decoder;
++ const char *i2c_encoder; /* i2c encoder device */
++ const char *mod_encoder; /* i2c encoder module */
++ const unsigned short *addrs_encoder;
+ u16 video_vfe, video_codec; /* videocodec types */
+ u16 audio_chip; /* audio type */
+
+@@ -356,7 +351,7 @@ struct card_info {
+ char name[32];
+ } input[BUZ_MAX_INPUT];
+
+- int norms;
++ v4l2_std_id norms;
+ struct tvnorm *tvn[3]; /* supported TV norms */
+
+ u32 jpeg_int; /* JPEG interrupt */
+@@ -377,14 +372,15 @@ struct card_info {
+ };
+
+ struct zoran {
++ struct v4l2_device v4l2_dev;
+ struct video_device *video_dev;
+
+ 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 */
++ struct v4l2_subdev *decoder; /* video decoder sub-device */
++ struct v4l2_subdev *encoder; /* video encoder sub-device */
+
+ struct videocodec *codec; /* video codec */
+ struct videocodec *vfe; /* video front end */
+@@ -405,9 +401,15 @@ struct zoran {
+ spinlock_t spinlock; /* Spinlock */
+
+ /* Video for Linux parameters */
+- 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 */
++ int input; /* card's norm and input - norm=VIDEO_MODE_* */
++ v4l2_std_id norm;
++
++ /* Current buffer params */
++ void *vbuf_base;
++ int vbuf_height, vbuf_width;
++ int vbuf_depth;
++ int vbuf_bytesperline;
++
+ struct zoran_overlay_settings overlay_settings;
+ u32 *overlay_mask; /* overlay mask */
+ enum zoran_lock_activity overlay_active; /* feature currently in use? */
+@@ -427,7 +429,7 @@ struct zoran {
+ unsigned long v4l_pend_tail;
+ unsigned long v4l_sync_tail;
+ int v4l_pend[V4L_MAX_FRAME];
+- struct zoran_v4l_struct v4l_buffers; /* V4L buffers' info */
++ struct zoran_buffer_col v4l_buffers; /* V4L buffers' info */
+
+ /* Buz MJPEG parameters */
+ enum zoran_codec_mode codec_mode; /* status of codec */
+@@ -454,7 +456,7 @@ struct zoran {
+ int jpg_pend[BUZ_MAX_FRAME];
+
+ /* array indexed by frame number */
+- struct zoran_jpg_struct jpg_buffers; /* MJPEG buffers' info */
++ struct zoran_buffer_col jpg_buffers; /* MJPEG buffers' info */
+
+ /* Additional stuff for testing */
+ #ifdef CONFIG_PROC_FS
+@@ -488,6 +490,11 @@ struct zoran {
+ wait_queue_head_t test_q;
+ };
+
++static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev)
++{
++ return container_of(v4l2_dev, struct zoran, v4l2_dev);
++}
++
+ /* There was something called _ALPHA_BUZ that used the PCI address instead of
+ * the kernel iomapped address for btread/btwrite. */
+ #define btwrite(dat,adr) writel((dat), zr->zr36057_mem+(adr))
+diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
+index 5d2f090..f91bba4 100644
+--- a/drivers/media/video/zoran/zoran_card.c
++++ b/drivers/media/video/zoran/zoran_card.c
+@@ -38,8 +38,7 @@
+ #include <linux/proc_fs.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-algo-bit.h>
+-#include <linux/videodev.h>
+-#include <media/v4l2-common.h>
++#include <linux/videodev2.h>
+ #include <linux/spinlock.h>
+ #include <linux/sem.h>
+ #include <linux/kmod.h>
+@@ -47,11 +46,10 @@
+
+ #include <linux/pci.h>
+ #include <linux/interrupt.h>
+-#include <linux/video_decoder.h>
+-#include <linux/video_encoder.h>
+ #include <linux/mutex.h>
+-
+-#include <asm/io.h>
++#include <linux/io.h>
++#include <media/v4l2-common.h>
++#include <media/bt819.h>
+
+ #include "videocodec.h"
+ #include "zoran.h"
+@@ -108,25 +106,8 @@ static int video_nr[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
+ module_param_array(video_nr, int, NULL, 0444);
+ MODULE_PARM_DESC(video_nr, "Video device number (-1=Auto)");
+
+-/*
+- 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 */
++int v4l_nbufs = 4;
++int v4l_bufsize = 864; /* Everybody should be able to work with this setting */
+ module_param(v4l_nbufs, int, 0644);
+ MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use");
+ module_param(v4l_bufsize, int, 0644);
+@@ -273,7 +254,7 @@ zr36016_write (struct videocodec *codec,
+ static void
+ dc10_init (struct zoran *zr)
+ {
+- dprintk(3, KERN_DEBUG "%s: dc10_init()\n", ZR_DEVNAME(zr));
++ dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+ /* Pixel clock selection */
+ GPIO(zr, 4, 0);
+@@ -285,13 +266,13 @@ dc10_init (struct zoran *zr)
+ static void
+ dc10plus_init (struct zoran *zr)
+ {
+- dprintk(3, KERN_DEBUG "%s: dc10plus_init()\n", ZR_DEVNAME(zr));
++ dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+ }
+
+ static void
+ buz_init (struct zoran *zr)
+ {
+- dprintk(3, KERN_DEBUG "%s: buz_init()\n", ZR_DEVNAME(zr));
++ dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+ /* some stuff from Iomega */
+ pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15);
+@@ -302,7 +283,7 @@ buz_init (struct zoran *zr)
+ static void
+ lml33_init (struct zoran *zr)
+ {
+- dprintk(3, KERN_DEBUG "%s: lml33_init()\n", ZR_DEVNAME(zr));
++ dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+ GPIO(zr, 2, 1); // Set Composite input/output
+ }
+@@ -332,50 +313,6 @@ avs6eyes_init (struct zoran *zr)
+ }
+
+ 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_BT866:
+- name = "bt866";
+- break;
+- case I2C_DRIVERID_VPX3220:
+- name = "vpx3220";
+- break;
+- case I2C_DRIVERID_KS0127:
+- name = "ks0127";
+- break;
+- }
+-
+- return name;
+-}
+-
+-static char *
+ codecid_to_modulename (u16 codecid)
+ {
+ char *name = NULL;
+@@ -425,11 +362,24 @@ static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 }
+ static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
+ static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
+
++static const unsigned short vpx3220_addrs[] = { 0x43, 0x47, I2C_CLIENT_END };
++static const unsigned short saa7110_addrs[] = { 0x4e, 0x4f, I2C_CLIENT_END };
++static const unsigned short saa7111_addrs[] = { 0x25, 0x24, I2C_CLIENT_END };
++static const unsigned short saa7114_addrs[] = { 0x21, 0x20, I2C_CLIENT_END };
++static const unsigned short adv717x_addrs[] = { 0x6a, 0x6b, 0x2a, 0x2b, I2C_CLIENT_END };
++static const unsigned short ks0127_addrs[] = { 0x6c, 0x6d, I2C_CLIENT_END };
++static const unsigned short saa7185_addrs[] = { 0x44, I2C_CLIENT_END };
++static const unsigned short bt819_addrs[] = { 0x45, I2C_CLIENT_END };
++static const unsigned short bt856_addrs[] = { 0x44, I2C_CLIENT_END };
++static const unsigned short bt866_addrs[] = { 0x44, I2C_CLIENT_END };
++
+ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ {
+ .type = DC10_old,
+ .name = "DC10(old)",
+- .i2c_decoder = I2C_DRIVERID_VPX3220,
++ .i2c_decoder = "vpx3220a",
++ .mod_decoder = "vpx3220",
++ .addrs_decoder = vpx3220_addrs,
+ .video_codec = CODEC_TYPE_ZR36050,
+ .video_vfe = CODEC_TYPE_ZR36016,
+
+@@ -439,7 +389,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ { 2, "S-Video" },
+ { 0, "Internal/comp" }
+ },
+- .norms = 3,
++ .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+ .tvn = {
+ &f50sqpixel_dc10,
+ &f60sqpixel_dc10,
+@@ -457,8 +407,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ }, {
+ .type = DC10_new,
+ .name = "DC10(new)",
+- .i2c_decoder = I2C_DRIVERID_SAA7110,
+- .i2c_encoder = I2C_DRIVERID_ADV7175,
++ .i2c_decoder = "saa7110",
++ .mod_decoder = "saa7110",
++ .addrs_decoder = saa7110_addrs,
++ .i2c_encoder = "adv7175",
++ .mod_encoder = "adv7175",
++ .addrs_encoder = adv717x_addrs,
+ .video_codec = CODEC_TYPE_ZR36060,
+
+ .inputs = 3,
+@@ -467,7 +421,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ { 7, "S-Video" },
+ { 5, "Internal/comp" }
+ },
+- .norms = 3,
++ .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+ .tvn = {
+ &f50sqpixel,
+ &f60sqpixel,
+@@ -484,8 +438,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ }, {
+ .type = DC10plus,
+ .name = "DC10plus",
+- .i2c_decoder = I2C_DRIVERID_SAA7110,
+- .i2c_encoder = I2C_DRIVERID_ADV7175,
++ .i2c_decoder = "saa7110",
++ .mod_decoder = "saa7110",
++ .addrs_decoder = saa7110_addrs,
++ .i2c_encoder = "adv7175",
++ .mod_encoder = "adv7175",
++ .addrs_encoder = adv717x_addrs,
+ .video_codec = CODEC_TYPE_ZR36060,
+
+ .inputs = 3,
+@@ -494,7 +452,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ { 7, "S-Video" },
+ { 5, "Internal/comp" }
+ },
+- .norms = 3,
++ .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+ .tvn = {
+ &f50sqpixel,
+ &f60sqpixel,
+@@ -512,8 +470,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ }, {
+ .type = DC30,
+ .name = "DC30",
+- .i2c_decoder = I2C_DRIVERID_VPX3220,
+- .i2c_encoder = I2C_DRIVERID_ADV7175,
++ .i2c_decoder = "vpx3220a",
++ .mod_decoder = "vpx3220",
++ .addrs_decoder = vpx3220_addrs,
++ .i2c_encoder = "adv7175",
++ .mod_encoder = "adv7175",
++ .addrs_encoder = adv717x_addrs,
+ .video_codec = CODEC_TYPE_ZR36050,
+ .video_vfe = CODEC_TYPE_ZR36016,
+
+@@ -523,7 +485,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ { 2, "S-Video" },
+ { 0, "Internal/comp" }
+ },
+- .norms = 3,
++ .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+ .tvn = {
+ &f50sqpixel_dc10,
+ &f60sqpixel_dc10,
+@@ -541,8 +503,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ }, {
+ .type = DC30plus,
+ .name = "DC30plus",
+- .i2c_decoder = I2C_DRIVERID_VPX3220,
+- .i2c_encoder = I2C_DRIVERID_ADV7175,
++ .i2c_decoder = "vpx3220a",
++ .mod_decoder = "vpx3220",
++ .addrs_decoder = vpx3220_addrs,
++ .i2c_encoder = "adv7175",
++ .mod_encoder = "adv7175",
++ .addrs_encoder = adv717x_addrs,
+ .video_codec = CODEC_TYPE_ZR36050,
+ .video_vfe = CODEC_TYPE_ZR36016,
+
+@@ -552,7 +518,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ { 2, "S-Video" },
+ { 0, "Internal/comp" }
+ },
+- .norms = 3,
++ .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+ .tvn = {
+ &f50sqpixel_dc10,
+ &f60sqpixel_dc10,
+@@ -570,8 +536,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ }, {
+ .type = LML33,
+ .name = "LML33",
+- .i2c_decoder = I2C_DRIVERID_BT819,
+- .i2c_encoder = I2C_DRIVERID_BT856,
++ .i2c_decoder = "bt819a",
++ .mod_decoder = "bt819",
++ .addrs_decoder = bt819_addrs,
++ .i2c_encoder = "bt856",
++ .mod_encoder = "bt856",
++ .addrs_encoder = bt856_addrs,
+ .video_codec = CODEC_TYPE_ZR36060,
+
+ .inputs = 2,
+@@ -579,7 +549,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ { 0, "Composite" },
+ { 7, "S-Video" }
+ },
+- .norms = 2,
++ .norms = V4L2_STD_NTSC|V4L2_STD_PAL,
+ .tvn = {
+ &f50ccir601_lml33,
+ &f60ccir601_lml33,
+@@ -597,8 +567,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ }, {
+ .type = LML33R10,
+ .name = "LML33R10",
+- .i2c_decoder = I2C_DRIVERID_SAA7114,
+- .i2c_encoder = I2C_DRIVERID_ADV7170,
++ .i2c_decoder = "saa7114",
++ .mod_decoder = "saa7115",
++ .addrs_decoder = saa7114_addrs,
++ .i2c_encoder = "adv7170",
++ .mod_encoder = "adv7170",
++ .addrs_encoder = adv717x_addrs,
+ .video_codec = CODEC_TYPE_ZR36060,
+
+ .inputs = 2,
+@@ -606,7 +580,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ { 0, "Composite" },
+ { 7, "S-Video" }
+ },
+- .norms = 2,
++ .norms = V4L2_STD_NTSC|V4L2_STD_PAL,
+ .tvn = {
+ &f50ccir601_lm33r10,
+ &f60ccir601_lm33r10,
+@@ -624,8 +598,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ }, {
+ .type = BUZ,
+ .name = "Buz",
+- .i2c_decoder = I2C_DRIVERID_SAA7111A,
+- .i2c_encoder = I2C_DRIVERID_SAA7185B,
++ .i2c_decoder = "saa7111",
++ .mod_decoder = "saa7115",
++ .addrs_decoder = saa7111_addrs,
++ .i2c_encoder = "saa7185",
++ .mod_encoder = "saa7185",
++ .addrs_encoder = saa7185_addrs,
+ .video_codec = CODEC_TYPE_ZR36060,
+
+ .inputs = 2,
+@@ -633,7 +611,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ { 3, "Composite" },
+ { 7, "S-Video" }
+ },
+- .norms = 3,
++ .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM,
+ .tvn = {
+ &f50ccir601,
+ &f60ccir601,
+@@ -653,8 +631,12 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ .name = "6-Eyes",
+ /* AverMedia chose not to brand the 6-Eyes. Thus it
+ can't be autodetected, and requires card=x. */
+- .i2c_decoder = I2C_DRIVERID_KS0127,
+- .i2c_encoder = I2C_DRIVERID_BT866,
++ .i2c_decoder = "ks0127",
++ .mod_decoder = "ks0127",
++ .addrs_decoder = ks0127_addrs,
++ .i2c_encoder = "bt866",
++ .mod_encoder = "bt866",
++ .addrs_encoder = bt866_addrs,
+ .video_codec = CODEC_TYPE_ZR36060,
+
+ .inputs = 10,
+@@ -670,7 +652,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+ {10, "S-Video 3" },
+ {15, "YCbCr" }
+ },
+- .norms = 2,
++ .norms = V4L2_STD_NTSC|V4L2_STD_PAL,
+ .tvn = {
+ &f50ccir601_avs6eyes,
+ &f60ccir601_avs6eyes,
+@@ -735,69 +717,6 @@ zoran_i2c_setscl (void *data,
+ 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);
+-
+- mutex_lock(&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:
+- mutex_unlock(&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));
+-
+- mutex_lock(&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:
+- mutex_unlock(&zr->resource_lock);
+- return res;
+-}
+-
+ static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
+ .setsda = zoran_i2c_setsda,
+ .setscl = zoran_i2c_setscl,
+@@ -813,13 +732,10 @@ 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;
+- zr->i2c_adapter.class = I2C_CLASS_TV_ANALOG;
+ zr->i2c_adapter.id = I2C_HW_B_ZR36067;
+- zr->i2c_adapter.client_register = zoran_i2c_client_register;
+- zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister;
+ strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
+ sizeof(zr->i2c_adapter.name));
+- i2c_set_adapdata(&zr->i2c_adapter, zr);
++ i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev);
+ zr->i2c_adapter.algo_data = &zr->i2c_algo;
+ zr->i2c_adapter.dev.parent = &zr->pci_dev->dev;
+ return i2c_bit_add_bus(&zr->i2c_adapter);
+@@ -835,19 +751,20 @@ zoran_unregister_i2c (struct zoran *zr)
+
+ int
+ zoran_check_jpg_settings (struct zoran *zr,
+- struct zoran_jpg_settings *settings)
++ struct zoran_jpg_settings *settings,
++ int try)
+ {
+ 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,
++ "%s: %s - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n",
++ ZR_DEVNAME(zr), __func__, 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,
++ "%s: %s - x: %d, y: %d, w: %d, y: %d\n",
++ ZR_DEVNAME(zr), __func__, 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) {
+@@ -879,8 +796,8 @@ zoran_check_jpg_settings (struct zoran *zr,
+ 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));
++ "%s: %s - HDec by 4 is not supported on the DC10\n",
++ ZR_DEVNAME(zr), __func__);
+ err0++;
+ break;
+ }
+@@ -900,50 +817,73 @@ zoran_check_jpg_settings (struct zoran *zr,
+ /* 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))
++ (zr->card.type == DC10_new || settings->HorDcm != 4)) {
++ settings->HorDcm = clamp(settings->HorDcm, 1, 2);
+ err0++;
+- if (settings->VerDcm != 1 && settings->VerDcm != 2)
++ }
++ if (settings->VerDcm != 1 && settings->VerDcm != 2) {
++ settings->VerDcm = clamp(settings->VerDcm, 1, 2);
+ err0++;
+- if (settings->TmpDcm != 1 && settings->TmpDcm != 2)
++ }
++ if (settings->TmpDcm != 1 && settings->TmpDcm != 2) {
++ settings->TmpDcm = clamp(settings->TmpDcm, 1, 2);
+ err0++;
++ }
+ if (settings->field_per_buff != 1 &&
+- settings->field_per_buff != 2)
++ settings->field_per_buff != 2) {
++ settings->field_per_buff = clamp(settings->field_per_buff, 1, 2);
+ err0++;
+- if (settings->img_x < 0)
++ }
++ if (settings->img_x < 0) {
++ settings->img_x = 0;
+ err0++;
+- if (settings->img_y < 0)
++ }
++ if (settings->img_y < 0) {
++ settings->img_y = 0;
+ err0++;
+- if (settings->img_width < 0)
++ }
++ if (settings->img_width < 0 || settings->img_width > BUZ_MAX_WIDTH) {
++ settings->img_width = clamp(settings->img_width, 0, (int)BUZ_MAX_WIDTH);
+ err0++;
+- if (settings->img_height < 0)
++ }
++ if (settings->img_height < 0 || settings->img_height > BUZ_MAX_HEIGHT / 2) {
++ settings->img_height = clamp(settings->img_height, 0, BUZ_MAX_HEIGHT / 2);
+ err0++;
+- if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH)
++ }
++ if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH) {
++ settings->img_x = BUZ_MAX_WIDTH - settings->img_width;
+ err0++;
+- if (settings->img_y + settings->img_height >
+- BUZ_MAX_HEIGHT / 2)
++ }
++ if (settings->img_y + settings->img_height > BUZ_MAX_HEIGHT / 2) {
++ settings->img_y = BUZ_MAX_HEIGHT / 2 - settings->img_height;
++ err0++;
++ }
++ if (settings->img_width % (16 * settings->HorDcm) != 0) {
++ settings->img_width -= settings->img_width % (16 * settings->HorDcm);
++ if (settings->img_width == 0)
++ settings->img_width = 16 * settings->HorDcm;
++ err0++;
++ }
++ if (settings->img_height % (8 * settings->VerDcm) != 0) {
++ settings->img_height -= settings->img_height % (8 * settings->VerDcm);
++ if (settings->img_height == 0)
++ settings->img_height = 8 * settings->VerDcm;
+ 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) {
++ if (!try && err0) {
+ dprintk(1,
+ KERN_ERR
+- "%s: check_jpg_settings() - error in params for decimation = 0\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - error in params for decimation = 0\n",
++ ZR_DEVNAME(zr), __func__);
+ 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);
++ "%s: %s - decimation = %d, must be 0, 1, 2 or 4\n",
++ ZR_DEVNAME(zr), __func__, settings->decimation);
+ err++;
+ break;
+ }
+@@ -1021,12 +961,10 @@ zoran_open_init_params (struct zoran *zr)
+ 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);
++ i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0);
+ if (i)
+- dprintk(1,
+- KERN_ERR
+- "%s: zoran_open_init_params() internal error\n",
+- ZR_DEVNAME(zr));
++ dprintk(1, KERN_ERR "%s: %s internal error\n",
++ ZR_DEVNAME(zr), __func__);
+
+ clear_interrupt_counters(zr);
+ zr->testing = 0;
+@@ -1062,13 +1000,11 @@ static int __devinit
+ zr36057_init (struct zoran *zr)
+ {
+ int j, err;
+- 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);
++ "%s: %s - initializing card[%d], zr=%p\n",
++ ZR_DEVNAME(zr), __func__, zr->id, zr);
+
+ /* default setup of all parameters which will persist between opens */
+ zr->user = 0;
+@@ -1079,24 +1015,32 @@ zr36057_init (struct zoran *zr)
+ 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;
++ zr->vbuf_base = (void *) vidmem;
++ zr->vbuf_width = 0;
++ zr->vbuf_height = 0;
++ zr->vbuf_depth = 0;
++ zr->vbuf_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])) {
++ if (default_norm < 0 && default_norm > 2)
++ default_norm = 0;
++ if (default_norm == 0) {
++ zr->norm = V4L2_STD_PAL;
++ zr->timing = zr->card.tvn[0];
++ } else if (default_norm == 1) {
++ zr->norm = V4L2_STD_NTSC;
++ zr->timing = zr->card.tvn[1];
++ } else {
++ zr->norm = V4L2_STD_SECAM;
++ zr->timing = zr->card.tvn[2];
++ }
++ if (zr->timing == NULL) {
+ 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];
++ "%s: %s - default TV standard not supported by hardware. PAL will be used.\n",
++ ZR_DEVNAME(zr), __func__);
++ zr->norm = V4L2_STD_PAL;
++ zr->timing = zr->card.tvn[0];
+ }
+
+ if (default_input > zr->card.inputs-1) {
+@@ -1108,12 +1052,6 @@ zr36057_init (struct zoran *zr)
+ }
+ zr->input = default_input;
+
+- /* 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);
+
+@@ -1124,8 +1062,8 @@ zr36057_init (struct zoran *zr)
+ if (!zr->stat_com || !zr->video_dev) {
+ dprintk(1,
+ KERN_ERR
+- "%s: zr36057_init() - kmalloc (STAT_COM) failed\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - kmalloc (STAT_COM) failed\n",
++ ZR_DEVNAME(zr), __func__);
+ err = -ENOMEM;
+ goto exit_free;
+ }
+@@ -1137,6 +1075,7 @@ zr36057_init (struct zoran *zr)
+ * Now add the template and register the device unit.
+ */
+ memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
++ zr->video_dev->parent = &zr->pci_dev->dev;
+ strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
+ err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]);
+ if (err < 0)
+@@ -1148,8 +1087,10 @@ zr36057_init (struct zoran *zr)
+ detect_guest_activity(zr);
+ test_interrupts(zr);
+ if (!pass_through) {
+- decoder_command(zr, DECODER_ENABLE_OUTPUT, &zero);
+- encoder_command(zr, ENCODER_SET_INPUT, &two);
++ struct v4l2_routing route = { 2, 0 };
++
++ decoder_call(zr, video, s_stream, 0);
++ encoder_call(zr, video, s_routing, &route);
+ }
+
+ zr->zoran_proc = NULL;
+@@ -1164,7 +1105,8 @@ exit_free:
+
+ static void __devexit zoran_remove(struct pci_dev *pdev)
+ {
+- struct zoran *zr = pci_get_drvdata(pdev);
++ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
++ struct zoran *zr = to_zoran(v4l2_dev);
+
+ if (!zr->initialized)
+ goto exit_free;
+@@ -1197,7 +1139,7 @@ static void __devexit zoran_remove(struct pci_dev *pdev)
+ pci_disable_device(zr->pci_dev);
+ video_unregister_device(zr->video_dev);
+ exit_free:
+- pci_set_drvdata(pdev, NULL);
++ v4l2_device_unregister(&zr->v4l2_dev);
+ kfree(zr);
+ }
+
+@@ -1215,10 +1157,8 @@ zoran_setup_videocodec (struct zoran *zr,
+
+ m = kmalloc(sizeof(struct videocodec_master), GFP_KERNEL);
+ if (!m) {
+- dprintk(1,
+- KERN_ERR
+- "%s: zoran_setup_videocodec() - no memory\n",
+- ZR_DEVNAME(zr));
++ dprintk(1, KERN_ERR "%s: %s - no memory\n",
++ ZR_DEVNAME(zr), __func__);
+ return m;
+ }
+
+@@ -1256,6 +1196,18 @@ zoran_setup_videocodec (struct zoran *zr,
+ return m;
+ }
+
++static void zoran_subdev_notify(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
++{
++ struct zoran *zr = to_zoran(sd->v4l2_dev);
++
++ /* Bt819 needs to reset its FIFO buffer using #FRST pin and
++ LML33 card uses GPIO(7) for that. */
++ if (cmd == BT819_FIFO_RESET_LOW)
++ GPIO(zr, 7, 0);
++ else if (cmd == BT819_FIFO_RESET_HIGH)
++ GPIO(zr, 7, 1);
++}
++
+ /*
+ * Scan for a Buz card (actually for the PCI controller ZR36057),
+ * request the irq and map the io memory
+@@ -1269,34 +1221,33 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ 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;
++ char *codec_name, *vfe_name;
+ unsigned int nr;
+
+
+ nr = zoran_num++;
+ if (nr >= BUZ_MAX) {
+- dprintk(1,
+- KERN_ERR
+- "%s: driver limited to %d card(s) maximum\n",
++ dprintk(1, KERN_ERR "%s: driver limited to %d card(s) maximum\n",
+ ZORAN_NAME, BUZ_MAX);
+ return -ENOENT;
+ }
+
+ zr = kzalloc(sizeof(struct zoran), GFP_KERNEL);
+ if (!zr) {
+- dprintk(1,
+- KERN_ERR
+- "%s: find_zr36057() - kzalloc failed\n",
+- ZORAN_NAME);
++ dprintk(1, KERN_ERR "%s: %s - kzalloc failed\n",
++ ZORAN_NAME, __func__);
+ return -ENOMEM;
+ }
++ zr->v4l2_dev.notify = zoran_subdev_notify;
++ if (v4l2_device_register(&pdev->dev, &zr->v4l2_dev))
++ goto zr_free_mem;
+ zr->pci_dev = pdev;
+ zr->id = nr;
+ snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
+ spin_lock_init(&zr->spinlock);
+ mutex_init(&zr->resource_lock);
+ if (pci_enable_device(pdev))
+- goto zr_free_mem;
++ goto zr_unreg;
+ pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
+
+ dprintk(1,
+@@ -1323,7 +1274,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ KERN_ERR
+ "%s: It is not possible to auto-detect ZR36057 based cards\n",
+ ZR_DEVNAME(zr));
+- goto zr_free_mem;
++ goto zr_unreg;
+ }
+
+ card_num = ent->driver_data;
+@@ -1332,7 +1283,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ KERN_ERR
+ "%s: Unknown card, try specifying card=X module parameter\n",
+ ZR_DEVNAME(zr));
+- goto zr_free_mem;
++ goto zr_unreg;
+ }
+ dprintk(3,
+ KERN_DEBUG
+@@ -1345,7 +1296,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ KERN_ERR
+ "%s: User specified card type %d out of range (0 .. %d)\n",
+ ZR_DEVNAME(zr), card_num, NUM_CARDS - 1);
+- goto zr_free_mem;
++ goto zr_unreg;
+ }
+ }
+
+@@ -1360,11 +1311,9 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+
+ zr->zr36057_mem = pci_ioremap_bar(zr->pci_dev, 0);
+ if (!zr->zr36057_mem) {
+- dprintk(1,
+- KERN_ERR
+- "%s: %s() - ioremap failed\n",
++ dprintk(1, KERN_ERR "%s: %s() - ioremap failed\n",
+ ZR_DEVNAME(zr), __func__);
+- goto zr_free_mem;
++ goto zr_unreg;
+ }
+
+ result = request_irq(zr->pci_dev->irq, zoran_irq,
+@@ -1373,18 +1322,18 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ if (result == -EINVAL) {
+ dprintk(1,
+ KERN_ERR
+- "%s: find_zr36057() - bad irq number or handler\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - bad irq number or handler\n",
++ ZR_DEVNAME(zr), __func__);
+ } 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);
++ "%s: %s - IRQ %d busy, change your PnP config in BIOS\n",
++ ZR_DEVNAME(zr), __func__, zr->pci_dev->irq);
+ } else {
+ dprintk(1,
+ KERN_ERR
+- "%s: find_zr36057() - can't assign irq, error code %d\n",
+- ZR_DEVNAME(zr), result);
++ "%s: %s - can't assign irq, error code %d\n",
++ ZR_DEVNAME(zr), __func__, result);
+ }
+ goto zr_unmap;
+ }
+@@ -1394,9 +1343,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ &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",
++ 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);
+@@ -1407,54 +1354,20 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ 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) {
+- result = request_module(i2c_dec_name);
+- if (result < 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) {
+- result = request_module(i2c_enc_name);
+- if (result < 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));
++ dprintk(1, KERN_ERR "%s: %s - can't initialize i2c bus\n",
++ ZR_DEVNAME(zr), __func__);
+ goto zr_free_irq;
+ }
+
++ zr->decoder = v4l2_i2c_new_probed_subdev(&zr->i2c_adapter,
++ zr->card.mod_decoder, zr->card.i2c_decoder, zr->card.addrs_decoder);
++
++ if (zr->card.mod_encoder)
++ zr->encoder = v4l2_i2c_new_probed_subdev(&zr->i2c_adapter,
++ zr->card.mod_encoder, zr->card.i2c_encoder,
++ zr->card.addrs_encoder);
++
+ dprintk(2,
+ KERN_INFO "%s: Initializing videocodec bus...\n",
+ ZR_DEVNAME(zr));
+@@ -1495,17 +1408,13 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ 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));
++ dprintk(1, KERN_ERR "%s: %s - no codec found\n",
++ ZR_DEVNAME(zr), __func__);
+ 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));
++ dprintk(1, KERN_ERR "%s: %s - wrong codec\n",
++ ZR_DEVNAME(zr), __func__);
+ goto zr_detach_codec;
+ }
+ }
+@@ -1515,17 +1424,13 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ 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));
++ dprintk(1, KERN_ERR "%s: %s - no VFE found\n",
++ ZR_DEVNAME(zr), __func__);
+ 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));
++ dprintk(1, KERN_ERR "%s: %s = wrong VFE\n",
++ ZR_DEVNAME(zr), __func__);
+ goto zr_detach_vfe;
+ }
+ }
+@@ -1533,8 +1438,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+ /* take care of Natoma chipset and a revision 1 zr36057 */
+ if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
+ zr->jpg_buffers.need_contiguous = 1;
+- dprintk(1,
+- KERN_INFO
++ dprintk(1, KERN_INFO
+ "%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
+ ZR_DEVNAME(zr));
+ }
+@@ -1544,8 +1448,6 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
+
+ zoran_proc_init(zr);
+
+- pci_set_drvdata(pdev, zr);
+-
+ return 0;
+
+ zr_detach_vfe:
+@@ -1563,6 +1465,8 @@ zr_free_irq:
+ free_irq(zr->pci_dev->irq, zr);
+ zr_unmap:
+ iounmap(zr->zr36057_mem);
++zr_unreg:
++ v4l2_device_unregister(&zr->v4l2_dev);
+ zr_free_mem:
+ kfree(zr);
+
+@@ -1613,9 +1517,6 @@ static int __init zoran_init(void)
+ ZORAN_NAME, vidmem);
+ }
+
+- /* random nonsense */
+- dprintk(6, KERN_DEBUG "Jotti is een held!\n");
+-
+ /* some mainboards might not do PCI-PCI data transfer well */
+ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
+ dprintk(1,
+diff --git a/drivers/media/video/zoran/zoran_card.h b/drivers/media/video/zoran/zoran_card.h
+index 4507bdc..4936fea 100644
+--- a/drivers/media/video/zoran/zoran_card.h
++++ b/drivers/media/video/zoran/zoran_card.h
+@@ -44,7 +44,8 @@ extern int zr36067_debug;
+ extern struct video_device zoran_template;
+
+ extern int zoran_check_jpg_settings(struct zoran *zr,
+- struct zoran_jpg_settings *settings);
++ struct zoran_jpg_settings *settings,
++ int try);
+ extern void zoran_open_init_params(struct zoran *zr);
+ extern void zoran_vdev_release(struct video_device *vdev);
+
+diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c
+index 5d948ff..e0223de 100644
+--- a/drivers/media/video/zoran/zoran_device.c
++++ b/drivers/media/video/zoran/zoran_device.c
+@@ -36,13 +36,12 @@
+ #include <linux/proc_fs.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-algo-bit.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-common.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 <linux/wait.h>
+
+@@ -312,9 +311,9 @@ zr36057_adjust_vfe (struct zoran *zr,
+ case BUZ_MODE_MOTION_COMPRESS:
+ case BUZ_MODE_IDLE:
+ default:
+- if (zr->norm == VIDEO_MODE_NTSC ||
++ if ((zr->norm & V4L2_STD_NTSC) ||
+ (zr->card.type == LML33R10 &&
+- zr->norm == VIDEO_MODE_PAL))
++ (zr->norm & V4L2_STD_PAL)))
+ btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+ else
+ btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+@@ -355,14 +354,6 @@ zr36057_set_vfe (struct zoran *zr,
+ 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) {
+@@ -426,7 +417,7 @@ zr36057_set_vfe (struct zoran *zr,
+ * 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)
++ if (!(zr->norm & V4L2_STD_NTSC))
+ reg |= ZR36057_VFESPFR_ExtFl; // NEEDED!!!!!!! Wolfgang
+ reg |= ZR36057_VFESPFR_TopField;
+ if (HorDcm >= 48) {
+@@ -497,11 +488,11 @@ zr36057_overlay (struct zoran *zr,
+ * All error messages are internal driver checking only! */
+
+ /* video display top and bottom registers */
+- reg = (long) zr->buffer.base +
++ reg = (long) zr->vbuf_base +
+ zr->overlay_settings.x *
+ ((zr->overlay_settings.format->depth + 7) / 8) +
+ zr->overlay_settings.y *
+- zr->buffer.bytesperline;
++ zr->vbuf_bytesperline;
+ btwrite(reg, ZR36057_VDTR);
+ if (reg & 3)
+ dprintk(1,
+@@ -509,15 +500,15 @@ zr36057_overlay (struct zoran *zr,
+ "%s: zr36057_overlay() - video_address not aligned\n",
+ ZR_DEVNAME(zr));
+ if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2)
+- reg += zr->buffer.bytesperline;
++ reg += zr->vbuf_bytesperline;
+ btwrite(reg, ZR36057_VDBR);
+
+ /* video stride, status, and frame grab register */
+- reg = zr->buffer.bytesperline -
++ reg = zr->vbuf_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;
++ reg += zr->vbuf_bytesperline;
+ if (reg & 3)
+ dprintk(1,
+ KERN_ERR
+@@ -544,12 +535,8 @@ zr36057_overlay (struct zoran *zr,
+ * 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)
++void write_overlay_mask(struct zoran_fh *fh, struct v4l2_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;
+@@ -563,10 +550,10 @@ write_overlay_mask (struct file *file,
+
+ 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;
++ x = vp[i].c.left;
++ y = vp[i].c.top;
++ width = vp[i].c.width;
++ height = vp[i].c.height;
+
+ /* trim clips that extend beyond the window */
+ if (x < 0) {
+@@ -981,11 +968,10 @@ void
+ zr36057_enable_jpg (struct zoran *zr,
+ enum zoran_codec_mode mode)
+ {
+- static int zero;
+- static int one = 1;
+ struct vfe_settings cap;
+ int field_size =
+ zr->jpg_buffers.buffer_size / zr->jpg_settings.field_per_buff;
++ struct v4l2_routing route = { 0, 0 };
+
+ zr->codec_mode = mode;
+
+@@ -1007,8 +993,9 @@ zr36057_enable_jpg (struct zoran *zr,
+ * 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);
++ decoder_call(zr, video, s_stream, 1);
++ route.input = 0;
++ encoder_call(zr, video, s_routing, &route);
+
+ /* Take the JPEG codec and the VFE out of sleep */
+ jpeg_codec_sleep(zr, 0);
+@@ -1054,9 +1041,10 @@ zr36057_enable_jpg (struct zoran *zr,
+ /* 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);
++ decoder_call(zr, video, s_stream, 0);
+ set_videobus_dir(zr, 1);
+- encoder_command(zr, ENCODER_SET_INPUT, &one);
++ route.input = 1;
++ encoder_call(zr, video, s_routing, &route);
+
+ /* Take the JPEG codec and the VFE out of sleep */
+ jpeg_codec_sleep(zr, 0);
+@@ -1100,8 +1088,9 @@ zr36057_enable_jpg (struct zoran *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);
++ decoder_call(zr, video, s_stream, 1);
++ route.input = 0;
++ encoder_call(zr, video, s_routing, &route);
+
+ dprintk(2, KERN_INFO "%s: enable_jpg(IDLE)\n", ZR_DEVNAME(zr));
+ break;
+@@ -1132,7 +1121,7 @@ zoran_feed_stat_com (struct zoran *zr)
+ if (!(zr->stat_com[i] & cpu_to_le32(1)))
+ break;
+ zr->stat_com[i] =
+- cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
++ cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
+ } else {
+ /* fill 2 stat_com entries */
+ i = ((zr->jpg_dma_head -
+@@ -1140,9 +1129,9 @@ zoran_feed_stat_com (struct zoran *zr)
+ if (!(zr->stat_com[i] & cpu_to_le32(1)))
+ break;
+ zr->stat_com[i] =
+- cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
++ cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
+ zr->stat_com[i + 1] =
+- cpu_to_le32(zr->jpg_buffers.buffer[frame].frag_tab_bus);
++ cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus);
+ }
+ zr->jpg_buffers.buffer[frame].state = BUZ_STATE_DMA;
+ zr->jpg_dma_head++;
+@@ -1162,7 +1151,7 @@ zoran_reap_stat_com (struct zoran *zr)
+ u32 stat_com;
+ unsigned int seq;
+ unsigned int dif;
+- struct zoran_jpg_buffer *buffer;
++ struct zoran_buffer *buffer;
+ int frame;
+
+ /* In motion decompress we don't have a hardware frame counter,
+@@ -1208,22 +1197,52 @@ zoran_reap_stat_com (struct zoran *zr)
+ }
+ }
+
++static void zoran_restart(struct zoran *zr)
++{
++ /* Now the stat_comm buffer is ready for restart */
++ int status = 0, mode;
++
++ if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
++ decoder_call(zr, video, g_input_status, &status);
++ mode = CODEC_DO_COMPRESSION;
++ } else {
++ status = V4L2_IN_ST_NO_SIGNAL;
++ mode = CODEC_DO_EXPANSION;
++ }
++ if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
++ !(status & V4L2_IN_ST_NO_SIGNAL)) {
++ /********** 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 ***********/
++ }
++}
++
+ static void
+ error_handler (struct zoran *zr,
+ u32 astat,
+ u32 stat)
+ {
++ int i, j;
++
+ /* 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);
++ if (zr->codec_mode != BUZ_MODE_MOTION_COMPRESS &&
++ zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS) {
+ 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) {
++ 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);
+@@ -1232,142 +1251,95 @@ error_handler (struct zoran *zr,
+ 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 (zr36067_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 (le32_to_cpu(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] |= cpu_to_le32(1);
+- if (zr->jpg_settings.TmpDcm != 1)
+- zr->stat_com[i + 1] |= cpu_to_le32(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;
+- __le32 bus_addr[BUZ_NUM_STAT_COM];
+-
+- /* Here we are copying the stat_com array, which
+- * is already in little endian format, so
+- * no endian conversions here
+- */
+- 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];
++ if (zr->JPEG_error == 1) {
++ zoran_restart(zr);
++ return;
++ }
+
+- }
+- zr->jpg_err_shift += i;
+- zr->jpg_err_shift &= BUZ_MASK_STAT_COM;
++ /*
++ * 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 (zr36067_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(KERN_INFO "stat_com frames:");
++ for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
++ for (i = 0; i < zr->jpg_buffers.num_buffers; i++) {
++ if (le32_to_cpu(zr->stat_com[j]) == zr->jpg_buffers.buffer[i].jpg.frag_tab_bus)
++ printk(KERN_CONT "% d->%d", j, i);
+ }
+- if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
+- zr->jpg_err_seq = zr->jpg_seq_num; /* + 1; */
+ }
++ printk(KERN_CONT "\n");
+ }
++ /* Find an entry in stat_com and rotate contents */
++ 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] |= cpu_to_le32(1);
++ if (zr->jpg_settings.TmpDcm != 1)
++ zr->stat_com[i + 1] |= cpu_to_le32(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;
++ __le32 bus_addr[BUZ_NUM_STAT_COM];
++
++ /* Here we are copying the stat_com array, which
++ * is already in little endian format, so
++ * no endian conversions here
++ */
++ memcpy(bus_addr, zr->stat_com, sizeof(bus_addr));
+
+- /* 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));
++ for (j = 0; j < BUZ_NUM_STAT_COM; j++)
++ zr->stat_com[j] = bus_addr[(i + j) & BUZ_MASK_STAT_COM];
+
+- zr->JPEG_missed = 0;
+- zr->JPEG_error = 2;
+- /********** End RESTART code ***********/
+- }
+- } while (0);
++ 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; */
++ zoran_restart(zr);
+ }
+
+ irqreturn_t
+@@ -1425,10 +1397,8 @@ zoran_irq (int irq,
+ * We simply ignore them */
+
+ if (zr->v4l_memgrab_active) {
+-
+ /* A lot more checks should be here ... */
+- if ((btread(ZR36057_VSSFGR) &
+- ZR36057_VSSFGR_SnapShot) == 0)
++ if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0)
+ dprintk(1,
+ KERN_WARNING
+ "%s: BuzIRQ with SnapShot off ???\n",
+@@ -1436,10 +1406,7 @@ zoran_irq (int irq,
+
+ 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) {
++ 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;
+@@ -1457,9 +1424,7 @@ zoran_irq (int irq,
+
+ 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];
++ int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME];
+ u32 reg;
+
+ zr->v4l_grab_frame = frame;
+@@ -1468,27 +1433,17 @@ zoran_irq (int irq,
+
+ /* Buffer address */
+
+- reg =
+- zr->v4l_buffers.buffer[frame].
+- fbuffer_bus;
++ reg = zr->v4l_buffers.buffer[frame].v4l.fbuffer_bus;
+ btwrite(reg, ZR36057_VDTR);
+- if (zr->v4l_settings.height >
+- BUZ_MAX_HEIGHT / 2)
+- reg +=
+- zr->v4l_settings.
+- bytesperline;
++ 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);
++ 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;
+@@ -1506,77 +1461,66 @@ zoran_irq (int irq,
+ #if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
+ if (astat & ZR36057_ISR_CodRepIRQ) {
+ zr->intr_counter_CodRepIRQ++;
+- IDEBUG(printk
+- (KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n",
++ 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 (zr36067_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 (le32_to_cpu(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 ((astat & ZR36057_ISR_JPEGRepIRQ) &&
++ (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
++ zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) {
++ if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) {
++ char sc[] = "0000";
++ char sv[5];
++ int i;
++
++ 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);
++
++ strcpy(sv, sc);
++ for (i = 0; i < 4; i++) {
++ if (le32_to_cpu(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 {
++ /* Get statistics */
++ if (zr->JPEG_missed > zr->JPEG_max_missed)
++ zr->JPEG_max_missed = zr->JPEG_missed;
++ if (zr->JPEG_missed < zr->JPEG_min_missed)
++ zr->JPEG_min_missed = zr->JPEG_missed;
++ }
+
+- if (zr36067_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",
+- le32_to_cpu(zr->stat_com[i]));
+- }
+- printk("\n");
++ if (zr36067_debug > 2 && zr->frame_num < 6) {
++ int i;
++
++ printk(KERN_INFO "%s: seq=%ld stat_com:",
++ ZR_DEVNAME(zr), zr->jpg_seq_num);
++ for (i = 0; i < 4; i++) {
++ printk(KERN_CONT " %08x",
++ le32_to_cpu(zr->stat_com[i]));
+ }
+- 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));
+- }*/
++ printk(KERN_CONT "\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);
+ }
+ #endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
+
+@@ -1585,8 +1529,7 @@ zoran_irq (int irq,
+ 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)))) {
++ (zr->frame_num & (zr->JPEG_missed > zr->jpg_settings.field_per_buff)))) {
+ error_handler(zr, astat, stat);
+ }
+
+@@ -1628,7 +1571,7 @@ zoran_set_pci_master (struct zoran *zr,
+ void
+ zoran_init_hardware (struct zoran *zr)
+ {
+- int j, zero = 0;
++ struct v4l2_routing route = { 0, 0 };
+
+ /* Enable bus-mastering */
+ zoran_set_pci_master(zr, 1);
+@@ -1638,15 +1581,16 @@ zoran_init_hardware (struct zoran *zr)
+ zr->card.init(zr);
+ }
+
+- j = zr->card.input[zr->input].muxsel;
++ route.input = 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);
++ decoder_call(zr, core, init, 0);
++ decoder_call(zr, tuner, s_std, zr->norm);
++ decoder_call(zr, video, s_routing, &route);
+
+- encoder_command(zr, 0, NULL);
+- encoder_command(zr, ENCODER_SET_NORM, &zr->norm);
+- encoder_command(zr, ENCODER_SET_INPUT, &zero);
++ encoder_call(zr, core, init, 0);
++ encoder_call(zr, video, s_std_output, zr->norm);
++ route.input = 0;
++ encoder_call(zr, video, s_routing, &route);
+
+ /* toggle JPEG codec sleep to sync PLL */
+ jpeg_codec_sleep(zr, 1);
+@@ -1706,42 +1650,3 @@ zr36057_init_vfe (struct zoran *zr)
+ 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 || cmd == DECODER_SET_INPUT)) {
+- int res;
+-
+- // Bt819 needs to reset its FIFO buffer using #FRST pin and
+- // LML33 card uses GPIO(7) for that.
+- GPIO(zr, 7, 0);
+- res = zr->decoder->driver->command(zr->decoder, cmd, data);
+- // Pull #FRST high.
+- GPIO(zr, 7, 1);
+- return res;
+- } else
+- return zr->decoder->driver->command(zr->decoder, cmd,
+- data);
+-}
+-
+-int
+-encoder_command (struct zoran *zr,
+- int cmd,
+- void *data)
+-{
+- if (zr->encoder == NULL)
+- return -1;
+-
+- return zr->encoder->driver->command(zr->encoder, cmd, data);
+-}
+diff --git a/drivers/media/video/zoran/zoran_device.h b/drivers/media/video/zoran/zoran_device.h
+index 74c6c8e..07f2c23 100644
+--- a/drivers/media/video/zoran/zoran_device.h
++++ b/drivers/media/video/zoran/zoran_device.h
+@@ -54,8 +54,8 @@ 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,
++extern void write_overlay_mask(struct zoran_fh *fh,
++ struct v4l2_clip *vp,
+ int count);
+ extern void zr36057_set_memgrab(struct zoran *zr,
+ int mode);
+@@ -87,11 +87,9 @@ extern int jpg_bufsize;
+ extern int pass_through;
+
+ /* i2c */
+-extern int decoder_command(struct zoran *zr,
+- int cmd,
+- void *data);
+-extern int encoder_command(struct zoran *zr,
+- int cmd,
+- void *data);
++#define decoder_call(zr, o, f, args...) \
++ v4l2_subdev_call(zr->decoder, o, f, ##args)
++#define encoder_call(zr, o, f, args...) \
++ v4l2_subdev_call(zr->encoder, o, f, ##args)
+
+ #endif /* __ZORAN_DEVICE_H__ */
+diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
+index 120ef23..f16e57c 100644
+--- a/drivers/media/video/zoran/zoran_driver.c
++++ b/drivers/media/video/zoran/zoran_driver.c
+@@ -58,16 +58,6 @@
+ #include <linux/i2c-algo-bit.h>
+
+ #include <linux/spinlock.h>
+-#define MAP_NR(x) virt_to_page(x)
+-#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 <media/v4l2-common.h>
+@@ -79,36 +69,17 @@
+ #include <asm/uaccess.h>
+ #include <linux/proc_fs.h>
+
+-#include <linux/video_decoder.h>
+-#include <linux/video_encoder.h>
+ #include <linux/mutex.h>
+ #include "zoran.h"
+ #include "zoran_device.h"
+ #include "zoran_card.h"
+
+- /* 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 \
+- )
+-
+-
+-#if defined(CONFIG_VIDEO_V4L1_COMPAT)
+-#define ZFMT(pal, fcc, cs) \
+- .palette = (pal), .fourcc = (fcc), .colorspace = (cs)
+-#else
+-#define ZFMT(pal, fcc, cs) \
+- .fourcc = (fcc), .colorspace = (cs)
+-#endif
+
+ const struct zoran_format zoran_formats[] = {
+ {
+ .name = "15-bit RGB LE",
+- ZFMT(VIDEO_PALETTE_RGB555,
+- V4L2_PIX_FMT_RGB555, V4L2_COLORSPACE_SRGB),
++ .fourcc = V4L2_PIX_FMT_RGB555,
++ .colorspace = V4L2_COLORSPACE_SRGB,
+ .depth = 15,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+@@ -116,16 +87,16 @@ const struct zoran_format zoran_formats[] = {
+ ZR36057_VFESPFR_LittleEndian,
+ }, {
+ .name = "15-bit RGB BE",
+- ZFMT(-1,
+- V4L2_PIX_FMT_RGB555X, V4L2_COLORSPACE_SRGB),
++ .fourcc = V4L2_PIX_FMT_RGB555X,
++ .colorspace = V4L2_COLORSPACE_SRGB,
+ .depth = 15,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif,
+ }, {
+ .name = "16-bit RGB LE",
+- ZFMT(VIDEO_PALETTE_RGB565,
+- V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
++ .fourcc = V4L2_PIX_FMT_RGB565,
++ .colorspace = V4L2_COLORSPACE_SRGB,
+ .depth = 16,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+@@ -133,56 +104,56 @@ const struct zoran_format zoran_formats[] = {
+ ZR36057_VFESPFR_LittleEndian,
+ }, {
+ .name = "16-bit RGB BE",
+- ZFMT(-1,
+- V4L2_PIX_FMT_RGB565X, V4L2_COLORSPACE_SRGB),
++ .fourcc = V4L2_PIX_FMT_RGB565X,
++ .colorspace = V4L2_COLORSPACE_SRGB,
+ .depth = 16,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif,
+ }, {
+ .name = "24-bit RGB",
+- ZFMT(VIDEO_PALETTE_RGB24,
+- V4L2_PIX_FMT_BGR24, V4L2_COLORSPACE_SRGB),
++ .fourcc = V4L2_PIX_FMT_BGR24,
++ .colorspace = V4L2_COLORSPACE_SRGB,
+ .depth = 24,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24,
+ }, {
+ .name = "32-bit RGB LE",
+- ZFMT(VIDEO_PALETTE_RGB32,
+- V4L2_PIX_FMT_BGR32, V4L2_COLORSPACE_SRGB),
++ .fourcc = V4L2_PIX_FMT_BGR32,
++ .colorspace = V4L2_COLORSPACE_SRGB,
+ .depth = 32,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian,
+ }, {
+ .name = "32-bit RGB BE",
+- ZFMT(-1,
+- V4L2_PIX_FMT_RGB32, V4L2_COLORSPACE_SRGB),
++ .fourcc = V4L2_PIX_FMT_RGB32,
++ .colorspace = V4L2_COLORSPACE_SRGB,
+ .depth = 32,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB888,
+ }, {
+ .name = "4:2:2, packed, YUYV",
+- ZFMT(VIDEO_PALETTE_YUV422,
+- V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_SMPTE170M),
++ .fourcc = V4L2_PIX_FMT_YUYV,
++ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ .depth = 16,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_YUV422,
+ }, {
+ .name = "4:2:2, packed, UYVY",
+- ZFMT(VIDEO_PALETTE_UYVY,
+- V4L2_PIX_FMT_UYVY, V4L2_COLORSPACE_SMPTE170M),
++ .fourcc = V4L2_PIX_FMT_UYVY,
++ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ .depth = 16,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian,
+ }, {
+ .name = "Hardware-encoded Motion-JPEG",
+- ZFMT(-1,
+- V4L2_PIX_FMT_MJPEG, V4L2_COLORSPACE_SMPTE170M),
++ .fourcc = V4L2_PIX_FMT_MJPEG,
++ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ .depth = 0,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_PLAYBACK |
+@@ -191,13 +162,6 @@ const struct zoran_format zoran_formats[] = {
+ };
+ #define NUM_FORMATS ARRAY_SIZE(zoran_formats)
+
+-// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
+-
+-
+-static int lock_norm; /* 0 = default 1 = Don't change TV standard (norm) */
+-module_param(lock_norm, int, 0644);
+-MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
+-
+ /* small helper function for calculating buffersizes for v4l2
+ * we calculate the nearest higher power-of-two, which
+ * will be the recommended buffersize */
+@@ -222,221 +186,106 @@ zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings)
+ }
+
+ /* forward references */
+-static void v4l_fbuffer_free(struct file *file);
+-static void jpg_fbuffer_free(struct file *file);
++static void v4l_fbuffer_free(struct zoran_fh *fh);
++static void jpg_fbuffer_free(struct zoran_fh *fh);
++
++/* Set mapping mode */
++static void map_mode_raw(struct zoran_fh *fh)
++{
++ fh->map_mode = ZORAN_MAP_MODE_RAW;
++ fh->buffers.buffer_size = v4l_bufsize;
++ fh->buffers.num_buffers = v4l_nbufs;
++}
++static void map_mode_jpg(struct zoran_fh *fh, int play)
++{
++ fh->map_mode = play ? ZORAN_MAP_MODE_JPG_PLAY : ZORAN_MAP_MODE_JPG_REC;
++ fh->buffers.buffer_size = jpg_bufsize;
++ fh->buffers.num_buffers = jpg_nbufs;
++}
++static inline const char *mode_name(enum zoran_map_mode mode)
++{
++ return mode == ZORAN_MAP_MODE_RAW ? "V4L" : "JPG";
++}
+
+ /*
+ * 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).
+ */
+
+-static unsigned long
+-get_high_mem (unsigned long size)
++static int v4l_fbuffer_alloc(struct zoran_fh *fh)
+ {
+-/*
+- * 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 __iomem *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;
+- writeb(c, mem + i);
+- if (readb(mem + i) != c)
+- break;
+- c = 255 - c;
+- writeb(c, mem + i);
+- if (readb(mem + i) != c)
+- break;
+- writeb(0, mem + i); /* zero out memory */
+-
+- /* give the kernel air to breath */
+- if ((i & 0x3ffff) == 0x3ffff)
+- schedule();
+- }
+-
+- iounmap(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;
+-}
+-
+-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;
+- unsigned long pmem = 0;
+
+- /* 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)
++ for (i = 0; i < fh->buffers.num_buffers; i++) {
++ if (fh->buffers.buffer[i].v4l.fbuffer)
+ dprintk(2,
+ KERN_WARNING
+- "%s: v4l_fbuffer_alloc() - buffer %d allready allocated!?\n",
+- ZR_DEVNAME(zr), i);
++ "%s: %s - buffer %d already allocated!?\n",
++ ZR_DEVNAME(zr), __func__, i);
+
+ //udelay(20);
+- if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
+- /* Use kmalloc */
+-
+- mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
+- if (!mem) {
+- 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 {
+-
+- /* 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 = NULL;
+- 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 = NULL;
+- 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;
+- }
++ mem = kmalloc(fh->buffers.buffer_size,
++ GFP_KERNEL | __GFP_NOWARN);
++ if (!mem) {
++ dprintk(1,
++ KERN_ERR
++ "%s: %s - kmalloc for V4L buf %d failed\n",
++ ZR_DEVNAME(zr), __func__, i);
++ v4l_fbuffer_free(fh);
++ return -ENOBUFS;
+ }
++ fh->buffers.buffer[i].v4l.fbuffer = mem;
++ fh->buffers.buffer[i].v4l.fbuffer_phys = virt_to_phys(mem);
++ fh->buffers.buffer[i].v4l.fbuffer_bus = virt_to_bus(mem);
++ for (off = 0; off < fh->buffers.buffer_size;
++ off += PAGE_SIZE)
++ SetPageReserved(virt_to_page(mem + off));
++ dprintk(4,
++ KERN_INFO
++ "%s: %s - V4L frame %d mem 0x%lx (bus: 0x%llx)\n",
++ ZR_DEVNAME(zr), __func__, i, (unsigned long) mem,
++ (unsigned long long)virt_to_bus(mem));
+ }
+
+- fh->v4l_buffers.allocated = 1;
++ fh->buffers.allocated = 1;
+
+ return 0;
+ }
+
+ /* free the V4L grab buffers */
+-static void
+-v4l_fbuffer_free (struct file *file)
++static void v4l_fbuffer_free(struct zoran_fh *fh)
+ {
+- 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));
++ dprintk(4, KERN_INFO "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+- for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
+- if (!fh->v4l_buffers.buffer[i].fbuffer)
++ for (i = 0; i < fh->buffers.num_buffers; i++) {
++ if (!fh->buffers.buffer[i].v4l.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);
+- }
+- fh->v4l_buffers.buffer[i].fbuffer = NULL;
++ mem = fh->buffers.buffer[i].v4l.fbuffer;
++ for (off = 0; off < fh->buffers.buffer_size;
++ off += PAGE_SIZE)
++ ClearPageReserved(virt_to_page(mem + off));
++ kfree(fh->buffers.buffer[i].v4l.fbuffer);
++ fh->buffers.buffer[i].v4l.fbuffer = NULL;
+ }
+
+- fh->v4l_buffers.allocated = 0;
+- fh->v4l_buffers.ready_to_be_freed = 0;
++ fh->buffers.allocated = 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
+@@ -458,162 +307,128 @@ v4l_fbuffer_free (struct file *file)
+ * and fragment buffers are not little-endian.
+ */
+
+-static int
+-jpg_fbuffer_alloc (struct file *file)
++static int jpg_fbuffer_alloc(struct zoran_fh *fh)
+ {
+- 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);
+- }
++ u8 *mem;
+
+- for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
+- if (fh->jpg_buffers.buffer[i].frag_tab)
++ for (i = 0; i < fh->buffers.num_buffers; i++) {
++ if (fh->buffers.buffer[i].jpg.frag_tab)
+ dprintk(2,
+ KERN_WARNING
+- "%s: jpg_fbuffer_alloc() - buffer %d allready allocated!?\n",
+- ZR_DEVNAME(zr), i);
++ "%s: %s - buffer %d already allocated!?\n",
++ ZR_DEVNAME(zr), __func__, i);
+
+ /* Allocate fragment table for this buffer */
+
+- mem = get_zeroed_page(GFP_KERNEL);
++ mem = (void *)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);
++ "%s: %s - get_zeroed_page (frag_tab) failed for buffer %d\n",
++ ZR_DEVNAME(zr), __func__, i);
++ jpg_fbuffer_free(fh);
+ return -ENOBUFS;
+ }
+- fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) 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) {
++ fh->buffers.buffer[i].jpg.frag_tab = (__le32 *)mem;
++ fh->buffers.buffer[i].jpg.frag_tab_bus = virt_to_bus(mem);
++
++ if (fh->buffers.need_contiguous) {
++ mem = kmalloc(fh->buffers.buffer_size, GFP_KERNEL);
++ if (mem == NULL) {
+ dprintk(1,
+ KERN_ERR
+- "%s: jpg_fbuffer_alloc() - kmalloc failed for buffer %d\n",
+- ZR_DEVNAME(zr), i);
+- jpg_fbuffer_free(file);
++ "%s: %s - kmalloc failed for buffer %d\n",
++ ZR_DEVNAME(zr), __func__, i);
++ jpg_fbuffer_free(fh);
+ return -ENOBUFS;
+ }
+- fh->jpg_buffers.buffer[i].frag_tab[0] =
+- cpu_to_le32(virt_to_bus((void *) mem));
+- fh->jpg_buffers.buffer[i].frag_tab[1] =
+- cpu_to_le32(((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));
++ fh->buffers.buffer[i].jpg.frag_tab[0] =
++ cpu_to_le32(virt_to_bus(mem));
++ fh->buffers.buffer[i].jpg.frag_tab[1] =
++ cpu_to_le32((fh->buffers.buffer_size >> 1) | 1);
++ for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE)
++ SetPageReserved(virt_to_page(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) {
++ /* jpg_bufsize is already page aligned */
++ for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) {
++ mem = (void *)get_zeroed_page(GFP_KERNEL);
++ if (mem == NULL) {
+ dprintk(1,
+ KERN_ERR
+- "%s: jpg_fbuffer_alloc() - get_zeroed_page failed for buffer %d\n",
+- ZR_DEVNAME(zr), i);
+- jpg_fbuffer_free(file);
++ "%s: %s - get_zeroed_page failed for buffer %d\n",
++ ZR_DEVNAME(zr), __func__, i);
++ jpg_fbuffer_free(fh);
+ return -ENOBUFS;
+ }
+
+- fh->jpg_buffers.buffer[i].frag_tab[2 * j] =
+- cpu_to_le32(virt_to_bus((void *) mem));
+- fh->jpg_buffers.buffer[i].frag_tab[2 * j +
+- 1] =
+- cpu_to_le32((PAGE_SIZE / 4) << 1);
+- SetPageReserved(MAP_NR(mem));
++ fh->buffers.buffer[i].jpg.frag_tab[2 * j] =
++ cpu_to_le32(virt_to_bus(mem));
++ fh->buffers.buffer[i].jpg.frag_tab[2 * j + 1] =
++ cpu_to_le32((PAGE_SIZE >> 2) << 1);
++ SetPageReserved(virt_to_page(mem));
+ }
+
+- fh->jpg_buffers.buffer[i].frag_tab[2 * j - 1] |= cpu_to_le32(1);
++ fh->buffers.buffer[i].jpg.frag_tab[2 * j - 1] |= cpu_to_le32(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);
++ KERN_DEBUG "%s: %s - %d KB allocated\n",
++ ZR_DEVNAME(zr), __func__,
++ (fh->buffers.num_buffers * fh->buffers.buffer_size) >> 10);
+
+- fh->jpg_buffers.allocated = 1;
++ fh->buffers.allocated = 1;
+
+ return 0;
+ }
+
+ /* free the MJPEG grab buffers */
+-static void
+-jpg_fbuffer_free (struct file *file)
++static void jpg_fbuffer_free(struct zoran_fh *fh)
+ {
+- struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+ int i, j, off;
+ unsigned char *mem;
++ __le32 frag_tab;
++ struct zoran_buffer *buffer;
+
+- dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_free()\n", ZR_DEVNAME(zr));
++ dprintk(4, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__);
+
+- for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
+- if (!fh->jpg_buffers.buffer[i].frag_tab)
++ for (i = 0, buffer = &fh->buffers.buffer[0];
++ i < fh->buffers.num_buffers; i++, buffer++) {
++ if (!buffer->jpg.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(le32_to_cpu(
+- 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));
++ if (fh->buffers.need_contiguous) {
++ frag_tab = buffer->jpg.frag_tab[0];
++
++ if (frag_tab) {
++ mem = bus_to_virt(le32_to_cpu(frag_tab));
++ for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE)
++ ClearPageReserved(virt_to_page(mem + off));
+ kfree(mem);
+- fh->jpg_buffers.buffer[i].frag_tab[0] = 0;
+- fh->jpg_buffers.buffer[i].frag_tab[1] = 0;
++ buffer->jpg.frag_tab[0] = 0;
++ buffer->jpg.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])
++ for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) {
++ frag_tab = buffer->jpg.frag_tab[2 * j];
++
++ if (!frag_tab)
+ break;
+- ClearPageReserved(MAP_NR
+- (bus_to_virt
+- (le32_to_cpu
+- (fh->jpg_buffers.
+- buffer[i].frag_tab[2 *
+- j]))));
+- free_page((unsigned long)
+- bus_to_virt
+- (le32_to_cpu
+- (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;
++ ClearPageReserved(virt_to_page(bus_to_virt(le32_to_cpu(frag_tab))));
++ free_page((unsigned long)bus_to_virt(le32_to_cpu(frag_tab)));
++ buffer->jpg.frag_tab[2 * j] = 0;
++ buffer->jpg.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;
++ free_page((unsigned long)buffer->jpg.frag_tab);
++ buffer->jpg.frag_tab = NULL;
+ }
+
+- fh->jpg_buffers.allocated = 0;
+- fh->jpg_buffers.ready_to_be_freed = 0;
++ fh->buffers.allocated = 0;
+ }
+
+ /*
+@@ -621,12 +436,11 @@ jpg_fbuffer_free (struct file *file)
+ */
+
+ static int
+-zoran_v4l_set_format (struct file *file,
++zoran_v4l_set_format (struct zoran_fh *fh,
+ int width,
+ int height,
+ const struct zoran_format *format)
+ {
+- struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+ int bpp;
+
+@@ -636,19 +450,19 @@ zoran_v4l_set_format (struct file *file,
+ 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);
++ "%s: %s - wrong frame size (%dx%d)\n",
++ ZR_DEVNAME(zr), __func__, width, height);
+ return -EINVAL;
+ }
+
+ bpp = (format->depth + 7) / 8;
+
+ /* Check against available buffer size */
+- if (height * width * bpp > fh->v4l_buffers.buffer_size) {
++ if (height * width * bpp > fh->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);
++ "%s: %s - video buffer size (%d kB) is too small\n",
++ ZR_DEVNAME(zr), __func__, fh->buffers.buffer_size >> 10);
+ return -EINVAL;
+ }
+
+@@ -657,8 +471,8 @@ zoran_v4l_set_format (struct file *file,
+ if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) {
+ dprintk(1,
+ KERN_ERR
+- "%s: v4l_set_format() - wrong frame alingment\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - wrong frame alignment\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+
+@@ -670,43 +484,40 @@ zoran_v4l_set_format (struct file *file,
+ return 0;
+ }
+
+-static int
+-zoran_v4l_queue_frame (struct file *file,
+- int num)
++static int zoran_v4l_queue_frame(struct zoran_fh *fh, 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) {
++ if (!fh->buffers.allocated) {
+ dprintk(1,
+ KERN_ERR
+- "%s: v4l_queue_frame() - buffers not yet allocated\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - buffers not yet allocated\n",
++ ZR_DEVNAME(zr), __func__);
+ res = -ENOMEM;
+ }
+
+ /* No grabbing outside the buffer range! */
+- if (num >= fh->v4l_buffers.num_buffers || num < 0) {
++ if (num >= fh->buffers.num_buffers || num < 0) {
+ dprintk(1,
+ KERN_ERR
+- "%s: v4l_queue_frame() - buffer %d is out of range\n",
+- ZR_DEVNAME(zr), num);
++ "%s: %s - buffer %d is out of range\n",
++ ZR_DEVNAME(zr), __func__, num);
+ res = -EINVAL;
+ }
+
+ spin_lock_irqsave(&zr->spinlock, flags);
+
+- if (fh->v4l_buffers.active == ZORAN_FREE) {
++ if (fh->buffers.active == ZORAN_FREE) {
+ if (zr->v4l_buffers.active == ZORAN_FREE) {
+- zr->v4l_buffers = fh->v4l_buffers;
+- fh->v4l_buffers.active = ZORAN_ACTIVE;
++ zr->v4l_buffers = fh->buffers;
++ fh->buffers.active = ZORAN_ACTIVE;
+ } else {
+ dprintk(1,
+ KERN_ERR
+- "%s: v4l_queue_frame() - another session is already capturing\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - another session is already capturing\n",
++ ZR_DEVNAME(zr), __func__);
+ res = -EBUSY;
+ }
+ }
+@@ -717,7 +528,7 @@ zoran_v4l_queue_frame (struct file *file,
+ default:
+ case BUZ_STATE_PEND:
+ if (zr->v4l_buffers.active == ZORAN_FREE) {
+- fh->v4l_buffers.active = ZORAN_FREE;
++ fh->buffers.active = ZORAN_FREE;
+ zr->v4l_buffers.allocated = 0;
+ }
+ res = -EBUSY; /* what are you doing? */
+@@ -725,19 +536,17 @@ zoran_v4l_queue_frame (struct file *file,
+ case BUZ_STATE_DONE:
+ dprintk(2,
+ KERN_WARNING
+- "%s: v4l_queue_frame() - queueing buffer %d in state DONE!?\n",
+- ZR_DEVNAME(zr), num);
++ "%s: %s - queueing buffer %d in state DONE!?\n",
++ ZR_DEVNAME(zr), __func__, 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_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];
++ fh->buffers.buffer[num] = zr->v4l_buffers.buffer[num];
+ break;
+ }
+ }
+@@ -745,65 +554,7 @@ zoran_v4l_queue_frame (struct file *file,
+ 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 < 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 == 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));
++ zr->v4l_buffers.active = fh->buffers.active;
+
+ return res;
+ }
+@@ -812,27 +563,24 @@ v4l_grab (struct file *file,
+ * Sync on a V4L buffer
+ */
+
+-static int
+-v4l_sync (struct file *file,
+- int frame)
++static int v4l_sync(struct zoran_fh *fh, int frame)
+ {
+- struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+ unsigned long flags;
+
+- if (fh->v4l_buffers.active == ZORAN_FREE) {
++ if (fh->buffers.active == ZORAN_FREE) {
+ dprintk(1,
+ KERN_ERR
+- "%s: v4l_sync() - no grab active for this session\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - no grab active for this session\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+
+ /* check passed-in frame number */
+- if (frame >= fh->v4l_buffers.num_buffers || frame < 0) {
++ if (frame >= fh->buffers.num_buffers || frame < 0) {
+ dprintk(1,
+- KERN_ERR "%s: v4l_sync() - frame %d is invalid\n",
+- ZR_DEVNAME(zr), frame);
++ KERN_ERR "%s: %s - frame %d is invalid\n",
++ ZR_DEVNAME(zr), __func__, frame);
+ return -EINVAL;
+ }
+
+@@ -840,15 +588,14 @@ v4l_sync (struct file *file,
+ 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));
++ "%s: %s - attempt to sync on a buffer which was not queued?\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EPROTO;
+ }
+
+ /* wait on this buffer to get ready */
+ if (!wait_event_interruptible_timeout(zr->v4l_capq,
+- (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND),
+- 10*HZ))
++ (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), 10*HZ))
+ return -ETIME;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+@@ -856,11 +603,11 @@ v4l_sync (struct file *file,
+ /* 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));
++ KERN_ERR "%s: %s - internal state error\n",
++ ZR_DEVNAME(zr), __func__);
+
+ zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER;
+- fh->v4l_buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
++ fh->buffers.buffer[frame] = zr->v4l_buffers.buffer[frame];
+
+ spin_lock_irqsave(&zr->spinlock, flags);
+
+@@ -868,8 +615,7 @@ v4l_sync (struct file *file,
+ 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;
++ fh->buffers.active = zr->v4l_buffers.active = ZORAN_FREE;
+ zr->v4l_buffers.allocated = 0;
+ }
+ }
+@@ -883,31 +629,28 @@ v4l_sync (struct file *file,
+ * Queue a MJPEG buffer for capture/playback
+ */
+
+-static int
+-zoran_jpg_queue_frame (struct file *file,
+- int num,
+- enum zoran_codec_mode mode)
++static int zoran_jpg_queue_frame(struct zoran_fh *fh, 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) {
++ if (!fh->buffers.allocated) {
+ dprintk(1,
+ KERN_ERR
+- "%s: jpg_queue_frame() - buffers not yet allocated\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - buffers not yet allocated\n",
++ ZR_DEVNAME(zr), __func__);
+ return -ENOMEM;
+ }
+
+ /* No grabbing outside the buffer range! */
+- if (num >= fh->jpg_buffers.num_buffers || num < 0) {
++ if (num >= fh->buffers.num_buffers || num < 0) {
+ dprintk(1,
+ KERN_ERR
+- "%s: jpg_queue_frame() - buffer %d out of range\n",
+- ZR_DEVNAME(zr), num);
++ "%s: %s - buffer %d out of range\n",
++ ZR_DEVNAME(zr), __func__, num);
+ return -EINVAL;
+ }
+
+@@ -918,20 +661,20 @@ zoran_jpg_queue_frame (struct file *file,
+ /* wrong codec mode active - invalid */
+ dprintk(1,
+ KERN_ERR
+- "%s: jpg_queue_frame() - codec in wrong mode\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - codec in wrong mode\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+
+- if (fh->jpg_buffers.active == ZORAN_FREE) {
++ if (fh->buffers.active == ZORAN_FREE) {
+ if (zr->jpg_buffers.active == ZORAN_FREE) {
+- zr->jpg_buffers = fh->jpg_buffers;
+- fh->jpg_buffers.active = ZORAN_ACTIVE;
++ zr->jpg_buffers = fh->buffers;
++ fh->buffers.active = ZORAN_ACTIVE;
+ } else {
+ dprintk(1,
+ KERN_ERR
+- "%s: jpg_queue_frame() - another session is already capturing\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - another session is already capturing\n",
++ ZR_DEVNAME(zr), __func__);
+ res = -EBUSY;
+ }
+ }
+@@ -948,23 +691,21 @@ zoran_jpg_queue_frame (struct file *file,
+ case BUZ_STATE_DONE:
+ dprintk(2,
+ KERN_WARNING
+- "%s: jpg_queue_frame() - queing frame in BUZ_STATE_DONE state!?\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - queing frame in BUZ_STATE_DONE state!?\n",
++ ZR_DEVNAME(zr), __func__);
+ 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_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];
++ fh->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;
++ fh->buffers.active = ZORAN_FREE;
+ zr->jpg_buffers.allocated = 0;
+ }
+ res = -EBUSY; /* what are you doing? */
+@@ -974,47 +715,41 @@ zoran_jpg_queue_frame (struct file *file,
+
+ spin_unlock_irqrestore(&zr->spinlock, flags);
+
+- if (!res && zr->jpg_buffers.active == ZORAN_FREE) {
+- zr->jpg_buffers.active = fh->jpg_buffers.active;
+- }
++ if (!res && zr->jpg_buffers.active == ZORAN_FREE)
++ zr->jpg_buffers.active = fh->buffers.active;
+
+ return res;
+ }
+
+-static int
+-jpg_qbuf (struct file *file,
+- int frame,
+- enum zoran_codec_mode mode)
++static int jpg_qbuf(struct zoran_fh *fh, 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) {
++ if (fh->buffers.active == ZORAN_FREE) {
+ dprintk(1,
+ KERN_ERR
+- "%s: jpg_qbuf(-1) - session not active\n",
+- ZR_DEVNAME(zr));
++ "%s: %s(-1) - session not active\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+- fh->jpg_buffers.active = zr->jpg_buffers.active =
+- ZORAN_FREE;
++ fh->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));
++ "%s: %s - stop streaming but not in streaming mode\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+ }
+
+- if ((res = zoran_jpg_queue_frame(file, frame, mode)))
++ if ((res = zoran_jpg_queue_frame(fh, frame, mode)))
+ return res;
+
+ /* Start the jpeg codec when the first frame is queued */
+@@ -1028,28 +763,25 @@ jpg_qbuf (struct file *file,
+ * Sync on a MJPEG buffer
+ */
+
+-static int
+-jpg_sync (struct file *file,
+- struct zoran_sync *bs)
++static int jpg_sync(struct zoran_fh *fh, struct zoran_sync *bs)
+ {
+- struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+ unsigned long flags;
+ int frame;
+
+- if (fh->jpg_buffers.active == ZORAN_FREE) {
++ if (fh->buffers.active == ZORAN_FREE) {
+ dprintk(1,
+ KERN_ERR
+- "%s: jpg_sync() - capture is not currently active\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - capture is not currently active\n",
++ ZR_DEVNAME(zr), __func__);
+ 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));
++ "%s: %s - codec not in streaming mode\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+ if (!wait_event_interruptible_timeout(zr->jpg_capq,
+@@ -1064,8 +796,8 @@ jpg_sync (struct file *file,
+ sizeof(isr), &isr);
+ dprintk(1,
+ KERN_ERR
+- "%s: jpg_sync() - timeout: codec isr=0x%02x\n",
+- ZR_DEVNAME(zr), isr);
++ "%s: %s - timeout: codec isr=0x%02x\n",
++ ZR_DEVNAME(zr), __func__, isr);
+
+ return -ETIME;
+
+@@ -1083,28 +815,26 @@ jpg_sync (struct file *file,
+ /* buffer should now be in BUZ_STATE_DONE */
+ if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
+ dprintk(2,
+- KERN_ERR "%s: jpg_sync() - internal state error\n",
+- ZR_DEVNAME(zr));
++ KERN_ERR "%s: %s - internal state error\n",
++ ZR_DEVNAME(zr), __func__);
+
+ *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];
++ fh->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)
++static void zoran_open_init_session(struct zoran_fh *fh)
+ {
+ 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;
++ map_mode_raw(fh);
+
+ /* take over the card's current settings */
+ fh->overlay_settings = zr->overlay_settings;
+@@ -1114,40 +844,21 @@ zoran_open_init_session (struct file *file)
+
+ /* 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;
++ /* buffers */
++ memset(&fh->buffers, 0, sizeof(fh->buffers));
++ for (i = 0; i < MAX_FRAME; i++) {
++ fh->buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */
++ fh->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;
++ fh->buffers.allocated = 0;
++ fh->buffers.active = ZORAN_FREE;
+ }
+
+-static void
+-zoran_close_end_session (struct file *file)
++static void zoran_close_end_session(struct zoran_fh *fh)
+ {
+- struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+
+ /* overlay */
+@@ -1159,36 +870,32 @@ zoran_close_end_session (struct file *file)
+ zr->overlay_mask = NULL;
+ }
+
+- /* v4l capture */
+- if (fh->v4l_buffers.active != ZORAN_FREE) {
+- unsigned long flags;
++ if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
++ /* v4l capture */
++ if (fh->buffers.active != ZORAN_FREE) {
++ unsigned long flags;
+
+- spin_lock_irqsave(&zr->spinlock, flags);
+- zr36057_set_memgrab(zr, 0);
+- zr->v4l_buffers.allocated = 0;
+- zr->v4l_buffers.active = fh->v4l_buffers.active =
+- ZORAN_FREE;
+- spin_unlock_irqrestore(&zr->spinlock, flags);
+- }
+-
+- /* v4l buffers */
+- if (fh->v4l_buffers.allocated ||
+- fh->v4l_buffers.ready_to_be_freed) {
+- v4l_fbuffer_free(file);
+- }
++ spin_lock_irqsave(&zr->spinlock, flags);
++ zr36057_set_memgrab(zr, 0);
++ zr->v4l_buffers.allocated = 0;
++ zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
++ spin_unlock_irqrestore(&zr->spinlock, flags);
++ }
+
+- /* 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;
+- }
++ /* v4l buffers */
++ if (fh->buffers.allocated)
++ v4l_fbuffer_free(fh);
++ } else {
++ /* jpg capture */
++ if (fh->buffers.active != ZORAN_FREE) {
++ zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
++ zr->jpg_buffers.allocated = 0;
++ zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE;
++ }
+
+- /* jpg buffers */
+- if (fh->jpg_buffers.allocated ||
+- fh->jpg_buffers.ready_to_be_freed) {
+- jpg_fbuffer_free(file);
++ /* jpg buffers */
++ if (fh->buffers.allocated)
++ jpg_fbuffer_free(fh);
+ }
+ }
+
+@@ -1202,15 +909,11 @@ static int zoran_open(struct file *file)
+ struct zoran_fh *fh;
+ int res, first_open = 0;
+
+- dprintk(2, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n",
+- ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user + 1);
++ dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(-)=%d\n",
++ ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user + 1);
+
+ lock_kernel();
+
+- /* see fs/device.c - the kernel already locks during open(),
+- * so locking ourselves only causes deadlocks */
+- /*mutex_lock(&zr->resource_lock);*/
+-
+ if (zr->user >= 2048) {
+ dprintk(1, KERN_ERR "%s: too many users (%d) on device\n",
+ ZR_DEVNAME(zr), zr->user);
+@@ -1218,41 +921,15 @@ static int zoran_open(struct file *file)
+ goto fail_unlock;
+ }
+
+- if (!zr->decoder) {
+- dprintk(1,
+- KERN_ERR "%s: no TV decoder loaded for device!\n",
+- ZR_DEVNAME(zr));
+- res = -EIO;
+- goto fail_unlock;
+- }
+-
+- if (!try_module_get(zr->decoder->driver->driver.owner)) {
+- dprintk(1,
+- KERN_ERR
+- "%s: failed to grab ownership of video decoder\n",
+- ZR_DEVNAME(zr));
+- res = -EIO;
+- goto fail_unlock;
+- }
+- if (zr->encoder &&
+- !try_module_get(zr->encoder->driver->driver.owner)) {
+- dprintk(1,
+- KERN_ERR
+- "%s: failed to grab ownership of video encoder\n",
+- ZR_DEVNAME(zr));
+- res = -EIO;
+- goto fail_decoder;
+- }
+-
+ /* now, create the open()-specific file_ops struct */
+ fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL);
+ if (!fh) {
+ dprintk(1,
+ KERN_ERR
+- "%s: zoran_open() - allocation of zoran_fh failed\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - allocation of zoran_fh failed\n",
++ ZR_DEVNAME(zr), __func__);
+ res = -ENOMEM;
+- goto fail_encoder;
++ goto fail_unlock;
+ }
+ /* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows
+ * on norm-change! */
+@@ -1261,8 +938,8 @@ static int zoran_open(struct file *file)
+ if (!fh->overlay_mask) {
+ dprintk(1,
+ KERN_ERR
+- "%s: zoran_open() - allocation of overlay_mask failed\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - allocation of overlay_mask failed\n",
++ ZR_DEVNAME(zr), __func__);
+ res = -ENOMEM;
+ goto fail_fh;
+ }
+@@ -1284,18 +961,13 @@ static int zoran_open(struct file *file)
+ /* set file_ops stuff */
+ file->private_data = fh;
+ fh->zr = zr;
+- zoran_open_init_session(file);
++ zoran_open_init_session(fh);
+ unlock_kernel();
+
+ return 0;
+
+ fail_fh:
+ kfree(fh);
+-fail_encoder:
+- if (zr->encoder)
+- module_put(zr->encoder->driver->driver.owner);
+-fail_decoder:
+- module_put(zr->decoder->driver->driver.owner);
+ fail_unlock:
+ unlock_kernel();
+
+@@ -1311,14 +983,14 @@ zoran_close(struct file *file)
+ struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+
+- dprintk(2, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n",
+- ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user - 1);
++ dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(+)=%d\n",
++ ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user - 1);
+
+ /* kernel locks (fs/device.c), so don't do that ourselves
+ * (prevents deadlocks) */
+ /*mutex_lock(&zr->resource_lock);*/
+
+- zoran_close_end_session(file);
++ zoran_close_end_session(fh);
+
+ if (zr->user-- == 1) { /* Last process */
+ /* Clean up JPEG process */
+@@ -1346,9 +1018,10 @@ zoran_close(struct file *file)
+ 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);
++ struct v4l2_routing route = { 2, 0 };
++
++ decoder_call(zr, video, s_stream, 0);
++ encoder_call(zr, video, s_routing, &route);
+ }
+ }
+
+@@ -1356,14 +1029,7 @@ zoran_close(struct file *file)
+ kfree(fh->overlay_mask);
+ kfree(fh);
+
+- /* release locks on the i2c modules */
+- module_put(zr->decoder->driver->driver.owner);
+- if (zr->encoder)
+- module_put(zr->encoder->driver->driver.owner);
+-
+- /*mutex_unlock(&zr->resource_lock);*/
+-
+- dprintk(4, KERN_INFO "%s: zoran_close() done\n", ZR_DEVNAME(zr));
++ dprintk(4, KERN_INFO "%s: %s done\n", ZR_DEVNAME(zr), __func__);
+
+ return 0;
+ }
+@@ -1391,15 +1057,13 @@ zoran_write (struct file *file,
+ return -EINVAL;
+ }
+
+-static int
+-setup_fbuffer (struct file *file,
++static int setup_fbuffer(struct zoran_fh *fh,
+ 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 */
+@@ -1427,8 +1091,8 @@ setup_fbuffer (struct file *file,
+ * 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));
++ "%s: %s - forced overlay turnoff because framebuffer changed\n",
++ ZR_DEVNAME(zr), __func__);
+ zr36057_overlay(zr, 0);
+ }
+ #endif
+@@ -1436,31 +1100,31 @@ setup_fbuffer (struct file *file,
+ if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) {
+ dprintk(1,
+ KERN_ERR
+- "%s: setup_fbuffer() - no valid overlay format given\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - no valid overlay format given\n",
++ ZR_DEVNAME(zr), __func__);
+ 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);
++ "%s: %s - invalid height/width/bpl value (%d|%d|%d)\n",
++ ZR_DEVNAME(zr), __func__, 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);
++ "%s: %s - bytesperline (%d) must be 4-byte aligned\n",
++ ZR_DEVNAME(zr), __func__, 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->vbuf_base = (void *) ((unsigned long) base & ~3);
++ zr->vbuf_height = height;
++ zr->vbuf_width = width;
++ zr->vbuf_depth = fmt->depth;
+ zr->overlay_settings.format = fmt;
+- zr->buffer.bytesperline = bytesperline;
++ zr->vbuf_bytesperline = bytesperline;
+
+ /* The user should set new window parameters */
+ zr->overlay_settings.is_set = 0;
+@@ -1469,35 +1133,27 @@ setup_fbuffer (struct file *file,
+ }
+
+
+-static int
+-setup_window (struct file *file,
+- int x,
+- int y,
+- int width,
+- int height,
+- struct video_clip __user *clips,
+- int clipcount,
+- void __user *bitmap)
++static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height,
++ struct v4l2_clip __user *clips, int clipcount, void __user *bitmap)
+ {
+- struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+- struct video_clip *vcp = NULL;
++ struct v4l2_clip *vcp = NULL;
+ int on, end;
+
+
+- if (!zr->buffer.base) {
++ if (!zr->vbuf_base) {
+ dprintk(1,
+ KERN_ERR
+- "%s: setup_window() - frame buffer has to be set first\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - frame buffer has to be set first\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+
+ if (!fh->overlay_settings.format) {
+ dprintk(1,
+ KERN_ERR
+- "%s: setup_window() - no overlay format set\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - no overlay format set\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+
+@@ -1505,13 +1161,13 @@ setup_window (struct file *file,
+ * 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) {
++ if (zr->vbuf_depth == 15 || zr->vbuf_depth == 16) {
+ end = (x + width) & ~1; /* round down */
+ x = (x + 1) & ~1; /* round up */
+ width = end - x;
+ }
+
+- if (zr->buffer.depth == 24) {
++ if (zr->vbuf_depth == 24) {
+ end = (x + width) & ~3; /* round down */
+ x = (x + 3) & ~3; /* round up */
+ width = end - x;
+@@ -1527,8 +1183,8 @@ setup_window (struct file *file,
+ 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);
++ "%s: %s - width = %d or height = %d invalid\n",
++ ZR_DEVNAME(zr), __func__, width, height);
+ return -EINVAL;
+ }
+
+@@ -1566,20 +1222,20 @@ setup_window (struct file *file,
+ }
+ } else if (clipcount > 0) {
+ /* write our own bitmap from the clips */
+- vcp = vmalloc(sizeof(struct video_clip) * (clipcount + 4));
++ vcp = vmalloc(sizeof(struct v4l2_clip) * (clipcount + 4));
+ if (vcp == NULL) {
+ dprintk(1,
+ KERN_ERR
+- "%s: setup_window() - Alloc of clip mask failed\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - Alloc of clip mask failed\n",
++ ZR_DEVNAME(zr), __func__);
+ return -ENOMEM;
+ }
+ if (copy_from_user
+- (vcp, clips, sizeof(struct video_clip) * clipcount)) {
++ (vcp, clips, sizeof(struct v4l2_clip) * clipcount)) {
+ vfree(vcp);
+ return -EFAULT;
+ }
+- write_overlay_mask(file, vcp, clipcount);
++ write_overlay_mask(fh, vcp, clipcount);
+ vfree(vcp);
+ }
+
+@@ -1595,11 +1251,8 @@ setup_window (struct file *file,
+ return wait_grab_pending(zr);
+ }
+
+-static int
+-setup_overlay (struct file *file,
+- int on)
++static int setup_overlay(struct zoran_fh *fh, int on)
+ {
+- struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+
+ /* If there is nothing to do, return immediatly */
+@@ -1612,16 +1265,16 @@ setup_overlay (struct file *file,
+ fh->overlay_active == ZORAN_FREE) {
+ dprintk(1,
+ KERN_ERR
+- "%s: setup_overlay() - overlay is already active for another session\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - overlay is already active for another session\n",
++ ZR_DEVNAME(zr), __func__);
+ 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));
++ "%s: %s - you cannot cancel someone else's session\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EPERM;
+ }
+
+@@ -1634,18 +1287,18 @@ setup_overlay (struct file *file,
+ zr36057_overlay(zr, 0);
+ zr->overlay_mask = NULL;
+ } else {
+- if (!zr->buffer.base || !fh->overlay_settings.is_set) {
++ if (!zr->vbuf_base || !fh->overlay_settings.is_set) {
+ dprintk(1,
+ KERN_ERR
+- "%s: setup_overlay() - buffer or window not set\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - buffer or window not set\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+ if (!fh->overlay_settings.format) {
+ dprintk(1,
+ KERN_ERR
+- "%s: setup_overlay() - no overlay format set\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - no overlay format set\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+ zr->overlay_active = fh->overlay_active = ZORAN_LOCKED;
+@@ -1662,41 +1315,47 @@ setup_overlay (struct file *file,
+ return wait_grab_pending(zr);
+ }
+
+- /* 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)
++/* get the status of a buffer in the clients buffer queue */
++static int zoran_v4l2_buffer_status(struct zoran_fh *fh,
++ struct v4l2_buffer *buf, int num)
+ {
+- struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
++ unsigned long flags;
+
+ 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) {
++ if (num < 0 || num >= fh->buffers.num_buffers ||
++ !fh->buffers.allocated) {
+ dprintk(1,
+ KERN_ERR
+- "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - wrong number or buffers not allocated\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+
++ spin_lock_irqsave(&zr->spinlock, flags);
++ dprintk(3,
++ KERN_DEBUG
++ "%s: %s() - raw active=%c, buffer %d: state=%c, map=%c\n",
++ ZR_DEVNAME(zr), __func__,
++ "FAL"[fh->buffers.active], num,
++ "UPMD"[zr->v4l_buffers.buffer[num].state],
++ fh->buffers.buffer[num].map ? 'Y' : 'N');
++ spin_unlock_irqrestore(&zr->spinlock, flags);
++
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- buf->length = fh->v4l_buffers.buffer_size;
++ buf->length = fh->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->bytesused = fh->buffers.buffer[num].bs.length;
++ if (fh->buffers.buffer[num].state == BUZ_STATE_DONE ||
++ fh->buffers.buffer[num].state == BUZ_STATE_USER) {
++ buf->sequence = fh->buffers.buffer[num].bs.seq;
+ buf->flags |= V4L2_BUF_FLAG_DONE;
+- buf->timestamp =
+- fh->v4l_buffers.buffer[num].bs.timestamp;
++ buf->timestamp = fh->buffers.buffer[num].bs.timestamp;
+ } else {
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ }
+@@ -1712,28 +1371,26 @@ zoran_v4l2_buffer_status (struct file *file,
+ case ZORAN_MAP_MODE_JPG_PLAY:
+
+ /* check range */
+- if (num < 0 || num >= fh->jpg_buffers.num_buffers ||
+- !fh->jpg_buffers.allocated) {
++ if (num < 0 || num >= fh->buffers.num_buffers ||
++ !fh->buffers.allocated) {
+ dprintk(1,
+ KERN_ERR
+- "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - wrong number or buffers not allocated\n",
++ ZR_DEVNAME(zr), __func__);
+ 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;
++ buf->length = fh->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;
++ if (fh->buffers.buffer[num].state == BUZ_STATE_DONE ||
++ fh->buffers.buffer[num].state == BUZ_STATE_USER) {
++ buf->sequence = fh->buffers.buffer[num].bs.seq;
++ buf->timestamp = fh->buffers.buffer[num].bs.timestamp;
++ buf->bytesused = fh->buffers.buffer[num].bs.length;
+ buf->flags |= V4L2_BUF_FLAG_DONE;
+ } else {
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+@@ -1741,14 +1398,11 @@ zoran_v4l2_buffer_status (struct file *file,
+
+ /* which fields are these? */
+ if (fh->jpg_settings.TmpDcm != 1)
+- buf->field =
+- fh->jpg_settings.
+- odd_even ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
++ 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;
++ buf->field = fh->jpg_settings.odd_even ?
++ V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT;
+
+ break;
+
+@@ -1756,8 +1410,8 @@ zoran_v4l2_buffer_status (struct file *file,
+
+ dprintk(5,
+ KERN_ERR
+- "%s: v4l2_buffer_status() - invalid buffer type|map_mode (%d|%d)\n",
+- ZR_DEVNAME(zr), buf->type, fh->map_mode);
++ "%s: %s - invalid buffer type|map_mode (%d|%d)\n",
++ ZR_DEVNAME(zr), __func__, buf->type, fh->map_mode);
+ return -EINVAL;
+ }
+
+@@ -1770,81 +1424,55 @@ zoran_v4l2_buffer_status (struct file *file,
+
+ static int
+ zoran_set_norm (struct zoran *zr,
+- int norm) /* VIDEO_MODE_* */
++ v4l2_std_id norm)
+ {
+- int norm_encoder, on;
++ int 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));
++ "%s: %s called while in playback/capture mode\n",
++ ZR_DEVNAME(zr), __func__);
+ 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])) {
++ if (!(norm & zr->card.norms)) {
+ dprintk(1,
+- KERN_ERR "%s: set_norm() - unsupported norm %d\n",
+- ZR_DEVNAME(zr), norm);
++ KERN_ERR "%s: %s - unsupported norm %llx\n",
++ ZR_DEVNAME(zr), __func__, norm);
+ return -EINVAL;
+ }
+
+- if (norm == VIDEO_MODE_AUTO) {
+- int status;
++ if (norm == V4L2_STD_ALL) {
++ int status = 0;
++ v4l2_std_id std = 0;
+
+- /* 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);
++ decoder_call(zr, video, querystd, &std);
++ decoder_call(zr, tuner, s_std, std);
+
+ /* let changes come into effect */
+ ssleep(2);
+
+- decoder_command(zr, DECODER_GET_STATUS, &status);
+- if (!(status & DECODER_STATUS_GOOD)) {
++ decoder_call(zr, video, g_input_status, &status);
++ if (status & V4L2_IN_ST_NO_SIGNAL) {
+ dprintk(1,
+ KERN_ERR
+- "%s: set_norm() - no norm detected\n",
+- ZR_DEVNAME(zr));
++ "%s: %s - no norm detected\n",
++ ZR_DEVNAME(zr), __func__);
+ /* reset norm */
+- decoder_command(zr, DECODER_SET_NORM, &zr->norm);
++ decoder_call(zr, tuner, s_std, 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;
++ norm = std;
+ }
+- zr->timing = zr->card.tvn[norm];
+- norm_encoder = norm;
++ if (norm & V4L2_STD_SECAM)
++ zr->timing = zr->card.tvn[2];
++ else if (norm & V4L2_STD_NTSC)
++ zr->timing = zr->card.tvn[1];
++ else
++ zr->timing = zr->card.tvn[0];
+
+ /* We switch overlay off and on since a change in the
+ * norm needs different VFE settings */
+@@ -1852,8 +1480,8 @@ zoran_set_norm (struct zoran *zr,
+ if (on)
+ zr36057_overlay(zr, 0);
+
+- decoder_command(zr, DECODER_SET_NORM, &norm);
+- encoder_command(zr, ENCODER_SET_NORM, &norm_encoder);
++ decoder_call(zr, tuner, s_std, norm);
++ encoder_call(zr, video, s_std_output, norm);
+
+ if (on)
+ zr36057_overlay(zr, 1);
+@@ -1868,7 +1496,7 @@ static int
+ zoran_set_input (struct zoran *zr,
+ int input)
+ {
+- int realinput;
++ struct v4l2_routing route = { 0, 0 };
+
+ if (input == zr->input) {
+ return 0;
+@@ -1878,23 +1506,23 @@ zoran_set_input (struct zoran *zr,
+ zr->jpg_buffers.active != ZORAN_FREE) {
+ dprintk(1,
+ KERN_WARNING
+- "%s: set_input() called while in playback/capture mode\n",
+- ZR_DEVNAME(zr));
++ "%s: %s called while in playback/capture mode\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EBUSY;
+ }
+
+ if (input < 0 || input >= zr->card.inputs) {
+ dprintk(1,
+ KERN_ERR
+- "%s: set_input() - unnsupported input %d\n",
+- ZR_DEVNAME(zr), input);
++ "%s: %s - unnsupported input %d\n",
++ ZR_DEVNAME(zr), __func__, input);
+ return -EINVAL;
+ }
+
+- realinput = zr->card.input[input].muxsel;
++ route.input = zr->card.input[input].muxsel;
+ zr->input = input;
+
+- decoder_command(zr, DECODER_SET_INPUT, &realinput);
++ decoder_call(zr, video, s_routing, &route);
+
+ return 0;
+ }
+@@ -1903,410 +1531,14 @@ zoran_set_input (struct zoran *zr,
+ * ioctl routine
+ */
+
+-static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++static long zoran_default(struct file *file, void *__fh, int cmd, void *arg)
+ {
+- struct zoran_fh *fh = file->private_data;
++ struct zoran_fh *fh = __fh;
+ struct zoran *zr = fh->zr;
+- /* CAREFUL: used in multiple places here */
+ struct zoran_jpg_settings settings;
+
+- /* 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 (mutex_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);
+-
+- mutex_unlock(&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)-1);
+- vcap->type = ZORAN_VID_TYPE;
+-
+- vcap->channels = zr->card.inputs;
+- vcap->audios = 0;
+- mutex_lock(&zr->resource_lock);
+- vcap->maxwidth = BUZ_MAX_WIDTH;
+- vcap->maxheight = BUZ_MAX_HEIGHT;
+- vcap->minwidth = BUZ_MIN_WIDTH;
+- vcap->minheight = BUZ_MIN_HEIGHT;
+- mutex_unlock(&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;
+- mutex_lock(&zr->resource_lock);
+- vchan->norm = zr->norm;
+- mutex_unlock(&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);
+-
+- mutex_lock(&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:
+- mutex_unlock(&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));
+- mutex_lock(&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;
+- }
+- mutex_unlock(&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 < 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 == NUM_FORMATS) {
+- dprintk(1,
+- KERN_ERR
+- "%s: VIDIOCSPICT - Invalid palette %d\n",
+- ZR_DEVNAME(zr), vpict->palette);
+- return -EINVAL;
+- }
+-
+- mutex_lock(&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];
+-
+- mutex_unlock(&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);
+-
+- mutex_lock(&zr->resource_lock);
+- res = setup_overlay(file, *on);
+- mutex_unlock(&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));
+- mutex_lock(&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;
+- mutex_unlock(&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);
+-
+- mutex_lock(&zr->resource_lock);
+- res =
+- setup_window(file, vwin->x, vwin->y, vwin->width,
+- vwin->height, vwin->clips,
+- vwin->clipcount, NULL);
+- mutex_unlock(&zr->resource_lock);
+-
+- return res;
+- }
+- break;
+-
+- case VIDIOCGFBUF:
+- {
+- struct video_buffer *vbuf = arg;
+-
+- dprintk(3, KERN_DEBUG "%s: VIDIOCGFBUF\n", ZR_DEVNAME(zr));
+-
+- mutex_lock(&zr->resource_lock);
+- *vbuf = zr->buffer;
+- mutex_unlock(&zr->resource_lock);
+- return 0;
+- }
+- break;
+-
+- case VIDIOCSFBUF:
+- {
+- struct video_buffer *vbuf = arg;
+- int i, res = 0;
+-
+- dprintk(3,
+- KERN_DEBUG
+- "%s: VIDIOCSFBUF - base=%p, w=%d, h=%d, depth=%d, bpl=%d\n",
+- ZR_DEVNAME(zr), vbuf->base, vbuf->width,
+- vbuf->height, vbuf->depth, vbuf->bytesperline);
+-
+- for (i = 0; i < NUM_FORMATS; i++)
+- if (zoran_formats[i].depth == vbuf->depth)
+- break;
+- if (i == NUM_FORMATS) {
+- dprintk(1,
+- KERN_ERR
+- "%s: VIDIOCSFBUF - invalid fbuf depth %d\n",
+- ZR_DEVNAME(zr), vbuf->depth);
+- return -EINVAL;
+- }
+-
+- mutex_lock(&zr->resource_lock);
+- res =
+- setup_fbuffer(file, vbuf->base, &zoran_formats[i],
+- vbuf->width, vbuf->height,
+- vbuf->bytesperline);
+- mutex_unlock(&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);
+-
+- mutex_lock(&zr->resource_lock);
+- res = v4l_sync(file, *frame);
+- mutex_unlock(&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);
+-
+- mutex_lock(&zr->resource_lock);
+- res = v4l_grab(file, vmap);
+- mutex_unlock(&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;
+- }
+-
+- mutex_lock(&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:
+- mutex_unlock(&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;
+@@ -2319,7 +1551,13 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+
+ mutex_lock(&zr->resource_lock);
+
+- bparams->norm = zr->norm;
++ if (zr->norm & V4L2_STD_NTSC)
++ bparams->norm = VIDEO_MODE_NTSC;
++ else if (zr->norm & V4L2_STD_PAL)
++ bparams->norm = VIDEO_MODE_PAL;
++ else
++ bparams->norm = VIDEO_MODE_SECAM;
++
+ bparams->input = zr->input;
+
+ bparams->decimation = fh->jpg_settings.decimation;
+@@ -2352,7 +1590,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+
+ return 0;
+ }
+- break;
+
+ case BUZIOC_S_PARAMS:
+ {
+@@ -2395,18 +1632,17 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+
+ /* Check the params first before overwriting our
+ * nternal values */
+- if (zoran_check_jpg_settings(zr, &settings)) {
++ if (zoran_check_jpg_settings(zr, &settings, 0)) {
+ res = -EINVAL;
+ goto sparams_unlock_and_return;
+ }
+
+ fh->jpg_settings = settings;
+- sparams_unlock_and_return:
++sparams_unlock_and_return:
+ mutex_unlock(&zr->resource_lock);
+
+ return res;
+ }
+- break;
+
+ case BUZIOC_REQBUFS:
+ {
+@@ -2430,38 +1666,34 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ * 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;
+
+ mutex_lock(&zr->resource_lock);
+
+- if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
++ if (fh->buffers.allocated) {
+ dprintk(1,
+ KERN_ERR
+- "%s: BUZIOC_REQBUFS - buffers allready allocated\n",
++ "%s: BUZIOC_REQBUFS - buffers already 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;
++ /* The next mmap will map the MJPEG buffers - could
++ * also be *_PLAY, but it doesn't matter here */
++ map_mode_jpg(fh, 0);
++ fh->buffers.num_buffers = breq->count;
++ fh->buffers.buffer_size = breq->size;
+
+- if (jpg_fbuffer_alloc(file)) {
++ if (jpg_fbuffer_alloc(fh)) {
+ 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:
++jpgreqbuf_unlock_and_return:
+ mutex_unlock(&zr->resource_lock);
+
+ return res;
+ }
+- break;
+
+ case BUZIOC_QBUF_CAPT:
+ {
+@@ -2471,12 +1703,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ ZR_DEVNAME(zr), *frame);
+
+ mutex_lock(&zr->resource_lock);
+- res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS);
++ res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_COMPRESS);
+ mutex_unlock(&zr->resource_lock);
+
+ return res;
+ }
+- break;
+
+ case BUZIOC_QBUF_PLAY:
+ {
+@@ -2486,12 +1717,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ ZR_DEVNAME(zr), *frame);
+
+ mutex_lock(&zr->resource_lock);
+- res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS);
++ res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_DECOMPRESS);
+ mutex_unlock(&zr->resource_lock);
+
+ return res;
+ }
+- break;
+
+ case BUZIOC_SYNC:
+ {
+@@ -2501,17 +1731,26 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));
+
+ mutex_lock(&zr->resource_lock);
+- res = jpg_sync(file, bsync);
++
++ if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
++ dprintk(2, KERN_WARNING
++ "%s: %s - not in jpg capture mode\n",
++ ZR_DEVNAME(zr), __func__);
++ res = -EINVAL;
++ } else {
++ res = jpg_sync(fh, bsync);
++ }
+ mutex_unlock(&zr->resource_lock);
+
+ return res;
+ }
+- break;
+
+ case BUZIOC_G_STATUS:
+ {
+ struct zoran_status *bstat = arg;
+- int norm, input, status, res = 0;
++ struct v4l2_routing route = { 0, 0 };
++ int status = 0, res = 0;
++ v4l2_std_id norm;
+
+ dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr));
+
+@@ -2523,8 +1762,7 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ return -EINVAL;
+ }
+
+- input = zr->card.input[bstat->input].muxsel;
+- norm = VIDEO_MODE_AUTO;
++ route.input = zr->card.input[bstat->input].muxsel;
+
+ mutex_lock(&zr->resource_lock);
+
+@@ -2537,1629 +1775,1262 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ goto gstat_unlock_and_return;
+ }
+
+- decoder_command(zr, DECODER_SET_INPUT, &input);
+- decoder_command(zr, DECODER_SET_NORM, &norm);
++ decoder_call(zr, video, s_routing, &route);
+
+ /* sleep 1 second */
+ ssleep(1);
+
+ /* Get status of video decoder */
+- decoder_command(zr, DECODER_GET_STATUS, &status);
++ decoder_call(zr, video, querystd, &norm);
++ decoder_call(zr, video, g_input_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:
++ route.input = zr->card.input[zr->input].muxsel;
++ decoder_call(zr, video, s_routing, &route);
++gstat_unlock_and_return:
+ mutex_unlock(&zr->resource_lock);
+
+ if (!res) {
+ bstat->signal =
+- (status & DECODER_STATUS_GOOD) ? 1 : 0;
+- if (status & DECODER_STATUS_NTSC)
++ (status & V4L2_IN_ST_NO_SIGNAL) ? 0 : 1;
++ if (norm & V4L2_STD_NTSC)
+ bstat->norm = VIDEO_MODE_NTSC;
+- else if (status & DECODER_STATUS_SECAM)
++ else if (norm & V4L2_STD_SECAM)
+ bstat->norm = VIDEO_MODE_SECAM;
+ else
+ bstat->norm = VIDEO_MODE_PAL;
+
+ bstat->color =
+- (status & DECODER_STATUS_COLOR) ? 1 : 0;
++ (status & V4L2_IN_ST_NO_COLOR) ? 0 : 1;
+ }
+
+ return res;
+ }
+- break;
+-
+- /* 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)-1);
+- strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
+- snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+- pci_name(zr->pci_dev));
+- cap->version =
+- KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
+- RELEASE_VERSION);
+- cap->capabilities = ZORAN_V4L2_VID_FLAGS;
+-
+- return 0;
++ default:
++ return -EINVAL;
+ }
+- break;
++}
+
+- case VIDIOC_ENUM_FMT:
+- {
+- struct v4l2_fmtdesc *fmt = arg;
+- int index = fmt->index, num = -1, i, flag = 0, type =
+- fmt->type;
++static int zoran_vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *vmbuf)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int i, res = 0;
+
+- 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;
+- }
++ mutex_lock(&zr->resource_lock);
+
+- for (i = 0; i < 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 == NUM_FORMATS)
+- return -EINVAL;
++ if (fh->buffers.allocated) {
++ dprintk(1,
++ KERN_ERR
++ "%s: VIDIOCGMBUF - buffers already allocated\n",
++ ZR_DEVNAME(zr));
++ res = -EINVAL;
++ goto v4l1reqbuf_unlock_and_return;
++ }
+
+- memset(fmt, 0, sizeof(*fmt));
+- fmt->index = index;
+- fmt->type = type;
+- strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
+- fmt->pixelformat = zoran_formats[i].fourcc;
+- if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
+- fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
++ /* The next mmap will map the V4L buffers */
++ map_mode_raw(fh);
+
+- return 0;
++ if (v4l_fbuffer_alloc(fh)) {
++ res = -ENOMEM;
++ goto v4l1reqbuf_unlock_and_return;
+ }
+- 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));
++ vmbuf->size = fh->buffers.num_buffers * fh->buffers.buffer_size;
++ vmbuf->frames = fh->buffers.num_buffers;
++ for (i = 0; i < vmbuf->frames; i++)
++ vmbuf->offsets[i] = i * fh->buffers.buffer_size;
+
+- memset(fmt, 0, sizeof(*fmt));
+- fmt->type = type;
++v4l1reqbuf_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
+
+- switch (fmt->type) {
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
++ return res;
++}
++#endif
+
+- mutex_lock(&zr->resource_lock);
++static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- 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;
++ memset(cap, 0, sizeof(*cap));
++ strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
++ strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
++ snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
++ pci_name(zr->pci_dev));
++ cap->version = KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
++ RELEASE_VERSION);
++ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
++ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY;
++ return 0;
++}
+
+- mutex_unlock(&zr->resource_lock);
++static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag)
++{
++ int num = -1, i;
+
++ for (i = 0; i < 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 == NUM_FORMATS)
++ return -EINVAL;
+
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-
+- mutex_lock(&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_settings.bytesperline *
+- fh->v4l_settings.height;
+- fmt->fmt.pix.pixelformat =
+- fh->v4l_settings.format->fourcc;
+- fmt->fmt.pix.colorspace =
+- fh->v4l_settings.format->colorspace;
+- fmt->fmt.pix.bytesperline =
+- fh->v4l_settings.bytesperline;
+- 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;
+- }
+-
+- mutex_unlock(&zr->resource_lock);
++ strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
++ fmt->pixelformat = zoran_formats[i].fourcc;
++ if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
++ fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
++ return 0;
++}
+
+- break;
++static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh,
++ struct v4l2_fmtdesc *f)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- default:
+- dprintk(1,
+- KERN_ERR
+- "%s: VIDIOC_G_FMT - unsupported type %d\n",
+- ZR_DEVNAME(zr), fmt->type);
+- return -EINVAL;
+- }
+- return 0;
+- }
+- break;
++ return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE);
++}
+
+- case VIDIOC_S_FMT:
+- {
+- struct v4l2_format *fmt = arg;
+- int i, res = 0;
+- __le32 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);
+- mutex_lock(&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 __user *)
+- fmt->fmt.win.clips,
+- fmt->fmt.win.clipcount,
+- fmt->fmt.win.bitmap);
+- mutex_unlock(&zr->resource_lock);
+- return res;
+- break;
++static int zoran_enum_fmt_vid_out(struct file *file, void *__fh,
++ struct v4l2_fmtdesc *f)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- 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);
+-
+- /* 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;
+- }
++ return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK);
++}
+
+- if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
+- mutex_lock(&zr->resource_lock);
++static int zoran_enum_fmt_vid_overlay(struct file *file, void *__fh,
++ struct v4l2_fmtdesc *f)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- settings = fh->jpg_settings;
++ return zoran_enum_fmt(zr, f, ZORAN_FORMAT_OVERLAY);
++}
+
+- 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;
+- }
++static int zoran_g_fmt_vid_out(struct file *file, void *__fh,
++ struct v4l2_format *fmt)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- /* 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.bytesperline = 0;
+- fmt->fmt.pix.sizeimage =
+- fh->jpg_buffers.buffer_size;
+- fmt->fmt.pix.colorspace =
+- V4L2_COLORSPACE_SMPTE170M;
+-
+- /* 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:
+- mutex_unlock(&zr->resource_lock);
+- } else {
+- for (i = 0; i < NUM_FORMATS; i++)
+- if (fmt->fmt.pix.pixelformat ==
+- zoran_formats[i].fourcc)
+- break;
+- if (i == 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;
+- }
+- mutex_lock(&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.bytesperline =
+- fh->v4l_settings.bytesperline;
+- fmt->fmt.pix.sizeimage =
+- fh->v4l_settings.height *
+- fh->v4l_settings.bytesperline;
+- fmt->fmt.pix.colorspace =
+- fh->v4l_settings.format->colorspace;
+- 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:
+- mutex_unlock(&zr->resource_lock);
+- }
++ mutex_lock(&zr->resource_lock);
+
+- break;
++ fmt->fmt.pix.width = fh->jpg_settings.img_width / fh->jpg_settings.HorDcm;
++ fmt->fmt.pix.height = fh->jpg_settings.img_height * 2 /
++ (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_TB : 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;
+
+- default:
+- dprintk(1,
+- KERN_ERR
+- "%s: VIDIOC_S_FMT - unsupported type %d\n",
+- ZR_DEVNAME(zr), fmt->type);
+- return -EINVAL;
+- }
++ mutex_unlock(&zr->resource_lock);
++ return 0;
++}
+
+- return res;
+- }
+- break;
++static int zoran_g_fmt_vid_cap(struct file *file, void *__fh,
++ struct v4l2_format *fmt)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- case VIDIOC_G_FBUF:
+- {
+- struct v4l2_framebuffer *fb = arg;
++ if (fh->map_mode != ZORAN_MAP_MODE_RAW)
++ return zoran_g_fmt_vid_out(file, fh, fmt);
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_G_FBUF\n", ZR_DEVNAME(zr));
++ mutex_lock(&zr->resource_lock);
++ fmt->fmt.pix.width = fh->v4l_settings.width;
++ fmt->fmt.pix.height = fh->v4l_settings.height;
++ fmt->fmt.pix.sizeimage = fh->v4l_settings.bytesperline *
++ fh->v4l_settings.height;
++ fmt->fmt.pix.pixelformat = fh->v4l_settings.format->fourcc;
++ fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace;
++ fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline;
++ if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2))
++ fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
++ else
++ fmt->fmt.pix.field = V4L2_FIELD_TOP;
++ mutex_unlock(&zr->resource_lock);
++ return 0;
++}
+
+- memset(fb, 0, sizeof(*fb));
+- mutex_lock(&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;
+- mutex_unlock(&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;
++static int zoran_g_fmt_vid_overlay(struct file *file, void *__fh,
++ struct v4l2_format *fmt)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- return 0;
+- }
+- break;
++ mutex_lock(&zr->resource_lock);
+
+- case VIDIOC_S_FBUF:
+- {
+- int i, res = 0;
+- struct v4l2_framebuffer *fb = arg;
+- __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
++ 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;
+
+- 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);
++ mutex_unlock(&zr->resource_lock);
++ return 0;
++}
+
+- for (i = 0; i < NUM_FORMATS; i++)
+- if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
+- break;
+- if (i == 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;
+- }
++static int zoran_try_fmt_vid_overlay(struct file *file, void *__fh,
++ struct v4l2_format *fmt)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- mutex_lock(&zr->resource_lock);
+- res =
+- setup_fbuffer(file, fb->base, &zoran_formats[i],
+- fb->fmt.width, fb->fmt.height,
+- fb->fmt.bytesperline);
+- mutex_unlock(&zr->resource_lock);
++ mutex_lock(&zr->resource_lock);
+
+- return res;
+- }
+- break;
++ 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;
+
+- case VIDIOC_OVERLAY:
+- {
+- int *on = arg, res;
++ mutex_unlock(&zr->resource_lock);
++ return 0;
++}
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_PREVIEW - on=%d\n",
+- ZR_DEVNAME(zr), *on);
++static int zoran_try_fmt_vid_out(struct file *file, void *__fh,
++ struct v4l2_format *fmt)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ struct zoran_jpg_settings settings;
++ int res = 0;
+
+- mutex_lock(&zr->resource_lock);
+- res = setup_overlay(file, *on);
+- mutex_unlock(&zr->resource_lock);
++ if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
++ return -EINVAL;
+
+- return res;
+- }
+- break;
++ mutex_lock(&zr->resource_lock);
++ settings = fh->jpg_settings;
+
+- case VIDIOC_REQBUFS:
+- {
+- struct v4l2_requestbuffers *req = arg;
+- int res = 0;
++ /* 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;
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_REQBUFS - type=%d\n",
+- ZR_DEVNAME(zr), req->type);
++ if (settings.HorDcm > 1) {
++ settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
++ settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
++ } else {
++ settings.img_x = 0;
++ settings.img_width = BUZ_MAX_WIDTH;
++ }
++
++ /* check */
++ res = zoran_check_jpg_settings(zr, &settings, 1);
++ if (res)
++ 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);
+
+- 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;
+- }
++ fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings);
++ fmt->fmt.pix.bytesperline = 0;
++ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
++tryfmt_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
++ return res;
++}
+
+- mutex_lock(&zr->resource_lock);
++static int zoran_try_fmt_vid_cap(struct file *file, void *__fh,
++ struct v4l2_format *fmt)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int bpp;
++ int i;
+
+- 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 (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
++ return zoran_try_fmt_vid_out(file, fh, fmt);
+
+- if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
+- req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++ mutex_lock(&zr->resource_lock);
+
+- /* 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;
++ for (i = 0; i < NUM_FORMATS; i++)
++ if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat)
++ break;
+
+- if (v4l_fbuffer_alloc(file)) {
+- res = -ENOMEM;
+- goto v4l2reqbuf_unlock_and_return;
+- }
++ if (i == NUM_FORMATS) {
++ mutex_unlock(&zr->resource_lock);
++ return -EINVAL;
++ }
+
+- /* The next mmap will map the V4L buffers */
+- fh->map_mode = ZORAN_MAP_MODE_RAW;
++ bpp = (zoran_formats[i].depth + 7) / 8;
++ fmt->fmt.pix.width &= ~((bpp == 2) ? 1 : 3);
++ 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;
++ mutex_unlock(&zr->resource_lock);
+
+- } else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
+- fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
++ return 0;
++}
+
+- /* 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);
++static int zoran_s_fmt_vid_overlay(struct file *file, void *__fh,
++ struct v4l2_format *fmt)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res;
++
++ 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);
++ mutex_lock(&zr->resource_lock);
++ res = setup_window(fh, fmt->fmt.win.w.left, fmt->fmt.win.w.top,
++ fmt->fmt.win.w.width, fmt->fmt.win.w.height,
++ (struct v4l2_clip __user *)fmt->fmt.win.clips,
++ fmt->fmt.win.clipcount, fmt->fmt.win.bitmap);
++ mutex_unlock(&zr->resource_lock);
++ return res;
++}
+
+- if (jpg_fbuffer_alloc(file)) {
+- res = -ENOMEM;
+- goto v4l2reqbuf_unlock_and_return;
+- }
++static int zoran_s_fmt_vid_out(struct file *file, void *__fh,
++ struct v4l2_format *fmt)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ __le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat);
++ struct zoran_jpg_settings settings;
++ int res = 0;
+
+- /* 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;
++ 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.pixelformat != V4L2_PIX_FMT_MJPEG)
++ return -EINVAL;
+
+- } 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:
+- mutex_unlock(&zr->resource_lock);
++ mutex_lock(&zr->resource_lock);
+
+- return 0;
++ if (fh->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;
+ }
+- break;
+
+- case VIDIOC_QUERYBUF:
+- {
+- struct v4l2_buffer *buf = arg;
+- __u32 type = buf->type;
+- int index = buf->index, res;
++ settings = fh->jpg_settings;
+
+- 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;
+-
+- mutex_lock(&zr->resource_lock);
+- res = zoran_v4l2_buffer_status(file, buf, buf->index);
+- mutex_unlock(&zr->resource_lock);
++ /* 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;
+
+- return res;
++ if (settings.HorDcm > 1) {
++ settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0;
++ settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH;
++ } else {
++ settings.img_x = 0;
++ settings.img_width = BUZ_MAX_WIDTH;
+ }
+- break;
+
+- case VIDIOC_QBUF:
+- {
+- struct v4l2_buffer *buf = arg;
+- int res = 0, codec_mode, buf_type;
++ /* check */
++ res = zoran_check_jpg_settings(zr, &settings, 0);
++ if (res)
++ goto sfmtjpg_unlock_and_return;
+
+- dprintk(3,
+- KERN_DEBUG "%s: VIDIOC_QBUF - type=%d, index=%d\n",
+- ZR_DEVNAME(zr), buf->type, buf->index);
++ /* it's ok, so set them */
++ fh->jpg_settings = settings;
+
+- mutex_lock(&zr->resource_lock);
++ map_mode_jpg(fh, fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
++ fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+
+- 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;
+- }
++ /* 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.bytesperline = 0;
++ fmt->fmt.pix.sizeimage = fh->buffers.buffer_size;
++ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+- 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;
++sfmtjpg_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
++ return res;
++}
+
+- 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;
+- }
++static int zoran_s_fmt_vid_cap(struct file *file, void *__fh,
++ struct v4l2_format *fmt)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int i;
++ int res = 0;
+
+- 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;
+- }
++ if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
++ return zoran_s_fmt_vid_out(file, fh, fmt);
+
+- 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);
+- }
++ for (i = 0; i < NUM_FORMATS; i++)
++ if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc)
+ 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:
+- mutex_unlock(&zr->resource_lock);
+-
+- return res;
++ if (i == NUM_FORMATS) {
++ dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x\n",
++ ZR_DEVNAME(zr), fmt->fmt.pix.pixelformat);
++ return -EINVAL;
+ }
+- 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);
+-
+- mutex_lock(&zr->resource_lock);
++ mutex_lock(&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;
+- }
++ if ((fh->map_mode != ZORAN_MAP_MODE_RAW && fh->buffers.allocated) ||
++ fh->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;
++
++ map_mode_raw(fh);
++
++ res = zoran_v4l_set_format(fh, fmt->fmt.pix.width, fmt->fmt.pix.height,
++ &zoran_formats[i]);
++ if (res)
++ goto sfmtv4l_unlock_and_return;
++
++ /* tell the user the results/missing stuff */
++ fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline;
++ fmt->fmt.pix.sizeimage = fh->v4l_settings.height * fh->v4l_settings.bytesperline;
++ fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace;
++ if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2))
++ fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
++ else
++ fmt->fmt.pix.field = V4L2_FIELD_TOP;
+
+- 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;
++sfmtv4l_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
++ return res;
++}
+
+- case ZORAN_MAP_MODE_JPG_REC:
+- case ZORAN_MAP_MODE_JPG_PLAY:
+- {
+- struct zoran_sync bs;
++static int zoran_g_fbuf(struct file *file, void *__fh,
++ struct v4l2_framebuffer *fb)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY)
+- buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+- else
+- buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ memset(fb, 0, sizeof(*fb));
++ mutex_lock(&zr->resource_lock);
++ fb->base = zr->vbuf_base;
++ fb->fmt.width = zr->vbuf_width;
++ fb->fmt.height = zr->vbuf_height;
++ if (zr->overlay_settings.format)
++ fb->fmt.pixelformat = fh->overlay_settings.format->fourcc;
++ fb->fmt.bytesperline = zr->vbuf_bytesperline;
++ mutex_unlock(&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;
+
+- 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;
+- }
++ return 0;
++}
+
+- num =
+- zr->jpg_pend[zr->
+- jpg_que_tail & BUZ_MASK_FRAME];
++static int zoran_s_fbuf(struct file *file, void *__fh,
++ struct v4l2_framebuffer *fb)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int i, res = 0;
++ __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
+
+- 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);
++ for (i = 0; i < NUM_FORMATS; i++)
++ if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
+ 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:
+- mutex_unlock(&zr->resource_lock);
+-
+- return res;
++ if (i == 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;
+ }
+- break;
+
+- case VIDIOC_STREAMON:
+- {
+- int res = 0;
++ mutex_lock(&zr->resource_lock);
++ res = setup_fbuffer(fh, fb->base, &zoran_formats[i], fb->fmt.width,
++ fb->fmt.height, fb->fmt.bytesperline);
++ mutex_unlock(&zr->resource_lock);
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMON\n", ZR_DEVNAME(zr));
++ return res;
++}
+
+- mutex_lock(&zr->resource_lock);
++static int zoran_overlay(struct file *file, void *__fh, unsigned int on)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res;
+
+- 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;
+- }
++ mutex_lock(&zr->resource_lock);
++ res = setup_overlay(fh, on);
++ mutex_unlock(&zr->resource_lock);
+
+- zr->v4l_buffers.active = fh->v4l_buffers.active =
+- ZORAN_LOCKED;
+- zr->v4l_settings = fh->v4l_settings;
++ return res;
++}
+
+- 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;
++static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type);
+
+- 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;
+- }
++static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *req)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res = 0;
+
+- zr->jpg_buffers.active = fh->jpg_buffers.active =
+- ZORAN_LOCKED;
++ if (req->memory != V4L2_MEMORY_MMAP) {
++ dprintk(2,
++ KERN_ERR
++ "%s: only MEMORY_MMAP capture is supported, not %d\n",
++ ZR_DEVNAME(zr), req->memory);
++ return -EINVAL;
++ }
+
+- if (zr->jpg_que_head != zr->jpg_que_tail) {
+- /* Start the jpeg codec when the first frame is queued */
+- jpeg_start(zr);
+- }
++ if (req->count == 0)
++ return zoran_streamoff(file, fh, req->type);
+
+- break;
+- default:
+- dprintk(1,
++ mutex_lock(&zr->resource_lock);
++ if (fh->buffers.allocated) {
++ dprintk(2,
+ 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:
+- mutex_unlock(&zr->resource_lock);
+-
+- return res;
++ "%s: VIDIOC_REQBUFS - buffers already allocated\n",
++ ZR_DEVNAME(zr));
++ res = -EBUSY;
++ goto v4l2reqbuf_unlock_and_return;
+ }
+- break;
+
+- case VIDIOC_STREAMOFF:
+- {
+- int i, res = 0;
++ 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;
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMOFF\n", ZR_DEVNAME(zr));
++ /* The next mmap will map the V4L buffers */
++ map_mode_raw(fh);
++ fh->buffers.num_buffers = req->count;
+
+- mutex_lock(&zr->resource_lock);
++ if (v4l_fbuffer_alloc(fh)) {
++ res = -ENOMEM;
++ goto v4l2reqbuf_unlock_and_return;
++ }
++ } 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;
+
+- 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;
++ /* The next mmap will map the MJPEG buffers */
++ map_mode_jpg(fh, req->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
++ fh->buffers.num_buffers = req->count;
++ fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
+
+- /* unload capture */
+- if (zr->v4l_memgrab_active) {
+- unsigned long flags;
++ if (jpg_fbuffer_alloc(fh)) {
++ res = -ENOMEM;
++ goto v4l2reqbuf_unlock_and_return;
++ }
++ } 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:
++ mutex_unlock(&zr->resource_lock);
+
+- spin_lock_irqsave(&zr->spinlock, flags);
+- zr36057_set_memgrab(zr, 0);
+- spin_unlock_irqrestore(&zr->spinlock, flags);
+- }
++ return res;
++}
+
+- 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;
++static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res;
+
+- zr->v4l_buffers.active = fh->v4l_buffers.active =
+- ZORAN_FREE;
++ mutex_lock(&zr->resource_lock);
++ res = zoran_v4l2_buffer_status(fh, buf, buf->index);
++ mutex_unlock(&zr->resource_lock);
+
+- zr->v4l_grab_seq = 0;
+- zr->v4l_pend_head = zr->v4l_pend_tail = 0;
+- zr->v4l_sync_tail = 0;
++ return res;
++}
+
+- break;
++static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res = 0, codec_mode, buf_type;
+
+- 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);
++ mutex_lock(&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 strmoff_unlock_and_return;
++ goto qbuf_unlock_and_return;
+ }
+- strmoff_unlock_and_return:
+- mutex_unlock(&zr->resource_lock);
+
+- return res;
+- }
++ res = zoran_v4l_queue_frame(fh, buf->index);
++ if (res)
++ goto qbuf_unlock_and_return;
++ if (!zr->v4l_memgrab_active && fh->buffers.active == ZORAN_LOCKED)
++ zr36057_set_memgrab(zr, 1);
+ 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;
++ 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;
+ }
+
+- switch (ctrl->id) {
+- case V4L2_CID_BRIGHTNESS:
+- strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
+- break;
+- case V4L2_CID_CONTRAST:
+- strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
+- break;
+- case V4L2_CID_SATURATION:
+- strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
+- break;
+- case V4L2_CID_HUE:
+- strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
+- break;
++ 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;
+ }
+
+- ctrl->minimum = 0;
+- ctrl->maximum = 65535;
+- ctrl->step = 1;
+- ctrl->default_value = 32768;
+- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
++ res = zoran_jpg_queue_frame(fh, buf->index, codec_mode);
++ if (res != 0)
++ goto qbuf_unlock_and_return;
++ if (zr->codec_mode == BUZ_MODE_IDLE &&
++ fh->buffers.active == ZORAN_LOCKED)
++ zr36057_enable_jpg(zr, codec_mode);
+
+- 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;
+-
+- mutex_lock(&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;
+- }
+- mutex_unlock(&zr->resource_lock);
+-
+- return 0;
+- }
++ default:
++ dprintk(1, KERN_ERR
++ "%s: VIDIOC_QBUF - unsupported type %d\n",
++ ZR_DEVNAME(zr), buf->type);
++ res = -EINVAL;
+ break;
++ }
++qbuf_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
+
+- case VIDIOC_S_CTRL:
+- {
+- struct v4l2_control *ctrl = arg;
+- struct video_picture pict;
++ return res;
++}
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_S_CTRL - id=%d\n",
+- ZR_DEVNAME(zr), ctrl->id);
++static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res = 0, buf_type, num = -1; /* compiler borks here (?) */
+
+- /* we only support hue/saturation/contrast/brightness */
+- if (ctrl->id < V4L2_CID_BRIGHTNESS ||
+- ctrl->id > V4L2_CID_HUE)
+- return -EINVAL;
++ mutex_lock(&zr->resource_lock);
+
+- 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;
++ 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;
+ }
+
+- mutex_lock(&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;
++ 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;
+ }
+- pict.brightness = zr->brightness;
+- pict.contrast = zr->contrast;
+- pict.colour = zr->saturation;
+- pict.hue = zr->hue;
+-
+- decoder_command(zr, DECODER_SET_PICTURE, &pict);
+-
+- mutex_unlock(&zr->resource_lock);
+-
+- return 0;
+- }
++ res = v4l_sync(fh, num);
++ if (res)
++ goto dqbuf_unlock_and_return;
++ zr->v4l_sync_tail++;
++ res = zoran_v4l2_buffer_status(fh, buf, num);
+ break;
+
+- case VIDIOC_ENUMSTD:
++ case ZORAN_MAP_MODE_JPG_REC:
++ case ZORAN_MAP_MODE_JPG_PLAY:
+ {
+- struct v4l2_standard *std = arg;
++ struct zoran_sync bs;
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMSTD - index=%d\n",
+- ZR_DEVNAME(zr), std->index);
++ 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 (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 (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;
+ }
+
+- 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", sizeof(std->name)-1);
+- return 0;
+- } else
+- return -EINVAL;
+- }
+- switch (std->index) {
+- case 0:
+- std->id = V4L2_STD_PAL;
+- strncpy(std->name, "PAL", sizeof(std->name)-1);
+- 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", sizeof(std->name)-1);
+- 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", sizeof(std->name)-1);
+- std->frameperiod.numerator = 1;
+- std->frameperiod.denominator = 25;
+- std->framelines = zr->card.tvn[2]->Ht;
+- break;
+- }
++ num = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
+
+- return 0;
++ 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(fh, &bs);
++ if (res)
++ goto dqbuf_unlock_and_return;
++ res = zoran_v4l2_buffer_status(fh, buf, bs.frame);
++ break;
+ }
++
++ default:
++ dprintk(1, KERN_ERR
++ "%s: VIDIOC_DQBUF - unsupported type %d\n",
++ ZR_DEVNAME(zr), buf->type);
++ res = -EINVAL;
+ break;
++ }
++dqbuf_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
+
+- case VIDIOC_G_STD:
+- {
+- v4l2_std_id *std = arg;
+- int norm;
++ return res;
++}
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_G_STD\n", ZR_DEVNAME(zr));
++static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res = 0;
+
+- mutex_lock(&zr->resource_lock);
+- norm = zr->norm;
+- mutex_unlock(&zr->resource_lock);
++ mutex_lock(&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;
++ switch (fh->map_mode) {
++ case ZORAN_MAP_MODE_RAW: /* raw capture */
++ if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
++ fh->buffers.active != ZORAN_ACTIVE) {
++ res = -EBUSY;
++ goto strmon_unlock_and_return;
+ }
+
+- return 0;
+- }
++ zr->v4l_buffers.active = fh->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 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), (unsigned long long)*std);
+-
+- if ((*std & V4L2_STD_PAL) && !(*std & ~V4L2_STD_PAL))
+- norm = VIDEO_MODE_PAL;
+- else if ((*std & V4L2_STD_NTSC) && !(*std & ~V4L2_STD_NTSC))
+- norm = VIDEO_MODE_NTSC;
+- else if ((*std & V4L2_STD_SECAM) && !(*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), (unsigned long long)*std);
+- return -EINVAL;
++ 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->buffers.active != ZORAN_ACTIVE) {
++ res = -EBUSY;
++ goto strmon_unlock_and_return;
+ }
+
+- mutex_lock(&zr->resource_lock);
+- if ((res = zoran_set_norm(zr, norm)))
+- goto sstd_unlock_and_return;
++ zr->jpg_buffers.active = fh->buffers.active = ZORAN_LOCKED;
+
+- res = wait_grab_pending(zr);
+- sstd_unlock_and_return:
+- mutex_unlock(&zr->resource_lock);
+- return res;
+- }
++ if (zr->jpg_que_head != zr->jpg_que_tail) {
++ /* Start the jpeg codec when the first frame is queued */
++ jpeg_start(zr);
++ }
+ 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);
++ default:
++ dprintk(1,
++ KERN_ERR
++ "%s: VIDIOC_STREAMON - invalid map mode %d\n",
++ ZR_DEVNAME(zr), fh->map_mode);
++ res = -EINVAL;
++ break;
++ }
++strmon_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
+
+- if (inp->index < 0 || inp->index >= zr->card.inputs)
+- return -EINVAL;
+- else {
+- int id = inp->index;
+- memset(inp, 0, sizeof(*inp));
+- inp->index = id;
+- }
++ return res;
++}
+
+- strncpy(inp->name, zr->card.input[inp->index].name,
+- sizeof(inp->name) - 1);
+- inp->type = V4L2_INPUT_TYPE_CAMERA;
+- inp->std = V4L2_STD_ALL;
++static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int i, res = 0;
++ unsigned long flags;
+
+- /* Get status of video decoder */
+- mutex_lock(&zr->resource_lock);
+- decoder_command(zr, DECODER_GET_STATUS, &status);
+- mutex_unlock(&zr->resource_lock);
++ mutex_lock(&zr->resource_lock);
+
+- if (!(status & DECODER_STATUS_GOOD)) {
+- inp->status |= V4L2_IN_ST_NO_POWER;
+- inp->status |= V4L2_IN_ST_NO_SIGNAL;
++ switch (fh->map_mode) {
++ case ZORAN_MAP_MODE_RAW: /* raw capture */
++ if (fh->buffers.active == ZORAN_FREE &&
++ zr->v4l_buffers.active != ZORAN_FREE) {
++ res = -EPERM; /* stay off other's settings! */
++ goto strmoff_unlock_and_return;
+ }
+- if (!(status & DECODER_STATUS_COLOR))
+- inp->status |= V4L2_IN_ST_NO_COLOR;
++ if (zr->v4l_buffers.active == ZORAN_FREE)
++ goto strmoff_unlock_and_return;
+
+- return 0;
+- }
+- break;
++ spin_lock_irqsave(&zr->spinlock, flags);
++ /* unload capture */
++ if (zr->v4l_memgrab_active) {
+
+- case VIDIOC_G_INPUT:
+- {
+- int *input = arg;
++ zr36057_set_memgrab(zr, 0);
++ }
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_G_INPUT\n", ZR_DEVNAME(zr));
++ for (i = 0; i < fh->buffers.num_buffers; i++)
++ zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER;
++ fh->buffers = zr->v4l_buffers;
+
+- mutex_lock(&zr->resource_lock);
+- *input = zr->input;
+- mutex_unlock(&zr->resource_lock);
++ zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
+
+- return 0;
+- }
+- break;
++ zr->v4l_grab_seq = 0;
++ zr->v4l_pend_head = zr->v4l_pend_tail = 0;
++ zr->v4l_sync_tail = 0;
+
+- case VIDIOC_S_INPUT:
+- {
+- int *input = arg, res = 0;
++ spin_unlock_irqrestore(&zr->spinlock, flags);
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_S_INPUT - input=%d\n",
+- ZR_DEVNAME(zr), *input);
++ break;
+
+- mutex_lock(&zr->resource_lock);
+- if ((res = zoran_set_input(zr, *input)))
+- goto sinput_unlock_and_return;
++ case ZORAN_MAP_MODE_JPG_REC:
++ case ZORAN_MAP_MODE_JPG_PLAY:
++ if (fh->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;
+
+- /* Make sure the changes come into effect */
+- res = wait_grab_pending(zr);
+- sinput_unlock_and_return:
+- mutex_unlock(&zr->resource_lock);
+- return res;
+- }
++ res = jpg_qbuf(fh, -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;
+ break;
++ }
++strmoff_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
+
+- case VIDIOC_ENUMOUTPUT:
+- {
+- struct v4l2_output *outp = arg;
++ return res;
++}
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMOUTPUT - index=%d\n",
+- ZR_DEVNAME(zr), outp->index);
++static int zoran_queryctrl(struct file *file, void *__fh,
++ struct v4l2_queryctrl *ctrl)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- if (outp->index != 0)
+- return -EINVAL;
++ /* we only support hue/saturation/contrast/brightness */
++ if (ctrl->id < V4L2_CID_BRIGHTNESS ||
++ ctrl->id > V4L2_CID_HUE)
++ return -EINVAL;
+
+- memset(outp, 0, sizeof(*outp));
+- outp->index = 0;
+- outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
+- strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
++ decoder_call(zr, core, queryctrl, ctrl);
+
+- return 0;
+- }
+- break;
++ return 0;
++}
+
+- case VIDIOC_G_OUTPUT:
+- {
+- int *output = arg;
++static int zoran_g_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_G_OUTPUT\n", ZR_DEVNAME(zr));
++ /* we only support hue/saturation/contrast/brightness */
++ if (ctrl->id < V4L2_CID_BRIGHTNESS ||
++ ctrl->id > V4L2_CID_HUE)
++ return -EINVAL;
+
+- *output = 0;
++ mutex_lock(&zr->resource_lock);
++ decoder_call(zr, core, g_ctrl, ctrl);
++ mutex_unlock(&zr->resource_lock);
+
+- return 0;
+- }
+- break;
++ return 0;
++}
+
+- case VIDIOC_S_OUTPUT:
+- {
+- int *output = arg;
++static int zoran_s_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_S_OUTPUT - output=%d\n",
+- ZR_DEVNAME(zr), *output);
++ /* we only support hue/saturation/contrast/brightness */
++ if (ctrl->id < V4L2_CID_BRIGHTNESS ||
++ ctrl->id > V4L2_CID_HUE)
++ return -EINVAL;
+
+- if (*output != 0)
+- return -EINVAL;
++ mutex_lock(&zr->resource_lock);
++ decoder_call(zr, core, s_ctrl, ctrl);
++ mutex_unlock(&zr->resource_lock);
+
+- return 0;
+- }
+- break;
++ return 0;
++}
+
+- /* cropping (sub-frame capture) */
+- case VIDIOC_CROPCAP:
+- {
+- struct v4l2_cropcap *cropcap = arg;
+- int type = cropcap->type, res = 0;
++static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- dprintk(3, KERN_ERR "%s: VIDIOC_CROPCAP - type=%d\n",
+- ZR_DEVNAME(zr), cropcap->type);
++ mutex_lock(&zr->resource_lock);
++ *std = zr->norm;
++ mutex_unlock(&zr->resource_lock);
++ return 0;
++}
+
+- memset(cropcap, 0, sizeof(*cropcap));
+- cropcap->type = type;
++static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res = 0;
+
+- mutex_lock(&zr->resource_lock);
++ mutex_lock(&zr->resource_lock);
++ res = zoran_set_norm(zr, *std);
++ if (res)
++ goto sstd_unlock_and_return;
+
+- 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;
+- }
++ res = wait_grab_pending(zr);
++sstd_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
++ return res;
++}
+
+- 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:
+- mutex_unlock(&zr->resource_lock);
+- return res;
+- }
+- break;
++static int zoran_enum_input(struct file *file, void *__fh,
++ struct v4l2_input *inp)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- case VIDIOC_G_CROP:
+- {
+- struct v4l2_crop *crop = arg;
+- int type = crop->type, res = 0;
++ if (inp->index < 0 || inp->index >= zr->card.inputs)
++ return -EINVAL;
++ else {
++ int id = inp->index;
++ memset(inp, 0, sizeof(*inp));
++ inp->index = id;
++ }
+
+- dprintk(3, KERN_ERR "%s: VIDIOC_G_CROP - type=%d\n",
+- ZR_DEVNAME(zr), crop->type);
++ strncpy(inp->name, zr->card.input[inp->index].name,
++ sizeof(inp->name) - 1);
++ inp->type = V4L2_INPUT_TYPE_CAMERA;
++ inp->std = V4L2_STD_ALL;
+
+- memset(crop, 0, sizeof(*crop));
+- crop->type = type;
++ /* Get status of video decoder */
++ mutex_lock(&zr->resource_lock);
++ decoder_call(zr, video, g_input_status, &inp->status);
++ mutex_unlock(&zr->resource_lock);
++ return 0;
++}
+
+- mutex_lock(&zr->resource_lock);
++static int zoran_g_input(struct file *file, void *__fh, unsigned int *input)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
+
+- 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;
+- }
++ mutex_lock(&zr->resource_lock);
++ *input = zr->input;
++ mutex_unlock(&zr->resource_lock);
+
+- 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;
++ return 0;
++}
+
+- gcrop_unlock_and_return:
+- mutex_unlock(&zr->resource_lock);
++static int zoran_s_input(struct file *file, void *__fh, unsigned int input)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res;
+
+- return res;
+- }
+- break;
++ mutex_lock(&zr->resource_lock);
++ res = zoran_set_input(zr, input);
++ if (res)
++ goto sinput_unlock_and_return;
+
+- case VIDIOC_S_CROP:
+- {
+- struct v4l2_crop *crop = arg;
+- int res = 0;
++ /* Make sure the changes come into effect */
++ res = wait_grab_pending(zr);
++sinput_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
++ return res;
++}
+
+- settings = fh->jpg_settings;
++static int zoran_enum_output(struct file *file, void *__fh,
++ struct v4l2_output *outp)
++{
++ if (outp->index != 0)
++ return -EINVAL;
+
+- 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);
++ memset(outp, 0, sizeof(*outp));
++ outp->index = 0;
++ outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
++ strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
+
+- mutex_lock(&zr->resource_lock);
++ return 0;
++}
+
+- 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;
+- }
++static int zoran_g_output(struct file *file, void *__fh, unsigned int *output)
++{
++ *output = 0;
+
+- 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;
+- }
++ return 0;
++}
+
+- /* 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;
++static int zoran_s_output(struct file *file, void *__fh, unsigned int output)
++{
++ if (output != 0)
++ return -EINVAL;
+
+- /* check validity */
+- if ((res = zoran_check_jpg_settings(zr, &settings)))
+- goto scrop_unlock_and_return;
++ return 0;
++}
+
+- /* accept */
+- fh->jpg_settings = settings;
++/* cropping (sub-frame capture) */
++static int zoran_cropcap(struct file *file, void *__fh,
++ struct v4l2_cropcap *cropcap)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int type = cropcap->type, res = 0;
+
+- scrop_unlock_and_return:
+- mutex_unlock(&zr->resource_lock);
+- return res;
+- }
+- break;
++ memset(cropcap, 0, sizeof(*cropcap));
++ cropcap->type = type;
+
+- case VIDIOC_G_JPEGCOMP:
+- {
+- struct v4l2_jpegcompression *params = arg;
++ mutex_lock(&zr->resource_lock);
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_G_JPEGCOMP\n",
++ 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;
++ }
+
+- memset(params, 0, sizeof(*params));
++ 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:
++ mutex_unlock(&zr->resource_lock);
++ return res;
++}
+
+- mutex_lock(&zr->resource_lock);
++static int zoran_g_crop(struct file *file, void *__fh, struct v4l2_crop *crop)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int type = crop->type, res = 0;
+
+- 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;
++ memset(crop, 0, sizeof(*crop));
++ crop->type = type;
+
+- mutex_unlock(&zr->resource_lock);
++ mutex_lock(&zr->resource_lock);
+
+- return 0;
++ 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;
+ }
+- break;
+-
+- case VIDIOC_S_JPEGCOMP:
+- {
+- struct v4l2_jpegcompression *params = arg;
+- int res = 0;
+
+- settings = fh->jpg_settings;
++ 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;
+
+- 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);
++gcrop_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
+
+- settings.jpg_comp = *params;
++ return res;
++}
+
+- mutex_lock(&zr->resource_lock);
++static int zoran_s_crop(struct file *file, void *__fh, struct v4l2_crop *crop)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res = 0;
++ struct zoran_jpg_settings settings;
+
+- 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;
+- }
++ settings = fh->jpg_settings;
+
+- 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:
+- mutex_unlock(&zr->resource_lock);
++ mutex_lock(&zr->resource_lock);
+
+- return 0;
++ if (fh->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;
+ }
+- 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), (unsigned long long)*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;
++ 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;
+ }
+- break;
+
+- case VIDIOC_TRY_FMT:
+- {
+- struct v4l2_format *fmt = arg;
+- int res = 0;
++ /* 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;
+
+- dprintk(3, KERN_DEBUG "%s: VIDIOC_TRY_FMT - type=%d\n",
+- ZR_DEVNAME(zr), fmt->type);
++ /* check validity */
++ res = zoran_check_jpg_settings(zr, &settings, 0);
++ if (res)
++ goto scrop_unlock_and_return;
+
+- switch (fmt->type) {
+- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- mutex_lock(&zr->resource_lock);
++ /* accept */
++ fh->jpg_settings = settings;
+
+- 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;
++scrop_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
++ return res;
++}
+
+- mutex_unlock(&zr->resource_lock);
+- break;
++static int zoran_g_jpegcomp(struct file *file, void *__fh,
++ struct v4l2_jpegcompression *params)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ memset(params, 0, sizeof(*params));
+
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- if (fmt->fmt.pix.bytesperline > 0)
+- return -EINVAL;
++ mutex_lock(&zr->resource_lock);
+
+- mutex_lock(&zr->resource_lock);
+-
+- if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
+- 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 < NUM_FORMATS; i++)
+- if (zoran_formats[i].fourcc ==
+- fmt->fmt.pix.pixelformat)
+- break;
+- if (i == NUM_FORMATS) {
+- res = -EINVAL;
+- goto tryfmt_unlock_and_return;
+- }
++ 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;
+
+- 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:
+- mutex_unlock(&zr->resource_lock);
++ mutex_unlock(&zr->resource_lock);
+
+- return res;
+- break;
++ return 0;
++}
+
+- default:
+- return -EINVAL;
+- }
++static int zoran_s_jpegcomp(struct file *file, void *__fh,
++ struct v4l2_jpegcompression *params)
++{
++ struct zoran_fh *fh = __fh;
++ struct zoran *zr = fh->zr;
++ int res = 0;
++ struct zoran_jpg_settings settings;
+
+- return 0;
+- }
+- break;
++ settings = fh->jpg_settings;
+
+- default:
+- dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
+- ZR_DEVNAME(zr), cmd);
+- return -ENOIOCTLCMD;
+- break;
++ settings.jpg_comp = *params;
++
++ mutex_lock(&zr->resource_lock);
+
++ if (fh->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;
+ }
+- return 0;
+-}
+
++ res = zoran_check_jpg_settings(zr, &settings, 0);
++ if (res)
++ goto sjpegc_unlock_and_return;
++ if (!fh->buffers.allocated)
++ fh->buffers.buffer_size =
++ zoran_v4l2_calc_bufsize(&fh->jpg_settings);
++ fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
++sjpegc_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
+
+-static long
+-zoran_ioctl(struct file *file,
+- unsigned int cmd,
+- unsigned long arg)
+-{
+- return video_usercopy(file, cmd, arg, zoran_do_ioctl);
++ return res;
+ }
+
+ static unsigned int
+@@ -4191,11 +3062,11 @@ zoran_poll (struct file *file,
+ KERN_DEBUG
+ "%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
+ ZR_DEVNAME(zr), __func__,
+- "FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
++ "FAL"[fh->buffers.active], zr->v4l_sync_tail,
+ "UPMD"[zr->v4l_buffers.buffer[frame].state],
+ zr->v4l_pend_tail, zr->v4l_pend_head);
+ /* Process is the one capturing? */
+- if (fh->v4l_buffers.active != ZORAN_FREE &&
++ if (fh->buffers.active != ZORAN_FREE &&
+ /* Buffer ready to DQBUF? */
+ zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
+ res = POLLIN | POLLRDNORM;
+@@ -4213,10 +3084,10 @@ zoran_poll (struct file *file,
+ KERN_DEBUG
+ "%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
+ ZR_DEVNAME(zr), __func__,
+- "FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
++ "FAL"[fh->buffers.active], zr->jpg_que_tail,
+ "UPMD"[zr->jpg_buffers.buffer[frame].state],
+ zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
+- if (fh->jpg_buffers.active != ZORAN_FREE &&
++ if (fh->buffers.active != ZORAN_FREE &&
+ zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
+ if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC)
+ res = POLLIN | POLLRDNORM;
+@@ -4230,8 +3101,8 @@ zoran_poll (struct file *file,
+ default:
+ dprintk(1,
+ KERN_ERR
+- "%s: zoran_poll() - internal error, unknown map_mode=%d\n",
+- ZR_DEVNAME(zr), fh->map_mode);
++ "%s: %s - internal error, unknown map_mode=%d\n",
++ ZR_DEVNAME(zr), __func__, fh->map_mode);
+ res = POLLNVAL;
+ }
+
+@@ -4265,98 +3136,53 @@ 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_fh *fh = map->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));
++ if (--map->count > 0)
++ return;
+
+- 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) {
+- mutex_lock(&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;
+-
+- mutex_unlock(&zr->resource_lock);
+- }
++ dprintk(3, KERN_INFO "%s: %s - munmap(%s)\n", ZR_DEVNAME(zr),
++ __func__, mode_name(fh->map_mode));
+
+- 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->buffers.num_buffers; i++) {
++ if (fh->buffers.buffer[i].map == map)
++ fh->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) {
+- mutex_lock(&zr->resource_lock);
+-
+- if (fh->v4l_buffers.active != ZORAN_FREE) {
+- unsigned long flags;
+-
+- spin_lock_irqsave(&zr->spinlock, flags);
+- zr36057_set_memgrab(zr, 0);
+- zr->v4l_buffers.allocated = 0;
+- zr->v4l_buffers.active =
+- fh->v4l_buffers.active =
+- ZORAN_FREE;
+- spin_unlock_irqrestore(&zr->spinlock, flags);
+- }
+- //v4l_fbuffer_free(file);
+- fh->v4l_buffers.allocated = 0;
+- fh->v4l_buffers.ready_to_be_freed = 1;
++ /* Any buffers still mapped? */
++ for (i = 0; i < fh->buffers.num_buffers; i++)
++ if (fh->buffers.buffer[i].map)
++ return;
+
+- mutex_unlock(&zr->resource_lock);
+- }
++ dprintk(3, KERN_INFO "%s: %s - free %s buffers\n", ZR_DEVNAME(zr),
++ __func__, mode_name(fh->map_mode));
+
+- break;
++ mutex_lock(&zr->resource_lock);
+
+- default:
+- printk(KERN_ERR
+- "%s: munmap() - internal error - unknown map mode %d\n",
+- ZR_DEVNAME(zr), fh->map_mode);
+- break;
++ if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
++ if (fh->buffers.active != ZORAN_FREE) {
++ unsigned long flags;
+
++ spin_lock_irqsave(&zr->spinlock, flags);
++ zr36057_set_memgrab(zr, 0);
++ zr->v4l_buffers.allocated = 0;
++ zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE;
++ spin_unlock_irqrestore(&zr->spinlock, flags);
+ }
++ v4l_fbuffer_free(fh);
++ } else {
++ if (fh->buffers.active != ZORAN_FREE) {
++ jpg_qbuf(fh, -1, zr->codec_mode);
++ zr->jpg_buffers.allocated = 0;
++ zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE;
++ }
++ jpg_fbuffer_free(fh);
+ }
++
++ mutex_unlock(&zr->resource_lock);
+ }
+
+ static struct vm_operations_struct zoran_vm_ops = {
+@@ -4379,90 +3205,106 @@ zoran_mmap (struct file *file,
+ 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);
++ KERN_INFO "%s: %s(%s) of 0x%08lx-0x%08lx (size=%lu)\n",
++ ZR_DEVNAME(zr), __func__,
++ mode_name(fh->map_mode), 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));
++ "%s: %s - no MAP_SHARED/PROT_{READ,WRITE} given\n",
++ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+
+- switch (fh->map_mode) {
++ mutex_lock(&zr->resource_lock);
+
+- case ZORAN_MAP_MODE_JPG_REC:
+- case ZORAN_MAP_MODE_JPG_PLAY:
++ if (!fh->buffers.allocated) {
++ dprintk(1,
++ KERN_ERR
++ "%s: %s(%s) - buffers not yet allocated\n",
++ ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode));
++ res = -ENOMEM;
++ goto mmap_unlock_and_return;
++ }
+
+- /* lock */
+- mutex_lock(&zr->resource_lock);
++ first = offset / fh->buffers.buffer_size;
++ last = first - 1 + size / fh->buffers.buffer_size;
++ if (offset % fh->buffers.buffer_size != 0 ||
++ size % fh->buffers.buffer_size != 0 || first < 0 ||
++ last < 0 || first >= fh->buffers.num_buffers ||
++ last >= fh->buffers.buffer_size) {
++ dprintk(1,
++ KERN_ERR
++ "%s: %s(%s) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n",
++ ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), offset, size,
++ fh->buffers.buffer_size,
++ fh->buffers.num_buffers);
++ res = -EINVAL;
++ goto mmap_unlock_and_return;
++ }
+
+- /* Map the MJPEG buffers */
+- if (!fh->jpg_buffers.allocated) {
++ /* Check if any buffers are already mapped */
++ for (i = first; i <= last; i++) {
++ if (fh->buffers.buffer[i].map) {
+ dprintk(1,
+ KERN_ERR
+- "%s: zoran_mmap(MJPEG) - buffers not yet allocated\n",
+- ZR_DEVNAME(zr));
+- res = -ENOMEM;
+- goto jpg_mmap_unlock_and_return;
++ "%s: %s(%s) - buffer %d already mapped\n",
++ ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), i);
++ res = -EBUSY;
++ goto 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;
+- }
++ /* map these buffers */
++ map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL);
++ if (!map) {
++ res = -ENOMEM;
++ goto 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;
++
++ if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
+ for (i = first; i <= last; i++) {
+- if (fh->jpg_buffers.buffer[i].map) {
++ todo = size;
++ if (todo > fh->buffers.buffer_size)
++ todo = fh->buffers.buffer_size;
++ page = fh->buffers.buffer[i].v4l.fbuffer_phys;
++ if (remap_pfn_range(vma, start, page >> PAGE_SHIFT,
++ todo, PAGE_SHARED)) {
+ dprintk(1,
+ KERN_ERR
+- "%s: mmap(MJPEG) - buffer %d already mapped\n",
+- ZR_DEVNAME(zr), i);
+- res = -EBUSY;
+- goto jpg_mmap_unlock_and_return;
++ "%s: %s(V4L) - remap_pfn_range failed\n",
++ ZR_DEVNAME(zr), __func__);
++ res = -EAGAIN;
++ goto mmap_unlock_and_return;
+ }
++ size -= todo;
++ start += todo;
++ fh->buffers.buffer[i].map = map;
++ if (size == 0)
++ break;
+ }
+-
+- /* 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;
+-
++ } else {
+ for (i = first; i <= last; i++) {
+ for (j = 0;
+- j < fh->jpg_buffers.buffer_size / PAGE_SIZE;
++ j < fh->buffers.buffer_size / PAGE_SIZE;
+ j++) {
+ fraglen =
+- (le32_to_cpu(fh->jpg_buffers.buffer[i].
++ (le32_to_cpu(fh->buffers.buffer[i].jpg.
+ frag_tab[2 * j + 1]) & ~1) << 1;
+ todo = size;
+ if (todo > fraglen)
+ todo = fraglen;
+ pos =
+- le32_to_cpu(fh->jpg_buffers.
+- buffer[i].frag_tab[2 * j]);
++ le32_to_cpu(fh->buffers.
++ buffer[i].jpg.frag_tab[2 * j]);
+ /* should just be pos on i386 */
+ page = virt_to_phys(bus_to_virt(pos))
+ >> PAGE_SHIFT;
+@@ -4470,123 +3312,82 @@ zoran_mmap (struct file *file,
+ todo, PAGE_SHARED)) {
+ dprintk(1,
+ KERN_ERR
+- "%s: zoran_mmap(V4L) - remap_pfn_range failed\n",
+- ZR_DEVNAME(zr));
++ "%s: %s(V4L) - remap_pfn_range failed\n",
++ ZR_DEVNAME(zr), __func__);
+ res = -EAGAIN;
+- goto jpg_mmap_unlock_and_return;
++ goto mmap_unlock_and_return;
+ }
+ size -= todo;
+ start += todo;
+ if (size == 0)
+ break;
+- if (le32_to_cpu(fh->jpg_buffers.buffer[i].
++ if (le32_to_cpu(fh->buffers.buffer[i].jpg.
+ frag_tab[2 * j + 1]) & 1)
+ break; /* was last fragment */
+ }
+- fh->jpg_buffers.buffer[i].map = map;
++ fh->buffers.buffer[i].map = map;
+ if (size == 0)
+ break;
+
+ }
+- jpg_mmap_unlock_and_return:
+- mutex_unlock(&zr->resource_lock);
+-
+- break;
+-
+- case ZORAN_MAP_MODE_RAW:
+-
+- mutex_lock(&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 (remap_pfn_range(vma, start, page >> PAGE_SHIFT,
+- todo, PAGE_SHARED)) {
+- dprintk(1,
+- KERN_ERR
+- "%s: zoran_mmap(V4L)i - remap_pfn_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:
+- mutex_unlock(&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;
+ }
+
++mmap_unlock_and_return:
++ mutex_unlock(&zr->resource_lock);
++
+ return 0;
+ }
+
++static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
++ .vidioc_querycap = zoran_querycap,
++ .vidioc_cropcap = zoran_cropcap,
++ .vidioc_s_crop = zoran_s_crop,
++ .vidioc_g_crop = zoran_g_crop,
++ .vidioc_enum_input = zoran_enum_input,
++ .vidioc_g_input = zoran_g_input,
++ .vidioc_s_input = zoran_s_input,
++ .vidioc_enum_output = zoran_enum_output,
++ .vidioc_g_output = zoran_g_output,
++ .vidioc_s_output = zoran_s_output,
++ .vidioc_g_fbuf = zoran_g_fbuf,
++ .vidioc_s_fbuf = zoran_s_fbuf,
++ .vidioc_g_std = zoran_g_std,
++ .vidioc_s_std = zoran_s_std,
++ .vidioc_g_jpegcomp = zoran_g_jpegcomp,
++ .vidioc_s_jpegcomp = zoran_s_jpegcomp,
++ .vidioc_overlay = zoran_overlay,
++ .vidioc_reqbufs = zoran_reqbufs,
++ .vidioc_querybuf = zoran_querybuf,
++ .vidioc_qbuf = zoran_qbuf,
++ .vidioc_dqbuf = zoran_dqbuf,
++ .vidioc_streamon = zoran_streamon,
++ .vidioc_streamoff = zoran_streamoff,
++ .vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap,
++ .vidioc_enum_fmt_vid_out = zoran_enum_fmt_vid_out,
++ .vidioc_enum_fmt_vid_overlay = zoran_enum_fmt_vid_overlay,
++ .vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap,
++ .vidioc_g_fmt_vid_out = zoran_g_fmt_vid_out,
++ .vidioc_g_fmt_vid_overlay = zoran_g_fmt_vid_overlay,
++ .vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap,
++ .vidioc_s_fmt_vid_out = zoran_s_fmt_vid_out,
++ .vidioc_s_fmt_vid_overlay = zoran_s_fmt_vid_overlay,
++ .vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap,
++ .vidioc_try_fmt_vid_out = zoran_try_fmt_vid_out,
++ .vidioc_try_fmt_vid_overlay = zoran_try_fmt_vid_overlay,
++ .vidioc_queryctrl = zoran_queryctrl,
++ .vidioc_s_ctrl = zoran_s_ctrl,
++ .vidioc_g_ctrl = zoran_g_ctrl,
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++ .vidioc_default = zoran_default,
++ .vidiocgmbuf = zoran_vidiocgmbuf,
++#endif
++};
++
+ static const struct v4l2_file_operations zoran_fops = {
+ .owner = THIS_MODULE,
+ .open = zoran_open,
+ .release = zoran_close,
+- .ioctl = zoran_ioctl,
++ .ioctl = video_ioctl2,
+ .read = zoran_read,
+ .write = zoran_write,
+ .mmap = zoran_mmap,
+@@ -4596,7 +3397,9 @@ static const struct v4l2_file_operations zoran_fops = {
+ struct video_device zoran_template __devinitdata = {
+ .name = ZORAN_NAME,
+ .fops = &zoran_fops,
++ .ioctl_ops = &zoran_ioctl_ops,
+ .release = &zoran_vdev_release,
++ .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+ .minor = -1
+ };
+
+diff --git a/drivers/media/video/zoran/zoran_procfs.c b/drivers/media/video/zoran/zoran_procfs.c
+index 870bc5a..f1423b7 100644
+--- a/drivers/media/video/zoran/zoran_procfs.c
++++ b/drivers/media/video/zoran/zoran_procfs.c
+@@ -36,7 +36,7 @@
+ #include <linux/pci.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-algo-bit.h>
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <linux/spinlock.h>
+ #include <linux/sem.h>
+ #include <linux/seq_file.h>
+diff --git a/drivers/media/video/zoran/zr36016.c b/drivers/media/video/zoran/zr36016.c
+index 00d132b..21c088e 100644
+--- a/drivers/media/video/zoran/zr36016.c
++++ b/drivers/media/video/zoran/zr36016.c
+@@ -34,15 +34,10 @@
+ #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"
+diff --git a/drivers/media/video/zoran/zr36050.c b/drivers/media/video/zoran/zr36050.c
+index cf8b271..639dd87 100644
+--- a/drivers/media/video/zoran/zr36050.c
++++ b/drivers/media/video/zoran/zr36050.c
+@@ -34,12 +34,8 @@
+ #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"
+diff --git a/drivers/media/video/zoran/zr36060.c b/drivers/media/video/zoran/zr36060.c
+index 8e74054..008746f 100644
+--- a/drivers/media/video/zoran/zr36060.c
++++ b/drivers/media/video/zoran/zr36060.c
+@@ -34,12 +34,8 @@
+ #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"
+diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
+index 9302356..221409f 100644
+--- a/drivers/media/video/zr364xx.c
++++ b/drivers/media/video/zr364xx.c
+@@ -96,6 +96,7 @@ static struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
+ {USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 },
+ {USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 },
++ {USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD2 },
+ {} /* Terminating entry */
+ };
+
+@@ -425,7 +426,6 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
+ static int zr364xx_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+ {
+- memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, DRIVER_DESC);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ return 0;
+@@ -436,8 +436,6 @@ static int zr364xx_vidioc_enum_input(struct file *file, void *priv,
+ {
+ if (i->index != 0)
+ return -EINVAL;
+- memset(i, 0, sizeof(*i));
+- i->index = 0;
+ strcpy(i->name, DRIVER_DESC " Camera");
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ return 0;
+@@ -529,11 +527,6 @@ static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
+ {
+ if (f->index > 0)
+ return -EINVAL;
+- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+- memset(f, 0, sizeof(*f));
+- f->index = 0;
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ strcpy(f->description, "JPEG");
+ f->pixelformat = V4L2_PIX_FMT_JPEG;
+@@ -550,8 +543,6 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ return -ENODEV;
+ cam = video_get_drvdata(vdev);
+
+- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+ return -EINVAL;
+ if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+@@ -577,10 +568,6 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ return -ENODEV;
+ cam = video_get_drvdata(vdev);
+
+- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+- memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.width = cam->width;
+@@ -602,8 +589,6 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ return -ENODEV;
+ cam = video_get_drvdata(vdev);
+
+- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+ return -EINVAL;
+ if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+index 106c3ba..5bd3efd 100644
+--- a/include/linux/Kbuild
++++ b/include/linux/Kbuild
+@@ -157,8 +157,6 @@ header-y += ultrasound.h
+ header-y += un.h
+ header-y += utime.h
+ header-y += veth.h
+-header-y += video_decoder.h
+-header-y += video_encoder.h
+ header-y += videotext.h
+ header-y += x25.h
+
+diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
+index 1ffc23b..f27604a 100644
+--- a/include/linux/i2c-id.h
++++ b/include/linux/i2c-id.h
+@@ -71,6 +71,7 @@
+ #define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */
+ #define I2C_DRIVERID_M52790 95 /* Mitsubishi M52790SP/FP AV switch */
+ #define I2C_DRIVERID_CS5345 96 /* cs5345 audio processor */
++#define I2C_DRIVERID_AU8522 97 /* Auvitek au8522 */
+
+ #define I2C_DRIVERID_OV7670 1048 /* Omnivision 7670 camera */
+
+@@ -87,6 +88,7 @@
+ #define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */
+ #define I2C_HW_B_CX23885 0x010022 /* conexant 23885 based tv cards (bus1) */
+ #define I2C_HW_B_AU0828 0x010023 /* auvitek au0828 usb bridge */
++#define I2C_HW_B_HDPVR 0x010025 /* Hauppauge HD PVR */
+
+ /* --- SGI adapters */
+ #define I2C_HW_SGI_VINO 0x160000
+diff --git a/include/linux/ivtv.h b/include/linux/ivtv.h
+index f272028..062d20f 100644
+--- a/include/linux/ivtv.h
++++ b/include/linux/ivtv.h
+@@ -60,10 +60,10 @@ struct ivtv_dma_frame {
+
+ #define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame)
+
+-/* These are the VBI types as they appear in the embedded VBI private packets. */
+-#define IVTV_SLICED_TYPE_TELETEXT_B (1)
+-#define IVTV_SLICED_TYPE_CAPTION_525 (4)
+-#define IVTV_SLICED_TYPE_WSS_625 (5)
+-#define IVTV_SLICED_TYPE_VPS (7)
++/* Deprecated defines: applications should use the defines from videodev2.h */
++#define IVTV_SLICED_TYPE_TELETEXT_B V4L2_MPEG_VBI_IVTV_TELETEXT_B
++#define IVTV_SLICED_TYPE_CAPTION_525 V4L2_MPEG_VBI_IVTV_CAPTION_525
++#define IVTV_SLICED_TYPE_WSS_625 V4L2_MPEG_VBI_IVTV_WSS_625
++#define IVTV_SLICED_TYPE_VPS V4L2_MPEG_VBI_IVTV_VPS
+
+ #endif /* _LINUX_IVTV_H */
+diff --git a/include/linux/video_decoder.h b/include/linux/video_decoder.h
+deleted file mode 100644
+index e26c0c8..0000000
+--- a/include/linux/video_decoder.h
++++ /dev/null
+@@ -1,48 +0,0 @@
+-#ifndef _LINUX_VIDEO_DECODER_H
+-#define _LINUX_VIDEO_DECODER_H
+-
+-#include <linux/types.h>
+-
+-#define HAVE_VIDEO_DECODER 1
+-
+-struct video_decoder_capability { /* this name is too long */
+- __u32 flags;
+-#define VIDEO_DECODER_PAL 1 /* can decode PAL signal */
+-#define VIDEO_DECODER_NTSC 2 /* can decode NTSC */
+-#define VIDEO_DECODER_SECAM 4 /* can decode SECAM */
+-#define VIDEO_DECODER_AUTO 8 /* can autosense norm */
+-#define VIDEO_DECODER_CCIR 16 /* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
+- int inputs; /* number of inputs */
+- int outputs; /* number of outputs */
+-};
+-
+-/*
+-DECODER_GET_STATUS returns the following flags. The only one you need is
+-DECODER_STATUS_GOOD, the others are just nice things to know.
+-*/
+-#define DECODER_STATUS_GOOD 1 /* receiving acceptable input */
+-#define DECODER_STATUS_COLOR 2 /* receiving color information */
+-#define DECODER_STATUS_PAL 4 /* auto detected */
+-#define DECODER_STATUS_NTSC 8 /* auto detected */
+-#define DECODER_STATUS_SECAM 16 /* auto detected */
+-
+-struct video_decoder_init {
+- unsigned char len;
+- const unsigned char *data;
+-};
+-
+-#define DECODER_GET_CAPABILITIES _IOR('d', 1, struct video_decoder_capability)
+-#define DECODER_GET_STATUS _IOR('d', 2, int)
+-#define DECODER_SET_NORM _IOW('d', 3, int)
+-#define DECODER_SET_INPUT _IOW('d', 4, int) /* 0 <= input < #inputs */
+-#define DECODER_SET_OUTPUT _IOW('d', 5, int) /* 0 <= output < #outputs */
+-#define DECODER_ENABLE_OUTPUT _IOW('d', 6, int) /* boolean output enable control */
+-#define DECODER_SET_PICTURE _IOW('d', 7, struct video_picture)
+-#define DECODER_SET_GPIO _IOW('d', 8, int) /* switch general purpose pin */
+-#define DECODER_INIT _IOW('d', 9, struct video_decoder_init) /* init internal registers at once */
+-#define DECODER_SET_VBI_BYPASS _IOW('d', 10, int) /* switch vbi bypass */
+-
+-#define DECODER_DUMP _IO('d', 192) /* debug hook */
+-
+-
+-#endif
+diff --git a/include/linux/video_encoder.h b/include/linux/video_encoder.h
+deleted file mode 100644
+index b7b6423..0000000
+--- a/include/linux/video_encoder.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-#ifndef _LINUX_VIDEO_ENCODER_H
+-#define _LINUX_VIDEO_ENCODER_H
+-
+-#include <linux/types.h>
+-
+-struct video_encoder_capability { /* this name is too long */
+- __u32 flags;
+-#define VIDEO_ENCODER_PAL 1 /* can encode PAL signal */
+-#define VIDEO_ENCODER_NTSC 2 /* can encode NTSC */
+-#define VIDEO_ENCODER_SECAM 4 /* can encode SECAM */
+-#define VIDEO_ENCODER_CCIR 16 /* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
+- int inputs; /* number of inputs */
+- int outputs; /* number of outputs */
+-};
+-
+-#define ENCODER_GET_CAPABILITIES _IOR('e', 1, struct video_encoder_capability)
+-#define ENCODER_SET_NORM _IOW('e', 2, int)
+-#define ENCODER_SET_INPUT _IOW('e', 3, int) /* 0 <= input < #inputs */
+-#define ENCODER_SET_OUTPUT _IOW('e', 4, int) /* 0 <= output < #outputs */
+-#define ENCODER_ENABLE_OUTPUT _IOW('e', 5, int) /* boolean output enable control */
+-
+-
+-#endif
+diff --git a/include/linux/videodev.h b/include/linux/videodev.h
+index 837f392..b19eab1 100644
+--- a/include/linux/videodev.h
++++ b/include/linux/videodev.h
+@@ -16,6 +16,23 @@
+ #include <linux/ioctl.h>
+ #include <linux/videodev2.h>
+
++#if defined(__MIN_V4L1) && defined (__KERNEL__)
++
++/*
++ * Used by those V4L2 core functions that need a minimum V4L1 support,
++ * in order to allow V4L1 Compatibilty code compilation.
++ */
++
++struct video_mbuf
++{
++ int size; /* Total memory to map */
++ int frames; /* Frames */
++ int offsets[VIDEO_MAX_FRAME];
++};
++
++#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */
++
++#else
+ #if defined(CONFIG_VIDEO_V4L1_COMPAT) || !defined (__KERNEL__)
+
+ #define VID_TYPE_CAPTURE 1 /* Can capture */
+@@ -312,6 +329,7 @@ struct video_code
+ #define VID_PLAY_END_MARK 14
+
+ #endif /* CONFIG_VIDEO_V4L1_COMPAT */
++#endif /* __MIN_V4L1 */
+
+ #endif /* __LINUX_VIDEODEV_H */
+
+diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
+index 5571dbe..139d234 100644
+--- a/include/linux/videodev2.h
++++ b/include/linux/videodev2.h
+@@ -344,6 +344,8 @@ struct v4l2_pix_format {
+ #define V4L2_PIX_FMT_SPCA508 v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */
+ #define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
+ #define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
++#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
++#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
+ #define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
+ #define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
+
+@@ -829,6 +831,7 @@ struct v4l2_querymenu {
+ #define V4L2_CTRL_FLAG_UPDATE 0x0008
+ #define V4L2_CTRL_FLAG_INACTIVE 0x0010
+ #define V4L2_CTRL_FLAG_SLIDER 0x0020
++#define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040
+
+ /* Query flag, to be ORed with the control ID */
+ #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000
+@@ -879,8 +882,15 @@ enum v4l2_power_line_frequency {
+ #define V4L2_CID_BACKLIGHT_COMPENSATION (V4L2_CID_BASE+28)
+ #define V4L2_CID_CHROMA_AGC (V4L2_CID_BASE+29)
+ #define V4L2_CID_COLOR_KILLER (V4L2_CID_BASE+30)
++#define V4L2_CID_COLORFX (V4L2_CID_BASE+31)
++enum v4l2_colorfx {
++ V4L2_COLORFX_NONE = 0,
++ V4L2_COLORFX_BW = 1,
++ V4L2_COLORFX_SEPIA = 2,
++};
++
+ /* last CID + 1 */
+-#define V4L2_CID_LASTP1 (V4L2_CID_BASE+31)
++#define V4L2_CID_LASTP1 (V4L2_CID_BASE+32)
+
+ /* MPEG-class control IDs defined by V4L2 */
+ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
+@@ -1339,6 +1349,53 @@ struct v4l2_sliced_vbi_data {
+ };
+
+ /*
++ * Sliced VBI data inserted into MPEG Streams
++ */
++
++/*
++ * V4L2_MPEG_STREAM_VBI_FMT_IVTV:
++ *
++ * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an
++ * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI
++ * data
++ *
++ * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header
++ * definitions are not included here. See the MPEG-2 specifications for details
++ * on these headers.
++ */
++
++/* Line type IDs */
++#define V4L2_MPEG_VBI_IVTV_TELETEXT_B (1)
++#define V4L2_MPEG_VBI_IVTV_CAPTION_525 (4)
++#define V4L2_MPEG_VBI_IVTV_WSS_625 (5)
++#define V4L2_MPEG_VBI_IVTV_VPS (7)
++
++struct v4l2_mpeg_vbi_itv0_line {
++ __u8 id; /* One of V4L2_MPEG_VBI_IVTV_* above */
++ __u8 data[42]; /* Sliced VBI data for the line */
++} __attribute__ ((packed));
++
++struct v4l2_mpeg_vbi_itv0 {
++ __le32 linemask[2]; /* Bitmasks of VBI service lines present */
++ struct v4l2_mpeg_vbi_itv0_line line[35];
++} __attribute__ ((packed));
++
++struct v4l2_mpeg_vbi_ITV0 {
++ struct v4l2_mpeg_vbi_itv0_line line[36];
++} __attribute__ ((packed));
++
++#define V4L2_MPEG_VBI_IVTV_MAGIC0 "itv0"
++#define V4L2_MPEG_VBI_IVTV_MAGIC1 "ITV0"
++
++struct v4l2_mpeg_vbi_fmt_ivtv {
++ __u8 magic[4];
++ union {
++ struct v4l2_mpeg_vbi_itv0 itv0;
++ struct v4l2_mpeg_vbi_ITV0 ITV0;
++ };
++} __attribute__ ((packed));
++
++/*
+ * A G G R E G A T E S T R U C T U R E S
+ */
+
+@@ -1403,14 +1460,6 @@ struct v4l2_dbg_chip_ident {
+ __u32 revision; /* chip revision, chip specific */
+ } __attribute__ ((packed));
+
+-/* VIDIOC_G_CHIP_IDENT_OLD: Deprecated, do not use */
+-struct v4l2_chip_ident_old {
+- __u32 match_type; /* Match type */
+- __u32 match_chip; /* Match this chip, meaning determined by match_type */
+- __u32 ident; /* chip identifier as specified in <media/v4l2-chip-ident.h> */
+- __u32 revision; /* chip revision, chip specific */
+-};
+-
+ /*
+ * I O C T L C O D E S F O R V I D E O D E V I C E S
+ *
+@@ -1488,8 +1537,6 @@ struct v4l2_chip_ident_old {
+ /* Experimental, meant for debugging, testing and internal use.
+ Never use this ioctl in applications! */
+ #define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident)
+-/* This is deprecated and will go away in 2.6.30 */
+-#define VIDIOC_G_CHIP_IDENT_OLD _IOWR('V', 81, struct v4l2_chip_ident_old)
+ #endif
+
+ #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek)
+diff --git a/include/media/bt819.h b/include/media/bt819.h
+new file mode 100644
+index 0000000..38f666b
+--- /dev/null
++++ b/include/media/bt819.h
+@@ -0,0 +1,33 @@
++/*
++ bt819.h - bt819 notifications
++
++ Copyright (C) 2009 Hans Verkuil (hverkuil@xs4all.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.
++*/
++
++#ifndef _BT819_H_
++#define _BT819_H_
++
++#include <linux/ioctl.h>
++
++/* v4l2_device notifications. */
++
++/* Needed to reset the FIFO buffer when changing the input
++ or the video standard. */
++#define BT819_FIFO_RESET_LOW _IO('b', 0)
++#define BT819_FIFO_RESET_HIGH _IO('b', 1)
++
++#endif
+diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h
+index 9ec4d58..9ebe855 100644
+--- a/include/media/cx2341x.h
++++ b/include/media/cx2341x.h
+@@ -1,5 +1,5 @@
+ /*
+- cx23415/6 header containing common defines.
++ cx23415/6/8 header containing common defines.
+
+ 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
+@@ -28,6 +28,7 @@ enum cx2341x_port {
+ enum cx2341x_cap {
+ CX2341X_CAP_HAS_SLICED_VBI = 1 << 0,
+ CX2341X_CAP_HAS_TS = 1 << 1,
++ CX2341X_CAP_HAS_AC3 = 1 << 2,
+ };
+
+ struct cx2341x_mpeg_params {
+@@ -47,11 +48,12 @@ struct cx2341x_mpeg_params {
+ enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq;
+ enum v4l2_mpeg_audio_encoding audio_encoding;
+ enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate;
++ enum v4l2_mpeg_audio_ac3_bitrate audio_ac3_bitrate;
+ enum v4l2_mpeg_audio_mode audio_mode;
+ enum v4l2_mpeg_audio_mode_extension audio_mode_extension;
+ enum v4l2_mpeg_audio_emphasis audio_emphasis;
+ enum v4l2_mpeg_audio_crc audio_crc;
+- u16 audio_properties;
++ u32 audio_properties;
+ u16 audio_mute;
+
+ /* video */
+diff --git a/include/media/cx25840.h b/include/media/cx25840.h
+index db431d5..2c3fbaa 100644
+--- a/include/media/cx25840.h
++++ b/include/media/cx25840.h
+@@ -21,6 +21,18 @@
+ #ifndef _CX25840_H_
+ #define _CX25840_H_
+
++/* Note that the cx25840 driver requires that the bridge driver calls the
++ v4l2_subdev's init operation in order to load the driver's firmware.
++ Without this the audio standard detection will fail and you will
++ only get mono.
++
++ Since loading the firmware is often problematic when the driver is
++ compiled into the kernel I recommend postponing calling this function
++ until the first open of the video device. Another reason for
++ postponing it is that loading this firmware takes a long time (seconds)
++ due to the slow i2c bus speed. So it will speed up the boot process if
++ you can avoid loading the fw as long as the video device isn't used. */
++
+ enum cx25840_video_input {
+ /* Composite video inputs In1-In8 */
+ CX25840_COMPOSITE1 = 1,
+diff --git a/include/media/ir-common.h b/include/media/ir-common.h
+index 5bf2ea0..7b5b91f 100644
+--- a/include/media/ir-common.h
++++ b/include/media/ir-common.h
+@@ -111,6 +111,7 @@ extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE];
++extern IR_KEYTAB_TYPE ir_codes_avermedia_cardbus[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_pixelview_new[IR_KEYTAB_SIZE];
+@@ -159,6 +160,8 @@ extern IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE];
+ extern IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE];
++extern IR_KEYTAB_TYPE ir_codes_kaiomy[IR_KEYTAB_SIZE];
++extern IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE];
+ #endif
+
+ /*
+diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
+index 00fa57e..07963d7 100644
+--- a/include/media/ir-kbd-i2c.h
++++ b/include/media/ir-kbd-i2c.h
+@@ -14,8 +14,7 @@ struct IR_i2c {
+ /* Used to avoid fast repeating */
+ unsigned char old;
+
+- struct work_struct work;
+- struct timer_list timer;
++ struct delayed_work work;
+ char phys[32];
+ int (*get_key)(struct IR_i2c*, u32*, u32*);
+ };
+diff --git a/include/media/ov772x.h b/include/media/ov772x.h
+index e391d55..57db48d 100644
+--- a/include/media/ov772x.h
++++ b/include/media/ov772x.h
+@@ -13,8 +13,13 @@
+
+ #include <media/soc_camera.h>
+
++/* for flags */
++#define OV772X_FLAG_VFLIP 0x00000001 /* Vertical flip image */
++#define OV772X_FLAG_HFLIP 0x00000002 /* Horizontal flip image */
++
+ struct ov772x_camera_info {
+ unsigned long buswidth;
++ unsigned long flags;
+ struct soc_camera_link link;
+ };
+
+diff --git a/include/media/saa7146.h b/include/media/saa7146.h
+index c5a6e22..fff4235 100644
+--- a/include/media/saa7146.h
++++ b/include/media/saa7146.h
+@@ -13,6 +13,7 @@
+ #include <linux/stringify.h>
+ #include <linux/mutex.h>
+ #include <linux/scatterlist.h>
++#include <media/v4l2-device.h>
+
+ #include <linux/vmalloc.h> /* for vmalloc() */
+ #include <linux/mm.h> /* for vmalloc_to_page() */
+@@ -110,6 +111,8 @@ struct saa7146_dev
+
+ struct list_head item;
+
++ struct v4l2_device v4l2_dev;
++
+ /* different device locks */
+ spinlock_t slock;
+ struct mutex lock;
+@@ -145,6 +148,11 @@ struct saa7146_dev
+ struct saa7146_dma d_rps1;
+ };
+
++static inline struct saa7146_dev *to_saa7146_dev(struct v4l2_device *v4l2_dev)
++{
++ return container_of(v4l2_dev, struct saa7146_dev, v4l2_dev);
++}
++
+ /* from saa7146_i2c.c */
+ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
+
+diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
+index c8d0b23..eed5fcc 100644
+--- a/include/media/saa7146_vv.h
++++ b/include/media/saa7146_vv.h
+@@ -150,16 +150,6 @@ struct saa7146_vv
+ unsigned int resources; /* resource management for device */
+ };
+
+-#define SAA7146_EXCLUSIVE 0x1
+-#define SAA7146_BEFORE 0x2
+-#define SAA7146_AFTER 0x4
+-
+-struct saa7146_extension_ioctls
+-{
+- unsigned int cmd;
+- int flags;
+-};
+-
+ /* flags */
+ #define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */
+
+@@ -176,8 +166,10 @@ struct saa7146_ext_vv
+ int num_stds;
+ int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
+
+- struct saa7146_extension_ioctls *ioctls;
+- long (*ioctl)(struct saa7146_fh *, unsigned int cmd, void *arg);
++ /* the extension can override this */
++ struct v4l2_ioctl_ops ops;
++ /* pointer to the saa7146 core ops */
++ const struct v4l2_ioctl_ops *core_ops;
+
+ struct v4l2_file_operations vbi_fops;
+ };
+@@ -213,6 +205,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sy
+ void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
+
+ /* from saa7146_video.c */
++extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
+ extern struct saa7146_use_ops saa7146_video_uops;
+ int saa7146_start_preview(struct saa7146_fh *fh);
+ int saa7146_stop_preview(struct saa7146_fh *fh);
+diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
+index b5dbefe..0f3524c 100644
+--- a/include/media/sh_mobile_ceu.h
++++ b/include/media/sh_mobile_ceu.h
+@@ -1,10 +1,11 @@
+ #ifndef __ASM_SH_MOBILE_CEU_H__
+ #define __ASM_SH_MOBILE_CEU_H__
+
+-#include <media/soc_camera.h>
++#define SH_CEU_FLAG_USE_8BIT_BUS (1 << 0) /* use 8bit bus width */
++#define SH_CEU_FLAG_USE_16BIT_BUS (1 << 1) /* use 16bit bus width */
+
+ struct sh_mobile_ceu_info {
+- unsigned long flags; /* SOCAM_... */
++ unsigned long flags;
+ };
+
+ #endif /* __ASM_SH_MOBILE_CEU_H__ */
+diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
+index 7440d92..3701368 100644
+--- a/include/media/soc_camera.h
++++ b/include/media/soc_camera.h
+@@ -45,6 +45,7 @@ struct soc_camera_device {
+ int num_formats;
+ struct soc_camera_format_xlate *user_formats;
+ int num_user_formats;
++ enum v4l2_field field; /* Preserve field over close() */
+ struct module *owner;
+ void *host_priv; /* Per-device host private data */
+ /* soc_camera.c private count. Only accessed with .video_lock held */
+@@ -74,7 +75,8 @@ struct soc_camera_host_ops {
+ int (*resume)(struct soc_camera_device *);
+ int (*get_formats)(struct soc_camera_device *, int,
+ struct soc_camera_format_xlate *);
+- int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *);
++ int (*set_crop)(struct soc_camera_device *, struct v4l2_rect *);
++ int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *);
+ int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
+ void (*init_videobuf)(struct videobuf_queue *,
+ struct soc_camera_device *);
+@@ -93,13 +95,18 @@ struct soc_camera_host_ops {
+ struct soc_camera_link {
+ /* Camera bus id, used to match a camera and a bus */
+ int bus_id;
+- /* GPIO number to switch between 8 and 10 bit modes */
+- unsigned int gpio;
+ /* Per camera SOCAM_SENSOR_* bus flags */
+ unsigned long flags;
+ /* Optional callbacks to power on or off and reset the sensor */
+ int (*power)(struct device *, int);
+ int (*reset)(struct device *);
++ /*
++ * some platforms may support different data widths than the sensors
++ * native ones due to different data line routing. Let the board code
++ * overwrite the width flags.
++ */
++ int (*set_bus_param)(struct soc_camera_link *, unsigned long flags);
++ unsigned long (*query_bus_param)(struct soc_camera_link *);
+ };
+
+ static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
+@@ -159,7 +166,8 @@ struct soc_camera_ops {
+ int (*release)(struct soc_camera_device *);
+ int (*start_capture)(struct soc_camera_device *);
+ int (*stop_capture)(struct soc_camera_device *);
+- int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *);
++ int (*set_crop)(struct soc_camera_device *, struct v4l2_rect *);
++ int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *);
+ int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
+ unsigned long (*query_bus_param)(struct soc_camera_device *);
+ int (*set_bus_param)(struct soc_camera_device *, unsigned long);
+@@ -239,15 +247,19 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
+ static inline unsigned long soc_camera_bus_param_compatible(
+ unsigned long camera_flags, unsigned long bus_flags)
+ {
+- unsigned long common_flags, hsync, vsync, pclk;
++ unsigned long common_flags, hsync, vsync, pclk, data, buswidth, mode;
+
+ common_flags = camera_flags & bus_flags;
+
+ hsync = common_flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
+ vsync = common_flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
+ pclk = common_flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
++ data = common_flags & (SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW);
++ mode = common_flags & (SOCAM_MASTER | SOCAM_SLAVE);
++ buswidth = common_flags & SOCAM_DATAWIDTH_MASK;
+
+- return (!hsync || !vsync || !pclk) ? 0 : common_flags;
++ return (!hsync || !vsync || !pclk || !data || !mode || !buswidth) ? 0 :
++ common_flags;
+ }
+
+ extern unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
+diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
+index 9aaf652..1be461a 100644
+--- a/include/media/v4l2-chip-ident.h
++++ b/include/media/v4l2-chip-ident.h
+@@ -37,10 +37,8 @@ enum {
+ /* module saa7110: just ident 100 */
+ V4L2_IDENT_SAA7110 = 100,
+
+- /* module saa7111: just ident 101 */
++ /* module saa7115: reserved range 101-149 */
+ V4L2_IDENT_SAA7111 = 101,
+-
+- /* module saa7115: reserved range 102-149 */
+ V4L2_IDENT_SAA7113 = 103,
+ V4L2_IDENT_SAA7114 = 104,
+ V4L2_IDENT_SAA7115 = 105,
+@@ -63,44 +61,96 @@ enum {
+ V4L2_IDENT_OV7720 = 251,
+ V4L2_IDENT_OV7725 = 252,
+
+- /* Conexant MPEG encoder/decoders: reserved range 410-420 */
++ /* module saa7146: reserved range 300-309 */
++ V4L2_IDENT_SAA7146 = 300,
++
++ /* Conexant MPEG encoder/decoders: reserved range 400-420 */
++ V4L2_IDENT_CX23418_843 = 403, /* Integrated A/V Decoder on the '418 */
+ V4L2_IDENT_CX23415 = 415,
+ V4L2_IDENT_CX23416 = 416,
+ V4L2_IDENT_CX23418 = 418,
+
++ /* module au0828 */
++ V4L2_IDENT_AU0828 = 828,
++
++ /* module indycam: just ident 2000 */
++ V4L2_IDENT_INDYCAM = 2000,
++
++ /* module bt819: reserved range 810-819 */
++ V4L2_IDENT_BT815A = 815,
++ V4L2_IDENT_BT817A = 817,
++ V4L2_IDENT_BT819A = 819,
++
++ /* module bt856: just ident 856 */
++ V4L2_IDENT_BT856 = 856,
++
++ /* module bt866: just ident 866 */
++ V4L2_IDENT_BT866 = 866,
++
++ /* module ks0127: reserved range 1120-1129 */
++ V4L2_IDENT_KS0122S = 1122,
++ V4L2_IDENT_KS0127 = 1127,
++ V4L2_IDENT_KS0127B = 1128,
++
+ /* module vp27smpx: just ident 2700 */
+ V4L2_IDENT_VP27SMPX = 2700,
+
++ /* module vpx3220: reserved range: 3210-3229 */
++ V4L2_IDENT_VPX3214C = 3214,
++ V4L2_IDENT_VPX3216B = 3216,
++ V4L2_IDENT_VPX3220A = 3220,
++
+ /* module tvp5150 */
+ V4L2_IDENT_TVP5150 = 5150,
+
++ /* module saa5246a: just ident 5246 */
++ V4L2_IDENT_SAA5246A = 5246,
++
++ /* module saa5249: just ident 5249 */
++ V4L2_IDENT_SAA5249 = 5249,
++
+ /* module cs5345: just ident 5345 */
+ V4L2_IDENT_CS5345 = 5345,
+
++ /* module tea6415c: just ident 6415 */
++ V4L2_IDENT_TEA6415C = 6415,
++
++ /* module tea6420: just ident 6420 */
++ V4L2_IDENT_TEA6420 = 6420,
++
++ /* module saa6588: just ident 6588 */
++ V4L2_IDENT_SAA6588 = 6588,
++
+ /* module saa6752hs: reserved range 6750-6759 */
+ V4L2_IDENT_SAA6752HS = 6752,
+ V4L2_IDENT_SAA6752HS_AC3 = 6753,
+
++ /* module adv7170: just ident 7170 */
++ V4L2_IDENT_ADV7170 = 7170,
++
++ /* module adv7175: just ident 7175 */
++ V4L2_IDENT_ADV7175 = 7175,
++
++ /* module saa7185: just ident 7185 */
++ V4L2_IDENT_SAA7185 = 7185,
++
++ /* module saa7191: just ident 7191 */
++ V4L2_IDENT_SAA7191 = 7191,
++
+ /* module wm8739: just ident 8739 */
+ V4L2_IDENT_WM8739 = 8739,
+
+ /* module wm8775: just ident 8775 */
+ V4L2_IDENT_WM8775 = 8775,
+
+- /* module tw9910: just ident 9910 */
+- V4L2_IDENT_TW9910 = 9910,
+-
+- /* module cs53132a: just ident 53132 */
+- V4L2_IDENT_CS53l32A = 53132,
+-
+- /* module upd64031a: just ident 64031 */
+- V4L2_IDENT_UPD64031A = 64031,
++ /* module tda9840: just ident 9840 */
++ V4L2_IDENT_TDA9840 = 9840,
+
+- /* module upd64083: just ident 64083 */
+- V4L2_IDENT_UPD64083 = 64083,
++ /* module cafe_ccic, just ident 8801 */
++ V4L2_IDENT_CAFE = 8801,
+
+- /* module m52790: just ident 52790 */
+- V4L2_IDENT_M52790 = 52790,
++ /* module tw9910: just ident 9910 */
++ V4L2_IDENT_TW9910 = 9910,
+
+ /* module msp3400: reserved range 34000-34999 and 44000-44999 */
+ V4L2_IDENT_MSPX4XX = 34000, /* generic MSPX4XX identifier, only
+@@ -178,6 +228,18 @@ enum {
+ V4L2_IDENT_MT9V022IX7ATC = 45010, /* No way to detect "normal" I77ATx */
+ V4L2_IDENT_MT9V022IX7ATM = 45015, /* and "lead free" IA7ATx chips */
+ V4L2_IDENT_MT9T031 = 45020,
++
++ /* module cs53132a: just ident 53132 */
++ V4L2_IDENT_CS53l32A = 53132,
++
++ /* module upd64031a: just ident 64031 */
++ V4L2_IDENT_UPD64031A = 64031,
++
++ /* module upd64083: just ident 64083 */
++ V4L2_IDENT_UPD64083 = 64083,
++
++ /* module m52790: just ident 52790 */
++ V4L2_IDENT_M52790 = 52790,
+ };
+
+ #endif
+diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
+index 95e74f1..3a69056 100644
+--- a/include/media/v4l2-common.h
++++ b/include/media/v4l2-common.h
+@@ -102,11 +102,15 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+ const char *v4l2_ctrl_get_name(u32 id);
+ const char **v4l2_ctrl_get_menu(u32 id);
+ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
+-int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl);
+ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
+ struct v4l2_queryctrl *qctrl, const char **menu_items);
+ #define V4L2_CTRL_MENU_IDS_END (0xffffffff)
+ int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids);
++
++/* Note: ctrl_classes points to an array of u32 pointers. Each u32 array is a
++ 0-terminated array of control IDs. Each array must be sorted low to high
++ and belong to the same control class. The array of u32 pointers must also
++ be sorted, from low class IDs to high class IDs. */
+ u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
+
+ /* ------------------------------------------------------------------------- */
+@@ -149,6 +153,21 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
+ /* Initialize an v4l2_subdev with data from an i2c_client struct */
+ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
+ const struct v4l2_subdev_ops *ops);
++/* Return i2c client address of v4l2_subdev. */
++unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd);
++
++enum v4l2_i2c_tuner_type {
++ ADDRS_RADIO, /* Radio tuner addresses */
++ ADDRS_DEMOD, /* Demod tuner addresses */
++ ADDRS_TV, /* TV tuner addresses */
++ /* TV tuner addresses if demod is present, this excludes
++ addresses used by the demodulator from the list of
++ candidates. */
++ ADDRS_TV_WITH_DEMOD,
++};
++/* Return a list of I2C tuner addresses to probe. Use only if the tuner
++ addresses are unknown. */
++const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type);
+
+ /* ------------------------------------------------------------------------- */
+
+@@ -284,4 +303,7 @@ struct v4l2_crystal_freq {
+ a v4l2_gpio struct if a direction is also needed. */
+ #define VIDIOC_INT_S_GPIO _IOW('d', 117, u32)
+
++/* Get input status. Same as the status field in the v4l2_input struct. */
++#define VIDIOC_INT_G_INPUT_STATUS _IOR('d', 118, u32)
++
+ #endif /* V4L2_COMMON_H_ */
+diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
+index e36faab..2058dd4 100644
+--- a/include/media/v4l2-dev.h
++++ b/include/media/v4l2-dev.h
+@@ -40,6 +40,8 @@ struct v4l2_file_operations {
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ long (*ioctl) (struct file *, unsigned int, unsigned long);
+ long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
++ unsigned long (*get_unmapped_area) (struct file *, unsigned long,
++ unsigned long, unsigned long, unsigned long);
+ int (*mmap) (struct file *, struct vm_area_struct *);
+ int (*open) (struct file *);
+ int (*release) (struct file *);
+diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h
+index 55e41af..0dd3e8e 100644
+--- a/include/media/v4l2-device.h
++++ b/include/media/v4l2-device.h
+@@ -33,7 +33,9 @@
+ #define V4L2_DEVICE_NAME_SIZE (BUS_ID_SIZE + 16)
+
+ struct v4l2_device {
+- /* dev->driver_data points to this struct */
++ /* dev->driver_data points to this struct.
++ Note: dev might be NULL if there is no parent device
++ as is the case with e.g. ISA devices. */
+ struct device *dev;
+ /* used to keep track of the registered subdevs */
+ struct list_head subdevs;
+@@ -42,33 +44,43 @@ struct v4l2_device {
+ spinlock_t lock;
+ /* unique device name, by default the driver name + bus ID */
+ char name[V4L2_DEVICE_NAME_SIZE];
++ /* notify callback called by some sub-devices. */
++ void (*notify)(struct v4l2_subdev *sd,
++ unsigned int notification, void *arg);
+ };
+
+-/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev */
++/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev.
++ dev may be NULL in rare cases (ISA devices). In that case you
++ must fill in the v4l2_dev->name field before calling this function. */
+ int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+-/* Set v4l2_dev->dev->driver_data to NULL and unregister all sub-devices */
++/* Set v4l2_dev->dev to NULL. Call when the USB parent disconnects.
++ Since the parent disappears this ensures that v4l2_dev doesn't have an
++ invalid parent pointer. */
++void v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
++/* Unregister all sub-devices and any other resources related to v4l2_dev. */
+ void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
+
+ /* Register a subdev with a v4l2 device. While registered the subdev module
+ is marked as in-use. An error is returned if the module is no longer
+ loaded when you attempt to register it. */
+-int __must_check v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd);
++int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
++ struct v4l2_subdev *sd);
+ /* Unregister a subdev with a v4l2 device. Can also be called if the subdev
+ wasn't registered. In that case it will do nothing. */
+ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
+
+ /* Iterate over all subdevs. */
+-#define v4l2_device_for_each_subdev(sd, dev) \
+- list_for_each_entry(sd, &(dev)->subdevs, list)
++#define v4l2_device_for_each_subdev(sd, v4l2_dev) \
++ list_for_each_entry(sd, &(v4l2_dev)->subdevs, list)
+
+ /* Call the specified callback for all subdevs matching the condition.
+ Ignore any errors. Note that you cannot add or delete a subdev
+ while walking the subdevs list. */
+-#define __v4l2_device_call_subdevs(dev, cond, o, f, args...) \
++#define __v4l2_device_call_subdevs(v4l2_dev, cond, o, f, args...) \
+ do { \
+ struct v4l2_subdev *sd; \
+ \
+- list_for_each_entry(sd, &(dev)->subdevs, list) \
++ list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) \
+ if ((cond) && sd->ops->o && sd->ops->o->f) \
+ sd->ops->o->f(sd , ##args); \
+ } while (0)
+@@ -77,12 +89,12 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
+ If the callback returns an error other than 0 or -ENOIOCTLCMD, then
+ return with that error code. Note that you cannot add or delete a
+ subdev while walking the subdevs list. */
+-#define __v4l2_device_call_subdevs_until_err(dev, cond, o, f, args...) \
++#define __v4l2_device_call_subdevs_until_err(v4l2_dev, cond, o, f, args...) \
+ ({ \
+ struct v4l2_subdev *sd; \
+ long err = 0; \
+ \
+- list_for_each_entry(sd, &(dev)->subdevs, list) { \
++ list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) { \
+ if ((cond) && sd->ops->o && sd->ops->o->f) \
+ err = sd->ops->o->f(sd , ##args); \
+ if (err && err != -ENOIOCTLCMD) \
+@@ -94,16 +106,16 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
+ /* Call the specified callback for all subdevs matching grp_id (if 0, then
+ match them all). Ignore any errors. Note that you cannot add or delete
+ a subdev while walking the subdevs list. */
+-#define v4l2_device_call_all(dev, grpid, o, f, args...) \
+- __v4l2_device_call_subdevs(dev, \
++#define v4l2_device_call_all(v4l2_dev, grpid, o, f, args...) \
++ __v4l2_device_call_subdevs(v4l2_dev, \
+ !(grpid) || sd->grp_id == (grpid), o, f , ##args)
+
+ /* Call the specified callback for all subdevs matching grp_id (if 0, then
+ match them all). If the callback returns an error other than 0 or
+ -ENOIOCTLCMD, then return with that error code. Note that you cannot
+ add or delete a subdev while walking the subdevs list. */
+-#define v4l2_device_call_until_err(dev, grpid, o, f, args...) \
+- __v4l2_device_call_subdevs_until_err(dev, \
++#define v4l2_device_call_until_err(v4l2_dev, grpid, o, f, args...) \
++ __v4l2_device_call_subdevs_until_err(v4l2_dev, \
+ !(grpid) || sd->grp_id == (grpid), o, f , ##args)
+
+ #endif
+diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
+index b01c044..7a4529d 100644
+--- a/include/media/v4l2-ioctl.h
++++ b/include/media/v4l2-ioctl.h
+@@ -15,6 +15,7 @@
+ #include <linux/mutex.h>
+ #include <linux/compiler.h> /* need __user */
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
++#define __MIN_V4L1
+ #include <linux/videodev.h>
+ #else
+ #include <linux/videodev2.h>
+@@ -267,6 +268,7 @@ struct v4l2_ioctl_ops {
+
+ /* Video standard functions */
+ extern const char *v4l2_norm_to_name(v4l2_std_id id);
++extern void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod);
+ extern int v4l2_video_std_construct(struct v4l2_standard *vs,
+ int id, const char *name);
+ /* Prints the ioctl in a human-readable format */
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 37b09e5..1d181b4 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -78,6 +78,9 @@ struct v4l2_subdev_core_ops {
+ int (*queryctrl)(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
+ int (*g_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
+ int (*s_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
++ int (*g_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls);
++ int (*s_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls);
++ int (*try_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls);
+ int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm);
+ long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+@@ -112,9 +115,17 @@ struct v4l2_subdev_video_ops {
+ int (*g_vbi_data)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *vbi_data);
+ int (*g_sliced_vbi_cap)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap);
+ int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
++ int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
++ int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
+ int (*s_stream)(struct v4l2_subdev *sd, int enable);
+- int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
++ int (*enum_fmt)(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmtdesc);
+ int (*g_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
++ int (*try_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
++ int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
++ int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
++ int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
++ int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize);
++ int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival);
+ };
+
+ struct v4l2_subdev_ops {
+@@ -132,7 +143,7 @@ struct v4l2_subdev_ops {
+ struct v4l2_subdev {
+ struct list_head list;
+ struct module *owner;
+- struct v4l2_device *dev;
++ struct v4l2_device *v4l2_dev;
+ const struct v4l2_subdev_ops *ops;
+ /* name must be unique */
+ char name[V4L2_SUBDEV_NAME_SIZE];
+@@ -171,7 +182,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
+ /* ops->core MUST be set */
+ BUG_ON(!ops || !ops->core);
+ sd->ops = ops;
+- sd->dev = NULL;
++ sd->v4l2_dev = NULL;
+ sd->name[0] = '\0';
+ sd->grp_id = 0;
+ sd->priv = NULL;
+@@ -186,4 +197,9 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
+ (!(sd) ? -ENODEV : (((sd) && (sd)->ops->o && (sd)->ops->o->f) ? \
+ (sd)->ops->o->f((sd) , ##args) : -ENOIOCTLCMD))
+
++/* Send a notification to v4l2_device. */
++#define v4l2_subdev_notify(sd, notification, arg) \
++ ((!(sd) || !(sd)->v4l2_dev || !(sd)->v4l2_dev->notify) ? -ENODEV : \
++ (sd)->v4l2_dev->notify((sd), (notification), (arg)))
++
+ #endif
+diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h
+index 874f134..1c5946c 100644
+--- a/include/media/videobuf-core.h
++++ b/include/media/videobuf-core.h
+@@ -18,6 +18,7 @@
+
+ #include <linux/poll.h>
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
++#define __MIN_V4L1
+ #include <linux/videodev.h>
+ #endif
+ #include <linux/videodev2.h>
+diff --git a/include/sound/tea575x-tuner.h b/include/sound/tea575x-tuner.h
+index 426899e..5718a02 100644
+--- a/include/sound/tea575x-tuner.h
++++ b/include/sound/tea575x-tuner.h
+@@ -22,8 +22,9 @@
+ *
+ */
+
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <media/v4l2-dev.h>
++#include <media/v4l2-ioctl.h>
+
+ struct snd_tea575x;
+
+@@ -35,11 +36,10 @@ struct snd_tea575x_ops {
+
+ struct snd_tea575x {
+ struct snd_card *card;
+- struct video_device vd; /* video device */
+- struct v4l2_file_operations fops;
++ struct video_device *vd; /* video device */
+ int dev_nr; /* requested device number + 1 */
+- int vd_registered; /* video device is registered */
+ int tea5759; /* 5759 chip is present */
++ int mute; /* Device is muted? */
+ unsigned int freq_fixup; /* crystal onboard */
+ unsigned int val; /* hw value */
+ unsigned long freq; /* frequency */
+diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
+index 9d98a66..d31c373 100644
+--- a/sound/i2c/other/tea575x-tuner.c
++++ b/sound/i2c/other/tea575x-tuner.c
+@@ -24,6 +24,7 @@
+ #include <linux/delay.h>
+ #include <linux/interrupt.h>
+ #include <linux/init.h>
++#include <linux/version.h>
+ #include <sound/core.h>
+ #include <sound/tea575x-tuner.h>
+
+@@ -31,6 +32,13 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
+ MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
+ MODULE_LICENSE("GPL");
+
++static int radio_nr = -1;
++module_param(radio_nr, int, 0);
++
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
++#define FREQ_LO (87 * 16000)
++#define FREQ_HI (108 * 16000)
++
+ /*
+ * definitions
+ */
+@@ -53,6 +61,17 @@ MODULE_LICENSE("GPL");
+ #define TEA575X_BIT_DUMMY (1<<15) /* buffer */
+ #define TEA575X_BIT_FREQ_MASK 0x7fff
+
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ }
++};
++
+ /*
+ * lowlevel part
+ */
+@@ -84,94 +103,146 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea)
+ * Linux Video interface
+ */
+
+-static long snd_tea575x_ioctl(struct file *file,
+- unsigned int cmd, unsigned long data)
++static int vidioc_querycap(struct file *file, void *priv,
++ struct v4l2_capability *v)
+ {
+ struct snd_tea575x *tea = video_drvdata(file);
+- void __user *arg = (void __user *)data;
+-
+- switch(cmd) {
+- case VIDIOCGCAP:
+- {
+- struct video_capability v;
+- v.type = VID_TYPE_TUNER;
+- v.channels = 1;
+- v.audios = 1;
+- /* No we don't do pictures */
+- v.maxwidth = 0;
+- v.maxheight = 0;
+- v.minwidth = 0;
+- v.minheight = 0;
+- strcpy(v.name, tea->tea5759 ? "TEA5759" : "TEA5757");
+- if (copy_to_user(arg,&v,sizeof(v)))
+- return -EFAULT;
+- return 0;
+- }
+- case VIDIOCGTUNER:
+- {
+- struct video_tuner v;
+- if (copy_from_user(&v, arg,sizeof(v))!=0)
+- return -EFAULT;
+- if (v.tuner) /* Only 1 tuner */
+- return -EINVAL;
+- v.rangelow = (87*16000);
+- v.rangehigh = (108*16000);
+- v.flags = VIDEO_TUNER_LOW;
+- v.mode = VIDEO_MODE_AUTO;
+- strcpy(v.name, "FM");
+- v.signal = 0xFFFF;
+- if (copy_to_user(arg, &v, sizeof(v)))
+- return -EFAULT;
+- return 0;
+- }
+- case VIDIOCSTUNER:
+- {
+- struct video_tuner v;
+- if(copy_from_user(&v, arg, sizeof(v)))
+- return -EFAULT;
+- if(v.tuner!=0)
+- return -EINVAL;
+- /* Only 1 tuner so no setting needed ! */
++
++ strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757");
++ strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
++ strlcpy(v->card, "Maestro Radio", sizeof(v->card));
++ sprintf(v->bus_info, "PCI");
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER;
++ return 0;
++}
++
++static int vidioc_g_tuner(struct file *file, void *priv,
++ struct v4l2_tuner *v)
++{
++ if (v->index > 0)
++ return -EINVAL;
++
++ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++ v->rangelow = FREQ_LO;
++ v->rangehigh = FREQ_HI;
++ v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
++ v->capability = V4L2_TUNER_CAP_LOW;
++ v->audmode = V4L2_TUNER_MODE_MONO;
++ v->signal = 0xffff;
++ return 0;
++}
++
++static int vidioc_s_tuner(struct file *file, void *priv,
++ struct v4l2_tuner *v)
++{
++ if (v->index > 0)
++ return -EINVAL;
++ return 0;
++}
++
++static int vidioc_g_frequency(struct file *file, void *priv,
++ struct v4l2_frequency *f)
++{
++ struct snd_tea575x *tea = video_drvdata(file);
++
++ f->type = V4L2_TUNER_RADIO;
++ f->frequency = tea->freq;
++ return 0;
++}
++
++static int vidioc_s_frequency(struct file *file, void *priv,
++ struct v4l2_frequency *f)
++{
++ struct snd_tea575x *tea = video_drvdata(file);
++
++ if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
++ return -EINVAL;
++
++ tea->freq = f->frequency;
++
++ snd_tea575x_set_freq(tea);
++
++ return 0;
++}
++
++static int vidioc_g_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ if (a->index > 1)
++ return -EINVAL;
++
++ strcpy(a->name, "Radio");
++ a->capability = V4L2_AUDCAP_STEREO;
++ return 0;
++}
++
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ if (a->index != 0)
++ return -EINVAL;
++ return 0;
++}
++
++static int vidioc_queryctrl(struct file *file, void *priv,
++ struct v4l2_queryctrl *qc)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]),
++ sizeof(*qc));
+ return 0;
+ }
+- case VIDIOCGFREQ:
+- if(copy_to_user(arg, &tea->freq, sizeof(tea->freq)))
+- return -EFAULT;
+- return 0;
+- case VIDIOCSFREQ:
+- if(copy_from_user(&tea->freq, arg, sizeof(tea->freq)))
+- return -EFAULT;
+- snd_tea575x_set_freq(tea);
+- return 0;
+- case VIDIOCGAUDIO:
+- {
+- struct video_audio v;
+- memset(&v, 0, sizeof(v));
+- strcpy(v.name, "Radio");
+- if(copy_to_user(arg,&v, sizeof(v)))
+- return -EFAULT;
++ }
++ return -EINVAL;
++}
++
++static int vidioc_g_ctrl(struct file *file, void *priv,
++ struct v4l2_control *ctrl)
++{
++ struct snd_tea575x *tea = video_drvdata(file);
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (tea->ops->mute) {
++ ctrl->value = tea->mute;
+ return 0;
+ }
+- case VIDIOCSAUDIO:
+- {
+- struct video_audio v;
+- if(copy_from_user(&v, arg, sizeof(v)))
+- return -EFAULT;
+- if (tea->ops->mute)
+- tea->ops->mute(tea,
+- (v.flags &
+- VIDEO_AUDIO_MUTE) ? 1 : 0);
+- if(v.audio)
+- return -EINVAL;
++ }
++ return -EINVAL;
++}
++
++static int vidioc_s_ctrl(struct file *file, void *priv,
++ struct v4l2_control *ctrl)
++{
++ struct snd_tea575x *tea = video_drvdata(file);
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_MUTE:
++ if (tea->ops->mute) {
++ tea->ops->mute(tea, ctrl->value);
++ tea->mute = 1;
+ return 0;
+ }
+- default:
+- return -ENOIOCTLCMD;
+ }
++ return -EINVAL;
++}
++
++static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
++{
++ *i = 0;
++ return 0;
+ }
+
+-static void snd_tea575x_release(struct video_device *vfd)
++static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+ {
++ if (i != 0)
++ return -EINVAL;
++ return 0;
+ }
+
+ static int snd_tea575x_exclusive_open(struct file *file)
+@@ -189,50 +260,91 @@ static int snd_tea575x_exclusive_release(struct file *file)
+ return 0;
+ }
+
++static const struct v4l2_file_operations tea575x_fops = {
++ .owner = THIS_MODULE,
++ .open = snd_tea575x_exclusive_open,
++ .release = snd_tea575x_exclusive_release,
++ .ioctl = video_ioctl2,
++};
++
++static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_g_tuner = vidioc_g_tuner,
++ .vidioc_s_tuner = vidioc_s_tuner,
++ .vidioc_g_audio = vidioc_g_audio,
++ .vidioc_s_audio = vidioc_s_audio,
++ .vidioc_g_input = vidioc_g_input,
++ .vidioc_s_input = vidioc_s_input,
++ .vidioc_g_frequency = vidioc_g_frequency,
++ .vidioc_s_frequency = vidioc_s_frequency,
++ .vidioc_queryctrl = vidioc_queryctrl,
++ .vidioc_g_ctrl = vidioc_g_ctrl,
++ .vidioc_s_ctrl = vidioc_s_ctrl,
++};
++
++static struct video_device tea575x_radio = {
++ .name = "tea575x-tuner",
++ .fops = &tea575x_fops,
++ .ioctl_ops = &tea575x_ioctl_ops,
++ .release = video_device_release,
++};
++
+ /*
+ * initialize all the tea575x chips
+ */
+ void snd_tea575x_init(struct snd_tea575x *tea)
+ {
++ int retval;
+ unsigned int val;
++ struct video_device *tea575x_radio_inst;
+
+ val = tea->ops->read(tea);
+ if (val == 0x1ffffff || val == 0) {
+- snd_printk(KERN_ERR "Cannot find TEA575x chip\n");
++ snd_printk(KERN_ERR
++ "tea575x-tuner: Cannot find TEA575x chip\n");
+ return;
+ }
+
+- memset(&tea->vd, 0, sizeof(tea->vd));
+- strcpy(tea->vd.name, tea->tea5759 ? "TEA5759 radio" : "TEA5757 radio");
+- tea->vd.release = snd_tea575x_release;
+- video_set_drvdata(&tea->vd, tea);
+- tea->vd.fops = &tea->fops;
+ tea->in_use = 0;
+- tea->fops.owner = tea->card->module;
+- tea->fops.open = snd_tea575x_exclusive_open;
+- tea->fops.release = snd_tea575x_exclusive_release;
+- tea->fops.ioctl = snd_tea575x_ioctl;
+- if (video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->dev_nr - 1) < 0) {
+- snd_printk(KERN_ERR "unable to register tea575x tuner\n");
++ tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
++ tea->freq = 90500 * 16; /* 90.5Mhz default */
++
++ tea575x_radio_inst = video_device_alloc();
++ if (tea575x_radio_inst == NULL) {
++ printk(KERN_ERR "tea575x-tuner: not enough memory\n");
+ return;
+ }
+- tea->vd_registered = 1;
+
+- tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
+- tea->freq = 90500 * 16; /* 90.5Mhz default */
++ memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
++
++ strcpy(tea575x_radio.name, tea->tea5759 ?
++ "TEA5759 radio" : "TEA5757 radio");
++
++ video_set_drvdata(tea575x_radio_inst, tea);
++
++ retval = video_register_device(tea575x_radio_inst,
++ VFL_TYPE_RADIO, radio_nr);
++ if (retval) {
++ printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
++ kfree(tea575x_radio_inst);
++ return;
++ }
+
+ snd_tea575x_set_freq(tea);
+
+ /* mute on init */
+- if (tea->ops->mute)
++ if (tea->ops->mute) {
+ tea->ops->mute(tea, 1);
++ tea->mute = 1;
++ }
++ tea->vd = tea575x_radio_inst;
+ }
+
+ void snd_tea575x_exit(struct snd_tea575x *tea)
+ {
+- if (tea->vd_registered) {
+- video_unregister_device(&tea->vd);
+- tea->vd_registered = 0;
++ if (tea->vd) {
++ video_unregister_device(tea->vd);
++ tea->vd = NULL;
+ }
+ }
+
+diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
+index 82b9bdd..6cc18bf 100644
+--- a/sound/pci/Kconfig
++++ b/sound/pci/Kconfig
+@@ -487,7 +487,7 @@ config SND_FM801
+ config SND_FM801_TEA575X_BOOL
+ bool "ForteMedia FM801 + TEA5757 tuner"
+ depends on SND_FM801
+- depends on VIDEO_V4L1=y || VIDEO_V4L1=SND_FM801
++ depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801
+ help
+ Say Y here to include support for soundcards based on the ForteMedia
+ FM801 chip with a TEA5757 tuner connected to GPIO1-3 pins (Media
+--- linux-2.6.30.noarch/drivers/media/video/hdpvr/hdpvr-i2c.c~ 2009-07-09 21:56:58.000000000 -0400
++++ linux-2.6.30.noarch/drivers/media/video/hdpvr/hdpvr-i2c.c 2009-07-09 21:57:34.000000000 -0400
+@@ -64,7 +64,7 @@ static int hdpvr_i2c_write(struct hdpvr_
+
+ ret = usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+- REQTYPE_I2C_WRITE_STAT, CTRL_READ_REQUEST,
++ REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
+ 0, 0, buf, 2, 1000);
+
+ if (ret == 2)