summary refs log tree commit diff
path: root/drivers/media
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-09 19:50:49 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-09 19:50:49 -0800
commit3e7468313758913c5e4d372f35b271b96bad1298 (patch)
treeeb612d252a9e2349a1173451cd779beebd18a33e /drivers/media
parent6825fbc4cb219f2c98bb7d157915d797cf5cb823 (diff)
parente97f4677961f68e29bd906022ebf60a6df7f530a (diff)
downloadlinux-3e7468313758913c5e4d372f35b271b96bad1298.tar.gz
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (345 commits)
  V4L/DVB (13542): ir-keytable: Allow dynamic table change
  V4L/DVB (13541): atbm8830: replace 64-bit division and floating point usage
  V4L/DVB (13540): ir-common: Cleanup get key evdev code
  V4L/DVB (13539): ir-common: add __func__ for debug messages
  V4L/DVB (13538): ir-common: Use a dynamic keycode table
  V4L/DVB (13537): ir: Prepare the code for dynamic keycode table allocation
  V4L/DVB (13536): em28xx: Use the full RC5 code on HVR-950 Remote Controller
  V4L/DVB (13535): ir-common: Add a hauppauge new table with the complete RC5 code
  V4L/DVB (13534): ir-common: Remove some unused fields/structs
  V4L/DVB (13533): ir: use dynamic tables, instead of static ones
  V4L/DVB (13532): ir-common: Add infrastructure to use a dynamic keycode table
  V4L/DVB (13531): ir-common: rename the debug routine to allow exporting it
  V4L/DVB (13458): go7007: subdev conversion
  V4L/DVB (13457): s2250: subdev conversion
  V4L/DVB (13456): s2250: Change module structure
  V4L/DVB (13528): em28xx: add support for em2800 VC211A card
  em28xx: don't reduce scale to half size for em2800
  em28xx: don't load audio modules when AC97 is mis-detected
  em28xx: em2800 chips support max width of 640
  V4L/DVB (13523): dvb-bt8xx: fix compile warning
  ...

Fix up trivial conflicts due to spelling fixes from the trivial tree in
	Documentation/video4linux/gspca.txt
	drivers/media/video/cx18/cx18-mailbox.h
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/common/Makefile2
-rw-r--r--drivers/media/common/ir-functions.c71
-rw-r--r--drivers/media/common/ir-keymaps.c167
-rw-r--r--drivers/media/common/ir-keytable.c429
-rw-r--r--drivers/media/common/saa7146_video.c16
-rw-r--r--drivers/media/common/tuners/Kconfig7
-rw-r--r--drivers/media/common/tuners/Makefile1
-rw-r--r--drivers/media/common/tuners/max2165.c442
-rw-r--r--drivers/media/common/tuners/max2165.h48
-rw-r--r--drivers/media/common/tuners/max2165_priv.h60
-rw-r--r--drivers/media/common/tuners/mxl5005s.c5
-rw-r--r--drivers/media/common/tuners/mxl5005s.h4
-rw-r--r--drivers/media/common/tuners/mxl5007t.c2
-rw-r--r--drivers/media/common/tuners/tda18271-common.c16
-rw-r--r--drivers/media/common/tuners/tda18271-fe.c114
-rw-r--r--drivers/media/common/tuners/tda18271-maps.c1
-rw-r--r--drivers/media/common/tuners/tda18271-priv.h47
-rw-r--r--drivers/media/common/tuners/tda18271.h12
-rw-r--r--drivers/media/common/tuners/tda8290.c1
-rw-r--r--drivers/media/common/tuners/tda9887.c2
-rw-r--r--drivers/media/common/tuners/xc5000.c97
-rw-r--r--drivers/media/common/tuners/xc5000.h6
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c2
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c12
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c39
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.h5
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c179
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h28
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig8
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c33
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.h215
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c117
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c182
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-dvb.c1
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h11
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h3
-rw-r--r--drivers/media/dvb/dvb-usb/ec168.c440
-rw-r--r--drivers/media/dvb/dvb-usb/ec168.h73
-rw-r--r--drivers/media/dvb/dvb-usb/friio-fe.c59
-rw-r--r--drivers/media/dvb/firewire/Kconfig7
-rw-r--r--drivers/media/dvb/firewire/Makefile1
-rw-r--r--drivers/media/dvb/firewire/firedtv-1394.c41
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c54
-rw-r--r--drivers/media/dvb/firewire/firedtv-dvb.c15
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c376
-rw-r--r--drivers/media/dvb/firewire/firedtv-rc.c2
-rw-r--r--drivers/media/dvb/firewire/firedtv.h19
-rw-r--r--drivers/media/dvb/frontends/Kconfig21
-rw-r--r--drivers/media/dvb/frontends/Makefile3
-rw-r--r--drivers/media/dvb/frontends/atbm8830.c495
-rw-r--r--drivers/media/dvb/frontends/atbm8830.h76
-rw-r--r--drivers/media/dvb/frontends/atbm8830_priv.h75
-rw-r--r--drivers/media/dvb/frontends/au8522_decoder.c22
-rw-r--r--drivers/media/dvb/frontends/au8522_priv.h2
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c33
-rw-r--r--drivers/media/dvb/frontends/dib7000p.h13
-rw-r--r--drivers/media/dvb/frontends/dib8000.c23
-rw-r--r--drivers/media/dvb/frontends/dib8000.h14
-rw-r--r--drivers/media/dvb/frontends/ds3000.c1367
-rw-r--r--drivers/media/dvb/frontends/ds3000.h45
-rw-r--r--drivers/media/dvb/frontends/ec100.c335
-rw-r--r--drivers/media/dvb/frontends/ec100.h46
-rw-r--r--drivers/media/dvb/frontends/ec100_priv.h39
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c149
-rw-r--r--drivers/media/dvb/frontends/s5h1409.h7
-rw-r--r--drivers/media/dvb/frontends/stb6100_proc.h138
-rw-r--r--drivers/media/dvb/frontends/stv0900.h3
-rw-r--r--drivers/media/dvb/frontends/stv0900_core.c1560
-rw-r--r--drivers/media/dvb/frontends/stv0900_init.h257
-rw-r--r--drivers/media/dvb/frontends/stv0900_priv.h81
-rw-r--r--drivers/media/dvb/frontends/stv0900_reg.h5000
-rw-r--r--drivers/media/dvb/frontends/stv0900_sw.c3171
-rw-r--r--drivers/media/dvb/frontends/stv090x.c242
-rw-r--r--drivers/media/dvb/frontends/stv090x_priv.h3
-rw-r--r--drivers/media/dvb/frontends/stv090x_reg.h70
-rw-r--r--drivers/media/dvb/frontends/stv6110.c13
-rw-r--r--drivers/media/dvb/frontends/stv6110.h1
-rw-r--r--drivers/media/dvb/frontends/stv6110x.c6
-rw-r--r--drivers/media/dvb/pt1/pt1.c1
-rw-r--r--drivers/media/dvb/pt1/va1j5jf8007s.c57
-rw-r--r--drivers/media/dvb/pt1/va1j5jf8007t.c49
-rw-r--r--drivers/media/dvb/siano/sms-cards.c4
-rw-r--r--drivers/media/dvb/siano/sms-cards.h2
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c2
-rw-r--r--drivers/media/dvb/siano/smssdio.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c18
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c2
-rw-r--r--drivers/media/radio/Kconfig12
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/radio-mr800.c358
-rw-r--r--drivers/media/radio/tef6862.c232
-rw-r--r--drivers/media/video/Kconfig33
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/adv7180.c323
-rw-r--r--drivers/media/video/au0828/au0828-video.c2
-rw-r--r--drivers/media/video/bt819.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c15
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c14
-rw-r--r--drivers/media/video/cx18/cx18-cards.h3
-rw-r--r--drivers/media/video/cx18/cx18-driver.c60
-rw-r--r--drivers/media/video/cx18/cx18-driver.h62
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c9
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c132
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c25
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c3
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c62
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.h6
-rw-r--r--drivers/media/video/cx18/cx18-queue.c346
-rw-r--r--drivers/media/video/cx18/cx18-queue.h41
-rw-r--r--drivers/media/video/cx18/cx18-scb.h4
-rw-r--r--drivers/media/video/cx18/cx18-streams.c92
-rw-r--r--drivers/media/video/cx18/cx18-streams.h10
-rw-r--r--drivers/media/video/cx18/cx18-vbi.c35
-rw-r--r--drivers/media/video/cx18/cx18-vbi.h2
-rw-r--r--drivers/media/video/cx18/cx18-version.h2
-rw-r--r--drivers/media/video/cx18/cx23418.h2
-rw-r--r--drivers/media/video/cx231xx/cx231xx-input.c11
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c2
-rw-r--r--drivers/media/video/cx23885/Kconfig2
-rw-r--r--drivers/media/video/cx23885/Makefile3
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c10
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c155
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c115
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c158
-rw-r--r--drivers/media/video/cx23885/cx23885-f300.c177
-rw-r--r--drivers/media/video/cx23885/cx23885-f300.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-input.c427
-rw-r--r--drivers/media/video/cx23885/cx23885-input.h30
-rw-r--r--drivers/media/video/cx23885/cx23885-ioctl.c208
-rw-r--r--drivers/media/video/cx23885/cx23885-ioctl.h39
-rw-r--r--drivers/media/video/cx23885/cx23885-ir.c101
-rw-r--r--drivers/media/video/cx23885/cx23885-ir.h31
-rw-r--r--drivers/media/video/cx23885/cx23885-reg.h5
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c44
-rw-r--r--drivers/media/video/cx23885/cx23885.h31
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.c1239
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.h28
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c463
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c324
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h22
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c10
-rw-r--r--drivers/media/video/cx88/Kconfig2
-rw-r--r--drivers/media/video/cx88/cx88-cards.c19
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c58
-rw-r--r--drivers/media/video/cx88/cx88-input.c47
-rw-r--r--drivers/media/video/cx88/cx88-video.c2
-rw-r--r--drivers/media/video/cx88/cx88.h1
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c47
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c4
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c50
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c22
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c24
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c27
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c8
-rw-r--r--drivers/media/video/em28xx/em28xx.h7
-rw-r--r--drivers/media/video/gspca/Kconfig23
-rw-r--r--drivers/media/video/gspca/Makefile4
-rw-r--r--drivers/media/video/gspca/conex.c12
-rw-r--r--drivers/media/video/gspca/etoms.c10
-rw-r--r--drivers/media/video/gspca/finepix.c23
-rw-r--r--drivers/media/video/gspca/gl860/gl860-mi1320.c55
-rw-r--r--drivers/media/video/gspca/gl860/gl860-mi2020.c69
-rw-r--r--drivers/media/video/gspca/gl860/gl860-ov2640.c140
-rw-r--r--drivers/media/video/gspca/gl860/gl860-ov9655.c43
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c61
-rw-r--r--drivers/media/video/gspca/gl860/gl860.h7
-rw-r--r--drivers/media/video/gspca/gspca.c137
-rw-r--r--drivers/media/video/gspca/gspca.h15
-rw-r--r--drivers/media/video/gspca/jeilinj.c34
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c25
-rw-r--r--drivers/media/video/gspca/mars.c11
-rw-r--r--drivers/media/video/gspca/mr97310a.c602
-rw-r--r--drivers/media/video/gspca/ov519.c1495
-rw-r--r--drivers/media/video/gspca/ov534.c1537
-rw-r--r--drivers/media/video/gspca/pac207.c13
-rw-r--r--drivers/media/video/gspca/pac7302.c1272
-rw-r--r--drivers/media/video/gspca/pac7311.c716
-rw-r--r--drivers/media/video/gspca/pac_common.h91
-rw-r--r--drivers/media/video/gspca/sn9c20x.c11
-rw-r--r--drivers/media/video/gspca/sonixb.c21
-rw-r--r--drivers/media/video/gspca/sonixj.c660
-rw-r--r--drivers/media/video/gspca/spca500.c11
-rw-r--r--drivers/media/video/gspca/spca501.c14
-rw-r--r--drivers/media/video/gspca/spca505.c10
-rw-r--r--drivers/media/video/gspca/spca506.c12
-rw-r--r--drivers/media/video/gspca/spca508.c10
-rw-r--r--drivers/media/video/gspca/spca561.c14
-rw-r--r--drivers/media/video/gspca/sq905.c75
-rw-r--r--drivers/media/video/gspca/sq905c.c31
-rw-r--r--drivers/media/video/gspca/stk014.c11
-rw-r--r--drivers/media/video/gspca/stv0680.c364
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c11
-rw-r--r--drivers/media/video/gspca/sunplus.c11
-rw-r--r--drivers/media/video/gspca/t613.c7
-rw-r--r--drivers/media/video/gspca/tv8532.c7
-rw-r--r--drivers/media/video/gspca/vc032x.c23
-rw-r--r--drivers/media/video/gspca/w996Xcf.c609
-rw-r--r--drivers/media/video/gspca/zc3xx.c1470
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c8
-rw-r--r--drivers/media/video/hexium_gemini.c2
-rw-r--r--drivers/media/video/hexium_orion.c2
-rw-r--r--drivers/media/video/ir-kbd-i2c.c19
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c16
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h51
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c23
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h6
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c153
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.h1
-rw-r--r--drivers/media/video/mxb.c2
-rw-r--r--drivers/media/video/ov9640.c801
-rw-r--r--drivers/media/video/ov9640.h209
-rw-r--r--drivers/media/video/pms.c1425
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c17
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c13
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.h1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c63
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c15
-rw-r--r--drivers/media/video/pwc/pwc-if.c23
-rw-r--r--drivers/media/video/rj54n1cb0c.c1219
-rw-r--r--drivers/media/video/s2255drv.c2
-rw-r--r--drivers/media/video/saa7110.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c55
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c66
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c55
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/video/saa7134/saa7134.h3
-rw-r--r--drivers/media/video/saa7164/saa7164-dvb.c1
-rw-r--r--drivers/media/video/saa717x.c4
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c83
-rw-r--r--drivers/media/video/tuner-core.c20
-rw-r--r--drivers/media/video/tvaudio.c2
-rw-r--r--drivers/media/video/tvp514x.c2
-rw-r--r--drivers/media/video/usbvideo/konicawc.c2
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c2
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c2
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c36
-rw-r--r--drivers/media/video/uvc/uvc_driver.c428
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c60
-rw-r--r--drivers/media/video/uvc/uvc_video.c26
-rw-r--r--drivers/media/video/uvc/uvcvideo.h23
-rw-r--r--drivers/media/video/v4l2-common.c9
-rw-r--r--drivers/media/video/videobuf-core.c12
-rw-r--r--drivers/media/video/videobuf-dma-contig.c2
-rw-r--r--drivers/media/video/videobuf-dma-sg.c6
-rw-r--r--drivers/media/video/videobuf-dvb.c11
-rw-r--r--drivers/media/video/videobuf-vmalloc.c4
-rw-r--r--drivers/media/video/vpx3220.c2
-rw-r--r--drivers/media/video/zoran/zoran_driver.c2
-rw-r--r--drivers/media/video/zr364xx.c1
257 files changed, 26827 insertions, 10725 deletions
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index 351b98b9b302..169b337b7c9d 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,6 +1,6 @@
 saa7146-objs    := saa7146_i2c.o saa7146_core.o
 saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
-ir-common-objs  := ir-functions.o ir-keymaps.o
+ir-common-objs  := ir-functions.o ir-keymaps.o ir-keytable.o
 
 obj-y += tuners/
 obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index abd4791acb0e..e616f624ceaa 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -34,22 +34,19 @@ static int repeat = 1;
 module_param(repeat, int, 0444);
 MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
 
-static int debug;    /* debug level (0,1,2) */
-module_param(debug, int, 0644);
-
-#define dprintk(level, fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG fmt , ## arg)
+int media_ir_debug;    /* media_ir_debug level (0,1,2) */
+module_param_named(debug, media_ir_debug, int, 0644);
 
 /* -------------------------------------------------------------------------- */
 
 static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
 {
 	if (KEY_RESERVED == ir->keycode) {
-		printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n",
-		       dev->name,ir->ir_key,ir->ir_raw,ir->keypressed);
+		printk(KERN_INFO "%s: unknown key: key=0x%02x down=%d\n",
+		       dev->name, ir->ir_key, ir->keypressed);
 		return;
 	}
-	dprintk(1,"%s: key event code=%d down=%d\n",
+	IR_dprintk(1,"%s: key event code=%d down=%d\n",
 		dev->name,ir->keycode,ir->keypressed);
 	input_report_key(dev,ir->keycode,ir->keypressed);
 	input_sync(dev);
@@ -57,39 +54,34 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
 
 /* -------------------------------------------------------------------------- */
 
-void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
+int ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
 		   int ir_type, struct ir_scancode_table *ir_codes)
 {
-	int i;
-
 	ir->ir_type = ir_type;
 
-	memset(ir->ir_codes, 0, sizeof(ir->ir_codes));
+	ir->keytable.size = ir_roundup_tablesize(ir_codes->size);
+	ir->keytable.scan = kzalloc(ir->keytable.size *
+				    sizeof(struct ir_scancode), GFP_KERNEL);
+	if (!ir->keytable.scan)
+		return -ENOMEM;
 
-	/*
-	 * FIXME: This is a temporary workaround to use the new IR tables
-	 * with the old approach. Later patches will replace this to a
-	 * proper method
-	 */
+	IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n",
+		ir->keytable.size,
+		ir->keytable.size * sizeof(ir->keytable.scan));
 
-	if (ir_codes)
-		for (i = 0; i < ir_codes->size; i++)
-			if (ir_codes->scan[i].scancode < IR_KEYTAB_SIZE)
-				ir->ir_codes[ir_codes->scan[i].scancode] = ir_codes->scan[i].keycode;
+	ir_copy_table(&ir->keytable, ir_codes);
+	ir_set_keycode_table(dev, &ir->keytable);
 
-	dev->keycode     = ir->ir_codes;
-	dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
-	dev->keycodemax  = IR_KEYTAB_SIZE;
-	for (i = 0; i < IR_KEYTAB_SIZE; i++)
-		set_bit(ir->ir_codes[i], dev->keybit);
 	clear_bit(0, dev->keybit);
-
 	set_bit(EV_KEY, dev->evbit);
 	if (repeat)
 		set_bit(EV_REP, dev->evbit);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(ir_input_init);
 
+
 void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
 {
 	if (ir->keypressed) {
@@ -100,9 +92,9 @@ void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
 EXPORT_SYMBOL_GPL(ir_input_nokey);
 
 void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
-		      u32 ir_key, u32 ir_raw)
+		      u32 ir_key)
 {
-	u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key);
+	u32 keycode = ir_g_keycode_from_table(dev, ir_key);
 
 	if (ir->keypressed && ir->keycode != keycode) {
 		ir->keypressed = 0;
@@ -110,7 +102,6 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
 	}
 	if (!ir->keypressed) {
 		ir->ir_key  = ir_key;
-		ir->ir_raw  = ir_raw;
 		ir->keycode = keycode;
 		ir->keypressed = 1;
 		ir_input_key_event(dev,ir);
@@ -275,7 +266,7 @@ EXPORT_SYMBOL_GPL(ir_decode_biphase);
  * saa7134 */
 
 /* decode raw bit pattern to RC5 code */
-static u32 ir_rc5_decode(unsigned int code)
+u32 ir_rc5_decode(unsigned int code)
 {
 	unsigned int org_code = code;
 	unsigned int pair;
@@ -295,15 +286,16 @@ static u32 ir_rc5_decode(unsigned int code)
 			rc5 |= 1;
 			break;
 		case 3:
-			dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
+			IR_dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
 			return 0;
 		}
 	}
-	dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+	IR_dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
 		"instr=%x\n", rc5, org_code, RC5_START(rc5),
 		RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
 	return rc5;
 }
+EXPORT_SYMBOL_GPL(ir_rc5_decode);
 
 void ir_rc5_timer_end(unsigned long data)
 {
@@ -330,20 +322,20 @@ void ir_rc5_timer_end(unsigned long data)
 
 	/* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
 	if (gap < 28000) {
-		dprintk(1, "ir-common: spurious timer_end\n");
+		IR_dprintk(1, "ir-common: spurious timer_end\n");
 		return;
 	}
 
 	if (ir->last_bit < 20) {
 		/* ignore spurious codes (caused by light/other remotes) */
-		dprintk(1, "ir-common: short code: %x\n", ir->code);
+		IR_dprintk(1, "ir-common: short code: %x\n", ir->code);
 	} else {
 		ir->code = (ir->code << ir->shift_by) | 1;
 		rc5 = ir_rc5_decode(ir->code);
 
 		/* two start bits? */
 		if (RC5_START(rc5) != ir->start) {
-			dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
+			IR_dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
 
 			/* right address? */
 		} else if (RC5_ADDR(rc5) == ir->addr) {
@@ -353,11 +345,10 @@ void ir_rc5_timer_end(unsigned long data)
 			/* Good code, decide if repeat/repress */
 			if (toggle != RC5_TOGGLE(ir->last_rc5) ||
 			    instr != RC5_INSTR(ir->last_rc5)) {
-				dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
+				IR_dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
 					toggle);
 				ir_input_nokey(ir->dev, &ir->ir);
-				ir_input_keydown(ir->dev, &ir->ir, instr,
-						 instr);
+				ir_input_keydown(ir->dev, &ir->ir, instr);
 			}
 
 			/* Set/reset key-up timer */
@@ -376,7 +367,7 @@ void ir_rc5_timer_keyup(unsigned long data)
 {
 	struct card_ir *ir = (struct card_ir *)data;
 
-	dprintk(1, "ir-common: key released\n");
+	IR_dprintk(1, "ir-common: key released\n");
 	ir_input_nokey(ir->dev, &ir->ir);
 }
 EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index f6790172736a..328c973a0838 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -1705,6 +1705,7 @@ static struct ir_scancode ir_codes_winfast[] = {
 	{ 0x37, KEY_RADIO },		/* FM */
 	{ 0x38, KEY_DVD },
 
+	{ 0x1a, KEY_MODE},		/* change to MCE mode on Y04G0051 */
 	{ 0x3e, KEY_F21 },		/* MCE +VOL, on Y04G0033 */
 	{ 0x3a, KEY_F22 },		/* MCE -VOL, on Y04G0033 */
 	{ 0x3b, KEY_F23 },		/* MCE +CH,  on Y04G0033 */
@@ -1846,6 +1847,76 @@ struct ir_scancode_table ir_codes_hauppauge_new_table = {
 };
 EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new_table);
 
+/*
+ * Hauppauge:the newer, gray remotes (seems there are multiple
+ * slightly different versions), shipped with cx88+ivtv cards.
+ *
+ * This table contains the complete RC5 code, instead of just the data part
+ */
+static struct ir_scancode ir_codes_rc5_hauppauge_new[] = {
+	/* Keys 0 to 9 */
+	{ 0x1e00, KEY_0 },
+	{ 0x1e01, KEY_1 },
+	{ 0x1e02, KEY_2 },
+	{ 0x1e03, KEY_3 },
+	{ 0x1e04, KEY_4 },
+	{ 0x1e05, KEY_5 },
+	{ 0x1e06, KEY_6 },
+	{ 0x1e07, KEY_7 },
+	{ 0x1e08, KEY_8 },
+	{ 0x1e09, KEY_9 },
+
+	{ 0x1e0a, KEY_TEXT },		/* keypad asterisk as well */
+	{ 0x1e0b, KEY_RED },		/* red button */
+	{ 0x1e0c, KEY_RADIO },
+	{ 0x1e0d, KEY_MENU },
+	{ 0x1e0e, KEY_SUBTITLE },		/* also the # key */
+	{ 0x1e0f, KEY_MUTE },
+	{ 0x1e10, KEY_VOLUMEUP },
+	{ 0x1e11, KEY_VOLUMEDOWN },
+	{ 0x1e12, KEY_PREVIOUS },		/* previous channel */
+	{ 0x1e14, KEY_UP },
+	{ 0x1e15, KEY_DOWN },
+	{ 0x1e16, KEY_LEFT },
+	{ 0x1e17, KEY_RIGHT },
+	{ 0x1e18, KEY_VIDEO },		/* Videos */
+	{ 0x1e19, KEY_AUDIO },		/* Music */
+	/* 0x1e1a: Pictures - presume this means
+	   "Multimedia Home Platform" -
+	   no "PICTURES" key in input.h
+	 */
+	{ 0x1e1a, KEY_MHP },
+
+	{ 0x1e1b, KEY_EPG },		/* Guide */
+	{ 0x1e1c, KEY_TV },
+	{ 0x1e1e, KEY_NEXTSONG },		/* skip >| */
+	{ 0x1e1f, KEY_EXIT },		/* back/exit */
+	{ 0x1e20, KEY_CHANNELUP },	/* channel / program + */
+	{ 0x1e21, KEY_CHANNELDOWN },	/* channel / program - */
+	{ 0x1e22, KEY_CHANNEL },		/* source (old black remote) */
+	{ 0x1e24, KEY_PREVIOUSSONG },	/* replay |< */
+	{ 0x1e25, KEY_ENTER },		/* OK */
+	{ 0x1e26, KEY_SLEEP },		/* minimize (old black remote) */
+	{ 0x1e29, KEY_BLUE },		/* blue key */
+	{ 0x1e2e, KEY_GREEN },		/* green button */
+	{ 0x1e30, KEY_PAUSE },		/* pause */
+	{ 0x1e32, KEY_REWIND },		/* backward << */
+	{ 0x1e34, KEY_FASTFORWARD },	/* forward >> */
+	{ 0x1e35, KEY_PLAY },
+	{ 0x1e36, KEY_STOP },
+	{ 0x1e37, KEY_RECORD },		/* recording */
+	{ 0x1e38, KEY_YELLOW },		/* yellow key */
+	{ 0x1e3b, KEY_SELECT },		/* top right button */
+	{ 0x1e3c, KEY_ZOOM },		/* full */
+	{ 0x1e3d, KEY_POWER },		/* system power (green button) */
+};
+
+struct ir_scancode_table ir_codes_rc5_hauppauge_new_table = {
+	.scan = ir_codes_rc5_hauppauge_new,
+	.size = ARRAY_SIZE(ir_codes_rc5_hauppauge_new),
+};
+EXPORT_SYMBOL_GPL(ir_codes_rc5_hauppauge_new_table);
+
 static struct ir_scancode ir_codes_npgtech[] = {
 	{ 0x1d, KEY_SWITCHVIDEOMODE },	/* switch inputs */
 	{ 0x2a, KEY_FRONT },
@@ -2964,6 +3035,101 @@ struct ir_scancode_table ir_codes_dm1105_nec_table = {
 };
 EXPORT_SYMBOL_GPL(ir_codes_dm1105_nec_table);
 
+static struct ir_scancode ir_codes_tevii_nec[] = {
+	{ 0x0a, KEY_POWER2},
+	{ 0x0c, KEY_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_MENU},
+	{ 0x0f, KEY_VOLUMEDOWN},
+	{ 0x1a, KEY_LAST},
+	{ 0x0e, KEY_OPEN},
+	{ 0x04, KEY_RECORD},
+	{ 0x09, KEY_VOLUMEUP},
+	{ 0x08, KEY_CHANNELUP},
+	{ 0x07, KEY_PVR},
+	{ 0x0b, KEY_TIME},
+	{ 0x02, KEY_RIGHT},
+	{ 0x03, KEY_LEFT},
+	{ 0x00, KEY_UP},
+	{ 0x1f, KEY_OK},
+	{ 0x01, KEY_DOWN},
+	{ 0x05, KEY_TUNER},
+	{ 0x06, KEY_CHANNELDOWN},
+	{ 0x40, KEY_PLAYPAUSE},
+	{ 0x1e, KEY_REWIND},
+	{ 0x1b, KEY_FAVORITES},
+	{ 0x1d, KEY_BACK},
+	{ 0x4d, KEY_FASTFORWARD},
+	{ 0x44, KEY_EPG},
+	{ 0x4c, KEY_INFO},
+	{ 0x41, KEY_AB},
+	{ 0x43, KEY_AUDIO},
+	{ 0x45, KEY_SUBTITLE},
+	{ 0x4a, KEY_LIST},
+	{ 0x46, KEY_F1},
+	{ 0x47, KEY_F2},
+	{ 0x5e, KEY_F3},
+	{ 0x5c, KEY_F4},
+	{ 0x52, KEY_F5},
+	{ 0x5a, KEY_F6},
+	{ 0x56, KEY_MODE},
+	{ 0x58, KEY_SWITCHVIDEOMODE},
+};
+struct ir_scancode_table ir_codes_tevii_nec_table = {
+	.scan = ir_codes_tevii_nec,
+	.size = ARRAY_SIZE(ir_codes_tevii_nec),
+};
+EXPORT_SYMBOL_GPL(ir_codes_tevii_nec_table);
+
+static struct ir_scancode ir_codes_tbs_nec[] = {
+	{ 0x04, KEY_POWER2},	/*power*/
+	{ 0x14, KEY_MUTE},	/*mute*/
+	{ 0x07, KEY_1},
+	{ 0x06, KEY_2},
+	{ 0x05, KEY_3},
+	{ 0x0b, KEY_4},
+	{ 0x0a, KEY_5},
+	{ 0x09, KEY_6},
+	{ 0x0f, KEY_7},
+	{ 0x0e, KEY_8},
+	{ 0x0d, KEY_9},
+	{ 0x12, KEY_0},
+	{ 0x16, KEY_CHANNELUP},	/*ch+*/
+	{ 0x11, KEY_CHANNELDOWN},/*ch-*/
+	{ 0x13, KEY_VOLUMEUP},	/*vol+*/
+	{ 0x0c, KEY_VOLUMEDOWN},/*vol-*/
+	{ 0x03, KEY_RECORD},	/*rec*/
+	{ 0x18, KEY_PAUSE},	/*pause*/
+	{ 0x19, KEY_OK},	/*ok*/
+	{ 0x1a, KEY_CAMERA},	/* snapshot */
+	{ 0x01, KEY_UP},
+	{ 0x10, KEY_LEFT},
+	{ 0x02, KEY_RIGHT},
+	{ 0x08, KEY_DOWN},
+	{ 0x15, KEY_FAVORITES},
+	{ 0x17, KEY_SUBTITLE},
+	{ 0x1d, KEY_ZOOM},
+	{ 0x1f, KEY_EXIT},
+	{ 0x1e, KEY_MENU},
+	{ 0x1c, KEY_EPG},
+	{ 0x00, KEY_PREVIOUS},
+	{ 0x1b, KEY_MODE},
+};
+struct ir_scancode_table ir_codes_tbs_nec_table = {
+	.scan = ir_codes_tbs_nec,
+	.size = ARRAY_SIZE(ir_codes_tbs_nec),
+};
+EXPORT_SYMBOL_GPL(ir_codes_tbs_nec_table);
+
 /* Terratec Cinergy Hybrid T USB XS
    Devin Heitmueller <dheitmueller@linuxtv.org>
  */
@@ -3147,3 +3313,4 @@ struct ir_scancode_table ir_codes_gadmei_rm008z_table = {
 	.size = ARRAY_SIZE(ir_codes_gadmei_rm008z),
 };
 EXPORT_SYMBOL_GPL(ir_codes_gadmei_rm008z_table);
+
diff --git a/drivers/media/common/ir-keytable.c b/drivers/media/common/ir-keytable.c
new file mode 100644
index 000000000000..26ce5bc2fdd5
--- /dev/null
+++ b/drivers/media/common/ir-keytable.c
@@ -0,0 +1,429 @@
+/* ir-register.c - handle IR scancode->keycode tables
+ *
+ * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ */
+
+#include <linux/usb/input.h>
+
+#include <media/ir-common.h>
+
+#define IR_TAB_MIN_SIZE	32
+#define IR_TAB_MAX_SIZE	1024
+
+/**
+ * ir_seek_table() - returns the element order on the table
+ * @rc_tab:	the ir_scancode_table with the keymap to be used
+ * @scancode:	the scancode that we're seeking
+ *
+ * This routine is used by the input routines when a key is pressed at the
+ * IR. The scancode is received and needs to be converted into a keycode.
+ * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the
+ * corresponding keycode from the table.
+ */
+static int ir_seek_table(struct ir_scancode_table *rc_tab, u32 scancode)
+{
+	int rc;
+	unsigned long flags;
+	struct ir_scancode *keymap = rc_tab->scan;
+
+	spin_lock_irqsave(&rc_tab->lock, flags);
+
+	/* FIXME: replace it by a binary search */
+
+	for (rc = 0; rc < rc_tab->size; rc++)
+		if (keymap[rc].scancode == scancode)
+			goto exit;
+
+	/* Not found */
+	rc = -EINVAL;
+
+exit:
+	spin_unlock_irqrestore(&rc_tab->lock, flags);
+	return rc;
+}
+
+/**
+ * ir_roundup_tablesize() - gets an optimum value for the table size
+ * @n_elems:		minimum number of entries to store keycodes
+ *
+ * This routine is used to choose the keycode table size.
+ *
+ * In order to have some empty space for new keycodes,
+ * and knowing in advance that kmalloc allocates only power of two
+ * segments, it optimizes the allocated space to have some spare space
+ * for those new keycodes by using the maximum number of entries that
+ * will be effectively be allocated by kmalloc.
+ * In order to reduce the quantity of table resizes, it has a minimum
+ * table size of IR_TAB_MIN_SIZE.
+ */
+int ir_roundup_tablesize(int n_elems)
+{
+	size_t size;
+
+	if (n_elems < IR_TAB_MIN_SIZE)
+		n_elems = IR_TAB_MIN_SIZE;
+
+	/*
+	 * As kmalloc only allocates sizes of power of two, get as
+	 * much entries as possible for the allocated memory segment
+	 */
+	size = roundup_pow_of_two(n_elems * sizeof(struct ir_scancode));
+	n_elems = size / sizeof(struct ir_scancode);
+
+	return n_elems;
+}
+
+/**
+ * ir_copy_table() - copies a keytable, discarding the unused entries
+ * @destin:	destin table
+ * @origin:	origin table
+ *
+ * Copies all entries where the keycode is not KEY_UNKNOWN/KEY_RESERVED
+ */
+
+int ir_copy_table(struct ir_scancode_table *destin,
+		 const struct ir_scancode_table *origin)
+{
+	int i, j = 0;
+
+	for (i = 0; i < origin->size; i++) {
+		if (origin->scan[i].keycode == KEY_UNKNOWN ||
+		   origin->scan[i].keycode == KEY_RESERVED)
+			continue;
+
+		memcpy(&destin->scan[j], &origin->scan[i], sizeof(struct ir_scancode));
+		j++;
+	}
+	destin->size = j;
+
+	IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size);
+
+	return 0;
+}
+
+/**
+ * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table
+ * @dev:	the struct input_dev device descriptor
+ * @scancode:	the desired scancode
+ * @keycode:	the keycode to be retorned.
+ *
+ * This routine is used to handle evdev EVIOCGKEY ioctl.
+ * If the key is not found, returns -EINVAL, otherwise, returns 0.
+ */
+static int ir_getkeycode(struct input_dev *dev,
+			 int scancode, int *keycode)
+{
+	int elem;
+	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
+
+	elem = ir_seek_table(rc_tab, scancode);
+	if (elem >= 0) {
+		*keycode = rc_tab->scan[elem].keycode;
+		return 0;
+	}
+
+	/*
+	 * Scancode not found and table can't be expanded
+	 */
+	if (elem < 0 && rc_tab->size == IR_TAB_MAX_SIZE)
+		return -EINVAL;
+
+	/*
+	 * If is there extra space, returns KEY_RESERVED,
+	 * otherwise, input core won't let ir_setkeycode to work
+	 */
+	*keycode = KEY_RESERVED;
+	return 0;
+}
+
+
+/**
+ * ir_is_resize_needed() - Check if the table needs rezise
+ * @table:		keycode table that may need to resize
+ * @n_elems:		minimum number of entries to store keycodes
+ *
+ * Considering that kmalloc uses power of two storage areas, this
+ * routine detects if the real alloced size will change. If not, it
+ * just returns without doing nothing. Otherwise, it will extend or
+ * reduce the table size to meet the new needs.
+ *
+ * It returns 0 if no resize is needed, 1 otherwise.
+ */
+static int ir_is_resize_needed(struct ir_scancode_table *table, int n_elems)
+{
+	int cur_size = ir_roundup_tablesize(table->size);
+	int new_size = ir_roundup_tablesize(n_elems);
+
+	if (cur_size == new_size)
+		return 0;
+
+	/* Resize is needed */
+	return 1;
+}
+
+/**
+ * ir_delete_key() - remove a keycode from the table
+ * @rc_tab:		keycode table
+ * @elem:		element to be removed
+ *
+ */
+static void ir_delete_key(struct ir_scancode_table *rc_tab, int elem)
+{
+	unsigned long flags = 0;
+	int newsize = rc_tab->size - 1;
+	int resize = ir_is_resize_needed(rc_tab, newsize);
+	struct ir_scancode *oldkeymap = rc_tab->scan;
+	struct ir_scancode *newkeymap;
+
+	if (resize) {
+		newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
+				    sizeof(*newkeymap), GFP_ATOMIC);
+
+		/* There's no memory for resize. Keep the old table */
+		if (!newkeymap)
+			resize = 0;
+	}
+
+	if (!resize) {
+		newkeymap = oldkeymap;
+
+		/* We'll modify the live table. Lock it */
+		spin_lock_irqsave(&rc_tab->lock, flags);
+	}
+
+	/*
+	 * Copy the elements before the one that will be deleted
+	 * if (!resize), both oldkeymap and newkeymap points
+	 * to the same place, so, there's no need to copy
+	 */
+	if (resize && elem > 0)
+		memcpy(newkeymap, oldkeymap,
+		       elem * sizeof(*newkeymap));
+
+	/*
+	 * Copy the other elements overwriting the element to be removed
+	 * This operation applies to both resize and non-resize case
+	 */
+	if (elem < newsize)
+		memcpy(&newkeymap[elem], &oldkeymap[elem + 1],
+		       (newsize - elem) * sizeof(*newkeymap));
+
+	if (resize) {
+		/*
+		 * As the copy happened to a temporary table, only here
+		 * it needs to lock while replacing the table pointers
+		 * to use the new table
+		 */
+		spin_lock_irqsave(&rc_tab->lock, flags);
+		rc_tab->size = newsize;
+		rc_tab->scan = newkeymap;
+		spin_unlock_irqrestore(&rc_tab->lock, flags);
+
+		/* Frees the old keytable */
+		kfree(oldkeymap);
+	} else {
+		rc_tab->size = newsize;
+		spin_unlock_irqrestore(&rc_tab->lock, flags);
+	}
+}
+
+/**
+ * ir_insert_key() - insert a keycode at the table
+ * @rc_tab:		keycode table
+ * @scancode:	the desired scancode
+ * @keycode:	the keycode to be retorned.
+ *
+ */
+static int ir_insert_key(struct ir_scancode_table *rc_tab,
+			  int scancode, int keycode)
+{
+	unsigned long flags;
+	int elem = rc_tab->size;
+	int newsize = rc_tab->size + 1;
+	int resize = ir_is_resize_needed(rc_tab, newsize);
+	struct ir_scancode *oldkeymap = rc_tab->scan;
+	struct ir_scancode *newkeymap;
+
+	if (resize) {
+		newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
+				    sizeof(*newkeymap), GFP_ATOMIC);
+		if (!newkeymap)
+			return -ENOMEM;
+
+		memcpy(newkeymap, oldkeymap,
+		       rc_tab->size * sizeof(*newkeymap));
+	} else
+		newkeymap  = oldkeymap;
+
+	/* Stores the new code at the table */
+	IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
+		   rc_tab->size, scancode, keycode);
+
+	spin_lock_irqsave(&rc_tab->lock, flags);
+	rc_tab->size = newsize;
+	if (resize) {
+		rc_tab->scan = newkeymap;
+		kfree(oldkeymap);
+	}
+	newkeymap[elem].scancode = scancode;
+	newkeymap[elem].keycode  = keycode;
+	spin_unlock_irqrestore(&rc_tab->lock, flags);
+
+	return 0;
+}
+
+/**
+ * ir_setkeycode() - set a keycode at the evdev scancode ->keycode table
+ * @dev:	the struct input_dev device descriptor
+ * @scancode:	the desired scancode
+ * @keycode:	the keycode to be retorned.
+ *
+ * This routine is used to handle evdev EVIOCSKEY ioctl.
+ * There's one caveat here: how can we increase the size of the table?
+ * If the key is not found, returns -EINVAL, otherwise, returns 0.
+ */
+static int ir_setkeycode(struct input_dev *dev,
+			 int scancode, int keycode)
+{
+	int rc = 0;
+	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
+	struct ir_scancode *keymap = rc_tab->scan;
+	unsigned long flags;
+
+	/*
+	 * Handle keycode table deletions
+	 *
+	 * If userspace is adding a KEY_UNKNOWN or KEY_RESERVED,
+	 * deal as a trial to remove an existing scancode attribution
+	 * if table become too big, reduce it to save space
+	 */
+	if (keycode == KEY_UNKNOWN || keycode == KEY_RESERVED) {
+		rc = ir_seek_table(rc_tab, scancode);
+		if (rc < 0)
+			return 0;
+
+		IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", rc, scancode);
+		clear_bit(keymap[rc].keycode, dev->keybit);
+		ir_delete_key(rc_tab, rc);
+
+		return 0;
+	}
+
+	/*
+	 * Handle keycode replacements
+	 *
+	 * If the scancode exists, just replace by the new value
+	 */
+	rc = ir_seek_table(rc_tab, scancode);
+	if (rc >= 0) {
+		IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
+			rc, scancode, keycode);
+
+		clear_bit(keymap[rc].keycode, dev->keybit);
+
+		spin_lock_irqsave(&rc_tab->lock, flags);
+		keymap[rc].keycode = keycode;
+		spin_unlock_irqrestore(&rc_tab->lock, flags);
+
+		set_bit(keycode, dev->keybit);
+
+		return 0;
+	}
+
+	/*
+	 * Handle new scancode inserts
+	 *
+	 * reallocate table if needed and insert a new keycode
+	 */
+
+	/* Avoid growing the table indefinitely */
+	if (rc_tab->size + 1 > IR_TAB_MAX_SIZE)
+		return -EINVAL;
+
+	rc = ir_insert_key(rc_tab, scancode, keycode);
+	if (rc < 0)
+		return rc;
+	set_bit(keycode, dev->keybit);
+
+	return 0;
+}
+
+/**
+ * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
+ * @input_dev:	the struct input_dev descriptor of the device
+ * @scancode:	the scancode that we're seeking
+ *
+ * This routine is used by the input routines when a key is pressed at the
+ * IR. The scancode is received and needs to be converted into a keycode.
+ * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the
+ * corresponding keycode from the table.
+ */
+u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
+{
+	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
+	struct ir_scancode *keymap = rc_tab->scan;
+	int elem;
+
+	elem = ir_seek_table(rc_tab, scancode);
+	if (elem >= 0) {
+		IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
+			   dev->name, scancode, keymap[elem].keycode);
+
+		return rc_tab->scan[elem].keycode;
+	}
+
+	printk(KERN_INFO "%s: unknown key for scancode 0x%04x\n",
+	       dev->name, scancode);
+
+	/* Reports userspace that an unknown keycode were got */
+	return KEY_RESERVED;
+}
+
+/**
+ * ir_set_keycode_table() - sets the IR keycode table and add the handlers
+ *			    for keymap table get/set
+ * @input_dev:	the struct input_dev descriptor of the device
+ * @rc_tab:	the struct ir_scancode_table table of scancode/keymap
+ *
+ * This routine is used to initialize the input infrastructure to work with
+ * an IR.
+ * It should be called before registering the IR device.
+ */
+int ir_set_keycode_table(struct input_dev *input_dev,
+			 struct ir_scancode_table *rc_tab)
+{
+	struct ir_scancode *keymap = rc_tab->scan;
+	int i;
+
+	spin_lock_init(&rc_tab->lock);
+
+	if (rc_tab->scan == NULL || !rc_tab->size)
+		return -EINVAL;
+
+	/* set the bits for the keys */
+	IR_dprintk(1, "key map size: %d\n", rc_tab->size);
+	for (i = 0; i < rc_tab->size; i++) {
+		IR_dprintk(1, "#%d: setting bit for keycode 0x%04x\n",
+			i, keymap[i].keycode);
+		set_bit(keymap[i].keycode, input_dev->keybit);
+	}
+
+	input_dev->getkeycode = ir_getkeycode;
+	input_dev->setkeycode = ir_setkeycode;
+	input_set_drvdata(input_dev, rc_tab);
+
+	return 0;
+}
+
+void ir_input_free(struct input_dev *dev)
+{
+	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
+
+	IR_dprintk(1, "Freed keycode table\n");
+
+	rc_tab->size = 0;
+	kfree(rc_tab->scan);
+	rc_tab->scan = NULL;
+}
+EXPORT_SYMBOL_GPL(ir_input_free);
+
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 552dab442d78..becbaadb3b77 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1205,6 +1205,13 @@ static int buffer_activate (struct saa7146_dev *dev,
 	return 0;
 }
 
+static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf)
+{
+	saa7146_pgtable_free(dev->pci, &buf->pt[0]);
+	saa7146_pgtable_free(dev->pci, &buf->pt[1]);
+	saa7146_pgtable_free(dev->pci, &buf->pt[2]);
+}
+
 static int buffer_prepare(struct videobuf_queue *q,
 			  struct videobuf_buffer *vb, enum v4l2_field field)
 {
@@ -1257,16 +1264,12 @@ static int buffer_prepare(struct videobuf_queue *q,
 
 		sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
 
+		release_all_pagetables(dev, buf);
 		if( 0 != IS_PLANAR(sfmt->trans)) {
-			saa7146_pgtable_free(dev->pci, &buf->pt[0]);
-			saa7146_pgtable_free(dev->pci, &buf->pt[1]);
-			saa7146_pgtable_free(dev->pci, &buf->pt[2]);
-
 			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
 			saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
 			saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
 		} else {
-			saa7146_pgtable_free(dev->pci, &buf->pt[0]);
 			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
 		}
 
@@ -1329,6 +1332,9 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 	struct saa7146_buf *buf = (struct saa7146_buf *)vb;
 
 	DEB_CAP(("vbuf:%p\n",vb));
+
+	release_all_pagetables(dev, buf);
+
 	saa7146_dma_free(dev,q,buf);
 }
 
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 607d319ce8ed..409a4261e5b5 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -172,4 +172,11 @@ config MEDIA_TUNER_MC44S803
 	help
 	  Say Y here to support the Freescale MC44S803 based tuners
 
+config MEDIA_TUNER_MAX2165
+	tristate "Maxim MAX2165 silicon tuner"
+	depends on VIDEO_MEDIA && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  A driver for the silicon tuner MAX2165 from Maxim.
+
 endif # MEDIA_TUNER_CUSTOMISE
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index 4132b2be79e5..a5438523f30d 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -23,6 +23,7 @@ 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
+obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c
new file mode 100644
index 000000000000..1b486cfb8ed9
--- /dev/null
+++ b/drivers/media/common/tuners/max2165.c
@@ -0,0 +1,442 @@
+/*
+ *  Driver for Maxim MAX2165 silicon tuner
+ *
+ *  Copyright (c) 2009 David T. L. Wong <davidtlwong@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
+ *  (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/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "max2165.h"
+#include "max2165_priv.h"
+#include "tuner-i2c.h"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "max2165: " args); \
+	} while (0)
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
+
+	msg.addr = priv->config->i2c_address;
+
+	if (debug >= 2)
+		printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
+			__func__, reg, data);
+
+	ret = i2c_transfer(priv->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk(KERN_DEBUG "%s: error reg=0x%x, data=0x%x, ret=%i\n",
+			__func__, reg, data, ret);
+
+	return (ret != 1) ? -EIO : 0;
+}
+
+static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data)
+{
+	int ret;
+	u8 dev_addr = priv->config->i2c_address;
+
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 },
+		{ .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 },
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret != 2) {
+		dprintk(KERN_DEBUG "%s: error reg=0x%x, ret=%i\n",
+			__func__, reg, ret);
+		return -EIO;
+	}
+
+	*p_data = b1[0];
+	if (debug >= 2)
+		printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
+			__func__, reg, b1[0]);
+	return 0;
+}
+
+static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg,
+	u8 mask, u8 data)
+{
+	int ret;
+	u8 v;
+
+	data &= mask;
+	ret = max2165_read_reg(priv, reg, &v);
+	if (ret != 0)
+		return ret;
+	v &= ~mask;
+	v |= data;
+	ret = max2165_write_reg(priv, reg, v);
+
+	return ret;
+}
+
+static int max2165_read_rom_table(struct max2165_priv *priv)
+{
+	u8 dat[3];
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1);
+		max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]);
+	}
+
+	priv->tf_ntch_low_cfg = dat[0] >> 4;
+	priv->tf_ntch_hi_cfg = dat[0] & 0x0F;
+	priv->tf_balun_low_ref = dat[1] & 0x0F;
+	priv->tf_balun_hi_ref = dat[1] >> 4;
+	priv->bb_filter_7mhz_cfg = dat[2] & 0x0F;
+	priv->bb_filter_8mhz_cfg = dat[2] >> 4;
+
+	dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg);
+	dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg);
+	dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref);
+	dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref);
+	dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg);
+	dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg);
+
+	return 0;
+}
+
+static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/)
+{
+	u8 v;
+
+	v = (osc / 2);
+	if (v == 2)
+		v = 0x7;
+	else
+		v -= 8;
+
+	max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v);
+
+	return 0;
+}
+
+static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw)
+{
+	u8 val;
+
+	if (bw == BANDWIDTH_8_MHZ)
+		val = priv->bb_filter_8mhz_cfg;
+	else
+		val = priv->bb_filter_7mhz_cfg;
+
+	max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4);
+
+	return 0;
+}
+
+int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction)
+{
+	u32 remainder;
+	u32 q, f = 0;
+	int i;
+
+	if (0 == divisor)
+		return -1;
+
+	q = dividend / divisor;
+	remainder = dividend - q * divisor;
+
+	for (i = 0; i < 31; i++) {
+		remainder <<= 1;
+		if (remainder >= divisor) {
+			f += 1;
+			remainder -= divisor;
+		}
+		f <<= 1;
+	}
+
+	*quotient = q;
+	*fraction = f;
+
+	return 0;
+}
+
+static int max2165_set_rf(struct max2165_priv *priv, u32 freq)
+{
+	u8 tf;
+	u8 tf_ntch;
+	double t;
+	u32 quotient, fraction;
+
+	/* Set PLL divider according to RF frequency */
+	fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
+		&quotient, &fraction);
+
+	/* 20-bit fraction */
+	fraction >>= 12;
+
+	max2165_write_reg(priv, REG_NDIV_INT, quotient);
+	max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16);
+	max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8);
+	max2165_write_reg(priv, REG_NDIV_FRAC0, fraction);
+
+	/* Norch Filter */
+	tf_ntch = (freq < 725000000) ?
+		priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg;
+
+	/* Tracking filter balun */
+	t = priv->tf_balun_low_ref;
+	t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref)
+		* (freq / 1000 - 470000) / (780000 - 470000);
+
+	tf = t;
+	dprintk("tf = %X\n", tf);
+	tf |= tf_ntch << 4;
+
+	max2165_write_reg(priv, REG_TRACK_FILTER, tf);
+
+	return 0;
+}
+
+static void max2165_debug_status(struct max2165_priv *priv)
+{
+	u8 status, autotune;
+	u8 auto_vco_success, auto_vco_active;
+	u8 pll_locked;
+	u8 dc_offset_low, dc_offset_hi;
+	u8 signal_lv_over_threshold;
+	u8 vco, vco_sub_band, adc;
+
+	max2165_read_reg(priv, REG_STATUS, &status);
+	max2165_read_reg(priv, REG_AUTOTUNE, &autotune);
+
+	auto_vco_success = (status >> 6) & 0x01;
+	auto_vco_active = (status >> 5) & 0x01;
+	pll_locked = (status >> 4) & 0x01;
+	dc_offset_low = (status >> 3) & 0x01;
+	dc_offset_hi = (status >> 2) & 0x01;
+	signal_lv_over_threshold = status & 0x01;
+
+	vco = autotune >> 6;
+	vco_sub_band = (autotune >> 3) & 0x7;
+	adc = autotune & 0x7;
+
+	dprintk("auto VCO active: %d, auto VCO success: %d\n",
+		auto_vco_active, auto_vco_success);
+	dprintk("PLL locked: %d\n", pll_locked);
+	dprintk("DC offset low: %d, DC offset high: %d\n",
+		dc_offset_low, dc_offset_hi);
+	dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold);
+	dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc);
+}
+
+static int max2165_set_params(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *params)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency);
+	if (fe->ops.info.type == FE_ATSC) {
+			return -EINVAL;
+	} else if (fe->ops.info.type == FE_OFDM) {
+		dprintk("%s() OFDM\n", __func__);
+		switch (params->u.ofdm.bandwidth) {
+		case BANDWIDTH_6_MHZ:
+			return -EINVAL;
+		case BANDWIDTH_7_MHZ:
+		case BANDWIDTH_8_MHZ:
+			priv->frequency = params->frequency;
+			priv->bandwidth = params->u.ofdm.bandwidth;
+			break;
+		default:
+			printk(KERN_ERR "MAX2165 bandwidth not set!\n");
+			return -EINVAL;
+		}
+	} else {
+		printk(KERN_ERR "MAX2165 modulation type not supported!\n");
+		return -EINVAL;
+	}
+
+	dprintk("%s() frequency=%d\n", __func__, priv->frequency);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	max2165_set_bandwidth(priv, priv->bandwidth);
+	ret = max2165_set_rf(priv, priv->frequency);
+	mdelay(50);
+	max2165_debug_status(priv);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret != 0)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	dprintk("%s()\n", __func__);
+	*freq = priv->frequency;
+	return 0;
+}
+
+static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	dprintk("%s()\n", __func__);
+
+	*bw = priv->bandwidth;
+	return 0;
+}
+
+static int max2165_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	u16 lock_status = 0;
+
+	dprintk("%s()\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+	max2165_debug_status(priv);
+	*status = lock_status;
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int max2165_sleep(struct dvb_frontend *fe)
+{
+	dprintk("%s()\n", __func__);
+	return 0;
+}
+
+static int max2165_init(struct dvb_frontend *fe)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	dprintk("%s()\n", __func__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* Setup initial values */
+	/* Fractional Mode on */
+	max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18);
+	/* LNA on */
+	max2165_write_reg(priv, REG_LNA, 0x01);
+	max2165_write_reg(priv, REG_PLL_CFG, 0x7A);
+	max2165_write_reg(priv, REG_TEST, 0x08);
+	max2165_write_reg(priv, REG_SHUTDOWN, 0x40);
+	max2165_write_reg(priv, REG_VCO_CTRL, 0x84);
+	max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3);
+	max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75);
+	max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00);
+	max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00);
+
+	max2165_set_osc(priv, priv->config->osc_clk);
+
+	max2165_read_rom_table(priv);
+
+	max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ);
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int max2165_release(struct dvb_frontend *fe)
+{
+	struct max2165_priv *priv = fe->tuner_priv;
+	dprintk("%s()\n", __func__);
+
+	kfree(priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops max2165_tuner_ops = {
+	.info = {
+		.name           = "Maxim MAX2165",
+		.frequency_min  = 470000000,
+		.frequency_max  = 780000000,
+		.frequency_step =     50000,
+	},
+
+	.release	   = max2165_release,
+	.init		   = max2165_init,
+	.sleep		   = max2165_sleep,
+
+	.set_params	   = max2165_set_params,
+	.set_analog_params = NULL,
+	.get_frequency	   = max2165_get_frequency,
+	.get_bandwidth	   = max2165_get_bandwidth,
+	.get_status	   = max2165_get_status
+};
+
+struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   struct max2165_config *cfg)
+{
+	struct max2165_priv *priv = NULL;
+
+	dprintk("%s(%d-%04x)\n", __func__,
+		i2c ? i2c_adapter_id(i2c) : -1,
+		cfg ? cfg->i2c_address : -1);
+
+	priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	priv->config = cfg;
+	priv->i2c = i2c;
+	fe->tuner_priv = priv;
+
+	max2165_init(fe);
+	max2165_debug_status(priv);
+
+	return fe;
+}
+EXPORT_SYMBOL(max2165_attach);
+
+MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
+MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/max2165.h b/drivers/media/common/tuners/max2165.h
new file mode 100644
index 000000000000..c063c36a93d3
--- /dev/null
+++ b/drivers/media/common/tuners/max2165.h
@@ -0,0 +1,48 @@
+/*
+ *  Driver for Maxim MAX2165 silicon tuner
+ *
+ *  Copyright (c) 2009 David T. L. Wong <davidtlwong@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
+ *  (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 __MAX2165_H__
+#define __MAX2165_H__
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct max2165_config {
+	u8 i2c_address;
+	u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \
+    (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE))
+extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c,
+	struct max2165_config *cfg);
+#else
+static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c,
+	struct max2165_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/max2165_priv.h b/drivers/media/common/tuners/max2165_priv.h
new file mode 100644
index 000000000000..91bbe021a08d
--- /dev/null
+++ b/drivers/media/common/tuners/max2165_priv.h
@@ -0,0 +1,60 @@
+/*
+ *  Driver for Maxim MAX2165 silicon tuner
+ *
+ *  Copyright (c) 2009 David T. L. Wong <davidtlwong@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
+ *  (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 __MAX2165_PRIV_H__
+#define __MAX2165_PRIV_H__
+
+#define REG_NDIV_INT 0x00
+#define REG_NDIV_FRAC2 0x01
+#define REG_NDIV_FRAC1 0x02
+#define REG_NDIV_FRAC0 0x03
+#define REG_TRACK_FILTER 0x04
+#define REG_LNA 0x05
+#define REG_PLL_CFG 0x06
+#define REG_TEST 0x07
+#define REG_SHUTDOWN 0x08
+#define REG_VCO_CTRL 0x09
+#define REG_BASEBAND_CTRL 0x0A
+#define REG_DC_OFFSET_CTRL 0x0B
+#define REG_DC_OFFSET_DAC 0x0C
+#define REG_ROM_TABLE_ADDR 0x0D
+
+/* Read Only Registers */
+#define REG_ROM_TABLE_DATA 0x10
+#define REG_STATUS 0x11
+#define REG_AUTOTUNE 0x12
+
+struct max2165_priv {
+	struct max2165_config *config;
+	struct i2c_adapter *i2c;
+
+	u32 frequency;
+	u32 bandwidth;
+
+	u8 tf_ntch_low_cfg;
+	u8 tf_ntch_hi_cfg;
+	u8 tf_balun_low_ref;
+	u8 tf_balun_hi_ref;
+	u8 bb_filter_7mhz_cfg;
+	u8 bb_filter_8mhz_cfg;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
index 0803dab58fff..605e28b73263 100644
--- a/drivers/media/common/tuners/mxl5005s.c
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -2789,7 +2789,10 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
 
 	/* add for 2.6.5 Special setting for QAM */
 	if (state->Mod_Type == MXL_QAM) {
-		if (state->RF_IN < 680000000)
+		if (state->config->qam_gain != 0)
+			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN,
+						   state->config->qam_gain);
+		else if (state->RF_IN < 680000000)
 			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
 		else
 			status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/common/tuners/mxl5005s.h
index 7ac6815b30aa..fc8a1ffc53b4 100644
--- a/drivers/media/common/tuners/mxl5005s.h
+++ b/drivers/media/common/tuners/mxl5005s.h
@@ -108,6 +108,10 @@ struct mxl5005s_config {
 #define MXL_LOW_IF  1
 	u8 if_mode;
 
+	/* Some boards need to override the built-in logic for determining
+	   the gain when in QAM mode (the HVR-1600 is one such case) */
+	u8 qam_gain;
+
 	/* Stuff I don't know what to do with */
 	u8 AgcMasterByte;
 };
diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c
index 2d02698d4f4f..7eb1bf75cd07 100644
--- a/drivers/media/common/tuners/mxl5007t.c
+++ b/drivers/media/common/tuners/mxl5007t.c
@@ -196,7 +196,7 @@ static void copy_reg_bits(struct reg_pair_t *reg_pair1,
 	i = j = 0;
 
 	while (reg_pair1[i].reg || reg_pair1[i].val) {
-		while (reg_pair2[j].reg || reg_pair2[j].reg) {
+		while (reg_pair2[j].reg || reg_pair2[j].val) {
 			if (reg_pair1[i].reg != reg_pair2[j].reg) {
 				j++;
 				continue;
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
index 155c93eb75da..e1f678281a58 100644
--- a/drivers/media/common/tuners/tda18271-common.c
+++ b/drivers/media/common/tuners/tda18271-common.c
@@ -326,12 +326,24 @@ int tda18271_init_regs(struct dvb_frontend *fe)
 	regs[R_EB22] = 0x48;
 	regs[R_EB23] = 0xb0;
 
-	if (priv->small_i2c) {
+	switch (priv->small_i2c) {
+	case TDA18271_08_BYTE_CHUNK_INIT:
+		tda18271_write_regs(fe, 0x00, 0x08);
+		tda18271_write_regs(fe, 0x08, 0x08);
+		tda18271_write_regs(fe, 0x10, 0x08);
+		tda18271_write_regs(fe, 0x18, 0x08);
+		tda18271_write_regs(fe, 0x20, 0x07);
+		break;
+	case TDA18271_16_BYTE_CHUNK_INIT:
 		tda18271_write_regs(fe, 0x00, 0x10);
 		tda18271_write_regs(fe, 0x10, 0x10);
 		tda18271_write_regs(fe, 0x20, 0x07);
-	} else
+		break;
+	case TDA18271_39_BYTE_CHUNK_INIT:
+	default:
 		tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
+		break;
+	}
 
 	/* setup agc1 gain */
 	regs[R_EB17] = 0x00;
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index 3a50ce96fcb9..b2e15456d5f3 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -256,8 +256,9 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
 	struct tda18271_priv *priv = fe->tuner_priv;
 	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
 	unsigned char *regs = priv->tda18271_regs;
-	int tm_current, rfcal_comp, approx, i, ret;
-	u8 dc_over_dt, rf_tab;
+	int i, ret;
+	u8 tm_current, dc_over_dt, rf_tab;
+	s32 rfcal_comp, approx;
 
 	/* power up */
 	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
@@ -277,11 +278,11 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
 		return i;
 
 	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
-		approx = map[i].rf_a1 *
-			(freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab;
+		approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) +
+			map[i].rf_b1 + rf_tab;
 	} else {
-		approx = map[i].rf_a2 *
-			(freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab;
+		approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) +
+			map[i].rf_b2 + rf_tab;
 	}
 
 	if (approx < 0)
@@ -292,9 +293,9 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
 	tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
 
 	/* calculate temperature compensation */
-	rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal) / 1000;
+	rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000;
 
-	regs[R_EB14] = approx + rfcal_comp;
+	regs[R_EB14] = (unsigned char)(approx + rfcal_comp);
 	ret = tda18271_write_regs(fe, R_EB14, 1);
 fail:
 	return ret;
@@ -572,6 +573,7 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
 	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
 	unsigned char *regs = priv->tda18271_regs;
 	int bcal, rf, i;
+	s32 divisor, dividend;
 #define RF1 0
 #define RF2 1
 #define RF3 2
@@ -610,20 +612,22 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
 		switch (rf) {
 		case RF1:
 			map[i].rf_a1 = 0;
-			map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1];
+			map[i].rf_b1 = (s32)(prog_cal[RF1] - prog_tab[RF1]);
 			map[i].rf1   = rf_freq[RF1] / 1000;
 			break;
 		case RF2:
-			map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] -
-					prog_cal[RF1] + prog_tab[RF1]) /
-				(s32)((rf_freq[RF2] - rf_freq[RF1]) / 1000);
+			dividend = (s32)(prog_cal[RF2] - prog_tab[RF2]) -
+				   (s32)(prog_cal[RF1] + prog_tab[RF1]);
+			divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000;
+			map[i].rf_a1 = (dividend / divisor);
 			map[i].rf2   = rf_freq[RF2] / 1000;
 			break;
 		case RF3:
-			map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] -
-					prog_cal[RF2] + prog_tab[RF2]) /
-				(s32)((rf_freq[RF3] - rf_freq[RF2]) / 1000);
-			map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2];
+			dividend = (s32)(prog_cal[RF3] - prog_tab[RF3]) -
+				   (s32)(prog_cal[RF2] + prog_tab[RF2]);
+			divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000;
+			map[i].rf_a2 = (dividend / divisor);
+			map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]);
 			map[i].rf3   = rf_freq[RF3] / 1000;
 			break;
 		default:
@@ -1181,6 +1185,48 @@ static int tda18271_get_id(struct dvb_frontend *fe)
 	return ret;
 }
 
+static int tda18271_setup_configuration(struct dvb_frontend *fe,
+					struct tda18271_config *cfg)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+	priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
+	priv->config = (cfg) ? cfg->config : 0;
+	priv->small_i2c = (cfg) ?
+		cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT;
+	priv->output_opt = (cfg) ?
+		cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON;
+
+	return 0;
+}
+
+static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg)
+{
+	/* tda18271_cal_on_startup == -1 when cal module option is unset */
+	return ((tda18271_cal_on_startup == -1) ?
+		/* honor configuration setting */
+		((cfg) && (cfg->rf_cal_on_startup)) :
+		/* module option overrides configuration setting */
+		(tda18271_cal_on_startup)) ? 1 : 0;
+}
+
+static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg;
+
+	tda18271_setup_configuration(fe, cfg);
+
+	if (tda18271_need_cal_on_startup(cfg))
+		tda18271_init(fe);
+
+	/* override default std map with values in config struct */
+	if ((cfg) && (cfg->std_map))
+		tda18271_update_std_map(fe, cfg->std_map);
+
+	return 0;
+}
+
 static struct dvb_tuner_ops tda18271_tuner_ops = {
 	.info = {
 		.name = "NXP TDA18271HD",
@@ -1193,6 +1239,7 @@ static struct dvb_tuner_ops tda18271_tuner_ops = {
 	.set_params        = tda18271_set_params,
 	.set_analog_params = tda18271_set_analog_params,
 	.release           = tda18271_release,
+	.set_config        = tda18271_set_config,
 	.get_frequency     = tda18271_get_frequency,
 	.get_bandwidth     = tda18271_get_bandwidth,
 };
@@ -1213,33 +1260,14 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
 	case 0:
 		goto fail;
 	case 1:
-	{
 		/* new tuner instance */
-		int rf_cal_on_startup;
-
-		priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
-		priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
-		priv->config = (cfg) ? cfg->config : 0;
-		priv->small_i2c = (cfg) ? cfg->small_i2c : 0;
-		priv->output_opt = (cfg) ?
-			cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON;
-
-		/* tda18271_cal_on_startup == -1 when cal
-		 * module option is unset */
-		if (tda18271_cal_on_startup == -1) {
-			/* honor attach-time configuration */
-			rf_cal_on_startup =
-				((cfg) && (cfg->rf_cal_on_startup)) ? 1 : 0;
-		} else {
-			/* module option overrides attach configuration */
-			rf_cal_on_startup = tda18271_cal_on_startup;
-		}
+		fe->tuner_priv = priv;
+
+		tda18271_setup_configuration(fe, cfg);
 
 		priv->cal_initialized = false;
 		mutex_init(&priv->lock);
 
-		fe->tuner_priv = priv;
-
 		if (tda_fail(tda18271_get_id(fe)))
 			goto fail;
 
@@ -1249,12 +1277,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
 		mutex_lock(&priv->lock);
 		tda18271_init_regs(fe);
 
-		if ((rf_cal_on_startup) && (priv->id == TDA18271HDC2))
+		if ((tda18271_need_cal_on_startup(cfg)) &&
+		    (priv->id == TDA18271HDC2))
 			tda18271c2_rf_cal_init(fe);
 
 		mutex_unlock(&priv->lock);
 		break;
-	}
 	default:
 		/* existing tuner instance */
 		fe->tuner_priv = priv;
@@ -1271,7 +1299,11 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
 				priv->small_i2c = cfg->small_i2c;
 			if (cfg->output_opt)
 				priv->output_opt = cfg->output_opt;
+			if (cfg->std_map)
+				tda18271_update_std_map(fe, cfg->std_map);
 		}
+		if (tda18271_need_cal_on_startup(cfg))
+			tda18271_init(fe);
 		break;
 	}
 
@@ -1298,7 +1330,7 @@ EXPORT_SYMBOL_GPL(tda18271_attach);
 MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.3");
+MODULE_VERSION("0.4");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c
index e21fdeff3ddf..e7f84c705da8 100644
--- a/drivers/media/common/tuners/tda18271-maps.c
+++ b/drivers/media/common/tuners/tda18271-maps.c
@@ -978,6 +978,7 @@ static struct tda18271_cid_target_map tda18271_cid_target[] = {
 int tda18271_lookup_cid_target(struct dvb_frontend *fe,
 			       u32 *freq, u8 *cid_target, u16 *count_limit)
 {
+	struct tda18271_priv *priv = fe->tuner_priv;
 	int i = 0;
 
 	while ((tda18271_cid_target[i].rfmax * 1000) < *freq) {
diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h
index 2bee229acd91..9589ab0576d2 100644
--- a/drivers/media/common/tuners/tda18271-priv.h
+++ b/drivers/media/common/tuners/tda18271-priv.h
@@ -80,10 +80,10 @@ struct tda18271_rf_tracking_filter_cal {
 	u32 rf1;
 	u32 rf2;
 	u32 rf3;
-	int rf_a1;
-	int rf_b1;
-	int rf_a2;
-	int rf_b2;
+	s32 rf_a1;
+	s32 rf_b1;
+	s32 rf_a2;
+	s32 rf_b2;
 };
 
 enum tda18271_pll {
@@ -109,11 +109,12 @@ struct tda18271_priv {
 	enum tda18271_i2c_gate gate;
 	enum tda18271_ver id;
 	enum tda18271_output_options output_opt;
+	enum tda18271_small_i2c small_i2c;
 
 	unsigned int config; /* interface to saa713x / tda829x */
-	unsigned int tm_rfcal;
 	unsigned int cal_initialized:1;
-	unsigned int small_i2c:1;
+
+	u8 tm_rfcal;
 
 	struct tda18271_map_layout *maps;
 	struct tda18271_std_map std;
@@ -135,27 +136,37 @@ extern int tda18271_debug;
 #define DBG_ADV  8
 #define DBG_CAL  16
 
-#define tda_printk(kern, fmt, arg...) \
-	printk(kern "%s: " fmt, __func__, ##arg)
-
-#define tda_dprintk(lvl, fmt, arg...) do {\
+#define tda_printk(st, kern, fmt, arg...) do {\
+	if (st) { \
+		struct tda18271_priv *state = st; \
+		printk(kern "%s: [%d-%04x|%s] " fmt, __func__, \
+			i2c_adapter_id(state->i2c_props.adap), \
+			state->i2c_props.addr, \
+			(state->role == TDA18271_MASTER) \
+			? "M" : "S", ##arg); \
+	} else \
+		printk(kern "%s: " fmt, __func__, ##arg); \
+} while (0)
+
+#define tda_dprintk(st, lvl, fmt, arg...) do {\
 	if (tda18271_debug & lvl) \
-		tda_printk(KERN_DEBUG, fmt, ##arg); } while (0)
+		tda_printk(st, KERN_DEBUG, fmt, ##arg); } while (0)
 
 #define tda_info(fmt, arg...)     printk(KERN_INFO     fmt, ##arg)
-#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING, fmt, ##arg)
-#define tda_err(fmt, arg...)  tda_printk(KERN_ERR,     fmt, ##arg)
-#define tda_dbg(fmt, arg...)  tda_dprintk(DBG_INFO,    fmt, ##arg)
-#define tda_map(fmt, arg...)  tda_dprintk(DBG_MAP,     fmt, ##arg)
-#define tda_reg(fmt, arg...)  tda_dprintk(DBG_REG,     fmt, ##arg)
-#define tda_cal(fmt, arg...)  tda_dprintk(DBG_CAL,     fmt, ##arg)
+#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg)
+#define tda_err(fmt, arg...)  tda_printk(priv, KERN_ERR,     fmt, ##arg)
+#define tda_dbg(fmt, arg...)  tda_dprintk(priv, DBG_INFO,    fmt, ##arg)
+#define tda_map(fmt, arg...)  tda_dprintk(priv, DBG_MAP,     fmt, ##arg)
+#define tda_reg(fmt, arg...)  tda_dprintk(priv, DBG_REG,     fmt, ##arg)
+#define tda_cal(fmt, arg...)  tda_dprintk(priv, DBG_CAL,     fmt, ##arg)
 
 #define tda_fail(ret)							     \
 ({									     \
 	int __ret;							     \
 	__ret = (ret < 0);						     \
 	if (__ret)							     \
-		tda_printk(KERN_ERR, "error %d on line %d\n", ret, __LINE__);\
+		tda_printk(priv, KERN_ERR,				     \
+			   "error %d on line %d\n", ret, __LINE__);	     \
 	__ret;								     \
 })
 
diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h
index 323f2912128d..d7fcc36dc6e6 100644
--- a/drivers/media/common/tuners/tda18271.h
+++ b/drivers/media/common/tuners/tda18271.h
@@ -78,6 +78,12 @@ enum tda18271_output_options {
 	TDA18271_OUTPUT_XT_OFF = 2,
 };
 
+enum tda18271_small_i2c {
+	TDA18271_39_BYTE_CHUNK_INIT = 0,
+	TDA18271_16_BYTE_CHUNK_INIT = 1,
+	TDA18271_08_BYTE_CHUNK_INIT = 2,
+};
+
 struct tda18271_config {
 	/* override default if freq / std settings (optional) */
 	struct tda18271_std_map *std_map;
@@ -91,12 +97,12 @@ struct tda18271_config {
 	/* output options that can be disabled */
 	enum tda18271_output_options output_opt;
 
+	/* some i2c providers cant write all 39 registers at once */
+	enum tda18271_small_i2c small_i2c;
+
 	/* force rf tracking filter calibration on startup */
 	unsigned int rf_cal_on_startup:1;
 
-	/* some i2c providers cant write all 39 registers at once */
-	unsigned int small_i2c:1;
-
 	/* interface to saa713x / tda829x */
 	unsigned int config;
 };
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
index 064d14c8d7b2..c190b0dedee4 100644
--- a/drivers/media/common/tuners/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -33,6 +33,7 @@ module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
 static int deemphasis_50;
+module_param(deemphasis_50, int, 0644);
 MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
 
 /* ---------------------------------------------------------------------- */
diff --git a/drivers/media/common/tuners/tda9887.c b/drivers/media/common/tuners/tda9887.c
index 544cdbe88a6c..a71c100c95df 100644
--- a/drivers/media/common/tuners/tda9887.c
+++ b/drivers/media/common/tuners/tda9887.c
@@ -463,7 +463,7 @@ static int tda9887_set_insmod(struct dvb_frontend *fe)
 			buf[1] &= ~cQSS;
 	}
 
-	if (adjust >= 0x00 && adjust < 0x20) {
+	if (adjust < 0x20) {
 		buf[2] &= ~cTopMask;
 		buf[2] |= adjust;
 	}
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index f4ffcdc9b848..432003dded7c 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -61,6 +61,7 @@ struct xc5000_priv {
 	u32 bandwidth;
 	u8  video_standard;
 	u8  rf_mode;
+	u8  radio_input;
 };
 
 /* Misc Defines */
@@ -632,8 +633,12 @@ static int xc5000_set_params(struct dvb_frontend *fe,
 	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret;
 
-	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
-		xc_load_fw_and_init_tuner(fe);
+	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
+		if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
+			dprintk(1, "Unable to load firmware and init tuner\n");
+			return -EINVAL;
+		}
+	}
 
 	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
 
@@ -739,15 +744,12 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
 	return ret;
 }
 
-static int xc5000_set_analog_params(struct dvb_frontend *fe,
+static int xc5000_set_tv_freq(struct dvb_frontend *fe,
 	struct analog_parameters *params)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret;
 
-	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
-		xc_load_fw_and_init_tuner(fe);
-
 	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
 		__func__, params->frequency);
 
@@ -827,6 +829,86 @@ tune_channel:
 	return 0;
 }
 
+static int xc5000_set_radio_freq(struct dvb_frontend *fe,
+	struct analog_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+	u8 radio_input;
+
+	dprintk(1, "%s() frequency=%d (in units of khz)\n",
+		__func__, params->frequency);
+
+	if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) {
+		dprintk(1, "%s() radio input not configured\n", __func__);
+		return -EINVAL;
+	}
+
+	if (priv->radio_input == XC5000_RADIO_FM1)
+		radio_input = FM_Radio_INPUT1;
+	else if  (priv->radio_input == XC5000_RADIO_FM2)
+		radio_input = FM_Radio_INPUT2;
+	else {
+		dprintk(1, "%s() unknown radio input %d\n", __func__,
+			priv->radio_input);
+		return -EINVAL;
+	}
+
+	priv->freq_hz = params->frequency * 125 / 2;
+
+	priv->rf_mode = XC_RF_MODE_AIR;
+
+	ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode,
+			       XC5000_Standard[radio_input].AudioMode);
+
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
+
+	return 0;
+}
+
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
+		if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
+			dprintk(1, "Unable to load firmware and init tuner\n");
+			return -EINVAL;
+		}
+	}
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		ret = xc5000_set_radio_freq(fe, params);
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+	case V4L2_TUNER_DIGITAL_TV:
+		ret = xc5000_set_tv_freq(fe, params);
+		break;
+	}
+
+	return ret;
+}
+
+
 static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
@@ -1000,6 +1082,9 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
 		priv->if_khz = cfg->if_khz;
 	}
 
+	if (priv->radio_input == 0)
+		priv->radio_input = cfg->radio_input;
+
 	/* Check if firmware has been loaded. It is possible that another
 	   instance of the driver has loaded the firmware.
 	 */
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index f4c146698a00..e6d7236c9ea1 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -30,11 +30,17 @@ struct i2c_adapter;
 struct xc5000_config {
 	u8   i2c_address;
 	u32  if_khz;
+	u8   radio_input;
 };
 
 /* xc5000 callback command */
 #define XC5000_TUNER_RESET		0
 
+/* Possible Radio inputs */
+#define XC5000_RADIO_NOT_CONFIGURED		0
+#define XC5000_RADIO_FM1			1
+#define XC5000_RADIO_FM2			2
+
 /* For each bridge framework, when it attaches either analog or digital,
  * it has to store a reference back to its _core equivalent structure,
  * so that it can service the hardware by steering gpio's etc.
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index b1857c19bbd2..78fc469f0f69 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -215,7 +215,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
 		freq = 2150000; /* satellite IF is 950..2150MHz */
 
 	/* decide which VCO to use for the input frequency */
-	for(i = 1; (i < ARRAY_SIZE(osci)) && (osci[i] < freq); i++);
+	for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++);
 	printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
 	band=bandsel[i];
 	/* the gain values must be set by SetSymbolrate */
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index 2d099e271751..53e3f2a7d31a 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -510,7 +510,7 @@ static void dm1105_emit_key(struct work_struct *work)
 
 	data = (ircom >> 8) & 0x7f;
 
-	ir_input_keydown(ir->input_dev, &ir->ir, data, data);
+	ir_input_keydown(ir->input_dev, &ir->ir, data);
 	ir_input_nokey(ir->input_dev, &ir->ir);
 }
 
@@ -589,7 +589,12 @@ 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));
 
-	ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes);
+	err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes);
+	if (err < 0) {
+		input_free_device(input_dev);
+		return err;
+	}
+
 	input_dev->name = "DVB on-card IR receiver";
 	input_dev->phys = dm1105->ir.input_phys;
 	input_dev->id.bustype = BUS_PCI;
@@ -608,6 +613,7 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
 
 	err = input_register_device(input_dev);
 	if (err) {
+		ir_input_free(input_dev);
 		input_free_device(input_dev);
 		return err;
 	}
@@ -617,8 +623,8 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
 
 void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
 {
+	ir_input_free(dm1105->ir.input_dev);
 	input_unregister_device(dm1105->ir.input_dev);
-
 }
 
 static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 91c537bca8ad..b78cfb7d1897 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -30,6 +30,7 @@
 #include <linux/string.h>
 #include <linux/crc32.h>
 #include <asm/uaccess.h>
+#include <asm/div64.h>
 
 #include "dvb_demux.h"
 
@@ -44,6 +45,11 @@ module_param(dvb_demux_tscheck, int, 0644);
 MODULE_PARM_DESC(dvb_demux_tscheck,
 		"enable transport stream continuity and TEI check");
 
+static int dvb_demux_speedcheck;
+module_param(dvb_demux_speedcheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_speedcheck,
+		"enable transport stream speed check");
+
 #define dprintk_tscheck(x...) do {                              \
 		if (dvb_demux_tscheck && printk_ratelimit())    \
 			printk(x);                              \
@@ -387,6 +393,39 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
 	u16 pid = ts_pid(buf);
 	int dvr_done = 0;
 
+	if (dvb_demux_speedcheck) {
+		struct timespec cur_time, delta_time;
+		u64 speed_bytes, speed_timedelta;
+
+		demux->speed_pkts_cnt++;
+
+		/* show speed every SPEED_PKTS_INTERVAL packets */
+		if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
+			cur_time = current_kernel_time();
+
+			if (demux->speed_last_time.tv_sec != 0 &&
+					demux->speed_last_time.tv_nsec != 0) {
+				delta_time = timespec_sub(cur_time,
+						demux->speed_last_time);
+				speed_bytes = (u64)demux->speed_pkts_cnt
+					* 188 * 8;
+				/* convert to 1024 basis */
+				speed_bytes = 1000 * div64_u64(speed_bytes,
+						1024);
+				speed_timedelta =
+					(u64)timespec_to_ns(&delta_time);
+				speed_timedelta = div64_u64(speed_timedelta,
+						1000000); /* nsec -> usec */
+				printk(KERN_INFO "TS speed %llu Kbits/sec \n",
+						div64_u64(speed_bytes,
+							speed_timedelta));
+			};
+
+			demux->speed_last_time = cur_time;
+			demux->speed_pkts_cnt = 0;
+		};
+	};
+
 	if (dvb_demux_tscheck) {
 		if (!demux->cnt_storage)
 			demux->cnt_storage = vmalloc(MAX_PID + 1);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 2fe05d03240d..a7d876fd02dd 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -44,6 +44,8 @@
 
 #define MAX_PID 0x1fff
 
+#define SPEED_PKTS_INTERVAL 50000
+
 struct dvb_demux_filter {
 	struct dmx_section_filter filter;
 	u8 maskandmode[DMX_MAX_FILTER_SIZE];
@@ -131,6 +133,9 @@ struct dvb_demux {
 	spinlock_t lock;
 
 	uint8_t *cnt_storage; /* for TS continuity check */
+
+	struct timespec speed_last_time; /* for TS speed check */
+	uint32_t speed_pkts_cnt; /* for TS speed check */
 };
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 98082416aa52..07461222a7f5 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -895,104 +895,27 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
 }
 
 static struct dtv_cmds_h dtv_cmds[] = {
-	[DTV_TUNE] = {
-		.name	= "DTV_TUNE",
-		.cmd	= DTV_TUNE,
-		.set	= 1,
-	},
-	[DTV_CLEAR] = {
-		.name	= "DTV_CLEAR",
-		.cmd	= DTV_CLEAR,
-		.set	= 1,
-	},
+	_DTV_CMD(DTV_TUNE, 1, 0),
+	_DTV_CMD(DTV_CLEAR, 1, 0),
 
 	/* Set */
-	[DTV_FREQUENCY] = {
-		.name	= "DTV_FREQUENCY",
-		.cmd	= DTV_FREQUENCY,
-		.set	= 1,
-	},
-	[DTV_BANDWIDTH_HZ] = {
-		.name	= "DTV_BANDWIDTH_HZ",
-		.cmd	= DTV_BANDWIDTH_HZ,
-		.set	= 1,
-	},
-	[DTV_MODULATION] = {
-		.name	= "DTV_MODULATION",
-		.cmd	= DTV_MODULATION,
-		.set	= 1,
-	},
-	[DTV_INVERSION] = {
-		.name	= "DTV_INVERSION",
-		.cmd	= DTV_INVERSION,
-		.set	= 1,
-	},
-	[DTV_DISEQC_MASTER] = {
-		.name	= "DTV_DISEQC_MASTER",
-		.cmd	= DTV_DISEQC_MASTER,
-		.set	= 1,
-		.buffer	= 1,
-	},
-	[DTV_SYMBOL_RATE] = {
-		.name	= "DTV_SYMBOL_RATE",
-		.cmd	= DTV_SYMBOL_RATE,
-		.set	= 1,
-	},
-	[DTV_INNER_FEC] = {
-		.name	= "DTV_INNER_FEC",
-		.cmd	= DTV_INNER_FEC,
-		.set	= 1,
-	},
-	[DTV_VOLTAGE] = {
-		.name	= "DTV_VOLTAGE",
-		.cmd	= DTV_VOLTAGE,
-		.set	= 1,
-	},
-	[DTV_TONE] = {
-		.name	= "DTV_TONE",
-		.cmd	= DTV_TONE,
-		.set	= 1,
-	},
-	[DTV_PILOT] = {
-		.name	= "DTV_PILOT",
-		.cmd	= DTV_PILOT,
-		.set	= 1,
-	},
-	[DTV_ROLLOFF] = {
-		.name	= "DTV_ROLLOFF",
-		.cmd	= DTV_ROLLOFF,
-		.set	= 1,
-	},
-	[DTV_DELIVERY_SYSTEM] = {
-		.name	= "DTV_DELIVERY_SYSTEM",
-		.cmd	= DTV_DELIVERY_SYSTEM,
-		.set	= 1,
-	},
-	[DTV_HIERARCHY] = {
-		.name	= "DTV_HIERARCHY",
-		.cmd	= DTV_HIERARCHY,
-		.set	= 1,
-	},
-	[DTV_CODE_RATE_HP] = {
-		.name	= "DTV_CODE_RATE_HP",
-		.cmd	= DTV_CODE_RATE_HP,
-		.set	= 1,
-	},
-	[DTV_CODE_RATE_LP] = {
-		.name	= "DTV_CODE_RATE_LP",
-		.cmd	= DTV_CODE_RATE_LP,
-		.set	= 1,
-	},
-	[DTV_GUARD_INTERVAL] = {
-		.name	= "DTV_GUARD_INTERVAL",
-		.cmd	= DTV_GUARD_INTERVAL,
-		.set	= 1,
-	},
-	[DTV_TRANSMISSION_MODE] = {
-		.name	= "DTV_TRANSMISSION_MODE",
-		.cmd	= DTV_TRANSMISSION_MODE,
-		.set	= 1,
-	},
+	_DTV_CMD(DTV_FREQUENCY, 1, 0),
+	_DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
+	_DTV_CMD(DTV_MODULATION, 1, 0),
+	_DTV_CMD(DTV_INVERSION, 1, 0),
+	_DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
+	_DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
+	_DTV_CMD(DTV_INNER_FEC, 1, 0),
+	_DTV_CMD(DTV_VOLTAGE, 1, 0),
+	_DTV_CMD(DTV_TONE, 1, 0),
+	_DTV_CMD(DTV_PILOT, 1, 0),
+	_DTV_CMD(DTV_ROLLOFF, 1, 0),
+	_DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
+	_DTV_CMD(DTV_HIERARCHY, 1, 0),
+	_DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
+	_DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
+	_DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
+	_DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
 
 	_DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
 	_DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
@@ -1035,43 +958,13 @@ static struct dtv_cmds_h dtv_cmds[] = {
 	_DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
 
 	/* Get */
-	[DTV_DISEQC_SLAVE_REPLY] = {
-		.name	= "DTV_DISEQC_SLAVE_REPLY",
-		.cmd	= DTV_DISEQC_SLAVE_REPLY,
-		.set	= 0,
-		.buffer	= 1,
-	},
-
-	[DTV_API_VERSION] = {
-		.name	= "DTV_API_VERSION",
-		.cmd	= DTV_API_VERSION,
-		.set	= 0,
-	},
-	[DTV_CODE_RATE_HP] = {
-		.name	= "DTV_CODE_RATE_HP",
-		.cmd	= DTV_CODE_RATE_HP,
-		.set	= 0,
-	},
-	[DTV_CODE_RATE_LP] = {
-		.name	= "DTV_CODE_RATE_LP",
-		.cmd	= DTV_CODE_RATE_LP,
-		.set	= 0,
-	},
-	[DTV_GUARD_INTERVAL] = {
-		.name	= "DTV_GUARD_INTERVAL",
-		.cmd	= DTV_GUARD_INTERVAL,
-		.set	= 0,
-	},
-	[DTV_TRANSMISSION_MODE] = {
-		.name	= "DTV_TRANSMISSION_MODE",
-		.cmd	= DTV_TRANSMISSION_MODE,
-		.set	= 0,
-	},
-	[DTV_HIERARCHY] = {
-		.name	= "DTV_HIERARCHY",
-		.cmd	= DTV_HIERARCHY,
-		.set	= 0,
-	},
+	_DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
+	_DTV_CMD(DTV_API_VERSION, 0, 0),
+	_DTV_CMD(DTV_CODE_RATE_HP, 0, 0),
+	_DTV_CMD(DTV_CODE_RATE_LP, 0, 0),
+	_DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
+	_DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
+	_DTV_CMD(DTV_HIERARCHY, 0, 0),
 };
 
 static void dtv_property_dump(struct dtv_property *tvp)
@@ -1712,7 +1605,18 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	int err = -EOPNOTSUPP;
+	int cb_err, err = -EOPNOTSUPP;
+
+	if (fe->dvb->fe_ioctl_override) {
+		cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
+						    DVB_FE_IOCTL_PRE);
+		if (cb_err < 0)
+			return cb_err;
+		if (cb_err > 0)
+			return 0;
+		/* fe_ioctl_override returning 0 allows
+		 * dvb-core to continue handling the ioctl */
+	}
 
 	switch (cmd) {
 	case FE_GET_INFO: {
@@ -1978,6 +1882,13 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
 		break;
 	};
 
+	if (fe->dvb->fe_ioctl_override) {
+		cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
+						    DVB_FE_IOCTL_POST);
+		if (cb_err < 0)
+			return cb_err;
+	}
+
 	return err;
 }
 
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 01fc70484743..f7b499d4a3c0 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -54,6 +54,8 @@
 	module_param_array(adapter_nr, short, NULL, 0444); \
 	MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
 
+struct dvb_frontend;
+
 struct dvb_adapter {
 	int num;
 	struct list_head list_head;
@@ -69,6 +71,32 @@ struct dvb_adapter {
 	int mfe_shared;			/* indicates mutually exclusive frontends */
 	struct dvb_device *mfe_dvbdev;	/* frontend device in use */
 	struct mutex mfe_lock;		/* access lock for thread creation */
+
+	/* Allow the adapter/bridge driver to perform an action before and/or
+	 * after the core handles an ioctl:
+	 *
+	 * DVB_FE_IOCTL_PRE indicates that the ioctl has not yet been handled.
+	 * DVB_FE_IOCTL_POST indicates that the ioctl has been handled.
+	 *
+	 * When DVB_FE_IOCTL_PRE is passed to the callback as the stage arg:
+	 *
+	 * return 0 to allow dvb-core to handle the ioctl.
+	 * return a positive int to prevent dvb-core from handling the ioctl,
+	 * 	and exit without error.
+	 * return a negative int to prevent dvb-core from handling the ioctl,
+	 * 	and return that value as an error.
+	 *
+	 * When DVB_FE_IOCTL_POST is passed to the callback as the stage arg:
+	 *
+	 * return 0 to allow the dvb_frontend ioctl handler to exit normally.
+	 * return a negative int to cause the dvb_frontend ioctl handler to
+	 * 	return that value as an error.
+	 */
+#define DVB_FE_IOCTL_PRE 0
+#define DVB_FE_IOCTL_POST 1
+	int (*fe_ioctl_override)(struct dvb_frontend *fe,
+				 unsigned int cmd, void *parg,
+				 unsigned int stage);
 };
 
 
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 0e4b97fba384..2dee1bf73577 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -322,3 +322,11 @@ config DVB_USB_FRIIO
 	depends on DVB_USB
 	help
 	  Say Y here to support the Japanese DTV receiver Friio.
+
+config DVB_USB_EC168
+	tristate "E3C EC168 DVB-T USB2.0 support"
+	depends on DVB_USB && EXPERIMENTAL
+	select DVB_EC100
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 85b83a43d55d..72c92cb69a22 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -82,6 +82,9 @@ obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
 dvb-usb-friio-objs = friio.o friio-fe.o
 obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
 
+dvb-usb-ec168-objs = ec168.o
+obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index cf042b309b46..8b60a601fb82 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -730,7 +730,7 @@ static int af9015_read_config(struct usb_device *udev)
 		goto error;
 	deb_info("%s: IR mode:%d\n", __func__, val);
 	for (i = 0; i < af9015_properties_count; i++) {
-		if (val == AF9015_IR_MODE_DISABLED || val == 0x04) {
+		if (val == AF9015_IR_MODE_DISABLED) {
 			af9015_properties[i].rc_key_map = NULL;
 			af9015_properties[i].rc_key_map_size  = 0;
 		} else if (dvb_usb_af9015_remote) {
@@ -868,6 +868,16 @@ static int af9015_read_config(struct usb_device *udev)
 				af9015_config.ir_table_size =
 				  ARRAY_SIZE(af9015_ir_table_avermedia);
 				break;
+			case USB_VID_MSI_2:
+				af9015_properties[i].rc_key_map =
+				  af9015_rc_keys_msi_digivox_iii;
+				af9015_properties[i].rc_key_map_size =
+				  ARRAY_SIZE(af9015_rc_keys_msi_digivox_iii);
+				af9015_config.ir_table =
+				  af9015_ir_table_msi_digivox_iii;
+				af9015_config.ir_table_size =
+				  ARRAY_SIZE(af9015_ir_table_msi_digivox_iii);
+				break;
 			}
 		}
 	}
@@ -1283,6 +1293,8 @@ static struct usb_device_id af9015_usb_table[] = {
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_MC810)},
 	{USB_DEVICE(USB_VID_KYE,       USB_PID_GENIUS_TVGO_DVB_T03)},
 /* 25 */{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_399U_2)},
+	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_PC160_T)},
+	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_SVEON_STV20)},
 	{0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1296,7 +1308,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 		.firmware = "dvb-usb-af9015.fw",
 		.no_reconnect = 1,
 
-		.size_of_priv = sizeof(struct af9015_state), \
+		.size_of_priv = sizeof(struct af9015_state),
 
 		.num_adapters = 2,
 		.adapter = {
@@ -1402,7 +1414,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 		.firmware = "dvb-usb-af9015.fw",
 		.no_reconnect = 1,
 
-		.size_of_priv = sizeof(struct af9015_state), \
+		.size_of_priv = sizeof(struct af9015_state),
 
 		.num_adapters = 2,
 		.adapter = {
@@ -1508,7 +1520,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 		.firmware = "dvb-usb-af9015.fw",
 		.no_reconnect = 1,
 
-		.size_of_priv = sizeof(struct af9015_state), \
+		.size_of_priv = sizeof(struct af9015_state),
 
 		.num_adapters = 2,
 		.adapter = {
@@ -1554,7 +1566,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
 		.i2c_algo = &af9015_i2c_algo,
 
-		.num_device_descs = 4, /* max 9 */
+		.num_device_descs = 6, /* max 9 */
 		.devices = {
 			{
 				.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1577,6 +1589,17 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 				.cold_ids = {&af9015_usb_table[24], NULL},
 				.warm_ids = {NULL},
 			},
+			{
+				.name = "KWorld PlusTV DVB-T PCI Pro Card " \
+					"(DVB-T PC160-T)",
+				.cold_ids = {&af9015_usb_table[26], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "Sveon STV20 Tuner USB DVB-T HDTV",
+				.cold_ids = {&af9015_usb_table[27], NULL},
+				.warm_ids = {NULL},
+			},
 		}
 	},
 };
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index c41f30e4a1b8..931c8515830d 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -95,6 +95,7 @@ enum af9015_ir_mode {
 	AF9015_IR_MODE_HID,
 	AF9015_IR_MODE_RLC,
 	AF9015_IR_MODE_RC6,
+	AF9015_IR_MODE_POLLING, /* just guess */
 };
 
 struct af9015_state {
@@ -119,6 +120,7 @@ enum af9015_remote {
 /* 5 */	AF9015_REMOTE_AVERMEDIA_KS,
 };
 
+/* LeadTek - Y04G0051 */
 /* Leadtek WinFast DTV Dongle Gold */
 static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
 	{ 0x001e, KEY_1 },
@@ -131,64 +133,96 @@ static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
 	{ 0x0025, KEY_8 },
 	{ 0x0026, KEY_9 },
 	{ 0x0027, KEY_0 },
-	{ 0x0028, KEY_ENTER },
-	{ 0x004f, KEY_VOLUMEUP },
-	{ 0x0050, KEY_VOLUMEDOWN },
-	{ 0x0051, KEY_CHANNELDOWN },
-	{ 0x0052, KEY_CHANNELUP },
+	{ 0x0028, KEY_OK },
+	{ 0x004f, KEY_RIGHT },
+	{ 0x0050, KEY_LEFT },
+	{ 0x0051, KEY_DOWN },
+	{ 0x0052, KEY_UP },
+	{ 0x011a, KEY_POWER2 },
+	{ 0x04b4, KEY_TV },
+	{ 0x04b3, KEY_RED },
+	{ 0x04b2, KEY_GREEN },
+	{ 0x04b1, KEY_YELLOW },
+	{ 0x04b0, KEY_BLUE },
+	{ 0x003d, KEY_TEXT },
+	{ 0x0113, KEY_SLEEP },
+	{ 0x0010, KEY_MUTE },
+	{ 0x0105, KEY_ESC },
+	{ 0x0009, KEY_SCREEN },
+	{ 0x010f, KEY_MENU },
+	{ 0x003f, KEY_CHANNEL },
+	{ 0x0013, KEY_REWIND },
+	{ 0x0012, KEY_PLAY },
+	{ 0x0011, KEY_FASTFORWARD },
+	{ 0x0005, KEY_PREVIOUS },
+	{ 0x0029, KEY_STOP },
+	{ 0x002b, KEY_NEXT },
+	{ 0x0041, KEY_EPG },
+	{ 0x0019, KEY_VIDEO },
+	{ 0x0016, KEY_AUDIO },
+	{ 0x0037, KEY_DOT },
+	{ 0x002a, KEY_AGAIN },
+	{ 0x002c, KEY_CAMERA },
+	{ 0x003c, KEY_NEW },
+	{ 0x0115, KEY_RECORD },
+	{ 0x010b, KEY_TIME },
+	{ 0x0043, KEY_VOLUMEUP },
+	{ 0x0042, KEY_VOLUMEDOWN },
+	{ 0x004b, KEY_CHANNELUP },
+	{ 0x004e, KEY_CHANNELDOWN },
 };
 
 static u8 af9015_ir_table_leadtek[] = {
-	0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00,
-	0x03, 0xfc, 0x56, 0xa9, 0x00, 0x00, 0x00,
-	0x03, 0xfc, 0x4b, 0xb4, 0x00, 0x00, 0x00,
-	0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00,
-	0x03, 0xfc, 0x4d, 0xb2, 0x00, 0x00, 0x00,
-	0x03, 0xfc, 0x4e, 0xb1, 0x00, 0x00, 0x00,
-	0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00,
-	0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00,
-	0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00,
-	0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00,
-	0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00,
-	0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00,
-	0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00,
-	0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00,
-	0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00,
-	0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00,
-	0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00,
-	0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00,
-	0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00,
-	0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00,
-	0x03, 0xfc, 0x43, 0xbc, 0x00, 0x00, 0x00,
-	0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00,
-	0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00,
-	0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00,
-	0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00,
-	0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00,
-	0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00,
-	0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00,
-	0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00,
-	0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00,
-	0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00,
-	0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00,
-	0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00,
-	0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00,
-	0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00,
-	0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00,
-	0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00,
-	0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00,
-	0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00,
-	0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00,
-	0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00,
-	0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00,
-	0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00,
-	0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00,
-	0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00,
-	0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00,
-	0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00,
-	0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00,
-	0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00,
-	0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00,
+	0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00, /* KEY_POWER2 */
+	0x03, 0xfc, 0x56, 0xa9, 0xb4, 0x04, 0x00, /* KEY_TV */
+	0x03, 0xfc, 0x4b, 0xb4, 0xb3, 0x04, 0x00, /* KEY_RED */
+	0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00, /* KEY_GREEN */
+	0x03, 0xfc, 0x4d, 0xb2, 0xb1, 0x04, 0x00, /* KEY_YELLOW */
+	0x03, 0xfc, 0x4e, 0xb1, 0xb0, 0x04, 0x00, /* KEY_BLUE */
+	0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00, /* KEY_TEXT */
+	0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00, /* KEY_SLEEP */
+	0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00, /* KEY_MUTE */
+	0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00, /* KEY_ESC */
+	0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00, /* KEY_STOP (1)*/
+	0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00, /* KEY_UP */
+	0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00, /* KEY_SCREEN */
+	0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00, /* KEY_LEFT */
+	0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00, /* KEY_OK (1) */
+	0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00, /* KEY_RIGHT */
+	0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00, /* KEY_MENU */
+	0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00, /* KEY_DOWN */
+	0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00, /* KEY_CHANNEL */
+	0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00, /* KEY_REWIND */
+	0x03, 0xfc, 0x43, 0xbc, 0x12, 0x00, 0x00, /* KEY_PLAY */
+	0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00, /* KEY_FASTFORWARD */
+	0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00, /* KEY_VIDEO (1) */
+	0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00, /* KEY_PREVIOUS */
+	0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00, /* KEY_STOP (2) */
+	0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00, /* KEY_NEXT */
+	0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00, /* KEY_EPG */
+	0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00, /* KEY_1 */
+	0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00, /* KEY_2 */
+	0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00, /* KEY_3 */
+	0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00, /* KEY_VIDEO (2) */
+	0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00, /* KEY_4 */
+	0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00, /* KEY_5 */
+	0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00, /* KEY_6 */
+	0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00, /* KEY_AUDIO */
+	0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00, /* KEY_7 */
+	0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00, /* KEY_8 */
+	0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00, /* KEY_9 */
+	0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* KEY_OK (2) */
+	0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00, /* KEY_DOT */
+	0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00, /* KEY_0 */
+	0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00, /* KEY_AGAIN */
+	0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00, /* KEY_CAMERA */
+	0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00, /* KEY_NEW */
+	0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00, /* KEY_RECORD */
+	0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00, /* KEY_TIME */
+	0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00, /* KEY_VOLUMEUP */
+	0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00, /* KEY_VOLUMEDOWN */
+	0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00, /* KEY_CHANNELUP */
+	0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00, /* KEY_CHANNELDOWN */
 };
 
 /* TwinHan AzureWave AD-TU700(704J) */
@@ -746,4 +780,75 @@ static u8 af9015_ir_table_trekstor[] = {
 	0x00, 0xff, 0x84, 0x7b, 0x27, 0x07, 0x00,
 };
 
+/* MSI DIGIVOX mini III */
+static struct dvb_usb_rc_key af9015_rc_keys_msi_digivox_iii[] = {
+	{ 0x0713, KEY_POWER },       /* [red power button] */
+	{ 0x073b, KEY_VIDEO },       /* Source */
+	{ 0x073e, KEY_ZOOM },        /* Zoom */
+	{ 0x070b, KEY_POWER2 },      /* ShutDown */
+	{ 0x071e, KEY_1 },
+	{ 0x071f, KEY_2 },
+	{ 0x0720, KEY_3 },
+	{ 0x0721, KEY_4 },
+	{ 0x0722, KEY_5 },
+	{ 0x0723, KEY_6 },
+	{ 0x0724, KEY_7 },
+	{ 0x0725, KEY_8 },
+	{ 0x0726, KEY_9 },
+	{ 0x0727, KEY_0 },
+	{ 0x0752, KEY_CHANNELUP },   /* CH+ */
+	{ 0x0751, KEY_CHANNELDOWN }, /* CH- */
+	{ 0x0750, KEY_VOLUMEUP },    /* Vol+ */
+	{ 0x074f, KEY_VOLUMEDOWN },  /* Vol- */
+	{ 0x0705, KEY_ESC },         /* [back up arrow] */
+	{ 0x0708, KEY_OK },          /* [enter arrow] */
+	{ 0x073f, KEY_RECORD },      /* Rec */
+	{ 0x0716, KEY_STOP },        /* Stop */
+	{ 0x072a, KEY_PLAY },        /* Play */
+	{ 0x073c, KEY_MUTE },        /* Mute */
+	{ 0x0718, KEY_UP },
+	{ 0x0707, KEY_DOWN },
+	{ 0x070f, KEY_LEFT },
+	{ 0x0715, KEY_RIGHT },
+	{ 0x0736, KEY_RED },
+	{ 0x0737, KEY_GREEN },
+	{ 0x072d, KEY_YELLOW },
+	{ 0x072e, KEY_BLUE },
+};
+
+static u8 af9015_ir_table_msi_digivox_iii[] = {
+	0x61, 0xd6, 0x43, 0xbc, 0x13, 0x07, 0x00, /* KEY_POWER */
+	0x61, 0xd6, 0x01, 0xfe, 0x3b, 0x07, 0x00, /* KEY_VIDEO */
+	0x61, 0xd6, 0x0b, 0xf4, 0x3e, 0x07, 0x00, /* KEY_ZOOM */
+	0x61, 0xd6, 0x03, 0xfc, 0x0b, 0x07, 0x00, /* KEY_POWER2 */
+	0x61, 0xd6, 0x04, 0xfb, 0x1e, 0x07, 0x00, /* KEY_1 */
+	0x61, 0xd6, 0x08, 0xf7, 0x1f, 0x07, 0x00, /* KEY_2 */
+	0x61, 0xd6, 0x02, 0xfd, 0x20, 0x07, 0x00, /* KEY_3 */
+	0x61, 0xd6, 0x0f, 0xf0, 0x21, 0x07, 0x00, /* KEY_4 */
+	0x61, 0xd6, 0x05, 0xfa, 0x22, 0x07, 0x00, /* KEY_5 */
+	0x61, 0xd6, 0x06, 0xf9, 0x23, 0x07, 0x00, /* KEY_6 */
+	0x61, 0xd6, 0x0c, 0xf3, 0x24, 0x07, 0x00, /* KEY_7 */
+	0x61, 0xd6, 0x0d, 0xf2, 0x25, 0x07, 0x00, /* KEY_8 */
+	0x61, 0xd6, 0x0a, 0xf5, 0x26, 0x07, 0x00, /* KEY_9 */
+	0x61, 0xd6, 0x11, 0xee, 0x27, 0x07, 0x00, /* KEY_0 */
+	0x61, 0xd6, 0x09, 0xf6, 0x52, 0x07, 0x00, /* KEY_CHANNELUP */
+	0x61, 0xd6, 0x07, 0xf8, 0x51, 0x07, 0x00, /* KEY_CHANNELDOWN */
+	0x61, 0xd6, 0x0e, 0xf1, 0x50, 0x07, 0x00, /* KEY_VOLUMEUP */
+	0x61, 0xd6, 0x13, 0xec, 0x4f, 0x07, 0x00, /* KEY_VOLUMEDOWN */
+	0x61, 0xd6, 0x10, 0xef, 0x05, 0x07, 0x00, /* KEY_ESC */
+	0x61, 0xd6, 0x12, 0xed, 0x08, 0x07, 0x00, /* KEY_OK */
+	0x61, 0xd6, 0x14, 0xeb, 0x3f, 0x07, 0x00, /* KEY_RECORD */
+	0x61, 0xd6, 0x15, 0xea, 0x16, 0x07, 0x00, /* KEY_STOP */
+	0x61, 0xd6, 0x16, 0xe9, 0x2a, 0x07, 0x00, /* KEY_PLAY */
+	0x61, 0xd6, 0x17, 0xe8, 0x3c, 0x07, 0x00, /* KEY_MUTE */
+	0x61, 0xd6, 0x18, 0xe7, 0x18, 0x07, 0x00, /* KEY_UP */
+	0x61, 0xd6, 0x19, 0xe6, 0x07, 0x07, 0x00, /* KEY_DOWN */
+	0x61, 0xd6, 0x1a, 0xe5, 0x0f, 0x07, 0x00, /* KEY_LEFT */
+	0x61, 0xd6, 0x1b, 0xe4, 0x15, 0x07, 0x00, /* KEY_RIGHT */
+	0x61, 0xd6, 0x1c, 0xe3, 0x36, 0x07, 0x00, /* KEY_RED */
+	0x61, 0xd6, 0x1d, 0xe2, 0x37, 0x07, 0x00, /* KEY_GREEN */
+	0x61, 0xd6, 0x1e, 0xe1, 0x2d, 0x07, 0x00, /* KEY_YELLOW */
+	0x61, 0xd6, 0x1f, 0xe0, 0x2e, 0x07, 0x00, /* KEY_BLUE */
+};
+
 #endif
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 2a53dd096eef..05fb28e9c69e 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -36,9 +36,11 @@
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
 #include "mxl5005s.h"
+#include "max2165.h"
 #include "dib7000p.h"
 #include "dib0070.h"
 #include "lgs8gxx.h"
+#include "atbm8830.h"
 
 /* debug */
 static int dvb_usb_cxusb_debug;
@@ -714,6 +716,11 @@ static struct mxl5005s_config d680_dmb_tuner = {
 	.AgcMasterByte   = 0x00,
 };
 
+static struct max2165_config mygica_d689_max2165_cfg = {
+	.i2c_address = 0x60,
+	.osc_clk = 20
+};
+
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -813,6 +820,14 @@ static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
 	return (fe == NULL) ? -EIO : 0;
 }
 
+static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend *fe;
+	fe = dvb_attach(max2165_attach, adap->fe,
+			&adap->dev->i2c_adap, &mygica_d689_max2165_cfg);
+	return (fe == NULL) ? -EIO : 0;
+}
+
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	u8 b;
@@ -1160,6 +1175,55 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
 	return 0;
 }
 
+static struct atbm8830_config mygica_d689_atbm8830_cfg = {
+	.prod = ATBM8830_PROD_8830,
+	.demod_address = 0x40,
+	.serial_ts = 0,
+	.ts_sampling_edge = 1,
+	.ts_clk_gated = 0,
+	.osc_clk_freq = 30400, /* in kHz */
+	.if_freq = 0, /* zero IF */
+	.zif_swap_iq = 1,
+};
+
+static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap->dev;
+
+	/* Select required USB configuration */
+	if (usb_set_interface(d->udev, 0, 0) < 0)
+		err("set interface failed");
+
+	/* Unblock all USB pipes */
+	usb_clear_halt(d->udev,
+		usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
+
+
+	/* Reset the tuner */
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
+		err("clear tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
+		err("set tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+
+	/* Attach frontend */
+	adap->fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg,
+		&d->i2c_adap);
+	if (adap->fe == NULL)
+		return -EIO;
+
+	return 0;
+}
+
 /*
  * DViCO has shipped two devices with the same USB ID, but only one of them
  * needs a firmware download.  Check the device class details to see if they
@@ -1240,6 +1304,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
 static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
 static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
+static struct dvb_usb_device_properties cxusb_mygica_d689_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
@@ -1268,6 +1333,8 @@ static int cxusb_probe(struct usb_interface *intf,
 				     THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
 				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
 	    0)
 		return 0;
 
@@ -1294,6 +1361,7 @@ static struct usb_device_id cxusb_table [] = {
 	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
 	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
+	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
 	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1837,6 +1905,55 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
 	}
 };
 
+static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
+			.frontend_attach  = cxusb_mygica_d689_frontend_attach,
+			.tuner_attach     = cxusb_mygica_d689_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = d680_dmb_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(d680_dmb_rc_keys),
+	.rc_query         = cxusb_d680_dmb_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			"Mygica D689 DMB-TH",
+			{ NULL },
+			{ &cxusb_table[19], NULL },
+		},
+	}
+};
+
 static struct usb_driver cxusb_driver = {
 	.name		= "dvb_usb_cxusb",
 	.probe		= cxusb_probe,
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 6bd8951ea02b..684146f98eb7 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -558,8 +558,7 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
 struct dib0700_rc_response {
 	u8 report_id;
 	u8 data_state;
-	u8 system_msb;
-	u8 system_lsb;
+	u16 system;
 	u8 data;
 	u8 not_data;
 };
@@ -589,37 +588,50 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
 		return 0;
 	}
 
-	if (actlen != sizeof(buf)) {
-		/* We didn't get back the 6 byte message we expected */
-		err("Unexpected RC response size [%d]", actlen);
-		return -1;
-	}
 
-	poll_reply.report_id  = buf[0];
-	poll_reply.data_state = buf[1];
-	poll_reply.system_msb = buf[2];
-	poll_reply.system_lsb = buf[3];
-	poll_reply.data       = buf[4];
-	poll_reply.not_data   = buf[5];
+	switch (dvb_usb_dib0700_ir_proto) {
+	case 0:
+		poll_reply.report_id  = 0;
+		poll_reply.data_state = 1;
+		poll_reply.system     = buf[2];
+		poll_reply.data       = buf[4];
+		poll_reply.not_data   = buf[5];
+
+		/* NEC protocol sends repeat code as 0 0 0 FF */
+		if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
+		    && (poll_reply.not_data == 0xff)) {
+			poll_reply.data_state = 2;
+			break;
+		}
+		break;
+	default:
+		if (actlen != sizeof(buf)) {
+			/* We didn't get back the 6 byte message we expected */
+			err("Unexpected RC response size [%d]", actlen);
+			return -1;
+		}
+
+		poll_reply.report_id  = buf[0];
+		poll_reply.data_state = buf[1];
+		poll_reply.system     = (buf[2] << 8) | buf[3];
+		poll_reply.data       = buf[4];
+		poll_reply.not_data   = buf[5];
 
-	/*
-	info("rid=%02x ds=%02x sm=%02x sl=%02x d=%02x nd=%02x\n",
-	     poll_reply.report_id, poll_reply.data_state,
-	     poll_reply.system_msb, poll_reply.system_lsb,
-	     poll_reply.data, poll_reply.not_data);
-	*/
+		break;
+	}
 
 	if ((poll_reply.data + poll_reply.not_data) != 0xff) {
 		/* Key failed integrity check */
-		err("key failed integrity check: %02x %02x %02x %02x",
-		    poll_reply.system_msb, poll_reply.system_lsb,
+		err("key failed integrity check: %04x %02x %02x",
+		    poll_reply.system,
 		    poll_reply.data, poll_reply.not_data);
 		return -1;
 	}
 
+
 	/* Find the key in the map */
 	for (i = 0; i < d->props.rc_key_map_size; i++) {
-		if (rc5_custom(&keymap[i]) == poll_reply.system_lsb &&
+		if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
 		    rc5_data(&keymap[i]) == poll_reply.data) {
 			*event = keymap[i].event;
 			found = 1;
@@ -628,8 +640,8 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
 	}
 
 	if (found == 0) {
-		err("Unknown remote controller key: %02x %02x %02x %02x",
-		    poll_reply.system_msb, poll_reply.system_lsb,
+		err("Unknown remote controller key: %04x %02x %02x",
+		    poll_reply.system,
 		    poll_reply.data, poll_reply.not_data);
 		d->last_event = 0;
 		return 0;
@@ -874,6 +886,49 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
 	{ 0x1d37, KEY_RECORD },
 	{ 0x1d3b, KEY_GOTO },
 	{ 0x1d3d, KEY_POWER },
+
+	/* Key codes for the Pixelview SBTVD remote (proto NEC) */
+	{ 0x8613, KEY_MUTE },
+	{ 0x8612, KEY_POWER },
+	{ 0x8601, KEY_1 },
+	{ 0x8602, KEY_2 },
+	{ 0x8603, KEY_3 },
+	{ 0x8604, KEY_4 },
+	{ 0x8605, KEY_5 },
+	{ 0x8606, KEY_6 },
+	{ 0x8607, KEY_7 },
+	{ 0x8608, KEY_8 },
+	{ 0x8609, KEY_9 },
+	{ 0x8600, KEY_0 },
+	{ 0x860d, KEY_CHANNELUP },
+	{ 0x8619, KEY_CHANNELDOWN },
+	{ 0x8610, KEY_VOLUMEUP },
+	{ 0x860c, KEY_VOLUMEDOWN },
+
+	{ 0x860a, KEY_CAMERA },
+	{ 0x860b, KEY_ZOOM },
+	{ 0x861b, KEY_BACKSPACE },
+	{ 0x8615, KEY_ENTER },
+
+	{ 0x861d, KEY_UP },
+	{ 0x861e, KEY_DOWN },
+	{ 0x860e, KEY_LEFT },
+	{ 0x860f, KEY_RIGHT },
+
+	{ 0x8618, KEY_RECORD },
+	{ 0x861a, KEY_STOP },
+
+	/* Key codes for the EvolutePC TVWay+ remote (proto NEC) */
+	{ 0x7a00, KEY_MENU },
+	{ 0x7a01, KEY_RECORD },
+	{ 0x7a02, KEY_PLAY },
+	{ 0x7a03, KEY_STOP },
+	{ 0x7a10, KEY_CHANNELUP },
+	{ 0x7a11, KEY_CHANNELDOWN },
+	{ 0x7a12, KEY_VOLUMEUP },
+	{ 0x7a13, KEY_VOLUMEDOWN },
+	{ 0x7a40, KEY_POWER },
+	{ 0x7a41, KEY_MUTE },
 };
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
@@ -1133,6 +1188,7 @@ static struct dib0070_config dib7770p_dib0070_config = {
 	 .clock_khz = 12000,
 	 .clock_pad_drive = 0,
 	 .flip_chip = 1,
+	 .charge_pump = 2,
 };
 
 static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
@@ -1209,6 +1265,16 @@ static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
 	return 0;
 }
 
+static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
+{
+    return dib7000p_pid_filter(adapter->fe, index, pid, onoff);
+}
+
+static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
+{
+    return dib7000p_pid_filter_ctrl(adapter->fe, onoff);
+}
+
 static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
 	60000, 15000, // internal, sampling
 	1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
@@ -1500,6 +1566,15 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
 	return 0;
 }
 
+static int stk807x_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
+{
+    return dib8000_pid_filter(adapter->fe, index, pid, onoff);
+}
+
+static int stk807x_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
+{
+    return dib8000_pid_filter_ctrl(adapter->fe, onoff);
+}
 
 /* STK807x */
 static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
@@ -1861,6 +1936,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
 	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK807XPVR) },
 	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK807XP) },
 	{ USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) },
+	{ USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) },
 	{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1895,6 +1971,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 1,
 		.adapter = {
 			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7700p_frontend_attach,
 				.tuner_attach     = stk7700p_tuner_attach,
 
@@ -1976,11 +2056,19 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 2,
 		.adapter = {
 			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7700d_frontend_attach,
 				.tuner_attach     = stk7700d_tuner_attach,
 
 				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
 			}, {
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7700d_frontend_attach,
 				.tuner_attach     = stk7700d_tuner_attach,
 
@@ -2023,6 +2111,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 1,
 		.adapter = {
 			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7700P2_frontend_attach,
 				.tuner_attach     = stk7700d_tuner_attach,
 
@@ -2055,6 +2147,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 1,
 		.adapter = {
 			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7070p_frontend_attach,
 				.tuner_attach     = dib7070p_tuner_attach,
 
@@ -2122,6 +2218,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 1,
 		.adapter = {
 			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7070p_frontend_attach,
 				.tuner_attach     = dib7070p_tuner_attach,
 
@@ -2157,6 +2257,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 2,
 		.adapter = {
 			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7070pd_frontend_attach0,
 				.tuner_attach     = dib7070p_tuner_attach,
 
@@ -2164,6 +2268,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 
 				.size_of_priv     = sizeof(struct dib0700_adapter_state),
 			}, {
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7070pd_frontend_attach1,
 				.tuner_attach     = dib7070p_tuner_attach,
 
@@ -2210,6 +2318,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 1,
 		.adapter = {
 			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7700ph_frontend_attach,
 				.tuner_attach     = stk7700ph_tuner_attach,
 
@@ -2322,6 +2434,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 1,
 		.adapter = {
 			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
 				.frontend_attach  = stk7070p_frontend_attach,
 				.tuner_attach     = dib7770p_tuner_attach,
 
@@ -2353,6 +2469,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 1,
 		.adapter = {
 			{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk807x_pid_filter,
+				.pid_filter_ctrl = stk807x_pid_filter_ctrl,
 				.frontend_attach  = stk807x_frontend_attach,
 				.tuner_attach     = dib807x_tuner_attach,
 
@@ -2363,7 +2483,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			},
 		},
 
-		.num_device_descs = 2,
+		.num_device_descs = 3,
 		.devices = {
 			{   "DiBcom STK807xP reference design",
 				{ &dib0700_usb_id_table[62], NULL },
@@ -2373,6 +2493,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ &dib0700_usb_id_table[63], NULL },
 				{ NULL },
 			},
+			{   "EvolutePC TVWay+",
+				{ &dib0700_usb_id_table[64], NULL },
+				{ NULL },
+			},
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
@@ -2384,6 +2508,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 2,
 		.adapter = {
 			{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk807x_pid_filter,
+				.pid_filter_ctrl = stk807x_pid_filter_ctrl,
 				.frontend_attach  = stk807xpvr_frontend_attach0,
 				.tuner_attach     = dib807x_tuner_attach,
 
@@ -2393,6 +2521,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 					sizeof(struct dib0700_adapter_state),
 			},
 			{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk807x_pid_filter,
+				.pid_filter_ctrl = stk807x_pid_filter_ctrl,
 				.frontend_attach  = stk807xpvr_frontend_attach1,
 				.tuner_attach     = dib807x_tuner_attach,
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index 8a7d87bcd1d9..df1ec3e69f4a 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -88,6 +88,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
 		goto err;
 	}
 	adap->dvb_adap.priv = adap;
+	adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override;
 
 	if (adap->dev->props.read_mac_address) {
 		if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index a548c14c1944..f1602d4ace6d 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -27,6 +27,7 @@
 #define USB_VID_DIBCOM				0x10b8
 #define USB_VID_DPOSH				0x1498
 #define USB_VID_DVICO				0x0fe9
+#define USB_VID_E3C				0x18b4
 #define USB_VID_ELGATO				0x0fd9
 #define USB_VID_EMPIA				0xeb1a
 #define USB_VID_GENPIX				0x09c0
@@ -61,6 +62,7 @@
 #define USB_VID_XTENSIONS			0x1ae7
 #define USB_VID_HUMAX_COEX			0x10b9
 #define USB_VID_774				0x7a69
+#define USB_VID_EVOLUTEPC			0x1e59
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
@@ -103,6 +105,11 @@
 #define USB_PID_DIBCOM_STK7770P				0x1e80
 #define USB_PID_DPOSH_M9206_COLD			0x9206
 #define USB_PID_DPOSH_M9206_WARM			0xa090
+#define USB_PID_E3C_EC168				0x1689
+#define USB_PID_E3C_EC168_2				0xfffa
+#define USB_PID_E3C_EC168_3				0xfffb
+#define USB_PID_E3C_EC168_4				0x1001
+#define USB_PID_E3C_EC168_5				0x1002
 #define USB_PID_UNIWILL_STK7700P			0x6003
 #define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
@@ -115,6 +122,7 @@
 #define USB_PID_KWORLD_395U_3				0xe395
 #define USB_PID_KWORLD_MC810				0xc810
 #define USB_PID_KWORLD_PC160_2T				0xc160
+#define USB_PID_KWORLD_PC160_T				0xc161
 #define USB_PID_KWORLD_VSTREAM_COLD			0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM			0x17df
 #define USB_PID_TERRATEC_CINERGY_T_USB_XE		0x0055
@@ -271,10 +279,13 @@
 #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_MYGICA_D689				0xd811
 #define USB_PID_ELGATO_EYETV_DTT			0x0021
 #define USB_PID_ELGATO_EYETV_DTT_Dlx			0x0020
 #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD		0x5000
 #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM		0x5001
 #define USB_PID_FRIIO_WHITE				0x0001
+#define USB_PID_TVWAY_PLUS				0x0002
+#define USB_PID_SVEON_STV20				0xe39d
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index fe2b87efb3f1..0143aef19ecd 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -162,6 +162,9 @@ struct dvb_usb_adapter_properties {
 	struct usb_data_stream_properties stream;
 
 	int size_of_priv;
+
+	int (*fe_ioctl_override) (struct dvb_frontend *,
+				  unsigned int, void *, unsigned int);
 };
 
 /**
diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c
new file mode 100644
index 000000000000..52f5d4f0f230
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/ec168.c
@@ -0,0 +1,440 @@
+/*
+ * E3C EC168 DVB USB driver
+ *
+ * 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 "ec168.h"
+#include "ec100.h"
+#include "mxl5005s.h"
+
+/* debug */
+static int dvb_usb_ec168_debug;
+module_param_named(debug, dvb_usb_ec168_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static struct ec100_config ec168_ec100_config;
+
+static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
+{
+	int ret;
+	unsigned int pipe;
+	u8 request, requesttype;
+	u8 buf[req->size];
+
+	switch (req->cmd) {
+	case DOWNLOAD_FIRMWARE:
+	case GPIO:
+	case WRITE_I2C:
+	case STREAMING_CTRL:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		request = req->cmd;
+		break;
+	case READ_I2C:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		request = req->cmd;
+		break;
+	case GET_CONFIG:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		request = CONFIG;
+		break;
+	case SET_CONFIG:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		request = CONFIG;
+		break;
+	case WRITE_DEMOD:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		request = DEMOD_RW;
+		break;
+	case READ_DEMOD:
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		request = DEMOD_RW;
+		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->size);
+		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, req->value,
+		req->index, buf, sizeof(buf), EC168_USB_TIMEOUT);
+
+	ec168_debug_dump(request, requesttype, req->value, req->index, buf,
+		req->size, deb_xfer);
+
+	if (ret < 0)
+		goto error;
+	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->size);
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)
+{
+	return ec168_rw_udev(d->udev, req);
+}
+
+/* I2C */
+static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+	int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct ec168_req req;
+	int i = 0;
+	int ret;
+
+	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 == ec168_ec100_config.demod_address) {
+				req.cmd = READ_DEMOD;
+				req.value = 0;
+				req.index = 0xff00 + msg[i].buf[0]; /* reg */
+				req.size = msg[i+1].len; /* bytes to read */
+				req.data = &msg[i+1].buf[0];
+				ret = ec168_ctrl_msg(d, &req);
+				i += 2;
+			} else {
+				err("I2C read not implemented");
+				ret = -ENOSYS;
+				i += 2;
+			}
+		} else {
+			if (msg[i].addr == ec168_ec100_config.demod_address) {
+				req.cmd = WRITE_DEMOD;
+				req.value = msg[i].buf[1]; /* val */
+				req.index = 0xff00 + msg[i].buf[0]; /* reg */
+				req.size = 0;
+				req.data = NULL;
+				ret = ec168_ctrl_msg(d, &req);
+				i += 1;
+			} else {
+				req.cmd = WRITE_I2C;
+				req.value = msg[i].buf[0]; /* val */
+				req.index = 0x0100 + msg[i].addr; /* I2C addr */
+				req.size = msg[i].len-1;
+				req.data = &msg[i].buf[1];
+				ret = ec168_ctrl_msg(d, &req);
+				i += 1;
+			}
+		}
+		if (ret)
+			goto error;
+
+	}
+	ret = i;
+
+error:
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+
+static u32 ec168_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ec168_i2c_algo = {
+	.master_xfer   = ec168_i2c_xfer,
+	.functionality = ec168_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static struct ec100_config ec168_ec100_config = {
+	.demod_address = 0xff, /* not real address, demod is integrated */
+};
+
+static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	deb_info("%s:\n", __func__);
+	adap->fe = dvb_attach(ec100_attach, &ec168_ec100_config,
+		&adap->dev->i2c_adap);
+	if (adap->fe == NULL)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct mxl5005s_config ec168_mxl5003s_config = {
+	.i2c_address     = 0xc6,
+	.if_freq         = IF_FREQ_4570000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_OFF,
+	.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 ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	deb_info("%s:\n", __func__);
+	return dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
+		&ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
+}
+
+static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};
+	deb_info("%s: onoff:%d\n", __func__, onoff);
+	if (onoff)
+		req.index = 0x0102;
+	return ec168_ctrl_msg(adap->dev, &req);
+}
+
+static int ec168_download_firmware(struct usb_device *udev,
+	const struct firmware *fw)
+{
+	int i, len, packets, remainder, ret;
+	u16 addr = 0x0000; /* firmware start address */
+	struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL};
+	deb_info("%s:\n", __func__);
+
+	#define FW_PACKET_MAX_DATA  2048
+	packets = fw->size / FW_PACKET_MAX_DATA;
+	remainder = fw->size % FW_PACKET_MAX_DATA;
+	len = FW_PACKET_MAX_DATA;
+	for (i = 0; i <= packets; i++) {
+		if (i == packets)  /* set size of the last packet */
+			len = remainder;
+
+		req.size = len;
+		req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
+		req.index = addr;
+		addr += FW_PACKET_MAX_DATA;
+
+		ret = ec168_rw_udev(udev, &req);
+		if (ret) {
+			err("firmware download failed:%d packet:%d", ret, i);
+			goto error;
+		}
+	}
+	req.size = 0;
+
+	/* set "warm"? */
+	req.cmd = SET_CONFIG;
+	req.value = 0;
+	req.index = 0x0001;
+	ret = ec168_rw_udev(udev, &req);
+	if (ret)
+		goto error;
+
+	/* really needed - no idea what does */
+	req.cmd = GPIO;
+	req.value = 0;
+	req.index = 0x0206;
+	ret = ec168_rw_udev(udev, &req);
+	if (ret)
+		goto error;
+
+	/* activate tuner I2C? */
+	req.cmd = WRITE_I2C;
+	req.value = 0;
+	req.index = 0x00c6;
+	ret = ec168_rw_udev(udev, &req);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec168_identify_state(struct usb_device *udev,
+	struct dvb_usb_device_properties *props,
+	struct dvb_usb_device_description **desc, int *cold)
+{
+	int ret;
+	u8 reply;
+	struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};
+	deb_info("%s:\n", __func__);
+
+	ret = ec168_rw_udev(udev, &req);
+	if (ret)
+		goto error;
+
+	deb_info("%s: reply:%02x\n", __func__, reply);
+
+	if (reply == 0x01)
+		*cold = 0;
+	else
+		*cold = 1;
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties ec168_properties;
+
+static int ec168_probe(struct usb_interface *intf,
+	const struct usb_device_id *id)
+{
+	int ret;
+	deb_info("%s: interface:%d\n", __func__,
+		intf->cur_altsetting->desc.bInterfaceNumber);
+
+	ret = dvb_usb_device_init(intf, &ec168_properties, THIS_MODULE, NULL,
+		adapter_nr);
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+#define E3C_EC168_1689                          0
+#define E3C_EC168_FFFA                          1
+#define E3C_EC168_FFFB                          2
+#define E3C_EC168_1001                          3
+#define E3C_EC168_1002                          4
+
+static struct usb_device_id ec168_id[] = {
+	[E3C_EC168_1689] =
+		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168)},
+	[E3C_EC168_FFFA] =
+		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2)},
+	[E3C_EC168_FFFB] =
+		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3)},
+	[E3C_EC168_1001] =
+		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4)},
+	[E3C_EC168_1002] =
+		{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5)},
+	{} /* terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ec168_id);
+
+static struct dvb_usb_device_properties ec168_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.download_firmware = ec168_download_firmware,
+	.firmware = "dvb-usb-ec168.fw",
+	.no_reconnect = 1,
+
+	.size_of_priv = 0,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = ec168_streaming_ctrl,
+			.frontend_attach  = ec168_ec100_frontend_attach,
+			.tuner_attach     = ec168_mxl5003s_tuner_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 6,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = (32*512),
+					}
+				}
+			},
+		}
+	},
+
+	.identify_state = ec168_identify_state,
+
+	.i2c_algo = &ec168_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			.name = "E3C EC168 DVB-T USB2.0 reference design",
+			.cold_ids = {
+				&ec168_id[E3C_EC168_1689],
+				&ec168_id[E3C_EC168_FFFA],
+				&ec168_id[E3C_EC168_FFFB],
+				&ec168_id[E3C_EC168_1001],
+				&ec168_id[E3C_EC168_1002],
+				NULL},
+			.warm_ids = {NULL},
+		},
+	}
+};
+
+static struct usb_driver ec168_driver = {
+	.name       = "dvb_usb_ec168",
+	.probe      = ec168_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table   = ec168_id,
+};
+
+/* module stuff */
+static int __init ec168_module_init(void)
+{
+	int ret;
+	deb_info("%s:\n", __func__);
+	ret = usb_register(&ec168_driver);
+	if (ret)
+		err("module init failed:%d", ret);
+
+	return ret;
+}
+
+static void __exit ec168_module_exit(void)
+{
+	deb_info("%s:\n", __func__);
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&ec168_driver);
+}
+
+module_init(ec168_module_init);
+module_exit(ec168_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("E3C EC168 DVB-T USB2.0 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ec168.h b/drivers/media/dvb/dvb-usb/ec168.h
new file mode 100644
index 000000000000..e7e0b831314e
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/ec168.h
@@ -0,0 +1,73 @@
+/*
+ * E3C EC168 DVB USB driver
+ *
+ * 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 EC168_H
+#define EC168_H
+
+#define DVB_USB_LOG_PREFIX "ec168"
+#include "dvb-usb.h"
+
+#define deb_info(args...) dprintk(dvb_usb_ec168_debug, 0x01, args)
+#define deb_rc(args...)   dprintk(dvb_usb_ec168_debug, 0x02, args)
+#define deb_xfer(args...) dprintk(dvb_usb_ec168_debug, 0x04, args)
+#define deb_reg(args...)  dprintk(dvb_usb_ec168_debug, 0x08, args)
+#define deb_i2c(args...)  dprintk(dvb_usb_ec168_debug, 0x10, args)
+#define deb_fw(args...)   dprintk(dvb_usb_ec168_debug, 0x20, args)
+
+#define ec168_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 EC168_USB_TIMEOUT 1000
+
+struct ec168_req {
+	u8  cmd;       /* [1] */
+	u16 value;     /* [2|3] */
+	u16 index;     /* [4|5] */
+	u16 size;      /* [6|7] */
+	u8  *data;
+};
+
+enum ec168_cmd {
+	DOWNLOAD_FIRMWARE    = 0x00,
+	CONFIG               = 0x01,
+	DEMOD_RW             = 0x03,
+	GPIO                 = 0x04,
+	STREAMING_CTRL       = 0x10,
+	READ_I2C             = 0x20,
+	WRITE_I2C            = 0x21,
+	HID_DOWNLOAD         = 0x30,
+	GET_CONFIG,
+	SET_CONFIG,
+	READ_DEMOD,
+	WRITE_DEMOD,
+};
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c
index c4dfe25cf60d..9cbbe42ca44b 100644
--- a/drivers/media/dvb/dvb-usb/friio-fe.c
+++ b/drivers/media/dvb/dvb-usb/friio-fe.c
@@ -232,12 +232,6 @@ static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state)
 	return 0;
 }
 
-static int jdvbt90502_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-	*ber = 0;
-	return 0;
-}
-
 static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
 					   u16 *strength)
 {
@@ -264,26 +258,26 @@ static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
 	return 0;
 }
 
-static int jdvbt90502_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-	*snr = 0x0101;
-	return 0;
-}
-
-static int jdvbt90502_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-	*ucblocks = 0;
-	return 0;
-}
 
-static int jdvbt90502_get_tune_settings(struct dvb_frontend *fe,
-					struct dvb_frontend_tune_settings *fs)
+/* filter out un-supported properties to notify users */
+static int jdvbt90502_set_property(struct dvb_frontend *fe,
+				   struct dtv_property *tvp)
 {
-	fs->min_delay_ms = 500;
-	fs->step_size = 0;
-	fs->max_drift = 0;
-
-	return 0;
+	int r = 0;
+
+	switch (tvp->cmd) {
+	case DTV_DELIVERY_SYSTEM:
+		if (tvp->u.data != SYS_ISDBT)
+			r = -EINVAL;
+		break;
+	case DTV_CLEAR:
+	case DTV_TUNE:
+	case DTV_FREQUENCY:
+		break;
+	default:
+		r = -EINVAL;
+	}
+	return r;
 }
 
 static int jdvbt90502_get_frontend(struct dvb_frontend *fe,
@@ -314,6 +308,9 @@ static int jdvbt90502_set_frontend(struct dvb_frontend *fe,
 
 	deb_fe("%s: Freq:%d\n", __func__, p->frequency);
 
+	/* for recovery from DTV_CLEAN */
+	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
 	ret = jdvbt90502_pll_set_freq(state, p->frequency);
 	if (ret) {
 		deb_fe("%s:ret == %d\n", __func__, ret);
@@ -323,12 +320,6 @@ static int jdvbt90502_set_frontend(struct dvb_frontend *fe,
 	return 0;
 }
 
-static int jdvbt90502_sleep(struct dvb_frontend *fe)
-{
-	deb_fe("%s called.\n", __func__);
-	return 0;
-}
-
 
 /**
  * (reg, val) commad list to initialize this module.
@@ -394,6 +385,7 @@ static int jdvbt90502_init(struct dvb_frontend *fe)
 		if (ret != 1)
 			goto error;
 	}
+	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
 	msleep(100);
 
 	return 0;
@@ -468,16 +460,13 @@ static struct dvb_frontend_ops jdvbt90502_ops = {
 	.release = jdvbt90502_release,
 
 	.init = jdvbt90502_init,
-	.sleep = jdvbt90502_sleep,
 	.write = _jdvbt90502_write,
 
+	.set_property = jdvbt90502_set_property,
+
 	.set_frontend = jdvbt90502_set_frontend,
 	.get_frontend = jdvbt90502_get_frontend,
-	.get_tune_settings = jdvbt90502_get_tune_settings,
 
 	.read_status = jdvbt90502_read_status,
-	.read_ber = jdvbt90502_read_ber,
 	.read_signal_strength = jdvbt90502_read_signal_strength,
-	.read_snr = jdvbt90502_read_snr,
-	.read_ucblocks = jdvbt90502_read_ucblocks,
 };
diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/dvb/firewire/Kconfig
index 69028253e984..4afa29256df1 100644
--- a/drivers/media/dvb/firewire/Kconfig
+++ b/drivers/media/dvb/firewire/Kconfig
@@ -1,6 +1,6 @@
 config DVB_FIREDTV
 	tristate "FireDTV and FloppyDTV"
-	depends on DVB_CORE && IEEE1394
+	depends on DVB_CORE && (FIREWIRE || IEEE1394)
 	help
 	  Support for DVB receivers from Digital Everywhere
 	  which are connected via IEEE 1394 (FireWire).
@@ -13,8 +13,11 @@ config DVB_FIREDTV
 
 if DVB_FIREDTV
 
+config DVB_FIREDTV_FIREWIRE
+	def_bool FIREWIRE = y || (FIREWIRE = m && DVB_FIREDTV = m)
+
 config DVB_FIREDTV_IEEE1394
-	def_bool IEEE1394
+	def_bool IEEE1394 = y || (IEEE1394 = m && DVB_FIREDTV = m)
 
 config DVB_FIREDTV_INPUT
 	def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile
index 2034695ba194..da84203d51c6 100644
--- a/drivers/media/dvb/firewire/Makefile
+++ b/drivers/media/dvb/firewire/Makefile
@@ -1,6 +1,7 @@
 obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
 
 firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o
+firedtv-$(CONFIG_DVB_FIREDTV_FIREWIRE) += firedtv-fw.o
 firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o
 firedtv-$(CONFIG_DVB_FIREDTV_INPUT)    += firedtv-rc.o
 
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c
index 2b6eeeab5b25..7c5459c27b75 100644
--- a/drivers/media/dvb/firewire/firedtv-1394.c
+++ b/drivers/media/dvb/firewire/firedtv-1394.c
@@ -1,5 +1,5 @@
 /*
- * FireDTV driver (formerly known as FireSAT)
+ * FireDTV driver -- ieee1394 I/O backend
  *
  * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
  * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com>
@@ -26,13 +26,16 @@
 #include <iso.h>
 #include <nodemgr.h>
 
+#include <dvb_demux.h>
+
 #include "firedtv.h"
 
 static LIST_HEAD(node_list);
 static DEFINE_SPINLOCK(node_list_lock);
 
-#define FIREWIRE_HEADER_SIZE	4
-#define CIP_HEADER_SIZE		8
+#define CIP_HEADER_SIZE			8
+#define MPEG2_TS_HEADER_SIZE		4
+#define MPEG2_TS_SOURCE_PACKET_SIZE	(4 + 188)
 
 static void rawiso_activity_cb(struct hpsb_iso *iso)
 {
@@ -62,20 +65,20 @@ static void rawiso_activity_cb(struct hpsb_iso *iso)
 		buf = dma_region_i(&iso->data_buf, unsigned char,
 			iso->infos[packet].offset + CIP_HEADER_SIZE);
 		count = (iso->infos[packet].len - CIP_HEADER_SIZE) /
-			(188 + FIREWIRE_HEADER_SIZE);
+			MPEG2_TS_SOURCE_PACKET_SIZE;
 
 		/* ignore empty packet */
 		if (iso->infos[packet].len <= CIP_HEADER_SIZE)
 			continue;
 
 		while (count--) {
-			if (buf[FIREWIRE_HEADER_SIZE] == 0x47)
+			if (buf[MPEG2_TS_HEADER_SIZE] == 0x47)
 				dvb_dmx_swfilter_packets(&fdtv->demux,
-						&buf[FIREWIRE_HEADER_SIZE], 1);
+						&buf[MPEG2_TS_HEADER_SIZE], 1);
 			else
 				dev_err(fdtv->device,
 					"skipping invalid packet\n");
-			buf += 188 + FIREWIRE_HEADER_SIZE;
+			buf += MPEG2_TS_SOURCE_PACKET_SIZE;
 		}
 	}
 out:
@@ -87,15 +90,20 @@ static inline struct node_entry *node_of(struct firedtv *fdtv)
 	return container_of(fdtv->device, struct unit_directory, device)->ne;
 }
 
-static int node_lock(struct firedtv *fdtv, u64 addr, void *data, __be32 arg)
+static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
 {
-	return hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP, data,
-			      (__force quadlet_t)arg);
+	int ret;
+
+	ret = hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP,
+		(__force quadlet_t *)&data[1], (__force quadlet_t)data[0]);
+	data[0] = data[1];
+
+	return ret;
 }
 
-static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len)
+static int node_read(struct firedtv *fdtv, u64 addr, void *data)
 {
-	return hpsb_node_read(node_of(fdtv), addr, data, len);
+	return hpsb_node_read(node_of(fdtv), addr, data, 4);
 }
 
 static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
@@ -212,6 +220,7 @@ static int node_probe(struct device *dev)
 		goto fail;
 
 	avc_register_remote_control(fdtv);
+
 	return 0;
 fail:
 	spin_lock_irq(&node_list_lock);
@@ -220,6 +229,7 @@ fail:
 	fdtv_unregister_rc(fdtv);
 fail_free:
 	kfree(fdtv);
+
 	return err;
 }
 
@@ -233,10 +243,9 @@ static int node_remove(struct device *dev)
 	list_del(&fdtv->list);
 	spin_unlock_irq(&node_list_lock);
 
-	cancel_work_sync(&fdtv->remote_ctrl_work);
 	fdtv_unregister_rc(fdtv);
-
 	kfree(fdtv);
+
 	return 0;
 }
 
@@ -252,6 +261,7 @@ static int node_update(struct unit_directory *ud)
 
 static struct hpsb_protocol_driver fdtv_driver = {
 	.name		= "firedtv",
+	.id_table	= fdtv_id_table,
 	.update		= node_update,
 	.driver         = {
 		.probe  = node_probe,
@@ -264,12 +274,11 @@ static struct hpsb_highlevel fdtv_highlevel = {
 	.fcp_request	= fcp_request,
 };
 
-int __init fdtv_1394_init(struct ieee1394_device_id id_table[])
+int __init fdtv_1394_init(void)
 {
 	int ret;
 
 	hpsb_register_highlevel(&fdtv_highlevel);
-	fdtv_driver.id_table = id_table;
 	ret = hpsb_register_protocol(&fdtv_driver);
 	if (ret) {
 		printk(KERN_ERR "firedtv: failed to register protocol\n");
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index 485d061319ab..50c42a4b972b 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -1236,14 +1236,14 @@ int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
 
 #define CMP_OUTPUT_PLUG_CONTROL_REG_0	0xfffff0000904ULL
 
-static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len)
+static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
 {
 	int ret;
 
 	if (mutex_lock_interruptible(&fdtv->avc_mutex))
 		return -EINTR;
 
-	ret = fdtv->backend->read(fdtv, addr, buf, len);
+	ret = fdtv->backend->read(fdtv, addr, data);
 	if (ret < 0)
 		dev_err(fdtv->device, "CMP: read I/O error\n");
 
@@ -1251,14 +1251,14 @@ static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len)
 	return ret;
 }
 
-static int cmp_lock(struct firedtv *fdtv, void *data, u64 addr, __be32 arg)
+static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
 {
 	int ret;
 
 	if (mutex_lock_interruptible(&fdtv->avc_mutex))
 		return -EINTR;
 
-	ret = fdtv->backend->lock(fdtv, addr, data, arg);
+	ret = fdtv->backend->lock(fdtv, addr, data);
 	if (ret < 0)
 		dev_err(fdtv->device, "CMP: lock I/O error\n");
 
@@ -1288,25 +1288,25 @@ static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
 
 int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel)
 {
-	__be32 old_opcr, opcr;
+	__be32 old_opcr, opcr[2];
 	u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
 	int attempts = 0;
 	int ret;
 
-	ret = cmp_read(fdtv, &opcr, opcr_address, 4);
+	ret = cmp_read(fdtv, opcr_address, opcr);
 	if (ret < 0)
 		return ret;
 
 repeat:
-	if (!get_opcr_online(opcr)) {
+	if (!get_opcr_online(*opcr)) {
 		dev_err(fdtv->device, "CMP: output offline\n");
 		return -EBUSY;
 	}
 
-	old_opcr = opcr;
+	old_opcr = *opcr;
 
-	if (get_opcr_p2p_connections(opcr)) {
-		if (get_opcr_channel(opcr) != channel) {
+	if (get_opcr_p2p_connections(*opcr)) {
+		if (get_opcr_channel(*opcr) != channel) {
 			dev_err(fdtv->device, "CMP: cannot change channel\n");
 			return -EBUSY;
 		}
@@ -1314,11 +1314,11 @@ repeat:
 
 		/* We don't allocate isochronous resources. */
 	} else {
-		set_opcr_channel(&opcr, channel);
-		set_opcr_data_rate(&opcr, 2); /* S400 */
+		set_opcr_channel(opcr, channel);
+		set_opcr_data_rate(opcr, 2); /* S400 */
 
 		/* FIXME: this is for the worst case - optimize */
-		set_opcr_overhead_id(&opcr, 0);
+		set_opcr_overhead_id(opcr, 0);
 
 		/*
 		 * FIXME: allocate isochronous channel and bandwidth at IRM
@@ -1326,13 +1326,16 @@ repeat:
 		 */
 	}
 
-	set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1);
+	set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1);
 
-	ret = cmp_lock(fdtv, &opcr, opcr_address, old_opcr);
+	opcr[1] = *opcr;
+	opcr[0] = old_opcr;
+
+	ret = cmp_lock(fdtv, opcr_address, opcr);
 	if (ret < 0)
 		return ret;
 
-	if (old_opcr != opcr) {
+	if (old_opcr != *opcr) {
 		/*
 		 * FIXME: if old_opcr.P2P_Connections > 0,
 		 * deallocate isochronous channel and bandwidth at IRM
@@ -1350,27 +1353,30 @@ repeat:
 
 void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel)
 {
-	__be32 old_opcr, opcr;
+	__be32 old_opcr, opcr[2];
 	u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
 	int attempts = 0;
 
-	if (cmp_read(fdtv, &opcr, opcr_address, 4) < 0)
+	if (cmp_read(fdtv, opcr_address, opcr) < 0)
 		return;
 
 repeat:
-	if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) ||
-	    get_opcr_channel(opcr) != channel) {
+	if (!get_opcr_online(*opcr) || !get_opcr_p2p_connections(*opcr) ||
+	    get_opcr_channel(*opcr) != channel) {
 		dev_err(fdtv->device, "CMP: no connection to break\n");
 		return;
 	}
 
-	old_opcr = opcr;
-	set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1);
+	old_opcr = *opcr;
+	set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) - 1);
+
+	opcr[1] = *opcr;
+	opcr[0] = old_opcr;
 
-	if (cmp_lock(fdtv, &opcr, opcr_address, old_opcr) < 0)
+	if (cmp_lock(fdtv, opcr_address, opcr) < 0)
 		return;
 
-	if (old_opcr != opcr) {
+	if (old_opcr != *opcr) {
 		/*
 		 * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
 		 * owner, deallocate isochronous channel and bandwidth at IRM
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
index 5742fde79d99..fc9996c13e13 100644
--- a/drivers/media/dvb/firewire/firedtv-dvb.c
+++ b/drivers/media/dvb/firewire/firedtv-dvb.c
@@ -297,7 +297,7 @@ struct firedtv *fdtv_alloc(struct device *dev,
 #define AVC_UNIT_SPEC_ID_ENTRY	0x00a02d
 #define AVC_SW_VERSION_ENTRY	0x010001
 
-static struct ieee1394_device_id fdtv_id_table[] = {
+const struct ieee1394_device_id fdtv_id_table[] = {
 	{
 		/* FloppyDTV S/CI and FloppyDTV S2 */
 		.match_flags	= MATCH_FLAGS,
@@ -346,12 +346,23 @@ MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
 
 static int __init fdtv_init(void)
 {
-	return fdtv_1394_init(fdtv_id_table);
+	int ret;
+
+	ret = fdtv_fw_init();
+	if (ret < 0)
+		return ret;
+
+	ret = fdtv_1394_init();
+	if (ret < 0)
+		fdtv_fw_exit();
+
+	return ret;
 }
 
 static void __exit fdtv_exit(void)
 {
 	fdtv_1394_exit();
+	fdtv_fw_exit();
 }
 
 module_init(fdtv_init);
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
new file mode 100644
index 000000000000..fe44789ab037
--- /dev/null
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -0,0 +1,376 @@
+/*
+ * FireDTV driver -- firewire I/O backend
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/page.h>
+
+#include <dvb_demux.h>
+
+#include "firedtv.h"
+
+static LIST_HEAD(node_list);
+static DEFINE_SPINLOCK(node_list_lock);
+
+static inline struct fw_device *device_of(struct firedtv *fdtv)
+{
+	return fw_device(fdtv->device->parent);
+}
+
+static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
+		    int tcode)
+{
+	struct fw_device *device = device_of(fdtv);
+	int rcode, generation = device->generation;
+
+	smp_rmb(); /* node_id vs. generation */
+
+	rcode = fw_run_transaction(device->card, tcode, device->node_id,
+			generation, device->max_speed, addr, data, len);
+
+	return rcode != RCODE_COMPLETE ? -EIO : 0;
+}
+
+static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
+{
+	return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
+}
+
+static int node_read(struct firedtv *fdtv, u64 addr, void *data)
+{
+	return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST);
+}
+
+static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
+{
+	return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST);
+}
+
+#define ISO_HEADER_SIZE			4
+#define CIP_HEADER_SIZE			8
+#define MPEG2_TS_HEADER_SIZE		4
+#define MPEG2_TS_SOURCE_PACKET_SIZE	(4 + 188)
+
+#define MAX_PACKET_SIZE		1024  /* 776, rounded up to 2^n */
+#define PACKETS_PER_PAGE	(PAGE_SIZE / MAX_PACKET_SIZE)
+#define N_PACKETS		64    /* buffer size */
+#define N_PAGES			DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE)
+#define IRQ_INTERVAL		16
+
+struct firedtv_receive_context {
+	struct fw_iso_context *context;
+	struct fw_iso_buffer buffer;
+	int interrupt_packet;
+	int current_packet;
+	char *pages[N_PAGES];
+};
+
+static int queue_iso(struct firedtv_receive_context *ctx, int index)
+{
+	struct fw_iso_packet p;
+
+	p.payload_length = MAX_PACKET_SIZE;
+	p.interrupt = !(++ctx->interrupt_packet & (IRQ_INTERVAL - 1));
+	p.skip = 0;
+	p.header_length = ISO_HEADER_SIZE;
+
+	return fw_iso_context_queue(ctx->context, &p, &ctx->buffer,
+				    index * MAX_PACKET_SIZE);
+}
+
+static void handle_iso(struct fw_iso_context *context, u32 cycle,
+		       size_t header_length, void *header, void *data)
+{
+	struct firedtv *fdtv = data;
+	struct firedtv_receive_context *ctx = fdtv->backend_data;
+	__be32 *h, *h_end;
+	int length, err, i = ctx->current_packet;
+	char *p, *p_end;
+
+	for (h = header, h_end = h + header_length / 4; h < h_end; h++) {
+		length = be32_to_cpup(h) >> 16;
+		if (unlikely(length > MAX_PACKET_SIZE)) {
+			dev_err(fdtv->device, "length = %d\n", length);
+			length = MAX_PACKET_SIZE;
+		}
+
+		p = ctx->pages[i / PACKETS_PER_PAGE]
+				+ (i % PACKETS_PER_PAGE) * MAX_PACKET_SIZE;
+		p_end = p + length;
+
+		for (p += CIP_HEADER_SIZE + MPEG2_TS_HEADER_SIZE; p < p_end;
+		     p += MPEG2_TS_SOURCE_PACKET_SIZE)
+			dvb_dmx_swfilter_packets(&fdtv->demux, p, 1);
+
+		err = queue_iso(ctx, i);
+		if (unlikely(err))
+			dev_err(fdtv->device, "requeue failed\n");
+
+		i = (i + 1) & (N_PACKETS - 1);
+	}
+	ctx->current_packet = i;
+}
+
+static int start_iso(struct firedtv *fdtv)
+{
+	struct firedtv_receive_context *ctx;
+	struct fw_device *device = device_of(fdtv);
+	int i, err;
+
+	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->context = fw_iso_context_create(device->card,
+			FW_ISO_CONTEXT_RECEIVE, fdtv->isochannel,
+			device->max_speed, ISO_HEADER_SIZE, handle_iso, fdtv);
+	if (IS_ERR(ctx->context)) {
+		err = PTR_ERR(ctx->context);
+		goto fail_free;
+	}
+
+	err = fw_iso_buffer_init(&ctx->buffer, device->card,
+				 N_PAGES, DMA_FROM_DEVICE);
+	if (err)
+		goto fail_context_destroy;
+
+	ctx->interrupt_packet = 0;
+	ctx->current_packet = 0;
+
+	for (i = 0; i < N_PAGES; i++)
+		ctx->pages[i] = page_address(ctx->buffer.pages[i]);
+
+	for (i = 0; i < N_PACKETS; i++) {
+		err = queue_iso(ctx, i);
+		if (err)
+			goto fail;
+	}
+
+	err = fw_iso_context_start(ctx->context, -1, 0,
+				   FW_ISO_CONTEXT_MATCH_ALL_TAGS);
+	if (err)
+		goto fail;
+
+	fdtv->backend_data = ctx;
+
+	return 0;
+fail:
+	fw_iso_buffer_destroy(&ctx->buffer, device->card);
+fail_context_destroy:
+	fw_iso_context_destroy(ctx->context);
+fail_free:
+	kfree(ctx);
+
+	return err;
+}
+
+static void stop_iso(struct firedtv *fdtv)
+{
+	struct firedtv_receive_context *ctx = fdtv->backend_data;
+
+	fw_iso_context_stop(ctx->context);
+	fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card);
+	fw_iso_context_destroy(ctx->context);
+	kfree(ctx);
+}
+
+static const struct firedtv_backend backend = {
+	.lock		= node_lock,
+	.read		= node_read,
+	.write		= node_write,
+	.start_iso	= start_iso,
+	.stop_iso	= stop_iso,
+};
+
+static void handle_fcp(struct fw_card *card, struct fw_request *request,
+		       int tcode, int destination, int source, int generation,
+		       int speed, unsigned long long offset,
+		       void *payload, size_t length, void *callback_data)
+{
+	struct firedtv *f, *fdtv = NULL;
+	struct fw_device *device;
+	unsigned long flags;
+	int su;
+
+	if ((tcode != TCODE_WRITE_QUADLET_REQUEST &&
+	     tcode != TCODE_WRITE_BLOCK_REQUEST) ||
+	    offset != CSR_REGISTER_BASE + CSR_FCP_RESPONSE ||
+	    length == 0 ||
+	    (((u8 *)payload)[0] & 0xf0) != 0) {
+		fw_send_response(card, request, RCODE_TYPE_ERROR);
+		return;
+	}
+
+	su = ((u8 *)payload)[1] & 0x7;
+
+	spin_lock_irqsave(&node_list_lock, flags);
+	list_for_each_entry(f, &node_list, list) {
+		device = device_of(f);
+		if (device->generation != generation)
+			continue;
+
+		smp_rmb(); /* node_id vs. generation */
+
+		if (device->card == card &&
+		    device->node_id == source &&
+		    (f->subunit == su || (f->subunit == 0 && su == 0x7))) {
+			fdtv = f;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&node_list_lock, flags);
+
+	if (fdtv) {
+		avc_recv(fdtv, payload, length);
+		fw_send_response(card, request, RCODE_COMPLETE);
+	}
+}
+
+static struct fw_address_handler fcp_handler = {
+	.length           = CSR_FCP_END - CSR_FCP_RESPONSE,
+	.address_callback = handle_fcp,
+};
+
+static const struct fw_address_region fcp_region = {
+	.start	= CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
+	.end	= CSR_REGISTER_BASE + CSR_FCP_END,
+};
+
+/* Adjust the template string if models with longer names appear. */
+#define MAX_MODEL_NAME_LEN ((int)DIV_ROUND_UP(sizeof("FireDTV ????"), 4))
+
+static size_t model_name(u32 *directory, __be32 *buffer)
+{
+	struct fw_csr_iterator ci;
+	int i, length, key, value, last_key = 0;
+	u32 *block = NULL;
+
+	fw_csr_iterator_init(&ci, directory);
+	while (fw_csr_iterator_next(&ci, &key, &value)) {
+		if (last_key == CSR_MODEL &&
+		    key == (CSR_DESCRIPTOR | CSR_LEAF))
+			block = ci.p - 1 + value;
+		last_key = key;
+	}
+
+	if (block == NULL)
+		return 0;
+
+	length = min((int)(block[0] >> 16) - 2, MAX_MODEL_NAME_LEN);
+	if (length <= 0)
+		return 0;
+
+	/* fast-forward to text string */
+	block += 3;
+
+	for (i = 0; i < length; i++)
+		buffer[i] = cpu_to_be32(block[i]);
+
+	return length * 4;
+}
+
+static int node_probe(struct device *dev)
+{
+	struct firedtv *fdtv;
+	__be32 name[MAX_MODEL_NAME_LEN];
+	int name_len, err;
+
+	name_len = model_name(fw_unit(dev)->directory, name);
+
+	fdtv = fdtv_alloc(dev, &backend, (char *)name, name_len);
+	if (!fdtv)
+		return -ENOMEM;
+
+	err = fdtv_register_rc(fdtv, dev);
+	if (err)
+		goto fail_free;
+
+	spin_lock_irq(&node_list_lock);
+	list_add_tail(&fdtv->list, &node_list);
+	spin_unlock_irq(&node_list_lock);
+
+	err = avc_identify_subunit(fdtv);
+	if (err)
+		goto fail;
+
+	err = fdtv_dvb_register(fdtv);
+	if (err)
+		goto fail;
+
+	avc_register_remote_control(fdtv);
+
+	return 0;
+fail:
+	spin_lock_irq(&node_list_lock);
+	list_del(&fdtv->list);
+	spin_unlock_irq(&node_list_lock);
+	fdtv_unregister_rc(fdtv);
+fail_free:
+	kfree(fdtv);
+
+	return err;
+}
+
+static int node_remove(struct device *dev)
+{
+	struct firedtv *fdtv = dev_get_drvdata(dev);
+
+	fdtv_dvb_unregister(fdtv);
+
+	spin_lock_irq(&node_list_lock);
+	list_del(&fdtv->list);
+	spin_unlock_irq(&node_list_lock);
+
+	fdtv_unregister_rc(fdtv);
+
+	kfree(fdtv);
+	return 0;
+}
+
+static void node_update(struct fw_unit *unit)
+{
+	struct firedtv *fdtv = dev_get_drvdata(&unit->device);
+
+	if (fdtv->isochannel >= 0)
+		cmp_establish_pp_connection(fdtv, fdtv->subunit,
+					    fdtv->isochannel);
+}
+
+static struct fw_driver fdtv_driver = {
+	.driver   = {
+		.owner  = THIS_MODULE,
+		.name   = "firedtv",
+		.bus    = &fw_bus_type,
+		.probe  = node_probe,
+		.remove = node_remove,
+	},
+	.update   = node_update,
+	.id_table = fdtv_id_table,
+};
+
+int __init fdtv_fw_init(void)
+{
+	int ret;
+
+	ret = fw_core_add_address_handler(&fcp_handler, &fcp_region);
+	if (ret < 0)
+		return ret;
+
+	return driver_register(&fdtv_driver.driver);
+}
+
+void fdtv_fw_exit(void)
+{
+	driver_unregister(&fdtv_driver.driver);
+	fw_core_remove_address_handler(&fcp_handler);
+}
diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c
index 27bca2e283df..599d66e5843d 100644
--- a/drivers/media/dvb/firewire/firedtv-rc.c
+++ b/drivers/media/dvb/firewire/firedtv-rc.c
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 
 #include "firedtv.h"
 
@@ -163,6 +164,7 @@ fail:
 
 void fdtv_unregister_rc(struct firedtv *fdtv)
 {
+	cancel_work_sync(&fdtv->remote_ctrl_work);
 	kfree(fdtv->remote_ctrl_dev->keycode);
 	input_unregister_device(fdtv->remote_ctrl_dev);
 }
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h
index d48530b81e61..35080dbb3c66 100644
--- a/drivers/media/dvb/firewire/firedtv.h
+++ b/drivers/media/dvb/firewire/firedtv.h
@@ -16,6 +16,7 @@
 #include <linux/dvb/dmx.h>
 #include <linux/dvb/frontend.h>
 #include <linux/list.h>
+#include <linux/mod_devicetable.h>
 #include <linux/mutex.h>
 #include <linux/spinlock_types.h>
 #include <linux/types.h>
@@ -72,8 +73,8 @@ struct input_dev;
 struct firedtv;
 
 struct firedtv_backend {
-	int (*lock)(struct firedtv *fdtv, u64 addr, void *data, __be32 arg);
-	int (*read)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
+	int (*lock)(struct firedtv *fdtv, u64 addr, __be32 data[]);
+	int (*read)(struct firedtv *fdtv, u64 addr, void *data);
 	int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
 	int (*start_iso)(struct firedtv *fdtv);
 	void (*stop_iso)(struct firedtv *fdtv);
@@ -119,10 +120,10 @@ struct firedtv {
 
 /* firedtv-1394.c */
 #ifdef CONFIG_DVB_FIREDTV_IEEE1394
-int fdtv_1394_init(struct ieee1394_device_id id_table[]);
+int fdtv_1394_init(void);
 void fdtv_1394_exit(void);
 #else
-static inline int fdtv_1394_init(struct ieee1394_device_id it[]) { return 0; }
+static inline int fdtv_1394_init(void) { return 0; }
 static inline void fdtv_1394_exit(void) {}
 #endif
 
@@ -163,10 +164,20 @@ struct firedtv *fdtv_alloc(struct device *dev,
 			   const struct firedtv_backend *backend,
 			   const char *name, size_t name_len);
 extern const char *fdtv_model_names[];
+extern const struct ieee1394_device_id fdtv_id_table[];
 
 /* firedtv-fe.c */
 void fdtv_frontend_init(struct firedtv *fdtv);
 
+/* firedtv-fw.c */
+#ifdef CONFIG_DVB_FIREDTV_FIREWIRE
+int fdtv_fw_init(void);
+void fdtv_fw_exit(void);
+#else
+static inline int fdtv_fw_init(void) { return 0; }
+static inline void fdtv_fw_exit(void) {}
+#endif
+
 /* firedtv-rc.c */
 #ifdef CONFIG_DVB_FIREDTV_INPUT
 int fdtv_register_rc(struct firedtv *fdtv, struct device *dev);
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index d7c4837fa71c..58aac018f109 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -201,6 +201,13 @@ config DVB_SI21XX
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_DS3000
+	tristate "Montage Tehnology DS3000 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
 comment "DVB-T (terrestrial) frontends"
 	depends on DVB_CORE
 
@@ -342,6 +349,13 @@ config DVB_AF9013
 	help
 	  Say Y when you want to support this frontend.
 
+config DVB_EC100
+	tristate "E3C EC100"
+	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
 
@@ -557,6 +571,13 @@ config DVB_LGS8GXX
 	help
 	  A DMB-TH tuner module. Say Y when you want to support this frontend.
 
+config DVB_ATBM8830
+	tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DMB-TH tuner module. Say Y when you want to support this frontend.
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 3523767e7a76..823482535d11 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
 obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
 obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
+obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
 obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
 obj-$(CONFIG_DVB_AF9013) += af9013.o
 obj-$(CONFIG_DVB_CX24116) += cx24116.o
@@ -76,3 +77,5 @@ obj-$(CONFIG_DVB_STV0900) += stv0900.o
 obj-$(CONFIG_DVB_STV090x) += stv090x.o
 obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
 obj-$(CONFIG_DVB_ISL6423) += isl6423.o
+obj-$(CONFIG_DVB_EC100) += ec100.o
+obj-$(CONFIG_DVB_DS3000) += ds3000.o
diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c
new file mode 100644
index 000000000000..59881a5944eb
--- /dev/null
+++ b/drivers/media/dvb/frontends/atbm8830.c
@@ -0,0 +1,495 @@
+/*
+ *    Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
+ *    ATBM8830, ATBM8831
+ *
+ *    Copyright (C) 2009 David T.L. Wong <davidtlwong@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
+ *    (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 <asm/div64.h>
+#include "dvb_frontend.h"
+
+#include "atbm8830.h"
+#include "atbm8830_priv.h"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "atbm8830: " args); \
+	} while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data)
+{
+	int ret = 0;
+	u8 dev_addr;
+	u8 buf1[] = { reg >> 8, reg & 0xFF };
+	u8 buf2[] = { data };
+	struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
+	struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 };
+
+	dev_addr = priv->config->demod_address;
+	msg1.addr = dev_addr;
+	msg2.addr = dev_addr;
+
+	if (debug >= 2)
+		printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n",
+			__func__, reg, data);
+
+	ret = i2c_transfer(priv->i2c, &msg1, 1);
+	if (ret != 1)
+		return -EIO;
+
+	ret = i2c_transfer(priv->i2c, &msg2, 1);
+	return (ret != 1) ? -EIO : 0;
+}
+
+static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
+{
+	int ret;
+	u8 dev_addr;
+
+	u8 buf1[] = { reg >> 8, reg & 0xFF };
+	u8 buf2[] = { 0 };
+	struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
+	struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 };
+
+	dev_addr = priv->config->demod_address;
+	msg1.addr = dev_addr;
+	msg2.addr = dev_addr;
+
+	ret = i2c_transfer(priv->i2c, &msg1, 1);
+	if (ret != 1) {
+		dprintk(KERN_DEBUG "%s: error reg=0x%04x, ret=%i\n",
+			__func__, reg, ret);
+		return -EIO;
+	}
+
+	ret = i2c_transfer(priv->i2c, &msg2, 1);
+	if (ret != 1)
+		return -EIO;
+
+	*p_data = buf2[0];
+	if (debug >= 2)
+		printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n",
+			__func__, reg, buf2[0]);
+
+	return 0;
+}
+
+/* Lock register latch so that multi-register read is atomic */
+static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock)
+{
+	return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0);
+}
+
+static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
+{
+	u32 val;
+	u64 t;
+
+	/* 0x100000 * freq / 30.4MHz */
+	t = (u64)0x100000 * freq;
+	do_div(t, 30400);
+	val = t;
+
+	atbm8830_write_reg(priv, REG_OSC_CLK, val);
+	atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8);
+	atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16);
+
+	return 0;
+}
+
+static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
+{
+
+	u32 fs = priv->config->osc_clk_freq;
+	u64 t;
+	u32 val;
+	u8 dat;
+
+	if (freq != 0) {
+		/* 2 * PI * (freq - fs) / fs * (2 ^ 22) */
+		t = (u64) 2 * 31416 * (freq - fs);
+		t <<= 22;
+		do_div(t, fs);
+		do_div(t, 1000);
+		val = t;
+
+		atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1);
+		atbm8830_write_reg(priv, REG_IF_FREQ, val);
+		atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8);
+		atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16);
+
+		atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
+		dat &= 0xFC;
+		atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
+	} else {
+		/* Zero IF */
+		atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0);
+
+		atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
+		dat &= 0xFC;
+		dat |= 0x02;
+		atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
+
+		if (priv->config->zif_swap_iq)
+			atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03);
+		else
+			atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01);
+	}
+
+	return 0;
+}
+
+static int is_locked(struct atbm_state *priv, u8 *locked)
+{
+	u8 status;
+
+	atbm8830_read_reg(priv, REG_LOCK_STATUS, &status);
+
+	if (locked != NULL)
+		*locked = (status == 1);
+	return 0;
+}
+
+
+static int set_static_channel_mode(struct atbm_state *priv)
+{
+	int i;
+
+	for (i = 0; i < 5; i++)
+		atbm8830_write_reg(priv, 0x099B + i, 0x08);
+
+	atbm8830_write_reg(priv, 0x095B, 0x7F);
+	atbm8830_write_reg(priv, 0x09CB, 0x01);
+	atbm8830_write_reg(priv, 0x09CC, 0x7F);
+	atbm8830_write_reg(priv, 0x09CD, 0x7F);
+	atbm8830_write_reg(priv, 0x0E01, 0x20);
+
+	/* For single carrier */
+	atbm8830_write_reg(priv, 0x0B03, 0x0A);
+	atbm8830_write_reg(priv, 0x0935, 0x10);
+	atbm8830_write_reg(priv, 0x0936, 0x08);
+	atbm8830_write_reg(priv, 0x093E, 0x08);
+	atbm8830_write_reg(priv, 0x096E, 0x06);
+
+	/* frame_count_max0 */
+	atbm8830_write_reg(priv, 0x0B09, 0x00);
+	/* frame_count_max1 */
+	atbm8830_write_reg(priv, 0x0B0A, 0x08);
+
+	return 0;
+}
+
+static int set_ts_config(struct atbm_state *priv)
+{
+	const struct atbm8830_config *cfg = priv->config;
+
+	/*Set parallel/serial ts mode*/
+	atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0);
+	atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0);
+	/*Set ts sampling edge*/
+	atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE,
+		cfg->ts_sampling_edge ? 1 : 0);
+	/*Set ts clock freerun*/
+	atbm8830_write_reg(priv, REG_TS_CLK_FREERUN,
+		cfg->ts_clk_gated ? 0 : 1);
+
+	return 0;
+}
+
+static int atbm8830_init(struct dvb_frontend *fe)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	const struct atbm8830_config *cfg = priv->config;
+
+	/*Set oscillator frequency*/
+	set_osc_freq(priv, cfg->osc_clk_freq);
+
+	/*Set IF frequency*/
+	set_if_freq(priv, cfg->if_freq);
+
+
+	/*Set static channel mode*/
+	set_static_channel_mode(priv);
+
+	set_ts_config(priv);
+	/*Turn off DSP reset*/
+	atbm8830_write_reg(priv, 0x000A, 0);
+
+	/*SW version test*/
+	atbm8830_write_reg(priv, 0x020C, 11);
+
+	/* Run */
+	atbm8830_write_reg(priv, REG_DEMOD_RUN, 1);
+
+	return 0;
+}
+
+
+static void atbm8830_release(struct dvb_frontend *fe)
+{
+	struct atbm_state *state = fe->demodulator_priv;
+	dprintk("%s\n", __func__);
+
+	kfree(state);
+}
+
+static int atbm8830_set_fe(struct dvb_frontend *fe,
+			  struct dvb_frontend_parameters *fe_params)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	int i;
+	u8 locked = 0;
+	dprintk("%s\n", __func__);
+
+	/* set frequency */
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.set_params(fe, fe_params);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* start auto lock */
+	for (i = 0; i < 10; i++) {
+		mdelay(100);
+		dprintk("Try %d\n", i);
+		is_locked(priv, &locked);
+		if (locked != 0) {
+			dprintk("ATBM8830 locked!\n");
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int atbm8830_get_fe(struct dvb_frontend *fe,
+			  struct dvb_frontend_parameters *fe_params)
+{
+	dprintk("%s\n", __func__);
+
+	/* TODO: get real readings from device */
+	/* inversion status */
+	fe_params->inversion = INVERSION_OFF;
+
+	/* bandwidth */
+	fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+
+	fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
+	fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
+
+	fe_params->u.ofdm.constellation = QAM_AUTO;
+
+	/* transmission mode */
+	fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+
+	/* guard interval */
+	fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+
+	/* hierarchy */
+	fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+
+	return 0;
+}
+
+static int atbm8830_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 0;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	u8 locked = 0;
+	u8 agc_locked = 0;
+
+	dprintk("%s\n", __func__);
+	*fe_status = 0;
+
+	is_locked(priv, &locked);
+	if (locked) {
+		*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	}
+	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
+
+	atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked);
+	dprintk("AGC Lock: %d\n", agc_locked);
+
+	return 0;
+}
+
+static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	u32 frame_err;
+	u8 t;
+
+	dprintk("%s\n", __func__);
+
+	atbm8830_reglatch_lock(priv, 1);
+
+	atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t);
+	frame_err = t & 0x7F;
+	frame_err <<= 8;
+	atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t);
+	frame_err |= t;
+
+	atbm8830_reglatch_lock(priv, 0);
+
+	*ber = frame_err * 100 / 32767;
+
+	dprintk("%s: ber=0x%x\n", __func__, *ber);
+	return 0;
+}
+
+static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+	u32 pwm;
+	u8 t;
+
+	dprintk("%s\n", __func__);
+	atbm8830_reglatch_lock(priv, 1);
+
+	atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t);
+	pwm = t & 0x03;
+	pwm <<= 8;
+	atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t);
+	pwm |= t;
+
+	atbm8830_reglatch_lock(priv, 0);
+
+	dprintk("AGC PWM = 0x%02X\n", pwm);
+	pwm = 0x400 - pwm;
+
+	*signal = pwm * 0x10000 / 0x400;
+
+	return 0;
+}
+
+static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	dprintk("%s\n", __func__);
+	*snr = 0;
+	return 0;
+}
+
+static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	dprintk("%s\n", __func__);
+	*ucblocks = 0;
+	return 0;
+}
+
+static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct atbm_state *priv = fe->demodulator_priv;
+
+	return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0);
+}
+
+static struct dvb_frontend_ops atbm8830_ops = {
+	.info = {
+		.name = "AltoBeam ATBM8830/8831 DMB-TH",
+		.type = FE_OFDM,
+		.frequency_min = 474000000,
+		.frequency_max = 858000000,
+		.frequency_stepsize = 10000,
+		.caps =
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO
+	},
+
+	.release = atbm8830_release,
+
+	.init = atbm8830_init,
+	.sleep = NULL,
+	.write = NULL,
+	.i2c_gate_ctrl = atbm8830_i2c_gate_ctrl,
+
+	.set_frontend = atbm8830_set_fe,
+	.get_frontend = atbm8830_get_fe,
+	.get_tune_settings = atbm8830_get_tune_settings,
+
+	.read_status = atbm8830_read_status,
+	.read_ber = atbm8830_read_ber,
+	.read_signal_strength = atbm8830_read_signal_strength,
+	.read_snr = atbm8830_read_snr,
+	.read_ucblocks = atbm8830_read_ucblocks,
+};
+
+struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
+	struct i2c_adapter *i2c)
+{
+	struct atbm_state *priv = NULL;
+	u8 data = 0;
+
+	dprintk("%s()\n", __func__);
+
+	if (config == NULL || i2c == NULL)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL);
+	if (priv == NULL)
+		goto error_out;
+
+	priv->config = config;
+	priv->i2c = i2c;
+
+	/* check if the demod is there */
+	if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) {
+		dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n",
+			__func__, priv->config->demod_address);
+		goto error_out;
+	}
+	dprintk("atbm8830 chip id: 0x%02X\n", data);
+
+	memcpy(&priv->frontend.ops, &atbm8830_ops,
+	       sizeof(struct dvb_frontend_ops));
+	priv->frontend.demodulator_priv = priv;
+
+	atbm8830_init(&priv->frontend);
+
+	atbm8830_i2c_gate_ctrl(&priv->frontend, 1);
+
+	return &priv->frontend;
+
+error_out:
+	dprintk("%s() error_out\n", __func__);
+	kfree(priv);
+	return NULL;
+
+}
+EXPORT_SYMBOL(atbm8830_attach);
+
+MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver");
+MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/atbm8830.h b/drivers/media/dvb/frontends/atbm8830.h
new file mode 100644
index 000000000000..e8149f393300
--- /dev/null
+++ b/drivers/media/dvb/frontends/atbm8830.h
@@ -0,0 +1,76 @@
+/*
+ *    Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
+ *    ATBM8830, ATBM8831
+ *
+ *    Copyright (C) 2009 David T.L. Wong <davidtlwong@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
+ *    (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 __ATBM8830_H__
+#define __ATBM8830_H__
+
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#define ATBM8830_PROD_8830 0
+#define ATBM8830_PROD_8831 1
+
+struct atbm8830_config {
+
+	/* product type */
+	u8 prod;
+
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* parallel or serial transport stream */
+	u8 serial_ts;
+
+	/* transport stream clock output only when receving valid stream */
+	u8 ts_clk_gated;
+
+	/* Decoder sample TS data at rising edge of clock */
+	u8 ts_sampling_edge;
+
+	/* Oscillator clock frequency */
+	u32 osc_clk_freq; /* in kHz */
+
+	/* IF frequency */
+	u32 if_freq; /* in kHz */
+
+	/* Swap I/Q for zero IF */
+	u8 zif_swap_iq;
+
+	/* Tuner AGC settings */
+	u8 agc_min;
+	u8 agc_max;
+	u8 agc_hold_loop;
+};
+
+#if defined(CONFIG_DVB_ATBM8830) || \
+	(defined(CONFIG_DVB_ATBM8830_MODULE) && defined(MODULE))
+extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
+		struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
+		struct i2c_adapter *i2c) {
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_ATBM8830 */
+
+#endif /* __ATBM8830_H__ */
diff --git a/drivers/media/dvb/frontends/atbm8830_priv.h b/drivers/media/dvb/frontends/atbm8830_priv.h
new file mode 100644
index 000000000000..ce960f76092a
--- /dev/null
+++ b/drivers/media/dvb/frontends/atbm8830_priv.h
@@ -0,0 +1,75 @@
+/*
+ *    Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
+ *    ATBM8830, ATBM8831
+ *
+ *    Copyright (C) 2009 David T.L. Wong <davidtlwong@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
+ *    (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 __ATBM8830_PRIV_H
+#define __ATBM8830_PRIV_H
+
+struct atbm_state {
+	struct i2c_adapter *i2c;
+	/* configuration settings */
+	const struct atbm8830_config *config;
+	struct dvb_frontend frontend;
+};
+
+#define REG_CHIP_ID	0x0000
+#define REG_TUNER_BASEBAND	0x0001
+#define REG_DEMOD_RUN	0x0004
+#define REG_DSP_RESET	0x0005
+#define REG_RAM_RESET	0x0006
+#define REG_ADC_RESET	0x0007
+#define REG_TSPORT_RESET	0x0008
+#define REG_BLKERR_POL	0x000C
+#define REG_I2C_GATE	0x0103
+#define REG_TS_SAMPLE_EDGE	0x0301
+#define REG_TS_PKT_LEN_204	0x0302
+#define REG_TS_PKT_LEN_AUTO	0x0303
+#define REG_TS_SERIAL	0x0305
+#define REG_TS_CLK_FREERUN	0x0306
+#define REG_TS_VALID_MODE	0x0307
+#define REG_TS_CLK_MODE	0x030B /* 1 for serial, 0 for parallel */
+
+#define REG_TS_ERRBIT_USE	0x030C
+#define REG_LOCK_STATUS	0x030D
+#define REG_ADC_CONFIG	0x0602
+#define REG_CARRIER_OFFSET	0x0827 /* 0x0827-0x0829 little endian */
+#define REG_DETECTED_PN_MODE	0x082D
+#define REG_READ_LATCH	0x084D
+#define REG_IF_FREQ	0x0A00 /* 0x0A00-0x0A02 little endian */
+#define REG_OSC_CLK	0x0A03 /* 0x0A03-0x0A05 little endian */
+#define REG_BYPASS_CCI	0x0A06
+#define REG_ANALOG_LUMA_DETECTED	0x0A25
+#define REG_ANALOG_AUDIO_DETECTED	0x0A26
+#define REG_ANALOG_CHROMA_DETECTED	0x0A39
+#define REG_FRAME_ERR_CNT	0x0B04
+#define REG_USE_EXT_ADC	0x0C00
+#define REG_SWAP_I_Q	0x0C01
+#define REG_TPS_MANUAL	0x0D01
+#define REG_TPS_CONFIG	0x0D02
+#define REG_BYPASS_DEINTERLEAVER	0x0E00
+#define REG_AGC_TARGET	0x1003 /* 0x1003-0x1005 little endian */
+#define REG_AGC_MIN	0x1020
+#define REG_AGC_MAX	0x1023
+#define REG_AGC_LOCK	0x1027
+#define REG_AGC_PWM_VAL	0x1028 /* 0x1028-0x1029 little endian */
+#define REG_AGC_HOLD_LOOP	0x1031
+
+#endif
+
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
index 7c6431fe33e0..2dc2723b724a 100644
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ b/drivers/media/dvb/frontends/au8522_decoder.c
@@ -23,7 +23,6 @@
 /* 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)
@@ -236,8 +235,10 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
 	state->contrast = 0x79;
 	au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
 	au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
+	state->saturation = 0x80;
 	au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
 	au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
+	state->hue = 0x00;
 
 	/* Other decoder registers */
 	au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
@@ -504,7 +505,19 @@ static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 				ctrl->value);
 		break;
 	case V4L2_CID_SATURATION:
+		state->saturation = ctrl->value;
+		au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH,
+				ctrl->value);
+		au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH,
+				ctrl->value);
+		break;
 	case V4L2_CID_HUE:
+		state->hue = ctrl->value;
+		au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH,
+				ctrl->value >> 8);
+		au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH,
+				ctrl->value & 0xFF);
+		break;
 	case V4L2_CID_AUDIO_VOLUME:
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
@@ -534,7 +547,11 @@ static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 		ctrl->value = state->contrast;
 		break;
 	case V4L2_CID_SATURATION:
+		ctrl->value = state->saturation;
+		break;
 	case V4L2_CID_HUE:
+		ctrl->value = state->hue;
+		break;
 	case V4L2_CID_AUDIO_VOLUME:
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
@@ -632,8 +649,9 @@ static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 	case V4L2_CID_BRIGHTNESS:
 		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
 	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
 	case V4L2_CID_HUE:
-		/* Not yet implemented */
+		return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0);
 	default:
 		break;
 	}
diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
index f328f2b3ad3d..c74c4e72fe91 100644
--- a/drivers/media/dvb/frontends/au8522_priv.h
+++ b/drivers/media/dvb/frontends/au8522_priv.h
@@ -62,6 +62,8 @@ struct au8522_state {
 	u32 rev;
 	u8 brightness;
 	u8 contrast;
+	u8 saturation;
+	s16 hue;
 };
 
 /* These are routines shared by both the VSB/QAM demodulator and the analog
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 0781f94e05d2..750ae61a20f4 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -108,7 +108,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
 
 	outreg = 0;
 	fifo_threshold = 1792;
-	smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
+	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
 
 	dprintk( "setting output mode for demod %p to %d",
 			&state->demod, mode);
@@ -162,18 +162,19 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
 	if (state->div_force_off) {
 		dprintk( "diversity combination deactivated - forced by COFDM parameters");
 		onoff = 0;
-	}
+		dib7000p_write_word(state, 207, 0);
+	} else
+		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+
 	state->div_state = (u8)onoff;
 
 	if (onoff) {
 		dib7000p_write_word(state, 204, 6);
 		dib7000p_write_word(state, 205, 16);
 		/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
-		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
 	} else {
 		dib7000p_write_word(state, 204, 1);
 		dib7000p_write_word(state, 205, 0);
-		dib7000p_write_word(state, 207, 0);
 	}
 
 	return 0;
@@ -1188,7 +1189,7 @@ static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
 		*stat |= FE_HAS_VITERBI;
 	if (lock & 0x0010)
 		*stat |= FE_HAS_SYNC;
-	if (lock & 0x0008)
+    if ((lock & 0x0038) == 0x38)
 		*stat |= FE_HAS_LOCK;
 
 	return 0;
@@ -1302,6 +1303,24 @@ struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum di
 }
 EXPORT_SYMBOL(dib7000p_get_i2c_master);
 
+int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+    struct dib7000p_state *state = fe->demodulator_priv;
+    u16 val = dib7000p_read_word(state, 235) & 0xffef;
+    val |= (onoff & 0x1) << 4;
+    dprintk("PID filter enabled %d", onoff);
+    return dib7000p_write_word(state, 235, val);
+}
+EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
+
+int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+    struct dib7000p_state *state = fe->demodulator_priv;
+    dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
+    return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
+}
+EXPORT_SYMBOL(dib7000p_pid_filter);
+
 int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
 {
 	struct dib7000p_state st = { .i2c_adap = i2c };
@@ -1314,8 +1333,10 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
 		/* designated i2c address */
 		new_addr          = (0x40 + k) << 1;
 		st.i2c_addr = new_addr;
+		dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */
 		if (dib7000p_identify(&st) != 0) {
 			st.i2c_addr = default_addr;
+			dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */
 			if (dib7000p_identify(&st) != 0) {
 				dprintk("DiB7000P #%d: not identified\n", k);
 				return -EIO;
@@ -1372,6 +1393,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
 	demod->demodulator_priv = st;
 	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
 
+    dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
+
 	if (dib7000p_identify(st) != 0)
 		goto error;
 
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index 02a4c82f0c70..805dd13a97ee 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -51,6 +51,8 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
 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);
+extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
+extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
 #else
 static inline
 struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
@@ -95,6 +97,17 @@ static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap)
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return -ENODEV;
 }
+static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+    printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+    return -ENODEV;
+}
+
+static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff)
+{
+    printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+    return -ENODEV;
+}
 #endif
 
 #endif
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
index 852c790d09d9..898400d331a3 100644
--- a/drivers/media/dvb/frontends/dib8000.c
+++ b/drivers/media/dvb/frontends/dib8000.c
@@ -954,7 +954,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
 	u8 guard, crate, constellation, timeI;
 	u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
 	u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff;	// All 13 segments enabled
-	const s16 *ncoeff, *ana_fe;
+	const s16 *ncoeff = NULL, *ana_fe;
 	u16 tmcc_pow = 0;
 	u16 coff_pow = 0x2800;
 	u16 init_prbs = 0xfff;
@@ -2121,7 +2121,7 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
 	else
 		result -= intlog10(2) * 10 * noise_exp - 100;
 
-	*snr = result / (1 << 24);
+	*snr = result / ((1 << 24) / 10);
 	return 0;
 }
 
@@ -2195,6 +2195,25 @@ struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000
 
 EXPORT_SYMBOL(dib8000_get_i2c_master);
 
+int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+	struct dib8000_state *st = fe->demodulator_priv;
+    u16 val = dib8000_read_word(st, 299) & 0xffef;
+    val |= (onoff & 0x1) << 4;
+
+    dprintk("pid filter enabled %d", onoff);
+    return dib8000_write_word(st, 299, val);
+}
+EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
+
+int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+	struct dib8000_state *st = fe->demodulator_priv;
+    dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
+    return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
+}
+EXPORT_SYMBOL(dib8000_pid_filter);
+
 static const struct dvb_frontend_ops dib8000_ops = {
 	.info = {
 		 .name = "DiBcom 8000 ISDB-T",
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h
index a86de340dd54..8c89482b738a 100644
--- a/drivers/media/dvb/frontends/dib8000.h
+++ b/drivers/media/dvb/frontends/dib8000.h
@@ -44,6 +44,8 @@ extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u
 
 extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
 extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value);
+extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff);
+extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
 #else
 static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
 {
@@ -74,6 +76,18 @@ int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return -ENODEV;
 }
+
+int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
 #endif
 
 #endif
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c
new file mode 100644
index 000000000000..cff3535566fe
--- /dev/null
+++ b/drivers/media/dvb/frontends/ds3000.c
@@ -0,0 +1,1367 @@
+/*
+    Montage Technology DS3000/TS2020 - DVBS/S2 Demodulator/Tuner driver
+    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+    Copyright (C) 2009 TurboSight.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "ds3000.h"
+
+static int debug;
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(args); \
+	} while (0)
+
+/* as of March 2009 current DS3000 firmware version is 1.78 */
+/* DS3000 FW v1.78 MD5: a32d17910c4f370073f9346e71d34b80 */
+#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw"
+
+#define DS3000_SAMPLE_RATE 96000 /* in kHz */
+#define DS3000_XTAL_FREQ   27000 /* in kHz */
+
+/* Register values to initialise the demod in DVB-S mode */
+static u8 ds3000_dvbs_init_tab[] = {
+	0x23, 0x05,
+	0x08, 0x03,
+	0x0c, 0x00,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x40,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x40,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0xc8,
+	0x50, 0x77,
+	0x51, 0x77,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x56, 0x01,
+	0x63, 0x43,
+	0x64, 0x30,
+	0x65, 0x40,
+	0x68, 0x26,
+	0x69, 0x4c,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0x76, 0x00,
+	0x77, 0xd1,
+	0x78, 0x0c,
+	0x79, 0x80,
+	0x7f, 0x04,
+	0x7c, 0x00,
+	0x80, 0x86,
+	0x81, 0xa6,
+	0x85, 0x04,
+	0xcd, 0xf4,
+	0x90, 0x33,
+	0xa0, 0x44,
+	0xc0, 0x18,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0x80,
+	0xc6, 0x80,
+	0xc7, 0x0a,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xfe, 0x92,
+	0xe0, 0xf8,
+	0xe6, 0x8b,
+	0xd0, 0x40,
+	0xf8, 0x20,
+	0xfa, 0x0f,
+	0xfd, 0x20,
+	0xad, 0x20,
+	0xae, 0x07,
+	0xb8, 0x00,
+};
+
+/* Register values to initialise the demod in DVB-S2 mode */
+static u8 ds3000_dvbs2_init_tab[] = {
+	0x23, 0x0f,
+	0x08, 0x07,
+	0x0c, 0x00,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x32,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x80,
+	0x4b, 0x04,
+	0x4d, 0x81,
+	0x5d, 0x88,
+	0x50, 0x36,
+	0x51, 0x36,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x63, 0x60,
+	0x64, 0x10,
+	0x65, 0x10,
+	0x68, 0x04,
+	0x69, 0x29,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0xa0, 0x44,
+	0xc0, 0x08,
+	0xc1, 0x10,
+	0xc2, 0x08,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0xf0,
+	0xc6, 0xf0,
+	0xc7, 0x0a,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xca, 0x23,
+	0xcb, 0x24,
+	0xce, 0x74,
+	0x90, 0x03,
+	0x76, 0x80,
+	0x77, 0x42,
+	0x78, 0x0a,
+	0x79, 0x80,
+	0xad, 0x40,
+	0xae, 0x07,
+	0x7f, 0xd4,
+	0x7c, 0x00,
+	0x80, 0xa8,
+	0x81, 0xda,
+	0x7c, 0x01,
+	0x80, 0xda,
+	0x81, 0xec,
+	0x7c, 0x02,
+	0x80, 0xca,
+	0x81, 0xeb,
+	0x7c, 0x03,
+	0x80, 0xba,
+	0x81, 0xdb,
+	0x85, 0x08,
+	0x86, 0x00,
+	0x87, 0x02,
+	0x89, 0x80,
+	0x8b, 0x44,
+	0x8c, 0xaa,
+	0x8a, 0x10,
+	0xba, 0x00,
+	0xf5, 0x04,
+	0xfe, 0x44,
+	0xd2, 0x32,
+	0xb8, 0x00,
+};
+
+/* DS3000 doesn't need some parameters as input and auto-detects them */
+/* save input from the application of those parameters */
+struct ds3000_tuning {
+	u32 frequency;
+	u32 symbol_rate;
+	fe_spectral_inversion_t inversion;
+	enum fe_code_rate fec;
+
+	/* input values */
+	u8 inversion_val;
+	fe_modulation_t delivery;
+	u8 rolloff;
+};
+
+struct ds3000_state {
+	struct i2c_adapter *i2c;
+	const struct ds3000_config *config;
+
+	struct dvb_frontend frontend;
+
+	struct ds3000_tuning dcur;
+	struct ds3000_tuning dnxt;
+
+	u8 skip_fw_load;
+
+	/* previous uncorrected block counter for DVB-S2 */
+	u16 prevUCBS2;
+};
+
+static int ds3000_writereg(struct ds3000_state *state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
+
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int ds3000_tuner_writereg(struct ds3000_state *state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = 0x60,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
+
+	ds3000_writereg(state, 0x03, 0x11);
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk("%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+/* I2C write for 8k firmware load */
+static int ds3000_writeFW(struct ds3000_state *state, int reg,
+				const u8 *data, u16 len)
+{
+	int i, ret = -EREMOTEIO;
+	struct i2c_msg msg;
+	u8 *buf;
+
+	buf = kmalloc(3, GFP_KERNEL);
+	if (buf == NULL) {
+		printk(KERN_ERR "Unable to kmalloc\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	*(buf) = reg;
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = 3;
+
+	for (i = 0; i < len; i += 2) {
+		memcpy(buf + 1, data + i, 2);
+
+		dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len);
+
+		ret = i2c_transfer(state->i2c, &msg, 1);
+		if (ret != 1) {
+			printk(KERN_ERR "%s: write error(err == %i, "
+				"reg == 0x%02x\n", __func__, ret, reg);
+			ret = -EREMOTEIO;
+		}
+	}
+
+error:
+	kfree(buf);
+
+	return ret;
+}
+
+static int ds3000_readreg(struct ds3000_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = state->config->demod_address,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.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: reg=0x%x(error=%d)\n", __func__, reg, ret);
+		return ret;
+	}
+
+	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
+
+	return b1[0];
+}
+
+static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = 0x60,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = 0x60,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ds3000_writereg(state, 0x03, 0x12);
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
+		return ret;
+	}
+
+	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
+
+	return b1[0];
+}
+
+static int ds3000_set_inversion(struct ds3000_state *state,
+					fe_spectral_inversion_t inversion)
+{
+	dprintk("%s(%d)\n", __func__, inversion);
+
+	switch (inversion) {
+	case INVERSION_OFF:
+	case INVERSION_ON:
+	case INVERSION_AUTO:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	state->dnxt.inversion = inversion;
+
+	return 0;
+}
+
+static int ds3000_set_symbolrate(struct ds3000_state *state, u32 rate)
+{
+	int ret = 0;
+
+	dprintk("%s()\n", __func__);
+
+	dprintk("%s() symbol_rate = %d\n", __func__, state->dnxt.symbol_rate);
+
+	/*  check if symbol rate is within limits */
+	if ((state->dnxt.symbol_rate >
+				state->frontend.ops.info.symbol_rate_max) ||
+	    (state->dnxt.symbol_rate <
+				state->frontend.ops.info.symbol_rate_min))
+		ret = -EOPNOTSUPP;
+
+	state->dnxt.symbol_rate = rate;
+
+	return ret;
+}
+
+static int ds3000_load_firmware(struct dvb_frontend *fe,
+					const struct firmware *fw);
+
+static int ds3000_firmware_ondemand(struct dvb_frontend *fe)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret = 0;
+
+	dprintk("%s()\n", __func__);
+
+	if (ds3000_readreg(state, 0xb2) <= 0)
+		return ret;
+
+	if (state->skip_fw_load)
+		return 0;
+	/* Load firmware */
+	/* request the firmware, this will block until someone uploads it */
+	printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
+				DS3000_DEFAULT_FIRMWARE);
+	ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
+				state->i2c->dev.parent);
+	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
+	if (ret) {
+		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
+				"found?)\n", __func__);
+		return ret;
+	}
+
+	/* Make sure we don't recurse back through here during loading */
+	state->skip_fw_load = 1;
+
+	ret = ds3000_load_firmware(fe, fw);
+	if (ret)
+		printk("%s: Writing firmware to device failed\n", __func__);
+
+	release_firmware(fw);
+
+	dprintk("%s: Firmware upload %s\n", __func__,
+			ret == 0 ? "complete" : "failed");
+
+	/* Ensure firmware is always loaded if required */
+	state->skip_fw_load = 0;
+
+	return ret;
+}
+
+static int ds3000_load_firmware(struct dvb_frontend *fe,
+					const struct firmware *fw)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
+			fw->size,
+			fw->data[0],
+			fw->data[1],
+			fw->data[fw->size - 2],
+			fw->data[fw->size - 1]);
+
+	/* Begin the firmware load process */
+	ds3000_writereg(state, 0xb2, 0x01);
+	/* write the entire firmware */
+	ds3000_writeFW(state, 0xb0, fw->data, fw->size);
+	ds3000_writereg(state, 0xb2, 0x00);
+
+	return 0;
+}
+
+static void ds3000_dump_registers(struct dvb_frontend *fe)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	int x, y, reg = 0, val;
+
+	for (y = 0; y < 16; y++) {
+		dprintk("%s: %02x: ", __func__, y);
+		for (x = 0; x < 16; x++) {
+			reg = (y << 4) + x;
+			val = ds3000_readreg(state, reg);
+			if (x != 15)
+				dprintk("%02x ",  val);
+			else
+				dprintk("%02x\n", val);
+		}
+	}
+	dprintk("%s: -- DS3000 DUMP DONE --\n", __func__);
+}
+
+static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int lock;
+
+	*status = 0;
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		lock = ds3000_readreg(state, 0xd1);
+		if ((lock & 0x07) == 0x07)
+			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC |
+				FE_HAS_LOCK;
+
+		break;
+	case SYS_DVBS2:
+		lock = ds3000_readreg(state, 0x0d);
+		if ((lock & 0x8f) == 0x8f)
+			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC |
+				FE_HAS_LOCK;
+
+		break;
+	default:
+		return 1;
+	}
+
+	dprintk("%s: status = 0x%02x\n", __func__, lock);
+
+	return 0;
+}
+
+#define FE_IS_TUNED (FE_HAS_SIGNAL + FE_HAS_LOCK)
+static int ds3000_is_tuned(struct dvb_frontend *fe)
+{
+	fe_status_t tunerstat;
+
+	ds3000_read_status(fe, &tunerstat);
+
+	return ((tunerstat & FE_IS_TUNED) == FE_IS_TUNED);
+}
+
+/* read DS3000 BER value */
+static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 data;
+	u32 ber_reading, lpdc_frames;
+
+	dprintk("%s()\n", __func__);
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		/* set the number of bytes checked during
+		BER estimation */
+		ds3000_writereg(state, 0xf9, 0x04);
+		/* read BER estimation status */
+		data = ds3000_readreg(state, 0xf8);
+		/* check if BER estimation is ready */
+		if ((data & 0x10) == 0) {
+			/* this is the number of error bits,
+			to calculate the bit error rate
+			divide to 8388608 */
+			*ber = (ds3000_readreg(state, 0xf7) << 8) |
+				ds3000_readreg(state, 0xf6);
+			/* start counting error bits */
+			/* need to be set twice
+			otherwise it fails sometimes */
+			data |= 0x10;
+			ds3000_writereg(state, 0xf8, data);
+			ds3000_writereg(state, 0xf8, data);
+		} else
+			/* used to indicate that BER estimation
+			is not ready, i.e. BER is unknown */
+			*ber = 0xffffffff;
+		break;
+	case SYS_DVBS2:
+		/* read the number of LPDC decoded frames */
+		lpdc_frames = (ds3000_readreg(state, 0xd7) << 16) |
+				(ds3000_readreg(state, 0xd6) << 8) |
+				ds3000_readreg(state, 0xd5);
+		/* read the number of packets with bad CRC */
+		ber_reading = (ds3000_readreg(state, 0xf8) << 8) |
+				ds3000_readreg(state, 0xf7);
+		if (lpdc_frames > 750) {
+			/* clear LPDC frame counters */
+			ds3000_writereg(state, 0xd1, 0x01);
+			/* clear bad packets counter */
+			ds3000_writereg(state, 0xf9, 0x01);
+			/* enable bad packets counter */
+			ds3000_writereg(state, 0xf9, 0x00);
+			/* enable LPDC frame counters */
+			ds3000_writereg(state, 0xd1, 0x00);
+			*ber = ber_reading;
+		} else
+			/* used to indicate that BER estimation is not ready,
+			i.e. BER is unknown */
+			*ber = 0xffffffff;
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+/* read TS2020 signal strength */
+static int ds3000_read_signal_strength(struct dvb_frontend *fe,
+						u16 *signal_strength)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	u16 sig_reading, sig_strength;
+	u8 rfgain, bbgain;
+
+	dprintk("%s()\n", __func__);
+
+	rfgain = ds3000_tuner_readreg(state, 0x3d) & 0x1f;
+	bbgain = ds3000_tuner_readreg(state, 0x21) & 0x1f;
+
+	if (rfgain > 15)
+		rfgain = 15;
+	if (bbgain > 13)
+		bbgain = 13;
+
+	sig_reading = rfgain * 2 + bbgain * 3;
+
+	sig_strength = 40 + (64 - sig_reading) * 50 / 64 ;
+
+	/* cook the value to be suitable for szap-s2 human readable output */
+	*signal_strength = sig_strength * 1000;
+
+	dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__,
+			sig_reading, *signal_strength);
+
+	return 0;
+}
+
+/* calculate DS3000 snr value in dB */
+static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 snr_reading, snr_value;
+	u32 dvbs2_signal_reading, dvbs2_noise_reading, tmp;
+	static const u16 dvbs_snr_tab[] = { /* 20 x Table (rounded up) */
+		0x0000, 0x1b13, 0x2aea, 0x3627, 0x3ede, 0x45fe, 0x4c03,
+		0x513a, 0x55d4, 0x59f2, 0x5dab, 0x6111, 0x6431, 0x6717,
+		0x69c9, 0x6c4e, 0x6eac, 0x70e8, 0x7304, 0x7505
+	};
+	static const u16 dvbs2_snr_tab[] = { /* 80 x Table (rounded up) */
+		0x0000, 0x0bc2, 0x12a3, 0x1785, 0x1b4e, 0x1e65, 0x2103,
+		0x2347, 0x2546, 0x2710, 0x28ae, 0x2a28, 0x2b83, 0x2cc5,
+		0x2df1, 0x2f09, 0x3010, 0x3109, 0x31f4, 0x32d2, 0x33a6,
+		0x3470, 0x3531, 0x35ea, 0x369b, 0x3746, 0x37ea, 0x3888,
+		0x3920, 0x39b3, 0x3a42, 0x3acc, 0x3b51, 0x3bd3, 0x3c51,
+		0x3ccb, 0x3d42, 0x3db6, 0x3e27, 0x3e95, 0x3f00, 0x3f68,
+		0x3fcf, 0x4033, 0x4094, 0x40f4, 0x4151, 0x41ac, 0x4206,
+		0x425e, 0x42b4, 0x4308, 0x435b, 0x43ac, 0x43fc, 0x444a,
+		0x4497, 0x44e2, 0x452d, 0x4576, 0x45bd, 0x4604, 0x4649,
+		0x468e, 0x46d1, 0x4713, 0x4755, 0x4795, 0x47d4, 0x4813,
+		0x4851, 0x488d, 0x48c9, 0x4904, 0x493f, 0x4978, 0x49b1,
+		0x49e9, 0x4a20, 0x4a57
+	};
+
+	dprintk("%s()\n", __func__);
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		snr_reading = ds3000_readreg(state, 0xff);
+		snr_reading /= 8;
+		if (snr_reading == 0)
+			*snr = 0x0000;
+		else {
+			if (snr_reading > 20)
+				snr_reading = 20;
+			snr_value = dvbs_snr_tab[snr_reading - 1] * 10 / 23026;
+			/* cook the value to be suitable for szap-s2
+			human readable output */
+			*snr = snr_value * 8 * 655;
+		}
+		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
+				snr_reading, *snr);
+		break;
+	case SYS_DVBS2:
+		dvbs2_noise_reading = (ds3000_readreg(state, 0x8c) & 0x3f) +
+				(ds3000_readreg(state, 0x8d) << 4);
+		dvbs2_signal_reading = ds3000_readreg(state, 0x8e);
+		tmp = dvbs2_signal_reading * dvbs2_signal_reading >> 1;
+		if (dvbs2_signal_reading == 0) {
+			*snr = 0x0000;
+			return 0;
+		}
+		if (dvbs2_noise_reading == 0) {
+			snr_value = 0x0013;
+			/* cook the value to be suitable for szap-s2
+			human readable output */
+			*snr = 0xffff;
+			return 0;
+		}
+		if (tmp > dvbs2_noise_reading) {
+			snr_reading = tmp / dvbs2_noise_reading;
+			if (snr_reading > 80)
+				snr_reading = 80;
+			snr_value = dvbs2_snr_tab[snr_reading - 1] / 1000;
+			/* cook the value to be suitable for szap-s2
+			human readable output */
+			*snr = snr_value * 5 * 655;
+		} else {
+			snr_reading = dvbs2_noise_reading / tmp;
+			if (snr_reading > 80)
+				snr_reading = 80;
+			*snr = -(dvbs2_snr_tab[snr_reading] / 1000);
+		}
+		dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
+				snr_reading, *snr);
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+/* read DS3000 uncorrected blocks */
+static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u8 data;
+	u16 _ucblocks;
+
+	dprintk("%s()\n", __func__);
+
+	switch (c->delivery_system) {
+	case SYS_DVBS:
+		*ucblocks = (ds3000_readreg(state, 0xf5) << 8) |
+				ds3000_readreg(state, 0xf4);
+		data = ds3000_readreg(state, 0xf8);
+		/* clear packet counters */
+		data &= ~0x20;
+		ds3000_writereg(state, 0xf8, data);
+		/* enable packet counters */
+		data |= 0x20;
+		ds3000_writereg(state, 0xf8, data);
+		break;
+	case SYS_DVBS2:
+		_ucblocks = (ds3000_readreg(state, 0xe2) << 8) |
+				ds3000_readreg(state, 0xe1);
+		if (_ucblocks > state->prevUCBS2)
+			*ucblocks = _ucblocks - state->prevUCBS2;
+		else
+			*ucblocks = state->prevUCBS2 - _ucblocks;
+		state->prevUCBS2 = _ucblocks;
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Overwrite the current tuning params, we are about to tune */
+static void ds3000_clone_params(struct dvb_frontend *fe)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
+}
+
+static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	u8 data;
+
+	dprintk("%s(%d)\n", __func__, tone);
+	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
+		return -EINVAL;
+	}
+
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	ds3000_writereg(state, 0xa2, data);
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		dprintk("%s: setting tone on\n", __func__);
+		data = ds3000_readreg(state, 0xa1);
+		data &= ~0x43;
+		data |= 0x04;
+		ds3000_writereg(state, 0xa1, data);
+		break;
+	case SEC_TONE_OFF:
+		dprintk("%s: setting tone off\n", __func__);
+		data = ds3000_readreg(state, 0xa2);
+		data |= 0x80;
+		ds3000_writereg(state, 0xa2, data);
+		break;
+	}
+
+	return 0;
+}
+
+static int ds3000_send_diseqc_msg(struct dvb_frontend *fe,
+				struct dvb_diseqc_master_cmd *d)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	int i;
+	u8 data;
+
+	/* Dump DiSEqC message */
+	dprintk("%s(", __func__);
+	for (i = 0 ; i < d->msg_len;) {
+		dprintk("0x%02x", d->msg[i]);
+		if (++i < d->msg_len)
+			dprintk(", ");
+	}
+
+	/* enable DiSEqC message send pin */
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	ds3000_writereg(state, 0xa2, data);
+
+	/* DiSEqC message */
+	for (i = 0; i < d->msg_len; i++)
+		ds3000_writereg(state, 0xa3 + i, d->msg[i]);
+
+	data = ds3000_readreg(state, 0xa1);
+	/* clear DiSEqC message length and status,
+	enable DiSEqC message send */
+	data &= ~0xf8;
+	/* set DiSEqC mode, modulation active during 33 pulses,
+	set DiSEqC message length */
+	data |= ((d->msg_len - 1) << 3) | 0x07;
+	ds3000_writereg(state, 0xa1, data);
+
+	/* wait up to 150ms for DiSEqC transmission to complete */
+	for (i = 0; i < 15; i++) {
+		data = ds3000_readreg(state, 0xa1);
+		if ((data & 0x40) == 0)
+			break;
+		msleep(10);
+	}
+
+	/* DiSEqC timeout after 150ms */
+	if (i == 15) {
+		data = ds3000_readreg(state, 0xa1);
+		data &= ~0x80;
+		data |= 0x40;
+		ds3000_writereg(state, 0xa1, data);
+
+		data = ds3000_readreg(state, 0xa2);
+		data &= ~0xc0;
+		data |= 0x80;
+		ds3000_writereg(state, 0xa2, data);
+
+		return 1;
+	}
+
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	data |= 0x80;
+	ds3000_writereg(state, 0xa2, data);
+
+	return 0;
+}
+
+/* Send DiSEqC burst */
+static int ds3000_diseqc_send_burst(struct dvb_frontend *fe,
+					fe_sec_mini_cmd_t burst)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	int i;
+	u8 data;
+
+	dprintk("%s()\n", __func__);
+
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	ds3000_writereg(state, 0xa2, data);
+
+	/* DiSEqC burst */
+	if (burst == SEC_MINI_A)
+		/* Unmodulated tone burst */
+		ds3000_writereg(state, 0xa1, 0x02);
+	else if (burst == SEC_MINI_B)
+		/* Modulated tone burst */
+		ds3000_writereg(state, 0xa1, 0x01);
+	else
+		return -EINVAL;
+
+	msleep(13);
+	for (i = 0; i < 5; i++) {
+		data = ds3000_readreg(state, 0xa1);
+		if ((data & 0x40) == 0)
+			break;
+		msleep(1);
+	}
+
+	if (i == 5) {
+		data = ds3000_readreg(state, 0xa1);
+		data &= ~0x80;
+		data |= 0x40;
+		ds3000_writereg(state, 0xa1, data);
+
+		data = ds3000_readreg(state, 0xa2);
+		data &= ~0xc0;
+		data |= 0x80;
+		ds3000_writereg(state, 0xa2, data);
+
+		return 1;
+	}
+
+	data = ds3000_readreg(state, 0xa2);
+	data &= ~0xc0;
+	data |= 0x80;
+	ds3000_writereg(state, 0xa2, data);
+
+	return 0;
+}
+
+static void ds3000_release(struct dvb_frontend *fe)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	dprintk("%s\n", __func__);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops ds3000_ops;
+
+struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct ds3000_state *state = NULL;
+	int ret;
+
+	dprintk("%s\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct ds3000_state), GFP_KERNEL);
+	if (state == NULL) {
+		printk(KERN_ERR "Unable to kmalloc\n");
+		goto error2;
+	}
+
+	/* setup the state */
+	memset(state, 0, sizeof(struct ds3000_state));
+
+	state->config = config;
+	state->i2c = i2c;
+	state->prevUCBS2 = 0;
+
+	/* check if the demod is present */
+	ret = ds3000_readreg(state, 0x00) & 0xfe;
+	if (ret != 0xe0) {
+		printk(KERN_ERR "Invalid probe, probably not a DS3000\n");
+		goto error3;
+	}
+
+	printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n",
+			ds3000_readreg(state, 0x02),
+			ds3000_readreg(state, 0x01));
+
+	memcpy(&state->frontend.ops, &ds3000_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error3:
+	kfree(state);
+error2:
+	return NULL;
+}
+EXPORT_SYMBOL(ds3000_attach);
+
+static int ds3000_set_property(struct dvb_frontend *fe,
+	struct dtv_property *tvp)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int ds3000_get_property(struct dvb_frontend *fe,
+	struct dtv_property *tvp)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int ds3000_tune(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct ds3000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	int ret = 0, retune, i;
+	u8 status, mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf;
+	u16 value, ndiv;
+	u32 f3db;
+
+	dprintk("%s() ", __func__);
+
+	/* Load the firmware if required */
+	ret = ds3000_firmware_ondemand(fe);
+	if (ret != 0) {
+		printk(KERN_ERR "%s: Unable initialise the firmware\n",
+								__func__);
+		return ret;
+	}
+
+	state->dnxt.delivery = c->modulation;
+	state->dnxt.frequency = c->frequency;
+	state->dnxt.rolloff = 2; /* fixme */
+	state->dnxt.fec = c->fec_inner;
+
+	ret = ds3000_set_inversion(state, p->inversion);
+	if (ret !=  0)
+		return ret;
+
+	ret = ds3000_set_symbolrate(state, c->symbol_rate);
+	if (ret !=  0)
+		return ret;
+
+	/* discard the 'current' tuning parameters and prepare to tune */
+	ds3000_clone_params(fe);
+
+	retune = 1;	/* try 1 times */
+	dprintk("%s:   retune = %d\n", __func__, retune);
+	dprintk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
+	dprintk("%s:   symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
+	dprintk("%s:   FEC	 = %d \n", __func__,
+		state->dcur.fec);
+	dprintk("%s:   Inversion   = %d\n", __func__, state->dcur.inversion);
+
+	do {
+		/* Reset status register */
+		status = 0;
+		/* Tune */
+		/* TS2020 init */
+		ds3000_tuner_writereg(state, 0x42, 0x73);
+		ds3000_tuner_writereg(state, 0x05, 0x01);
+		ds3000_tuner_writereg(state, 0x62, 0xf5);
+		/* unknown */
+		ds3000_tuner_writereg(state, 0x07, 0x02);
+		ds3000_tuner_writereg(state, 0x10, 0x00);
+		ds3000_tuner_writereg(state, 0x60, 0x79);
+		ds3000_tuner_writereg(state, 0x08, 0x01);
+		ds3000_tuner_writereg(state, 0x00, 0x01);
+		/* calculate and set freq divider */
+		if (state->dcur.frequency < 1146000) {
+			ds3000_tuner_writereg(state, 0x10, 0x11);
+			ndiv = ((state->dcur.frequency * (6 + 8) * 4) +
+					(DS3000_XTAL_FREQ / 2)) /
+					DS3000_XTAL_FREQ - 1024;
+		} else {
+			ds3000_tuner_writereg(state, 0x10, 0x01);
+			ndiv = ((state->dcur.frequency * (6 + 8) * 2) +
+					(DS3000_XTAL_FREQ / 2)) /
+					DS3000_XTAL_FREQ - 1024;
+		}
+
+		ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
+		ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
+
+		/* set pll */
+		ds3000_tuner_writereg(state, 0x03, 0x06);
+		ds3000_tuner_writereg(state, 0x51, 0x0f);
+		ds3000_tuner_writereg(state, 0x51, 0x1f);
+		ds3000_tuner_writereg(state, 0x50, 0x10);
+		ds3000_tuner_writereg(state, 0x50, 0x00);
+		msleep(5);
+
+		/* unknown */
+		ds3000_tuner_writereg(state, 0x51, 0x17);
+		ds3000_tuner_writereg(state, 0x51, 0x1f);
+		ds3000_tuner_writereg(state, 0x50, 0x08);
+		ds3000_tuner_writereg(state, 0x50, 0x00);
+		msleep(5);
+
+		value = ds3000_tuner_readreg(state, 0x3d);
+		value &= 0x0f;
+		if ((value > 4) && (value < 15)) {
+			value -= 3;
+			if (value < 4)
+				value = 4;
+			value = ((value << 3) | 0x01) & 0x79;
+		}
+
+		ds3000_tuner_writereg(state, 0x60, value);
+		ds3000_tuner_writereg(state, 0x51, 0x17);
+		ds3000_tuner_writereg(state, 0x51, 0x1f);
+		ds3000_tuner_writereg(state, 0x50, 0x08);
+		ds3000_tuner_writereg(state, 0x50, 0x00);
+
+		/* set low-pass filter period */
+		ds3000_tuner_writereg(state, 0x04, 0x2e);
+		ds3000_tuner_writereg(state, 0x51, 0x1b);
+		ds3000_tuner_writereg(state, 0x51, 0x1f);
+		ds3000_tuner_writereg(state, 0x50, 0x04);
+		ds3000_tuner_writereg(state, 0x50, 0x00);
+		msleep(5);
+
+		f3db = ((state->dcur.symbol_rate / 1000) << 2) / 5 + 2000;
+		if ((state->dcur.symbol_rate / 1000) < 5000)
+			f3db += 3000;
+		if (f3db < 7000)
+			f3db = 7000;
+		if (f3db > 40000)
+			f3db = 40000;
+
+		/* set low-pass filter baseband */
+		value = ds3000_tuner_readreg(state, 0x26);
+		mlpf = 0x2e * 207 / ((value << 1) + 151);
+		mlpf_max = mlpf * 135 / 100;
+		mlpf_min = mlpf * 78 / 100;
+		if (mlpf_max > 63)
+			mlpf_max = 63;
+
+		/* rounded to the closest integer */
+		nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
+				/ (2766 * DS3000_XTAL_FREQ);
+		if (nlpf > 23)
+			nlpf = 23;
+		if (nlpf < 1)
+			nlpf = 1;
+
+		/* rounded to the closest integer */
+		mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+				(1000 * f3db / 2)) / (1000 * f3db);
+
+		if (mlpf_new < mlpf_min) {
+			nlpf++;
+			mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+					(1000 * f3db / 2)) / (1000 * f3db);
+		}
+
+		if (mlpf_new > mlpf_max)
+			mlpf_new = mlpf_max;
+
+		ds3000_tuner_writereg(state, 0x04, mlpf_new);
+		ds3000_tuner_writereg(state, 0x06, nlpf);
+		ds3000_tuner_writereg(state, 0x51, 0x1b);
+		ds3000_tuner_writereg(state, 0x51, 0x1f);
+		ds3000_tuner_writereg(state, 0x50, 0x04);
+		ds3000_tuner_writereg(state, 0x50, 0x00);
+		msleep(5);
+
+		/* unknown */
+		ds3000_tuner_writereg(state, 0x51, 0x1e);
+		ds3000_tuner_writereg(state, 0x51, 0x1f);
+		ds3000_tuner_writereg(state, 0x50, 0x01);
+		ds3000_tuner_writereg(state, 0x50, 0x00);
+		msleep(60);
+
+		/* ds3000 global reset */
+		ds3000_writereg(state, 0x07, 0x80);
+		ds3000_writereg(state, 0x07, 0x00);
+		/* ds3000 build-in uC reset */
+		ds3000_writereg(state, 0xb2, 0x01);
+		/* ds3000 software reset */
+		ds3000_writereg(state, 0x00, 0x01);
+
+		switch (c->delivery_system) {
+		case SYS_DVBS:
+			/* initialise the demod in DVB-S mode */
+			for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
+				ds3000_writereg(state,
+					ds3000_dvbs_init_tab[i],
+					ds3000_dvbs_init_tab[i + 1]);
+			value = ds3000_readreg(state, 0xfe);
+			value &= 0xc0;
+			value |= 0x1b;
+			ds3000_writereg(state, 0xfe, value);
+			break;
+		case SYS_DVBS2:
+			/* initialise the demod in DVB-S2 mode */
+			for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
+				ds3000_writereg(state,
+					ds3000_dvbs2_init_tab[i],
+					ds3000_dvbs2_init_tab[i + 1]);
+			ds3000_writereg(state, 0xfe, 0x54);
+			break;
+		default:
+			return 1;
+		}
+
+		/* enable 27MHz clock output */
+		ds3000_writereg(state, 0x29, 0x80);
+		/* enable ac coupling */
+		ds3000_writereg(state, 0x25, 0x8a);
+
+		/* enhance symbol rate performance */
+		if ((state->dcur.symbol_rate / 1000) <= 5000) {
+			value = 29777 / (state->dcur.symbol_rate / 1000) + 1;
+			if (value % 2 != 0)
+				value++;
+			ds3000_writereg(state, 0xc3, 0x0d);
+			ds3000_writereg(state, 0xc8, value);
+			ds3000_writereg(state, 0xc4, 0x10);
+			ds3000_writereg(state, 0xc7, 0x0e);
+		} else if ((state->dcur.symbol_rate / 1000) <= 10000) {
+			value = 92166 / (state->dcur.symbol_rate / 1000) + 1;
+			if (value % 2 != 0)
+				value++;
+			ds3000_writereg(state, 0xc3, 0x07);
+			ds3000_writereg(state, 0xc8, value);
+			ds3000_writereg(state, 0xc4, 0x09);
+			ds3000_writereg(state, 0xc7, 0x12);
+		} else if ((state->dcur.symbol_rate / 1000) <= 20000) {
+			value = 64516 / (state->dcur.symbol_rate / 1000) + 1;
+			ds3000_writereg(state, 0xc3, value);
+			ds3000_writereg(state, 0xc8, 0x0e);
+			ds3000_writereg(state, 0xc4, 0x07);
+			ds3000_writereg(state, 0xc7, 0x18);
+		} else {
+			value = 129032 / (state->dcur.symbol_rate / 1000) + 1;
+			ds3000_writereg(state, 0xc3, value);
+			ds3000_writereg(state, 0xc8, 0x0a);
+			ds3000_writereg(state, 0xc4, 0x05);
+			ds3000_writereg(state, 0xc7, 0x24);
+		}
+
+		/* normalized symbol rate rounded to the closest integer */
+		value = (((state->dcur.symbol_rate / 1000) << 16) +
+				(DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
+		ds3000_writereg(state, 0x61, value & 0x00ff);
+		ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
+
+		/* co-channel interference cancellation disabled */
+		ds3000_writereg(state, 0x56, 0x00);
+
+		/* equalizer disabled */
+		ds3000_writereg(state, 0x76, 0x00);
+
+		/*ds3000_writereg(state, 0x08, 0x03);
+		ds3000_writereg(state, 0xfd, 0x22);
+		ds3000_writereg(state, 0x08, 0x07);
+		ds3000_writereg(state, 0xfd, 0x42);
+		ds3000_writereg(state, 0x08, 0x07);*/
+
+		/* ds3000 out of software reset */
+		ds3000_writereg(state, 0x00, 0x00);
+		/* start ds3000 build-in uC */
+		ds3000_writereg(state, 0xb2, 0x00);
+
+		/* TODO: calculate and set carrier offset */
+
+		/* wait before retrying */
+		for (i = 0; i < 30 ; i++) {
+			if (ds3000_is_tuned(fe)) {
+				dprintk("%s: Tuned\n", __func__);
+				ds3000_dump_registers(fe);
+				goto tuned;
+			}
+			msleep(1);
+		}
+
+		dprintk("%s: Not tuned\n", __func__);
+		ds3000_dump_registers(fe);
+
+	} while (--retune);
+
+tuned:
+	return ret;
+}
+
+static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
+{
+	dprintk("%s()\n", __func__);
+	return DVBFE_ALGO_SW;
+}
+
+/*
+ * Initialise or wake up device
+ *
+ * Power config will reset and load initial firmware if required
+ */
+static int ds3000_initfe(struct dvb_frontend *fe)
+{
+	dprintk("%s()\n", __func__);
+	return 0;
+}
+
+/* Put device to sleep */
+static int ds3000_sleep(struct dvb_frontend *fe)
+{
+	dprintk("%s()\n", __func__);
+	return 0;
+}
+
+static struct dvb_frontend_ops ds3000_ops = {
+
+	.info = {
+		.name = "Montage Technology DS3000/TS2020",
+		.type = FE_QPSK,
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
+		.frequency_tolerance = 5000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_2G_MODULATION |
+			FE_CAN_QPSK | FE_CAN_RECOVER
+	},
+
+	.release = ds3000_release,
+
+	.init = ds3000_initfe,
+	.sleep = ds3000_sleep,
+	.read_status = ds3000_read_status,
+	.read_ber = ds3000_read_ber,
+	.read_signal_strength = ds3000_read_signal_strength,
+	.read_snr = ds3000_read_snr,
+	.read_ucblocks = ds3000_read_ucblocks,
+	.set_tone = ds3000_set_tone,
+	.diseqc_send_master_cmd = ds3000_send_diseqc_msg,
+	.diseqc_send_burst = ds3000_diseqc_send_burst,
+	.get_frontend_algo = ds3000_get_algo,
+
+	.set_property = ds3000_set_property,
+	.get_property = ds3000_get_property,
+	.set_frontend = ds3000_tune,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+MODULE_DESCRIPTION("DVB Frontend module for Montage Technology "
+			"DS3000/TS2020 hardware");
+MODULE_AUTHOR("Konstantin Dimitrov");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/ds3000.h b/drivers/media/dvb/frontends/ds3000.h
new file mode 100644
index 000000000000..67f67038740a
--- /dev/null
+++ b/drivers/media/dvb/frontends/ds3000.h
@@ -0,0 +1,45 @@
+/*
+    Montage Technology DS3000/TS2020 - DVBS/S2 Satellite demod/tuner driver
+    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+    Copyright (C) 2009 TurboSight.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef DS3000_H
+#define DS3000_H
+
+#include <linux/dvb/frontend.h>
+
+struct ds3000_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_DS3000) || \
+			(defined(CONFIG_DVB_DS3000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_DS3000 */
+#endif /* DS3000_H */
diff --git a/drivers/media/dvb/frontends/ec100.c b/drivers/media/dvb/frontends/ec100.c
new file mode 100644
index 000000000000..2414dc6ee5d9
--- /dev/null
+++ b/drivers/media/dvb/frontends/ec100.c
@@ -0,0 +1,335 @@
+/*
+ * E3C EC100 demodulator driver
+ *
+ * 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 "dvb_frontend.h"
+#include "ec100_priv.h"
+#include "ec100.h"
+
+int ec100_debug;
+module_param_named(debug, ec100_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+struct ec100_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend frontend;
+	struct ec100_config config;
+
+	u16 ber;
+};
+
+/* write single register */
+static int ec100_write_reg(struct ec100_state *state, u8 reg, u8 val)
+{
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = {
+		.addr = state->config.demod_address,
+		.flags = 0,
+		.len = 2,
+		.buf = buf};
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		warn("I2C write failed reg:%02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* read single register */
+static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{
+			.addr = state->config.demod_address,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg
+		}, {
+			.addr = state->config.demod_address,
+			.flags = I2C_M_RD,
+			.len = 1,
+			.buf = val
+		}
+	};
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		warn("I2C read failed reg:%02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int ec100_set_frontend(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *params)
+{
+	struct ec100_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp, tmp2;
+
+	deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency,
+		params->u.ofdm.bandwidth);
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe, params);
+
+	ret = ec100_write_reg(state, 0x04, 0x06);
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x67, 0x58);
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x05, 0x18);
+	if (ret)
+		goto error;
+
+	/* reg/bw |   6  |   7  |   8
+	   -------+------+------+------
+	   A 0x1b | 0xa1 | 0xe7 | 0x2c
+	   A 0x1c | 0x55 | 0x63 | 0x72
+	   -------+------+------+------
+	   B 0x1b | 0xb7 | 0x00 | 0x49
+	   B 0x1c | 0x55 | 0x64 | 0x72 */
+
+	switch (params->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		tmp = 0xb7;
+		tmp2 = 0x55;
+		break;
+	case BANDWIDTH_7_MHZ:
+		tmp = 0x00;
+		tmp2 = 0x64;
+		break;
+	case BANDWIDTH_8_MHZ:
+	default:
+		tmp = 0x49;
+		tmp2 = 0x72;
+	}
+
+	ret = ec100_write_reg(state, 0x1b, tmp);
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x1c, tmp2);
+	if (ret)
+		goto error;
+
+	ret = ec100_write_reg(state, 0x0c, 0xbb); /* if freq */
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x0d, 0x31); /* if freq */
+	if (ret)
+		goto error;
+
+	ret = ec100_write_reg(state, 0x08, 0x24);
+	if (ret)
+		goto error;
+
+	ret = ec100_write_reg(state, 0x00, 0x00); /* go */
+	if (ret)
+		goto error;
+	ret = ec100_write_reg(state, 0x00, 0x20); /* go */
+	if (ret)
+		goto error;
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec100_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 300;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+
+	return 0;
+}
+
+static int ec100_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct ec100_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+	*status = 0;
+
+	ret = ec100_read_reg(state, 0x42, &tmp);
+	if (ret)
+		goto error;
+
+	if (tmp & 0x80) {
+		/* bit7 set - have lock */
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+			FE_HAS_SYNC | FE_HAS_LOCK;
+	} else {
+		ret = ec100_read_reg(state, 0x01, &tmp);
+		if (ret)
+			goto error;
+
+		if (tmp & 0x10) {
+			/* bit4 set - have signal */
+			*status |= FE_HAS_SIGNAL;
+			if (!(tmp & 0x01)) {
+				/* bit0 clear - have ~valid signal */
+				*status |= FE_HAS_CARRIER |  FE_HAS_VITERBI;
+			}
+		}
+	}
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec100_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct ec100_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp, tmp2;
+	u16 ber2;
+
+	*ber = 0;
+
+	ret = ec100_read_reg(state, 0x65, &tmp);
+	if (ret)
+		goto error;
+	ret = ec100_read_reg(state, 0x66, &tmp2);
+	if (ret)
+		goto error;
+
+	ber2 = (tmp2 << 8) | tmp;
+
+	/* if counter overflow or clear */
+	if (ber2 < state->ber)
+		*ber = ber2;
+	else
+		*ber = ber2 - state->ber;
+
+	state->ber = ber2;
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec100_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct ec100_state *state = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+
+	ret = ec100_read_reg(state, 0x24, &tmp);
+	if (ret) {
+		*strength = 0;
+		goto error;
+	}
+
+	*strength = ((tmp << 8) | tmp);
+
+	return ret;
+error:
+	deb_info("%s: failed:%d\n", __func__, ret);
+	return ret;
+}
+
+static int ec100_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	*snr = 0;
+	return 0;
+}
+
+static int ec100_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+	return 0;
+}
+
+static void ec100_release(struct dvb_frontend *fe)
+{
+	struct ec100_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops ec100_ops;
+
+struct dvb_frontend *ec100_attach(const struct ec100_config *config,
+	struct i2c_adapter *i2c)
+{
+	int ret;
+	struct ec100_state *state = NULL;
+	u8 tmp;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct ec100_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->config, config, sizeof(struct ec100_config));
+
+	/* check if the demod is there */
+	ret = ec100_read_reg(state, 0x33, &tmp);
+	if (ret || tmp != 0x0b)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &ec100_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(ec100_attach);
+
+static struct dvb_frontend_ops ec100_ops = {
+	.info = {
+		.name = "E3C EC100 DVB-T",
+		.type = FE_OFDM,
+		.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_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = ec100_release,
+	.set_frontend = ec100_set_frontend,
+	.get_tune_settings = ec100_get_tune_settings,
+	.read_status = ec100_read_status,
+	.read_ber = ec100_read_ber,
+	.read_signal_strength = ec100_read_signal_strength,
+	.read_snr = ec100_read_snr,
+	.read_ucblocks = ec100_read_ucblocks,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("E3C EC100 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/ec100.h b/drivers/media/dvb/frontends/ec100.h
new file mode 100644
index 000000000000..ee8e52417958
--- /dev/null
+++ b/drivers/media/dvb/frontends/ec100.h
@@ -0,0 +1,46 @@
+/*
+ * E3C EC100 demodulator driver
+ *
+ * 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 EC100_H
+#define EC100_H
+
+#include <linux/dvb/frontend.h>
+
+struct ec100_config {
+	/* demodulator's I2C address */
+	u8 demod_address;
+};
+
+
+#if defined(CONFIG_DVB_EC100) || \
+	(defined(CONFIG_DVB_EC100_MODULE) && defined(MODULE))
+extern struct dvb_frontend *ec100_attach(const struct ec100_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ec100_attach(
+	const struct ec100_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif /* EC100_H */
diff --git a/drivers/media/dvb/frontends/ec100_priv.h b/drivers/media/dvb/frontends/ec100_priv.h
new file mode 100644
index 000000000000..5c990144bc47
--- /dev/null
+++ b/drivers/media/dvb/frontends/ec100_priv.h
@@ -0,0 +1,39 @@
+/*
+ * E3C EC100 demodulator driver
+ *
+ * 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 EC100_PRIV
+#define EC100_PRIV
+
+#define LOG_PREFIX "ec100"
+
+#define dprintk(var, level, args...) \
+	do { if ((var & level)) printk(args); } while (0)
+
+#define deb_info(args...) dprintk(ec100_debug, 0x01, args)
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#endif /* EC100_PRIV */
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index fb3011518427..0e2f61a8978f 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -44,7 +44,15 @@ struct s5h1409_state {
 	int if_freq;
 
 	u32 is_qam_locked;
-	u32 qam_state;
+
+	/* QAM tuning state goes through the following state transitions */
+#define QAM_STATE_UNTUNED 0
+#define QAM_STATE_TUNING_STARTED 1
+#define QAM_STATE_INTERLEAVE_SET 2
+#define QAM_STATE_QAM_OPTIMIZED_L1 3
+#define QAM_STATE_QAM_OPTIMIZED_L2 4
+#define QAM_STATE_QAM_OPTIMIZED_L3 5
+	u8  qam_state;
 };
 
 static int debug;
@@ -347,7 +355,7 @@ static int s5h1409_softreset(struct dvb_frontend *fe)
 	s5h1409_writereg(state, 0xf5, 0);
 	s5h1409_writereg(state, 0xf5, 1);
 	state->is_qam_locked = 0;
-	state->qam_state = 0;
+	state->qam_state = QAM_STATE_UNTUNED;
 	return 0;
 }
 
@@ -474,6 +482,59 @@ static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
 	struct s5h1409_state *state = fe->demodulator_priv;
 	u16 reg;
 
+	if (state->qam_state < QAM_STATE_INTERLEAVE_SET) {
+		/* We should not perform amhum optimization until
+		   the interleave mode has been configured */
+		return;
+	}
+
+	if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) {
+		/* We've already reached the maximum optimization level, so
+		   dont bother banging on the status registers */
+		return;
+	}
+
+	/* QAM EQ lock check */
+	reg = s5h1409_readreg(state, 0xf0);
+
+	if ((reg >> 13) & 0x1) {
+		reg &= 0xff;
+
+		s5h1409_writereg(state, 0x96, 0x000c);
+		if (reg < 0x68) {
+			if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L3) {
+				dprintk("%s() setting QAM state to OPT_L3\n",
+					__func__);
+				s5h1409_writereg(state, 0x93, 0x3130);
+				s5h1409_writereg(state, 0x9e, 0x2836);
+				state->qam_state = QAM_STATE_QAM_OPTIMIZED_L3;
+			}
+		} else {
+			if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L2) {
+				dprintk("%s() setting QAM state to OPT_L2\n",
+					__func__);
+				s5h1409_writereg(state, 0x93, 0x3332);
+				s5h1409_writereg(state, 0x9e, 0x2c37);
+				state->qam_state = QAM_STATE_QAM_OPTIMIZED_L2;
+			}
+		}
+
+	} else {
+		if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L1) {
+			dprintk("%s() setting QAM state to OPT_L1\n", __func__);
+			s5h1409_writereg(state, 0x96, 0x0008);
+			s5h1409_writereg(state, 0x93, 0x3332);
+			s5h1409_writereg(state, 0x9e, 0x2c37);
+			state->qam_state = QAM_STATE_QAM_OPTIMIZED_L1;
+		}
+	}
+}
+
+static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 reg;
+
 	if (state->is_qam_locked)
 		return;
 
@@ -506,6 +567,44 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
 	struct s5h1409_state *state = fe->demodulator_priv;
 	u16 reg, reg1, reg2;
 
+	if (state->qam_state >= QAM_STATE_INTERLEAVE_SET) {
+		/* We've done the optimization already */
+		return;
+	}
+
+	reg = s5h1409_readreg(state, 0xf1);
+
+	/* Master lock */
+	if ((reg >> 15) & 0x1) {
+		if (state->qam_state == QAM_STATE_UNTUNED ||
+		    state->qam_state == QAM_STATE_TUNING_STARTED) {
+			dprintk("%s() setting QAM state to INTERLEAVE_SET\n",
+				__func__);
+			reg1 = s5h1409_readreg(state, 0xb2);
+			reg2 = s5h1409_readreg(state, 0xad);
+
+			s5h1409_writereg(state, 0x96, 0x0020);
+			s5h1409_writereg(state, 0xad,
+				(((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
+			state->qam_state = QAM_STATE_INTERLEAVE_SET;
+		}
+	} else {
+		if (state->qam_state == QAM_STATE_UNTUNED) {
+			dprintk("%s() setting QAM state to TUNING_STARTED\n",
+				__func__);
+			s5h1409_writereg(state, 0x96, 0x08);
+			s5h1409_writereg(state, 0xab,
+				s5h1409_readreg(state, 0xab) | 0x1001);
+			state->qam_state = QAM_STATE_TUNING_STARTED;
+		}
+	}
+}
+
+static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 reg, reg1, reg2;
+
 	reg = s5h1409_readreg(state, 0xf1);
 
 	/* Master lock */
@@ -553,16 +652,24 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe,
 			fe->ops.i2c_gate_ctrl(fe, 0);
 	}
 
-	/* Optimize the demod for QAM */
-	if (p->u.vsb.modulation != VSB_8) {
-		s5h1409_set_qam_amhum_mode(fe);
-		s5h1409_set_qam_interleave_mode(fe);
-	}
-
 	/* Issue a reset to the demod so it knows to resync against the
 	   newly tuned frequency */
 	s5h1409_softreset(fe);
 
+	/* Optimize the demod for QAM */
+	if (state->current_modulation != VSB_8) {
+		/* This almost certainly applies to all boards, but for now
+		   only do it for the HVR-1600.  Once the other boards are
+		   tested, the "legacy" versions can just go away */
+		if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
+			s5h1409_set_qam_interleave_mode(fe);
+			s5h1409_set_qam_amhum_mode(fe);
+		} else {
+			s5h1409_set_qam_amhum_mode_legacy(fe);
+			s5h1409_set_qam_interleave_mode_legacy(fe);
+		}
+	}
+
 	return 0;
 }
 
@@ -614,6 +721,21 @@ static int s5h1409_init(struct dvb_frontend *fe)
 	/* The datasheet says that after initialisation, VSB is default */
 	state->current_modulation = VSB_8;
 
+	/* Optimize for the HVR-1600 if appropriate.  Note that some of these
+	   may get folded into the generic case after testing with other
+	   devices */
+	if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
+		/* VSB AGC REF */
+		s5h1409_writereg(state, 0x09, 0x0050);
+
+		/* Unknown but Windows driver does it... */
+		s5h1409_writereg(state, 0x21, 0x0001);
+		s5h1409_writereg(state, 0x50, 0x030e);
+
+		/* QAM AGC REF */
+		s5h1409_writereg(state, 0x82, 0x0800);
+	}
+
 	if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
 		s5h1409_writereg(state, 0xab,
 			s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
@@ -641,6 +763,17 @@ static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
 	*status = 0;
 
+	/* Optimize the demod for QAM */
+	if (state->current_modulation != VSB_8) {
+		/* This almost certainly applies to all boards, but for now
+		   only do it for the HVR-1600.  Once the other boards are
+		   tested, the "legacy" versions can just go away */
+		if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
+			s5h1409_set_qam_interleave_mode(fe);
+			s5h1409_set_qam_amhum_mode(fe);
+		}
+	}
+
 	/* Get the demodulator status */
 	reg = s5h1409_readreg(state, 0xf1);
 	if (reg & 0x1000)
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
index 070d9743e330..91f2ebd1a534 100644
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -57,6 +57,13 @@ struct s5h1409_config {
 #define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
 #define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
 	u16 mpeg_timing;
+
+	/* HVR-1600 optimizations (to better work with MXL5005s)
+	   Note: some of these are likely to be folded into the generic driver
+	   after being regression tested with other boards */
+#define S5H1409_HVR1600_NOOPTIMIZE 0
+#define S5H1409_HVR1600_OPTIMIZE   1
+	u8 hvr1600_opt;
 };
 
 #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \
diff --git a/drivers/media/dvb/frontends/stb6100_proc.h b/drivers/media/dvb/frontends/stb6100_proc.h
new file mode 100644
index 000000000000..112163a48622
--- /dev/null
+++ b/drivers/media/dvb/frontends/stb6100_proc.h
@@ -0,0 +1,138 @@
+/*
+	STB6100 Silicon Tuner wrapper
+	Copyright (C)2009 Igor M. Liplianin (liplianin@me.by)
+
+	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.
+*/
+
+static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	state;
+	int err = 0;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->get_state) {
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 1);
+
+		err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &state);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+			return err;
+		}
+
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 0);
+
+		*frequency = state.frequency;
+	}
+
+	return 0;
+}
+
+static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	state;
+	int err = 0;
+
+	state.frequency = frequency;
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->set_state) {
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 1);
+
+		err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &state);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+			return err;
+		}
+
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 0);
+
+	}
+
+	return 0;
+}
+
+static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	state;
+	int err = 0;
+
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->get_state) {
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 1);
+
+		err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+			return err;
+		}
+
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 0);
+
+		*bandwidth = state.bandwidth;
+	}
+
+	return 0;
+}
+
+static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth)
+{
+	struct dvb_frontend_ops	*frontend_ops = NULL;
+	struct dvb_tuner_ops	*tuner_ops = NULL;
+	struct tuner_state	state;
+	int err = 0;
+
+	state.bandwidth = bandwidth;
+	if (&fe->ops)
+		frontend_ops = &fe->ops;
+	if (&frontend_ops->tuner_ops)
+		tuner_ops = &frontend_ops->tuner_ops;
+	if (tuner_ops->set_state) {
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 1);
+
+		err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
+		if (err < 0) {
+			printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+			return err;
+		}
+
+		if (frontend_ops->i2c_gate_ctrl)
+			frontend_ops->i2c_gate_ctrl(fe, 0);
+
+	}
+
+	return 0;
+}
diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb/frontends/stv0900.h
index bf4e9b633044..29c3fa85c227 100644
--- a/drivers/media/dvb/frontends/stv0900.h
+++ b/drivers/media/dvb/frontends/stv0900.h
@@ -36,6 +36,7 @@ struct stv0900_reg {
 
 struct stv0900_config {
 	u8 demod_address;
+	u8 demod_mode;
 	u32 xtal;
 	u8 clkmode;/* 0 for CLKI,  2 for XTALI */
 
@@ -48,6 +49,8 @@ struct stv0900_config {
 	u8 tun2_maddress;
 	u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
 	u8 tun2_adc;
+	/* Set device param to start dma */
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
 };
 
 #if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
index 3bde3324a032..df49ea0983bc 100644
--- a/drivers/media/dvb/frontends/stv0900_core.c
+++ b/drivers/media/dvb/frontends/stv0900_core.c
@@ -34,7 +34,7 @@
 #include "stv0900_priv.h"
 #include "stv0900_init.h"
 
-static int stvdebug = 1;
+int stvdebug = 1;
 module_param_named(debug, stvdebug, int, 0644);
 
 /* internal params node */
@@ -105,7 +105,8 @@ static struct stv0900_inode *append_internal(struct stv0900_internal *internal)
 		while (new_node->next_inode != NULL)
 			new_node = new_node->next_inode;
 
-		new_node->next_inode = kmalloc(sizeof(struct stv0900_inode), GFP_KERNEL);
+		new_node->next_inode = kmalloc(sizeof(struct stv0900_inode),
+								GFP_KERNEL);
 		if (new_node->next_inode != NULL)
 			new_node = new_node->next_inode;
 		else
@@ -128,13 +129,13 @@ s32 ge2comp(s32 a, s32 width)
 		return (a >= (1 << (width - 1))) ? (a - (1 << width)) : a;
 }
 
-void stv0900_write_reg(struct stv0900_internal *i_params, u16 reg_addr,
+void stv0900_write_reg(struct stv0900_internal *intp, u16 reg_addr,
 								u8 reg_data)
 {
 	u8 data[3];
 	int ret;
 	struct i2c_msg i2cmsg = {
-		.addr  = i_params->i2c_addr,
+		.addr  = intp->i2c_addr,
 		.flags = 0,
 		.len   = 3,
 		.buf   = data,
@@ -144,33 +145,33 @@ void stv0900_write_reg(struct stv0900_internal *i_params, u16 reg_addr,
 	data[1] = LSB(reg_addr);
 	data[2] = reg_data;
 
-	ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
+	ret = i2c_transfer(intp->i2c_adap, &i2cmsg, 1);
 	if (ret != 1)
-		dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
+		dprintk("%s: i2c error %d\n", __func__, ret);
 }
 
-u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg)
+u8 stv0900_read_reg(struct stv0900_internal *intp, u16 reg)
 {
 	int ret;
 	u8 b0[] = { MSB(reg), LSB(reg) };
 	u8 buf = 0;
 	struct i2c_msg msg[] = {
 		{
-			.addr	= i_params->i2c_addr,
+			.addr	= intp->i2c_addr,
 			.flags	= 0,
 			.buf = b0,
 			.len = 2,
 		}, {
-			.addr	= i_params->i2c_addr,
+			.addr	= intp->i2c_addr,
 			.flags	= I2C_M_RD,
 			.buf = &buf,
 			.len = 1,
 		},
 	};
 
-	ret = i2c_transfer(i_params->i2c_adap, msg, 2);
+	ret = i2c_transfer(intp->i2c_adap, msg, 2);
 	if (ret != 2)
-		dprintk(KERN_ERR "%s: i2c error %d, reg[0x%02x]\n",
+		dprintk("%s: i2c error %d, reg[0x%02x]\n",
 				__func__, ret, reg);
 
 	return buf;
@@ -190,169 +191,165 @@ void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
 	(*pos) = (i - 1);
 }
 
-void stv0900_write_bits(struct stv0900_internal *i_params, u32 label, u8 val)
+void stv0900_write_bits(struct stv0900_internal *intp, u32 label, u8 val)
 {
 	u8 reg, mask, pos;
 
-	reg = stv0900_read_reg(i_params, (label >> 16) & 0xffff);
+	reg = stv0900_read_reg(intp, (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);
+	stv0900_write_reg(intp, (label >> 16) & 0xffff, reg);
 
 }
 
-u8 stv0900_get_bits(struct stv0900_internal *i_params, u32 label)
+u8 stv0900_get_bits(struct stv0900_internal *intp, u32 label)
 {
 	u8 val = 0xff;
 	u8 mask, pos;
 
 	extract_mask_pos(label, &mask, &pos);
 
-	val = stv0900_read_reg(i_params, label >> 16);
+	val = stv0900_read_reg(intp, label >> 16);
 	val = (val & mask) >> pos;
 
 	return val;
 }
 
-enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *i_params)
+enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
 {
 	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, 0x20);
-			stv0900_write_reg(i_params, R0900_P2_I2CRPT, 0x20);
-			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 (intp == NULL)
+		return STV0900_INVALID_HANDLE;
 
-			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]);
-			}
+	intp->chip_id = stv0900_read_reg(intp, R0900_MID);
 
-			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;
+	if (intp->errs != STV0900_NO_ERROR)
+		return intp->errs;
 
-	return error;
+	/*Startup sequence*/
+	stv0900_write_reg(intp, R0900_P1_DMDISTATE, 0x5c);
+	stv0900_write_reg(intp, R0900_P2_DMDISTATE, 0x5c);
+	msleep(3);
+	stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x6c);
+	stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x6f);
+	stv0900_write_reg(intp, R0900_P1_I2CRPT, 0x20);
+	stv0900_write_reg(intp, R0900_P2_I2CRPT, 0x20);
+	stv0900_write_reg(intp, R0900_NCOARSE, 0x13);
+	msleep(3);
+	stv0900_write_reg(intp, R0900_I2CCFG, 0x08);
 
+	switch (intp->clkmode) {
+	case 0:
+	case 2:
+		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20
+				| intp->clkmode);
+		break;
+	default:
+		/* preserve SELOSCI bit */
+		i = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL);
+		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | i);
+		break;
+	}
+
+	msleep(3);
+	for (i = 0; i < 181; i++)
+		stv0900_write_reg(intp, STV0900_InitVal[i][0],
+				STV0900_InitVal[i][1]);
+
+	if (stv0900_read_reg(intp, R0900_MID) >= 0x20) {
+		stv0900_write_reg(intp, R0900_TSGENERAL, 0x0c);
+		for (i = 0; i < 32; i++)
+			stv0900_write_reg(intp, STV0900_Cut20_AddOnVal[i][0],
+					STV0900_Cut20_AddOnVal[i][1]);
+	}
+
+	stv0900_write_reg(intp, R0900_P1_FSPYCFG, 0x6c);
+	stv0900_write_reg(intp, R0900_P2_FSPYCFG, 0x6c);
+
+	stv0900_write_reg(intp, R0900_P1_PDELCTRL2, 0x01);
+	stv0900_write_reg(intp, R0900_P2_PDELCTRL2, 0x21);
+
+	stv0900_write_reg(intp, R0900_P1_PDELCTRL3, 0x20);
+	stv0900_write_reg(intp, R0900_P2_PDELCTRL3, 0x20);
+
+	stv0900_write_reg(intp, R0900_TSTRES0, 0x80);
+	stv0900_write_reg(intp, R0900_TSTRES0, 0x00);
+
+	return STV0900_NO_ERROR;
 }
 
-u32 stv0900_get_mclk_freq(struct stv0900_internal *i_params, u32 ext_clk)
+u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, 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);
+	div = stv0900_get_bits(intp, F0900_M_DIV);
+	ad_div = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6);
 
 	mclk = (div + 1) * ext_clk / ad_div;
 
-	dprintk(KERN_INFO "%s: Calculated Mclk = %d\n", __func__, mclk);
+	dprintk("%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 stv0900_set_mclk(struct stv0900_internal *intp, 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);
+	dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk,
+			intp->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;
-		}
-	}
+	if (intp == NULL)
+		return STV0900_INVALID_HANDLE;
 
-	return error;
+	if (intp->errs)
+		return STV0900_I2C_ERROR;
+
+	clk_sel = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6);
+	m_div = ((clk_sel * mclk) / intp->quartz) - 1;
+	stv0900_write_bits(intp, F0900_M_DIV, m_div);
+	intp->mclk = stv0900_get_mclk_freq(intp,
+					intp->quartz);
+
+	/*Set the DiseqC frequency to 22KHz */
+	/*
+		Formula:
+		DiseqC_TX_Freq= MasterClock/(32*F22TX_Reg)
+		DiseqC_RX_Freq= MasterClock/(32*F22RX_Reg)
+	*/
+	m_div = intp->mclk / 704000;
+	stv0900_write_reg(intp, R0900_P1_F22TX, m_div);
+	stv0900_write_reg(intp, R0900_P1_F22RX, m_div);
+
+	stv0900_write_reg(intp, R0900_P2_F22TX, m_div);
+	stv0900_write_reg(intp, R0900_P2_F22RX, m_div);
+
+	if ((intp->errs))
+		return STV0900_I2C_ERROR;
+
+	return STV0900_NO_ERROR;
 }
 
-u32 stv0900_get_err_count(struct stv0900_internal *i_params, int cntr,
+u32 stv0900_get_err_count(struct stv0900_internal *intp, 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);
+		hsb = stv0900_get_bits(intp, ERR_CNT12);
+		msb = stv0900_get_bits(intp, ERR_CNT11);
+		lsb = stv0900_get_bits(intp, ERR_CNT10);
 		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);
+		hsb = stv0900_get_bits(intp, ERR_CNT22);
+		msb = stv0900_get_bits(intp, ERR_CNT21);
+		lsb = stv0900_get_bits(intp, ERR_CNT20);
 		break;
 	}
 
@@ -364,26 +361,22 @@ u32 stv0900_get_err_count(struct stv0900_internal *i_params, int cntr,
 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;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_demod_num demod = state->demod;
 
-	u32 fi2c;
-
-	dmd_reg(fi2c, F0900_P1_I2CT_ON, F0900_P2_I2CT_ON);
-
-	stv0900_write_bits(i_params, fi2c, enable);
+	stv0900_write_bits(intp, I2CT_ON, enable);
 
 	return 0;
 }
 
-static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params,
+static void stv0900_set_ts_parallel_serial(struct stv0900_internal *intp,
 					enum fe_stv0900_clock_type path1_ts,
 					enum fe_stv0900_clock_type path2_ts)
 {
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%s\n", __func__);
 
-	if (i_params->chip_id >= 0x20) {
+	if (intp->chip_id >= 0x20) {
 		switch (path1_ts) {
 		case STV0900_PARALLEL_PUNCT_CLOCK:
 		case STV0900_DVBCI_CLOCK:
@@ -391,20 +384,20 @@ static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params,
 			case STV0900_SERIAL_PUNCT_CLOCK:
 			case STV0900_SERIAL_CONT_CLOCK:
 			default:
-				stv0900_write_reg(i_params, R0900_TSGENERAL,
+				stv0900_write_reg(intp, R0900_TSGENERAL,
 							0x00);
 				break;
 			case STV0900_PARALLEL_PUNCT_CLOCK:
 			case STV0900_DVBCI_CLOCK:
-				stv0900_write_reg(i_params, R0900_TSGENERAL,
+				stv0900_write_reg(intp, R0900_TSGENERAL,
 							0x06);
-				stv0900_write_bits(i_params,
+				stv0900_write_bits(intp,
 						F0900_P1_TSFIFO_MANSPEED, 3);
-				stv0900_write_bits(i_params,
+				stv0900_write_bits(intp,
 						F0900_P2_TSFIFO_MANSPEED, 0);
-				stv0900_write_reg(i_params,
+				stv0900_write_reg(intp,
 						R0900_P1_TSSPEED, 0x14);
-				stv0900_write_reg(i_params,
+				stv0900_write_reg(intp,
 						R0900_P2_TSSPEED, 0x28);
 				break;
 			}
@@ -416,14 +409,14 @@ static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params,
 			case STV0900_SERIAL_PUNCT_CLOCK:
 			case STV0900_SERIAL_CONT_CLOCK:
 			default:
-				stv0900_write_reg(i_params,
+				stv0900_write_reg(intp,
 						R0900_TSGENERAL, 0x0C);
 				break;
 			case STV0900_PARALLEL_PUNCT_CLOCK:
 			case STV0900_DVBCI_CLOCK:
-				stv0900_write_reg(i_params,
+				stv0900_write_reg(intp,
 						R0900_TSGENERAL, 0x0A);
-				dprintk(KERN_INFO "%s: 0x0a\n", __func__);
+				dprintk("%s: 0x0a\n", __func__);
 				break;
 			}
 			break;
@@ -436,20 +429,20 @@ static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params,
 			case STV0900_SERIAL_PUNCT_CLOCK:
 			case STV0900_SERIAL_CONT_CLOCK:
 			default:
-				stv0900_write_reg(i_params, R0900_TSGENERAL1X,
+				stv0900_write_reg(intp, R0900_TSGENERAL1X,
 							0x10);
 				break;
 			case STV0900_PARALLEL_PUNCT_CLOCK:
 			case STV0900_DVBCI_CLOCK:
-				stv0900_write_reg(i_params, R0900_TSGENERAL1X,
+				stv0900_write_reg(intp, R0900_TSGENERAL1X,
 							0x16);
-				stv0900_write_bits(i_params,
+				stv0900_write_bits(intp,
 						F0900_P1_TSFIFO_MANSPEED, 3);
-				stv0900_write_bits(i_params,
+				stv0900_write_bits(intp,
 						F0900_P2_TSFIFO_MANSPEED, 0);
-				stv0900_write_reg(i_params, R0900_P1_TSSPEED,
+				stv0900_write_reg(intp, R0900_P1_TSSPEED,
 							0x14);
-				stv0900_write_reg(i_params, R0900_P2_TSSPEED,
+				stv0900_write_reg(intp, R0900_P2_TSSPEED,
 							0x28);
 				break;
 			}
@@ -462,14 +455,14 @@ static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params,
 			case STV0900_SERIAL_PUNCT_CLOCK:
 			case STV0900_SERIAL_CONT_CLOCK:
 			default:
-				stv0900_write_reg(i_params, R0900_TSGENERAL1X,
+				stv0900_write_reg(intp, R0900_TSGENERAL1X,
 							0x14);
 				break;
 			case STV0900_PARALLEL_PUNCT_CLOCK:
 			case STV0900_DVBCI_CLOCK:
-				stv0900_write_reg(i_params, R0900_TSGENERAL1X,
+				stv0900_write_reg(intp, R0900_TSGENERAL1X,
 							0x12);
-				dprintk(KERN_INFO "%s: 0x12\n", __func__);
+				dprintk("%s: 0x12\n", __func__);
 				break;
 			}
 
@@ -479,20 +472,20 @@ static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params,
 
 	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);
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00);
+		stv0900_write_bits(intp, 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);
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00);
+		stv0900_write_bits(intp, 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);
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01);
+		stv0900_write_bits(intp, 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);
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01);
+		stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x01);
 		break;
 	default:
 		break;
@@ -500,29 +493,29 @@ static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params,
 
 	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);
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00);
+		stv0900_write_bits(intp, 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);
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00);
+		stv0900_write_bits(intp, 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);
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01);
+		stv0900_write_bits(intp, 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);
+		stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01);
+		stv0900_write_bits(intp, 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);
+	stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1);
+	stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0);
+	stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1);
+	stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
 }
 
 void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
@@ -574,7 +567,7 @@ void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
 	}
 }
 
-static s32 stv0900_get_rf_level(struct stv0900_internal *i_params,
+static s32 stv0900_get_rf_level(struct stv0900_internal *intp,
 				const struct stv0900_table *lookup,
 				enum fe_stv0900_demod_num demod)
 {
@@ -584,45 +577,41 @@ static s32 stv0900_get_rf_level(struct stv0900_internal *i_params,
 		i,
 		rf_lvl = 0;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%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;
-		}
+	if ((lookup == NULL) || (lookup->size <= 0))
+		return 0;
 
-		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;
+	agc_gain = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
+				stv0900_get_bits(intp, AGCIQ_VALUE0));
 
-				if (INRANGE(lookup->table[imin].regval, agc_gain, lookup->table[i].regval))
-					imax = i;
-				else
-					imin = i;
-			}
+	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;
 
-			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;
+			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;
+		rf_lvl *= (lookup->table[imax].realval -
+				lookup->table[imin].realval);
+		rf_lvl /= (lookup->table[imax].regval -
+				lookup->table[imin].regval);
+		rf_lvl += 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);
+	dprintk("%s: RFLevel = %d\n", __func__, rf_lvl);
 
 	return rf_lvl;
 }
@@ -634,50 +623,51 @@ static int stv0900_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 	s32 rflevel = stv0900_get_rf_level(internal, &stv0900_rf,
 								state->demod);
 
-	*strength = (rflevel + 100) * (16383 / 105);
+	rflevel = (rflevel + 100) * (65535 / 70);
+	if (rflevel < 0)
+		rflevel = 0;
+
+	if (rflevel > 65535)
+		rflevel = 65535;
+
+	*strength = rflevel;
 
 	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;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_demod_num demod = state->demod;
 
-	s32 c_n = -100,
-		regval, imin, imax,
+	s32	c_n = -100,
+		regval,
+		imin,
+		imax,
 		i,
-		lock_flag_field,
 		noise_field1,
 		noise_field0;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%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);
+		noise_field1 = NOSPLHT_NORMED1;
+		noise_field0 = 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);
+		noise_field1 = NOSDATAT_NORMED1;
+		noise_field0 = NOSDATAT_NORMED0;
 	}
 
-	if (stv0900_get_bits(i_params, lock_flag_field)) {
+	if (stv0900_get_bits(intp, LOCK_DEFINITIF)) {
 		if ((lookup != NULL) && lookup->size) {
 			regval = 0;
 			msleep(5);
 			for (i = 0; i < 16; i++) {
-				regval += MAKEWORD(stv0900_get_bits(i_params,
+				regval += MAKEWORD(stv0900_get_bits(intp,
 								noise_field1),
-						stv0900_get_bits(i_params,
+						stv0900_get_bits(intp,
 								noise_field0));
 				msleep(1);
 			}
@@ -715,10 +705,9 @@ static s32 stv0900_carr_get_quality(struct dvb_frontend *fe,
 static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
 {
 	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *i_params = state->internal;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_demod_num demod = state->demod;
 	u8 err_val1, err_val0;
-	s32 err_field1, err_field0;
 	u32 header_err_val = 0;
 
 	*ucblocks = 0x0;
@@ -726,24 +715,14 @@ static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
 		/* DVB-S2 delineator errors count */
 
 		/* retreiving number for errnous headers */
-		dmd_reg(err_field0, R0900_P1_BBFCRCKO0,
-					R0900_P2_BBFCRCKO0);
-		dmd_reg(err_field1, R0900_P1_BBFCRCKO1,
-					R0900_P2_BBFCRCKO1);
-
-		err_val1 = stv0900_read_reg(i_params, err_field1);
-		err_val0 = stv0900_read_reg(i_params, err_field0);
-		header_err_val = (err_val1<<8) | err_val0;
+		err_val1 = stv0900_read_reg(intp, BBFCRCKO1);
+		err_val0 = stv0900_read_reg(intp, BBFCRCKO0);
+		header_err_val = (err_val1 << 8) | err_val0;
 
 		/* retreiving number for errnous packets */
-		dmd_reg(err_field0, R0900_P1_UPCRCKO0,
-					R0900_P2_UPCRCKO0);
-		dmd_reg(err_field1, R0900_P1_UPCRCKO1,
-					R0900_P2_UPCRCKO1);
-
-		err_val1 = stv0900_read_reg(i_params, err_field1);
-		err_val0 = stv0900_read_reg(i_params, err_field0);
-		*ucblocks = (err_val1<<8) | err_val0;
+		err_val1 = stv0900_read_reg(intp, UPCRCKO1);
+		err_val0 = stv0900_read_reg(intp, UPCRCKO0);
+		*ucblocks = (err_val1 << 8) | err_val0;
 		*ucblocks += header_err_val;
 	}
 
@@ -752,33 +731,27 @@ static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
 
 static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-	*snr = stv0900_carr_get_quality(fe,
+	s32 snrlcl = stv0900_carr_get_quality(fe,
 			(const struct stv0900_table *)&stv0900_s2_cn);
-	*snr += 30;
-	*snr *= (16383 / 1030);
+	snrlcl = (snrlcl + 30) * 384;
+	if (snrlcl < 0)
+		snrlcl = 0;
+
+	if (snrlcl > 65535)
+		snrlcl = 65535;
+
+	*snr = snrlcl;
 
 	return 0;
 }
 
-static u32 stv0900_get_ber(struct stv0900_internal *i_params,
+static u32 stv0900_get_ber(struct stv0900_internal *intp,
 				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);
+	demod_state = stv0900_get_bits(intp, HEADER_MODE);
 
 	switch (demod_state) {
 	case STV0900_SEARCH:
@@ -790,11 +763,11 @@ static u32 stv0900_get_ber(struct stv0900_internal *i_params,
 		ber = 0;
 		for (i = 0; i < 5; i++) {
 			msleep(5);
-			ber += stv0900_get_err_count(i_params, 0, demod);
+			ber += stv0900_get_err_count(intp, 0, demod);
 		}
 
 		ber /= 5;
-		if (stv0900_get_bits(i_params, prvit_field)) {
+		if (stv0900_get_bits(intp, PRFVIT)) {
 			ber *= 9766;
 			ber = ber >> 13;
 		}
@@ -804,11 +777,11 @@ static u32 stv0900_get_ber(struct stv0900_internal *i_params,
 		ber = 0;
 		for (i = 0; i < 5; i++) {
 			msleep(5);
-			ber += stv0900_get_err_count(i_params, 0, demod);
+			ber += stv0900_get_err_count(intp, 0, demod);
 		}
 
 		ber /= 5;
-		if (stv0900_get_bits(i_params, pdel_lock_field)) {
+		if (stv0900_get_bits(intp, PKTDELIN_LOCK)) {
 			ber *= 9766;
 			ber = ber >> 13;
 		}
@@ -829,20 +802,16 @@ static int stv0900_read_ber(struct dvb_frontend *fe, u32 *ber)
 	return 0;
 }
 
-int stv0900_get_demod_lock(struct stv0900_internal *i_params,
+int stv0900_get_demod_lock(struct stv0900_internal *intp,
 			enum fe_stv0900_demod_num demod, s32 time_out)
 {
 	s32 timer = 0,
-		lock = 0,
-		header_field,
-		lock_field;
+		lock = 0;
 
 	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);
+		dmd_state = stv0900_get_bits(intp, HEADER_MODE);
 		dprintk("Demod State = %d\n", dmd_state);
 		switch (dmd_state) {
 		case STV0900_SEARCH:
@@ -852,7 +821,7 @@ int stv0900_get_demod_lock(struct stv0900_internal *i_params,
 			break;
 		case STV0900_DVBS2_FOUND:
 		case STV0900_DVBS_FOUND:
-			lock = stv0900_get_bits(i_params, lock_field);
+			lock = stv0900_get_bits(intp, LOCK_DEFINITIF);
 			break;
 		}
 
@@ -870,56 +839,40 @@ int stv0900_get_demod_lock(struct stv0900_internal *i_params,
 	return lock;
 }
 
-void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params,
+void stv0900_stop_all_s2_modcod(struct stv0900_internal *intp,
 				enum fe_stv0900_demod_num demod)
 {
 	s32 regflist,
 	i;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%s\n", __func__);
 
-	dmd_reg(regflist, R0900_P1_MODCODLST0, R0900_P2_MODCODLST0);
+	regflist = MODCODLST0;
 
 	for (i = 0; i < 16; i++)
-		stv0900_write_reg(i_params, regflist + i, 0xff);
+		stv0900_write_reg(intp, regflist + i, 0xff);
 }
 
-void stv0900_activate_s2_modcode(struct stv0900_internal *i_params,
+void stv0900_activate_s2_modcod(struct stv0900_internal *intp,
 				enum fe_stv0900_demod_num demod)
 {
 	u32 matype,
-	mod_code,
-	fmod,
-	reg_index,
-	field_index;
+		mod_code,
+		fmod,
+		reg_index,
+		field_index;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%s\n", __func__);
 
-	if (i_params->chip_id <= 0x11) {
+	if (intp->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;
-		}
+		mod_code = stv0900_read_reg(intp, PLHMODCOD);
+		matype = mod_code & 0x3;
+		mod_code = (mod_code & 0x7f) >> 2;
 
+		reg_index = MODCODLSTF - mod_code / 2;
+		field_index = mod_code % 2;
 
 		switch (matype) {
 		case 0:
@@ -938,70 +891,41 @@ void stv0900_activate_s2_modcode(struct stv0900_internal *i_params,
 		}
 
 		if ((INRANGE(STV0900_QPSK_12, mod_code, STV0900_8PSK_910))
-							&& (matype <= 1)) {
+						&& (matype <= 1)) {
 			if (field_index == 0)
-				stv0900_write_reg(i_params, reg_index,
+				stv0900_write_reg(intp, reg_index,
 							0xf0 | fmod);
 			else
-				stv0900_write_reg(i_params, reg_index,
+				stv0900_write_reg(intp, 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);
+	} else if (intp->chip_id >= 0x12) {
+		for (reg_index = 0; reg_index < 7; reg_index++)
+			stv0900_write_reg(intp, MODCODLST0 + reg_index, 0xff);
 
-			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(intp, MODCODLSTE, 0xff);
+		stv0900_write_reg(intp, MODCODLSTF, 0xcf);
+		for (reg_index = 0; reg_index < 8; reg_index++)
+			stv0900_write_reg(intp, MODCODLST7 + reg_index, 0xcc);
 
-			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,
+void stv0900_activate_s2_modcod_single(struct stv0900_internal *intp,
 					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);
+	dprintk("%s\n", __func__);
 
-		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);
+	stv0900_write_reg(intp, MODCODLST0, 0xff);
+	stv0900_write_reg(intp, MODCODLST1, 0xf0);
+	stv0900_write_reg(intp, MODCODLSTF, 0x0f);
+	for (reg_index = 0; reg_index < 13; reg_index++)
+		stv0900_write_reg(intp, MODCODLST2 + reg_index, 0);
 
-		break;
-	}
 }
 
 static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe)
@@ -1012,7 +936,7 @@ static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe)
 static int stb0900_set_property(struct dvb_frontend *fe,
 				struct dtv_property *tvp)
 {
-	dprintk(KERN_INFO "%s(..)\n", __func__);
+	dprintk("%s(..)\n", __func__);
 
 	return 0;
 }
@@ -1020,166 +944,123 @@ static int stb0900_set_property(struct dvb_frontend *fe,
 static int stb0900_get_property(struct dvb_frontend *fe,
 				struct dtv_property *tvp)
 {
-	dprintk(KERN_INFO "%s(..)\n", __func__);
+	dprintk("%s(..)\n", __func__);
 
 	return 0;
 }
 
-void stv0900_start_search(struct stv0900_internal *i_params,
+void stv0900_start_search(struct stv0900_internal *intp,
 				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);
+	u32 freq;
+	s16 freq_s16 ;
+
+	stv0900_write_bits(intp, DEMOD_MODE, 0x1f);
+	if (intp->chip_id == 0x10)
+		stv0900_write_reg(intp, CORRELEXP, 0xaa);
+
+	if (intp->chip_id < 0x20)
+		stv0900_write_reg(intp, CARHDR, 0x55);
+
+	if (intp->chip_id <= 0x20) {
+		if (intp->symbol_rate[0] <= 5000000) {
+			stv0900_write_reg(intp, CARCFG, 0x44);
+			stv0900_write_reg(intp, CFRUP1, 0x0f);
+			stv0900_write_reg(intp, CFRUP0, 0xff);
+			stv0900_write_reg(intp, CFRLOW1, 0xf0);
+			stv0900_write_reg(intp, CFRLOW0, 0x00);
+			stv0900_write_reg(intp, 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(intp, CARCFG, 0xc4);
+			stv0900_write_reg(intp, RTCS2, 0x44);
 		}
 
-		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 { /*cut 3.0 above*/
+		if (intp->symbol_rate[demod] <= 5000000)
+			stv0900_write_reg(intp, RTCS2, 0x68);
+		else
+			stv0900_write_reg(intp, RTCS2, 0x44);
 
+		stv0900_write_reg(intp, CARCFG, 0x46);
+		if (intp->srch_algo[demod] == STV0900_WARM_START) {
+			freq = 1000 << 16;
+			freq /= (intp->mclk / 1000);
+			freq_s16 = (s16)freq;
 		} else {
-			if (i_params->dmd1_symbol_rate < 10000000)
-				stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xef);
+			freq = (intp->srch_range[demod] / 2000);
+			if (intp->symbol_rate[demod] <= 5000000)
+				freq += 80;
 			else
-				stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0xed);
-		}
+				freq += 600;
 
-		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);
+			freq = freq << 16;
+			freq /= (intp->mclk / 1000);
+			freq_s16 = (s16)freq;
 		}
 
-		stv0900_write_reg(i_params, R0900_P2_CFRINIT1, 0);
-		stv0900_write_reg(i_params, R0900_P2_CFRINIT0, 0);
+		stv0900_write_bits(intp, CFR_UP1, MSB(freq_s16));
+		stv0900_write_bits(intp, CFR_UP0, LSB(freq_s16));
+		freq_s16 *= (-1);
+		stv0900_write_bits(intp, CFR_LOW1, MSB(freq_s16));
+		stv0900_write_bits(intp, CFR_LOW0, LSB(freq_s16));
+	}
 
-		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(intp, CFRINIT1, 0);
+	stv0900_write_reg(intp, CFRINIT0, 0);
 
-		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 (intp->chip_id >= 0x20) {
+		stv0900_write_reg(intp, EQUALCFG, 0x41);
+		stv0900_write_reg(intp, FFECFG, 0x41);
 
-			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);
-			}
+		if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) ||
+			(intp->srch_standard[demod] == STV0900_SEARCH_DSS) ||
+			(intp->srch_standard[demod] == STV0900_AUTO_SEARCH)) {
+			stv0900_write_reg(intp, VITSCALE,
+								0x82);
+			stv0900_write_reg(intp, VAVSRVIT, 0x0);
+		}
+	}
 
+	stv0900_write_reg(intp, SFRSTEP, 0x00);
+	stv0900_write_reg(intp, TMGTHRISE, 0xe0);
+	stv0900_write_reg(intp, TMGTHFALL, 0xc0);
+	stv0900_write_bits(intp, SCAN_ENABLE, 0);
+	stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+	stv0900_write_bits(intp, S1S2_SEQUENTIAL, 0);
+	stv0900_write_reg(intp, RTC, 0x88);
+	if (intp->chip_id >= 0x20) {
+		if (intp->symbol_rate[demod] < 2000000) {
+			if (intp->chip_id <= 0x20)
+				stv0900_write_reg(intp, CARFREQ, 0x39);
+			else  /*cut 3.0*/
+				stv0900_write_reg(intp, CARFREQ, 0x89);
+
+			stv0900_write_reg(intp, CARHDR, 0x40);
+		} else if (intp->symbol_rate[demod] < 10000000) {
+			stv0900_write_reg(intp, CARFREQ, 0x4c);
+			stv0900_write_reg(intp, 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);
+			stv0900_write_reg(intp, CARFREQ, 0x4b);
+			stv0900_write_reg(intp, CARHDR, 0x20);
 		}
 
-		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;
-		}
+	} else {
+		if (intp->symbol_rate[demod] < 10000000)
+			stv0900_write_reg(intp, CARFREQ, 0xef);
+		else
+			stv0900_write_reg(intp, CARFREQ, 0xed);
+	}
 
+	switch (intp->srch_algo[demod]) {
+	case STV0900_WARM_START:
+		stv0900_write_reg(intp, DMDISTATE, 0x1f);
+		stv0900_write_reg(intp, DMDISTATE, 0x18);
+		break;
+	case STV0900_COLD_START:
+		stv0900_write_reg(intp, DMDISTATE, 0x1f);
+		stv0900_write_reg(intp, DMDISTATE, 0x15);
+		break;
+	default:
 		break;
 	}
 }
@@ -1188,33 +1069,40 @@ 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;
+	s32 i;
+	const struct stv0900_car_loop_optim *cls2, *cllqs2, *cllas2;
+
+	dprintk("%s\n", __func__);
+
+	if (chip_id <= 0x12) {
+		cls2 = FE_STV0900_S2CarLoop;
+		cllqs2 = FE_STV0900_S2LowQPCarLoopCut30;
+		cllas2 = FE_STV0900_S2APSKCarLoopCut30;
+	} else if (chip_id == 0x20) {
+		cls2 = FE_STV0900_S2CarLoopCut20;
+		cllqs2 = FE_STV0900_S2LowQPCarLoopCut20;
+		cllas2 = FE_STV0900_S2APSKCarLoopCut20;
+	} else {
+		cls2 = FE_STV0900_S2CarLoopCut30;
+		cllqs2 = FE_STV0900_S2LowQPCarLoopCut30;
+		cllas2 = FE_STV0900_S2APSKCarLoopCut30;
+	}
 
 	if (modcode < STV0900_QPSK_12) {
 		i = 0;
-		while ((i < 3) && (modcode != FE_STV0900_S2LowQPCarLoopCut20[i].modcode))
+		while ((i < 3) && (modcode != cllqs2[i].modcode))
 			i++;
 
 		if (i >= 3)
 			i = 2;
 	} else {
 		i = 0;
-		while ((i < 14) && (modcode != car_loop_s2[i].modcode))
+		while ((i < 14) && (modcode != cls2[i].modcode))
 			i++;
 
 		if (i >= 14) {
 			i = 0;
-			while ((i < 11) && (modcode != FE_STV0900_S2APSKCarLoopCut20[i].modcode))
+			while ((i < 11) && (modcode != cllas2[i].modcode))
 				i++;
 
 			if (i >= 11)
@@ -1225,76 +1113,82 @@ u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode,
 	if (modcode <= STV0900_QPSK_25) {
 		if (pilot) {
 			if (srate <= 3000000)
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_2;
+				aclc_value = cllqs2[i].car_loop_pilots_on_2;
 			else if (srate <= 7000000)
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_5;
+				aclc_value = cllqs2[i].car_loop_pilots_on_5;
 			else if (srate <= 15000000)
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_10;
+				aclc_value = cllqs2[i].car_loop_pilots_on_10;
 			else if (srate <= 25000000)
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_20;
+				aclc_value = cllqs2[i].car_loop_pilots_on_20;
 			else
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_on_30;
+				aclc_value = cllqs2[i].car_loop_pilots_on_30;
 		} else {
 			if (srate <= 3000000)
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_2;
+				aclc_value = cllqs2[i].car_loop_pilots_off_2;
 			else if (srate <= 7000000)
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_5;
+				aclc_value = cllqs2[i].car_loop_pilots_off_5;
 			else if (srate <= 15000000)
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_10;
+				aclc_value = cllqs2[i].car_loop_pilots_off_10;
 			else if (srate <= 25000000)
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_20;
+				aclc_value = cllqs2[i].car_loop_pilots_off_20;
 			else
-				aclc_value = FE_STV0900_S2LowQPCarLoopCut20[i].car_loop_pilots_off_30;
+				aclc_value = cllqs2[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;
+				aclc_value = cls2[i].car_loop_pilots_on_2;
 			else if (srate <= 7000000)
-				aclc_value = car_loop_s2[i].car_loop_pilots_on_5;
+				aclc_value = cls2[i].car_loop_pilots_on_5;
 			else if (srate <= 15000000)
-				aclc_value = car_loop_s2[i].car_loop_pilots_on_10;
+				aclc_value = cls2[i].car_loop_pilots_on_10;
 			else if (srate <= 25000000)
-				aclc_value = car_loop_s2[i].car_loop_pilots_on_20;
+				aclc_value = cls2[i].car_loop_pilots_on_20;
 			else
-				aclc_value = car_loop_s2[i].car_loop_pilots_on_30;
+				aclc_value = cls2[i].car_loop_pilots_on_30;
 		} else {
 			if (srate <= 3000000)
-				aclc_value = car_loop_s2[i].car_loop_pilots_off_2;
+				aclc_value = cls2[i].car_loop_pilots_off_2;
 			else if (srate <= 7000000)
-				aclc_value = car_loop_s2[i].car_loop_pilots_off_5;
+				aclc_value = cls2[i].car_loop_pilots_off_5;
 			else if (srate <= 15000000)
-				aclc_value = car_loop_s2[i].car_loop_pilots_off_10;
+				aclc_value = cls2[i].car_loop_pilots_off_10;
 			else if (srate <= 25000000)
-				aclc_value = car_loop_s2[i].car_loop_pilots_off_20;
+				aclc_value = cls2[i].car_loop_pilots_off_20;
 			else
-				aclc_value = car_loop_s2[i].car_loop_pilots_off_30;
+				aclc_value = cls2[i].car_loop_pilots_off_30;
 		}
 
 	} else {
 		if (srate <= 3000000)
-			aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_2;
+			aclc_value = cllas2[i].car_loop_pilots_on_2;
 		else if (srate <= 7000000)
-			aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_5;
+			aclc_value = cllas2[i].car_loop_pilots_on_5;
 		else if (srate <= 15000000)
-			aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_10;
+			aclc_value = cllas2[i].car_loop_pilots_on_10;
 		else if (srate <= 25000000)
-			aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_20;
+			aclc_value = cllas2[i].car_loop_pilots_on_20;
 		else
-			aclc_value = FE_STV0900_S2APSKCarLoopCut20[i].car_loop_pilots_on_30;
+			aclc_value = cllas2[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)
+u8 stv0900_get_optim_short_carr_loop(s32 srate,
+				enum fe_stv0900_modulation modulation,
+				u8 chip_id)
 {
+	const struct stv0900_short_frames_car_loop_optim *s2scl;
+	const struct stv0900_short_frames_car_loop_optim_vs_mod *s2sclc30;
 	s32 mod_index = 0;
-
 	u8 aclc_value = 0x0b;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%s\n", __func__);
+
+	s2scl = FE_STV0900_S2ShortCarLoop;
+	s2sclc30 = FE_STV0900_S2ShortCarLoopCut30;
 
 	switch (modulation) {
 	case STV0900_QPSK:
@@ -1312,75 +1206,116 @@ u8 stv0900_get_optim_short_carr_loop(s32 srate, enum fe_stv0900_modulation modul
 		break;
 	}
 
-	switch (chip_id) {
-	case 0x20:
+	if (chip_id >= 0x30) {
 		if (srate <= 3000000)
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_2;
+			aclc_value = s2sclc30[mod_index].car_loop_2;
 		else if (srate <= 7000000)
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_5;
+			aclc_value = s2sclc30[mod_index].car_loop_5;
 		else if (srate <= 15000000)
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_10;
+			aclc_value = s2sclc30[mod_index].car_loop_10;
 		else if (srate <= 25000000)
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_20;
+			aclc_value = s2sclc30[mod_index].car_loop_20;
 		else
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut20_30;
+			aclc_value = s2sclc30[mod_index].car_loop_30;
 
-		break;
-	case 0x12:
-	default:
+	} else if (chip_id >= 0x20) {
 		if (srate <= 3000000)
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_2;
+			aclc_value = s2scl[mod_index].car_loop_cut20_2;
 		else if (srate <= 7000000)
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_5;
+			aclc_value = s2scl[mod_index].car_loop_cut20_5;
 		else if (srate <= 15000000)
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_10;
+			aclc_value = s2scl[mod_index].car_loop_cut20_10;
 		else if (srate <= 25000000)
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_20;
+			aclc_value = s2scl[mod_index].car_loop_cut20_20;
 		else
-			aclc_value = FE_STV0900_S2ShortCarLoop[mod_index].car_loop_cut12_30;
+			aclc_value = s2scl[mod_index].car_loop_cut20_30;
+
+	} else {
+		if (srate <= 3000000)
+			aclc_value = s2scl[mod_index].car_loop_cut12_2;
+		else if (srate <= 7000000)
+			aclc_value = s2scl[mod_index].car_loop_cut12_5;
+		else if (srate <= 15000000)
+			aclc_value = s2scl[mod_index].car_loop_cut12_10;
+		else if (srate <= 25000000)
+			aclc_value = s2scl[mod_index].car_loop_cut12_20;
+		else
+			aclc_value = s2scl[mod_index].car_loop_cut12_30;
 
-		break;
 	}
 
 	return aclc_value;
 }
 
-static enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *i_params,
+static
+enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp,
 					enum fe_stv0900_demod_mode LDPC_Mode,
 					enum fe_stv0900_demod_num demod)
 {
 	enum fe_stv0900_error error = STV0900_NO_ERROR;
+	s32 reg_ind;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%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);
+		if ((intp->demod_mode != STV0900_DUAL)
+			|| (stv0900_get_bits(intp, F0900_DDEMOD) != 1)) {
+			stv0900_write_reg(intp, R0900_GENCFG, 0x1d);
+
+			intp->demod_mode = STV0900_DUAL;
+
+			stv0900_write_bits(intp, F0900_FRESFEC, 1);
+			stv0900_write_bits(intp, F0900_FRESFEC, 0);
+
+			for (reg_ind = 0; reg_ind < 7; reg_ind++)
+				stv0900_write_reg(intp,
+						R0900_P1_MODCODLST0 + reg_ind,
+						0xff);
+			for (reg_ind = 0; reg_ind < 8; reg_ind++)
+				stv0900_write_reg(intp,
+						R0900_P1_MODCODLST7 + reg_ind,
+						0xcc);
+
+			stv0900_write_reg(intp, R0900_P1_MODCODLSTE, 0xff);
+			stv0900_write_reg(intp, R0900_P1_MODCODLSTF, 0xcf);
+
+			for (reg_ind = 0; reg_ind < 7; reg_ind++)
+				stv0900_write_reg(intp,
+						R0900_P2_MODCODLST0 + reg_ind,
+						0xff);
+			for (reg_ind = 0; reg_ind < 8; reg_ind++)
+				stv0900_write_reg(intp,
+						R0900_P2_MODCODLST7 + reg_ind,
+						0xcc);
+
+			stv0900_write_reg(intp, R0900_P2_MODCODLSTE, 0xff);
+			stv0900_write_reg(intp, R0900_P2_MODCODLSTF, 0xcf);
 		}
 
 		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);
+		if (demod == STV0900_DEMOD_2) {
+			stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_1);
+			stv0900_activate_s2_modcod_single(intp,
+							STV0900_DEMOD_2);
+			stv0900_write_reg(intp, R0900_GENCFG, 0x06);
+		} else {
+			stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_2);
+			stv0900_activate_s2_modcod_single(intp,
+							STV0900_DEMOD_1);
+			stv0900_write_reg(intp, R0900_GENCFG, 0x04);
+		}
 
-		i_params->demod_mode = STV0900_SINGLE;
+		intp->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);
+		stv0900_write_bits(intp, F0900_FRESFEC, 1);
+		stv0900_write_bits(intp, F0900_FRESFEC, 0);
+		stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 1);
+		stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 0);
+		stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 1);
+		stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 0);
 		break;
 	}
 
@@ -1393,131 +1328,131 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
 	struct stv0900_state *state = fe->demodulator_priv;
 	enum fe_stv0900_error error = STV0900_NO_ERROR;
 	enum fe_stv0900_error demodError = STV0900_NO_ERROR;
+	struct stv0900_internal *intp = NULL;
+
 	int selosci, i;
 
 	struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
 						state->config->demod_address);
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%s\n", __func__);
 
-	if (temp_int != NULL) {
+	if ((temp_int != NULL) && (p_init->demod_mode == STV0900_DUAL)) {
 		state->internal = temp_int->internal;
 		(state->internal->dmds_used)++;
-		dprintk(KERN_INFO "%s: Find Internal Structure!\n", __func__);
+		dprintk("%s: Find Internal Structure!\n", __func__);
 		return STV0900_NO_ERROR;
 	} else {
-		state->internal = kmalloc(sizeof(struct stv0900_internal), GFP_KERNEL);
+		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__);
+		dprintk("%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) {
+		error = STV0900_INVALID_HANDLE;
+		return 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);
-
-				state->internal->ts_config = p_init->ts_config;
-				if (state->internal->ts_config == NULL)
-					stv0900_set_ts_parallel_serial(state->internal,
-							p_init->path1_ts_clock,
-							p_init->path2_ts_clock);
-				else {
-					for (i = 0; state->internal->ts_config[i].addr != 0xffff; i++)
-						stv0900_write_reg(state->internal,
-								state->internal->ts_config[i].addr,
-								state->internal->ts_config[i].val);
-
-					stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 1);
-					stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 0);
-					stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 1);
-					stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 0);
-				}
+	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;
 
-				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;
-				}
+		return error;
+	}
 
-				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;
-				}
+	if (state->internal == NULL) {
+		error = STV0900_INVALID_HANDLE;
+		return error;
+	}
 
-				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);
+	intp = state->internal;
 
-				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;
-		}
+	intp->demod_mode = p_init->demod_mode;
+	stv0900_st_dvbs2_single(intp, intp->demod_mode,	STV0900_DEMOD_1);
+	intp->chip_id = stv0900_read_reg(intp, R0900_MID);
+	intp->rolloff = p_init->rolloff;
+	intp->quartz = p_init->dmd_ref_clk;
+
+	stv0900_write_bits(intp, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff);
+	stv0900_write_bits(intp, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff);
+
+	intp->ts_config = p_init->ts_config;
+	if (intp->ts_config == NULL)
+		stv0900_set_ts_parallel_serial(intp,
+				p_init->path1_ts_clock,
+				p_init->path2_ts_clock);
+	else {
+		for (i = 0; intp->ts_config[i].addr != 0xffff; i++)
+			stv0900_write_reg(intp,
+					intp->ts_config[i].addr,
+					intp->ts_config[i].val);
+
+		stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1);
+		stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0);
+		stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1);
+		stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
+	}
+
+	stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
+	switch (p_init->tuner1_adc) {
+	case 1:
+		stv0900_write_reg(intp, R0900_TSTTNR1, 0x26);
+		break;
+	default:
+		break;
+	}
+
+	stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
+	switch (p_init->tuner2_adc) {
+	case 1:
+		stv0900_write_reg(intp, R0900_TSTTNR3, 0x26);
+		break;
+	default:
+		break;
+	}
+
+	stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv);
+	stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv);
+	stv0900_set_mclk(intp, 135000000);
+	msleep(3);
+
+	switch (intp->clkmode) {
+	case 0:
+	case 2:
+		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | intp->clkmode);
+		break;
+	default:
+		selosci = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL);
+		stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | selosci);
+		break;
 	}
+	msleep(3);
+
+	intp->mclk = stv0900_get_mclk_freq(intp, intp->quartz);
+	if (intp->errs)
+		error = STV0900_I2C_ERROR;
 
 	return error;
 }
 
-static int stv0900_status(struct stv0900_internal *i_params,
+static int stv0900_status(struct stv0900_internal *intp,
 					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);
+	demod_state = stv0900_get_bits(intp, HEADER_MODE);
 	switch (demod_state) {
 	case STV0900_SEARCH:
 	case STV0900_PLH_DETECTED:
@@ -1525,17 +1460,19 @@ static int stv0900_status(struct stv0900_internal *i_params,
 		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);
+		locked = stv0900_get_bits(intp, LOCK_DEFINITIF) &&
+				stv0900_get_bits(intp, PKTDELIN_LOCK) &&
+				stv0900_get_bits(intp, TSFIFO_LINEOK);
 		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);
+		locked = stv0900_get_bits(intp, LOCK_DEFINITIF) &&
+				stv0900_get_bits(intp, LOCKEDVIT) &&
+				stv0900_get_bits(intp, TSFIFO_LINEOK);
 		break;
 	}
 
+	dprintk("%s: locked = %d\n", __func__, locked);
+
 	return locked;
 }
 
@@ -1543,7 +1480,8 @@ 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 stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
 	struct stv0900_search_params p_search;
@@ -1551,10 +1489,16 @@ static enum dvbfe_search stv0900_search(struct dvb_frontend *fe,
 
 	enum fe_stv0900_error error = STV0900_NO_ERROR;
 
-	dprintk(KERN_INFO "%s: ", __func__);
+	dprintk("%s: ", __func__);
+
+	if (!(INRANGE(100000, c->symbol_rate, 70000000)))
+		return DVBFE_ALGO_SEARCH_FAILED;
+
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
 
 	p_result.locked = FALSE;
-	p_search.path = state->demod;
+	p_search.path = demod;
 	p_search.frequency = c->frequency;
 	p_search.symbol_rate = c->symbol_rate;
 	p_search.search_range = 10000000;
@@ -1563,103 +1507,47 @@ static enum dvbfe_search stv0900_search(struct dvb_frontend *fe,
 	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;
+	intp->srch_standard[demod] = p_search.standard;
+	intp->symbol_rate[demod] = p_search.symbol_rate;
+	intp->srch_range[demod] = p_search.search_range;
+	intp->freq[demod] = p_search.frequency;
+	intp->srch_algo[demod] = p_search.search_algo;
+	intp->srch_iq_inv[demod] = p_search.iq_inversion;
+	intp->fec[demod] = p_search.fec;
+	if ((stv0900_algo(fe) == STV0900_RANGEOK) &&
+				(intp->errs == STV0900_NO_ERROR)) {
+		p_result.locked = intp->result[demod].locked;
+		p_result.standard = intp->result[demod].standard;
+		p_result.frequency = intp->result[demod].frequency;
+		p_result.symbol_rate = intp->result[demod].symbol_rate;
+		p_result.fec = intp->result[demod].fec;
+		p_result.modcode = intp->result[demod].modcode;
+		p_result.pilot = intp->result[demod].pilot;
+		p_result.frame_len = intp->result[demod].frame_len;
+		p_result.spectrum = intp->result[demod].spectrum;
+		p_result.rolloff = intp->result[demod].rolloff;
+		p_result.modulation = intp->result[demod].modulation;
+	} else {
+		p_result.locked = FALSE;
+		switch (intp->err[demod]) {
+		case STV0900_I2C_ERROR:
+			error = STV0900_I2C_ERROR;
 			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;
+		case STV0900_NO_ERROR:
+		default:
+			error = STV0900_SEARCH_FAILED;
 			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");
+		dprintk("Search Success\n");
 		return DVBFE_ALGO_SEARCH_SUCCESS;
 	} else {
-		dprintk(KERN_INFO "Search Fail\n");
+		dprintk("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)
@@ -1690,16 +1578,13 @@ 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;
+	struct stv0900_internal *intp = 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);
+		stv0900_write_bits(intp, RST_HWARE, 1);
 	else
-		stv0900_write_bits(i_params, rst_field, 0);
+		stv0900_write_bits(intp, RST_HWARE, 0);
 
 	return 0;
 }
@@ -1707,23 +1592,19 @@ static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts)
 static int stv0900_diseqc_init(struct dvb_frontend *fe)
 {
 	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *i_params = state->internal;
+	struct stv0900_internal *intp = 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);
+	stv0900_write_bits(intp, DISTX_MODE, state->config->diseqc_mode);
+	stv0900_write_bits(intp, DISEQC_RESET, 1);
+	stv0900_write_bits(intp, DISEQC_RESET, 0);
 
 	return 0;
 }
 
 static int stv0900_init(struct dvb_frontend *fe)
 {
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%s\n", __func__);
 
 	stv0900_stop_ts(fe, 1);
 	stv0900_diseqc_init(fe);
@@ -1731,48 +1612,24 @@ static int stv0900_init(struct dvb_frontend *fe)
 	return 0;
 }
 
-static int stv0900_diseqc_send(struct stv0900_internal *i_params , u8 *Data,
+static int stv0900_diseqc_send(struct stv0900_internal *intp , 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++;
-		}
+	stv0900_write_bits(intp, DIS_PRECHARGE, 1);
+	while (i < NbData) {
+		while (stv0900_get_bits(intp, FIFO_FULL))
+			;/* checkpatch complains */
+		stv0900_write_reg(intp, DISTXDATA, data[i]);
+		i++;
+	}
 
-		break;
+	stv0900_write_bits(intp, DIS_PRECHARGE, 0);
+	i = 0;
+	while ((stv0900_get_bits(intp, TX_IDLE) != 1) && (i < 10)) {
+		msleep(10);
+		i++;
 	}
 
 	return 0;
@@ -1792,22 +1649,21 @@ static int stv0900_send_master_cmd(struct dvb_frontend *fe,
 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;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_demod_num demod = state->demod;
-	s32 mode_field;
-	u32 diseqc_fifo;
+	u8 data;
 
-	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);
+		stv0900_write_bits(intp, DISTX_MODE, 3);/* Unmodulated */
+		data = 0x00;
+		stv0900_diseqc_send(intp, &data, 1, state->demod);
 		break;
 	case SEC_MINI_B:
-		stv0900_write_bits(i_params, mode_field, 2);/* Modulated */
-		stv0900_write_reg(i_params, diseqc_fifo, 0xff);
+		stv0900_write_bits(intp, DISTX_MODE, 2);/* Modulated */
+		data = 0xff;
+		stv0900_diseqc_send(intp, &data, 1, state->demod);
 		break;
 	}
 
@@ -1818,68 +1674,54 @@ 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;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
 	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;
+	reply->msg_len = 0;
 
-		while ((stv0900_get_bits(i_params, F0900_P2_RX_END) != 1) && (i < 10)) {
-			msleep(10);
-			i++;
-		}
+	while ((stv0900_get_bits(intp, 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);
+	if (stv0900_get_bits(intp, RX_END)) {
+		reply->msg_len = stv0900_get_bits(intp, FIFO_BYTENBR);
 
-			for (i = 0; i < reply->msg_len; i++)
-				reply->msg[i] = stv0900_read_reg(i_params, R0900_P2_DISRXDATA);
-		}
-		break;
+		for (i = 0; i < reply->msg_len; i++)
+			reply->msg[i] = stv0900_read_reg(intp, DISRXDATA);
 	}
 
 	return 0;
 }
 
-static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t toneoff)
 {
 	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *i_params = state->internal;
+	struct stv0900_internal *intp = 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);
+	dprintk("%s: %s\n", __func__, ((toneoff == 0) ? "On" : "Off"));
 
-	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);
+	switch (toneoff) {
+	case SEC_TONE_ON:
+		/*Set the DiseqC mode to 22Khz _continues_ tone*/
+		stv0900_write_bits(intp, DISTX_MODE, 0);
+		stv0900_write_bits(intp, DISEQC_RESET, 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);
+		stv0900_write_bits(intp, DISEQC_RESET, 0);
+		break;
+	case SEC_TONE_OFF:
+		/*return diseqc mode to config->diseqc_mode.
+		Usually it's without _continues_ tone */
+		stv0900_write_bits(intp, DISTX_MODE,
+				state->config->diseqc_mode);
 		/*maintain the DiseqC reset to disable the 22KHz tone*/
-		stv0900_write_bits(i_params, reset_field, 1);
+		stv0900_write_bits(intp, DISEQC_RESET, 1);
+		stv0900_write_bits(intp, DISEQC_RESET, 0);
+		break;
+	default:
+		return -EINVAL;
 	}
 
 	return 0;
@@ -1889,11 +1731,11 @@ static void stv0900_release(struct dvb_frontend *fe)
 {
 	struct stv0900_state *state = fe->demodulator_priv;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%s\n", __func__);
 
 	if ((--(state->internal->dmds_used)) <= 0) {
 
-		dprintk(KERN_INFO "%s: Actually removing\n", __func__);
+		dprintk("%s: Actually removing\n", __func__);
 
 		remove_inode(state->internal);
 		kfree(state->internal);
@@ -1963,17 +1805,17 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
 	case 0:
 	case 1:
 		init_params.dmd_ref_clk  	= config->xtal;
-		init_params.demod_mode		= STV0900_DUAL;
+		init_params.demod_mode		= config->demod_mode;
 		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.tun1_iq_inv		= STV0900_IQ_NORMAL;
 		init_params.tuner1_adc		= config->tun1_adc;
 		init_params.path2_ts_clock	= config->path2_mode;
 		init_params.ts_config		= config->ts_config_regs;
 		init_params.tun2_maddress	= config->tun2_maddress;
 		init_params.tuner2_adc		= config->tun2_adc;
-		init_params.tun2_iq_inversion	= STV0900_IQ_SWAPPED;
+		init_params.tun2_iq_inv		= STV0900_IQ_SWAPPED;
 
 		err_stv0900 = stv0900_init_internal(&state->frontend,
 							&init_params);
diff --git a/drivers/media/dvb/frontends/stv0900_init.h b/drivers/media/dvb/frontends/stv0900_init.h
index ff388b47a4e3..b684df9995d8 100644
--- a/drivers/media/dvb/frontends/stv0900_init.h
+++ b/drivers/media/dvb/frontends/stv0900_init.h
@@ -141,85 +141,228 @@ struct stv0900_short_frames_car_loop_optim {
 
 };
 
+struct stv0900_short_frames_car_loop_optim_vs_mod {
+	enum fe_stv0900_modulation modulation;
+	u8 car_loop_2;	  /* SR<3msps      */
+	u8 car_loop_5;	  /* 3<SR<=7msps   */
+	u8 car_loop_10;   /* 7<SR<=15msps  */
+	u8 car_loop_20;   /* 10<SR<=25msps */
+	u8 car_loop_30;   /* 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 }
+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 }
+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 }
+	/* 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 }
+	/* 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
+struct stv0900_short_frames_car_loop_optim FE_STV0900_S2ShortCarLoop[4] = {
+	/*Mod		2Mcut1.2 2Mcut2.0 5Mcut1.2 5Mcut2.0 10Mcut1.2
+			10Mcut2.0 20Mcut1.2 20M_cut2.0 30Mcut1.2 30Mcut2.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 struct stv0900_car_loop_optim FE_STV0900_S2CarLoopCut30[14] = {
+	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff	*/
+	{ STV0900_QPSK_12,	0x3C,	0x2C,	0x0C,	0x2C,	0x1B,
+				0x2C,	0x1B,	0x1C,	0x0B, 	0x3B },
+	{ STV0900_QPSK_35,	0x0D,	0x0D,	0x0C,	0x0D,	0x1B,
+				0x3C,	0x1B,	0x1C,	0x0B,	0x3B },
+	{ STV0900_QPSK_23,	0x1D,	0x0D,	0x0C,	0x1D,	0x2B,
+				0x3C,	0x1B,	0x1C,	0x0B,	0x3B },
+	{ STV0900_QPSK_34,	0x1D,	0x1D,	0x0C,	0x1D,	0x2B,
+				0x3C,	0x1B,	0x1C,	0x0B,	0x3B },
+	{ STV0900_QPSK_45,	0x2D,	0x1D,	0x1C,	0x1D,	0x2B,
+				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
+	{ STV0900_QPSK_56,	0x2D,	0x1D,	0x1C,	0x1D,	0x2B,
+				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
+	{ STV0900_QPSK_89,	0x3D,	0x2D,	0x1C,	0x1D,	0x3B,
+				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
+	{ STV0900_QPSK_910,	0x3D,	0x2D,	0x1C,	0x1D,	0x3B,
+				0x3C,	0x2B,	0x0C,	0x1B,	0x3B },
+	{ STV0900_8PSK_35,	0x39,	0x19,	0x39,	0x19,	0x19,
+				0x19,	0x19,	0x19,	0x09,	0x19 },
+	{ STV0900_8PSK_23,	0x2A,	0x39,	0x1A,	0x0A,	0x39,
+				0x0A,	0x29,	0x39,	0x29,	0x0A },
+	{ STV0900_8PSK_34,	0x0B,	0x3A,	0x0B,	0x0B,	0x3A,
+				0x1B,	0x1A,	0x0B,	0x1A,	0x3A },
+	{ STV0900_8PSK_56,	0x0C,	0x1B,	0x3B,	0x2B,	0x1B,
+				0x3B,	0x3A,	0x3B,	0x3A,	0x1B },
+	{ STV0900_8PSK_89,	0x2C,	0x2C,	0x2C,	0x1C,	0x2B,
+				0x0C,	0x0B,	0x3B,	0x0B,	0x1B },
+	{ STV0900_8PSK_910,	0x2C,	0x3C,	0x2C,	0x1C,	0x3B,
+				0x1C,	0x0B,	0x3B,	0x0B,	0x1B }
+};
+
+static	const
+struct stv0900_car_loop_optim FE_STV0900_S2APSKCarLoopCut30[11] = {
+	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff	*/
+	{ STV0900_16APSK_23,	0x0A,	0x0A,	0x0A,	0x0A,	0x1A,
+				0x0A,	0x3A,	0x0A,	0x2A,	0x0A },
+	{ STV0900_16APSK_34,	0x0A,	0x0A,	0x0A,	0x0A,	0x0B,
+				0x0A,	0x3B,	0x0A,	0x1B,	0x0A },
+	{ STV0900_16APSK_45,	0x0A,	0x0A,	0x0A,	0x0A,	0x1B,
+				0x0A,	0x3B,	0x0A,	0x2B,	0x0A },
+	{ STV0900_16APSK_56,	0x0A,	0x0A,	0x0A,	0x0A,	0x1B,
+				0x0A,	0x3B,	0x0A,	0x2B,	0x0A },
+	{ STV0900_16APSK_89,	0x0A,	0x0A,	0x0A,	0x0A,	0x2B,
+				0x0A,	0x0C,	0x0A,	0x3B,	0x0A },
+	{ STV0900_16APSK_910,	0x0A,	0x0A,	0x0A,	0x0A,	0x2B,
+				0x0A,	0x0C,	0x0A,	0x3B,	0x0A },
+	{ STV0900_32APSK_34,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
+	{ STV0900_32APSK_45,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
+	{ STV0900_32APSK_56,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
+	{ STV0900_32APSK_89,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A },
+	{ STV0900_32APSK_910,	0x0A,	0x0A,	0x0A,	0x0A,	0x0A,
+				0x0A,	0x0A,	0x0A,	0x0A,	0x0A }
+};
+
+static	const
+struct stv0900_car_loop_optim FE_STV0900_S2LowQPCarLoopCut30[3] = {
+	/*Modcod		2MPon 	2MPoff	5MPon 	5MPoff	10MPon
+				10MPoff	20MPon 	20MPoff	30MPon 	30MPoff*/
+	{ STV0900_QPSK_14,	0x0C,	0x3C,	0x0B,	0x3C,	0x2A,
+				0x2C,	0x2A,	0x1C,	0x3A,	0x3B },
+	{ STV0900_QPSK_13,	0x0C,	0x3C,	0x0B,	0x3C,	0x2A,
+				0x2C,	0x3A,	0x0C,	0x3A,	0x2B },
+	{ STV0900_QPSK_25,	0x1C,	0x3C,	0x1B,	0x3C,	0x3A,
+				0x1C,	0x3A,	0x3B,	0x3A,	0x2B }
+};
+
+static	const struct stv0900_short_frames_car_loop_optim_vs_mod
+FE_STV0900_S2ShortCarLoopCut30[4] = {
+	/*Mod		2Mcut3.0 5Mcut3.0 10Mcut3.0 20Mcut3.0 30Mcut3.0*/
+	{ STV0900_QPSK,		0x2C,	0x2B,	0x0B,	0x0B,	0x3A },
+	{ STV0900_8PSK,		0x3B,	0x0B,	0x2A,	0x0A,	0x39 },
+	{ STV0900_16APSK,	0x1B,	0x1B,	0x1B,	0x3A,	0x2A },
+	{ STV0900_32APSK,	0x1B,	0x1B,	0x1B,	0x3A,	0x2A },
+
 };
 
-static const u16 STV0900_InitVal[182][2] = {
+static const u16 STV0900_InitVal[181][2] = {
 	{ R0900_OUTCFG		, 0x00	},
-	{ R0900_MODECFG		, 0xff	},
 	{ R0900_AGCRF1CFG	, 0x11	},
 	{ R0900_AGCRF2CFG	, 0x13	},
 	{ R0900_TSGENERAL1X	, 0x14	},
@@ -381,7 +524,7 @@ static const u16 STV0900_InitVal[182][2] = {
 	{ R0900_GAINLLR_NF15	, 0x1A	},
 	{ R0900_GAINLLR_NF16	, 0x1F	},
 	{ R0900_GAINLLR_NF17	, 0x21	},
-	{ R0900_RCCFGH		, 0x20	},
+	{ R0900_RCCFG2		, 0x20	},
 	{ R0900_P1_FECM		, 0x01	}, /*disable DSS modes*/
 	{ R0900_P2_FECM		, 0x01	}, /*disable DSS modes*/
 	{ R0900_P1_PRVIT	, 0x2F	}, /*disable puncture rate 6/7*/
diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h
index 5ed7a145c7d3..d8ba8a984abe 100644
--- a/drivers/media/dvb/frontends/stv0900_priv.h
+++ b/drivers/media/dvb/frontends/stv0900_priv.h
@@ -46,22 +46,6 @@
 #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)
-
-static int stvdebug;
-
 #define dprintk(args...) \
 	do { \
 		if (stvdebug) \
@@ -70,6 +54,8 @@ static int stvdebug;
 
 #define STV0900_MAXLOOKUPSIZE 500
 #define STV0900_BLIND_SEARCH_AGC2_TH 700
+#define STV0900_BLIND_SEARCH_AGC2_TH_CUT30 1400
+#define IQPOWER_THRESHOLD  30
 
 /* One point of the lookup table */
 struct stv000_lookpoint {
@@ -263,14 +249,14 @@ struct stv0900_init_params{
 	int	tuner1_adc;
 
 	/* IQ from the tuner1 to the demod */
-	enum stv0900_iq_inversion	tun1_iq_inversion;
+	enum stv0900_iq_inversion	tun1_iq_inv;
 	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;
+	enum stv0900_iq_inversion	tun2_iq_inv;
 	struct stv0900_reg		*ts_config;
 };
 
@@ -300,7 +286,7 @@ struct stv0900_signal_info {
 	enum fe_stv0900_modcode			modcode;
 	enum fe_stv0900_modulation		modulation;
 	enum fe_stv0900_pilot			pilot;
-	enum fe_stv0900_frame_length		frame_length;
+	enum fe_stv0900_frame_length		frame_len;
 	enum stv0900_iq_inversion		spectrum;
 	enum fe_stv0900_rolloff			rolloff;
 
@@ -318,47 +304,25 @@ struct stv0900_internal{
 	/* 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;
+	/*Demods */
+	s32	freq[2];
+	s32	bw[2];
+	s32	symbol_rate[2];
+	s32	srch_range[2];
 
 	/* algorithm for search Blind, Cold or Warm*/
-	enum fe_stv0900_search_algo	dmd1_srch_algo;
+	enum fe_stv0900_search_algo	srch_algo[2];
 	/* search standard: Auto, DVBS1/DSS only or DVBS2 only*/
-	enum fe_stv0900_search_standard	dmd1_srch_standard;
+	enum fe_stv0900_search_standard	srch_standard[2];
 	/* 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_search_iq	srch_iq_inv[2];
+	enum fe_stv0900_modcode		modcode[2];
+	enum fe_stv0900_modulation	modulation[2];
+	enum fe_stv0900_fec		fec[2];
 
-	enum fe_stv0900_error		dmd1_err;
+	struct stv0900_signal_info	result[2];
+	enum fe_stv0900_error		err[2];
 
-	/*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;
@@ -379,6 +343,8 @@ struct stv0900_state {
 	int demod;
 };
 
+extern int stvdebug;
+
 extern s32 ge2comp(s32 a, s32 width);
 
 extern void stv0900_write_reg(struct stv0900_internal *i_params,
@@ -418,13 +384,14 @@ extern u8 stv0900_get_optim_short_carr_loop(s32 srate,
 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,
+extern void stv0900_activate_s2_modcod(struct stv0900_internal *i_params,
 				enum fe_stv0900_demod_num demod);
 
-extern void stv0900_activate_s2_modcode_single(struct stv0900_internal *i_params,
+extern void stv0900_activate_s2_modcod_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,
+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
index 264f9cf9a17e..7b8edf192e97 100644
--- a/drivers/media/dvb/frontends/stv0900_reg.h
+++ b/drivers/media/dvb/frontends/stv0900_reg.h
@@ -14,7 +14,7 @@
  *
  * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  *
  * GNU General Public License for more details.
  *
@@ -26,3762 +26,3950 @@
 #ifndef STV0900_REG_H
 #define STV0900_REG_H
 
+extern s32 shiftx(s32 x, int demod, s32 shift);
+
+#define REGx(x) shiftx(x, demod, 0x200)
+#define FLDx(x) shiftx(x, demod, 0x2000000)
+
 /*MID*/
-#define R0900_MID  0xf100
-#define F0900_MCHIP_IDENT  0xf10000f0
-#define F0900_MRELEASE  0xf100000f
+#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
+#define R0900_DACR1 0xf113
+#define F0900_DAC_MODE 0xf11300e0
+#define F0900_DAC_VALUE1 0xf113000f
 
 /*DACR2*/
-#define R0900_DACR2  0xf114
-#define F0900_DAC_VALUE0  0xf11400ff
+#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
+#define R0900_OUTCFG 0xf11c
+#define F0900_OUTSERRS1_HZ 0xf11c0040
+#define F0900_OUTSERRS2_HZ 0xf11c0020
+#define F0900_OUTSERRS3_HZ 0xf11c0010
+#define F0900_OUTPARRS3_HZ 0xf11c0008
 
 /*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
+#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
+#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
+#define R0900_IRQSTATUS1 0xf122
+#define F0900_SPKTDEL_LOCK_1 0xf1220080
+#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
+#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
+#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
+#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
+#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
+#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
+#define R0900_I2CCFG 0xf129
+#define F0900_I2C_FASTMODE 0xf1290008
+#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
+#define R0900_P1_I2CRPT 0xf12a
+#define I2CRPT shiftx(R0900_P1_I2CRPT, demod, -1)
+#define F0900_P1_I2CT_ON 0xf12a0080
+#define I2CT_ON shiftx(F0900_P1_I2CT_ON, demod, -0x10000)
+#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
+#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
+
+/*IOPVALUE6*/
+#define R0900_IOPVALUE6 0xf138
+#define F0900_VSCL 0xf1380004
+#define F0900_VSDA 0xf1380002
+#define F0900_VDATA3_0 0xf1380001
+
+/*IOPVALUE5*/
+#define R0900_IOPVALUE5 0xf139
+#define F0900_VDATA3_1 0xf1390080
+#define F0900_VDATA3_2 0xf1390040
+#define F0900_VDATA3_3 0xf1390020
+#define F0900_VDATA3_4 0xf1390010
+#define F0900_VDATA3_5 0xf1390008
+#define F0900_VDATA3_6 0xf1390004
+#define F0900_VDATA3_7 0xf1390002
+#define F0900_VCLKOUT3 0xf1390001
+
+/*IOPVALUE4*/
+#define R0900_IOPVALUE4 0xf13a
+#define F0900_VSTROUT3 0xf13a0080
+#define F0900_VDPN3 0xf13a0040
+#define F0900_VERROR3 0xf13a0020
+#define F0900_VDATA2_7 0xf13a0010
+#define F0900_VCLKOUT2 0xf13a0008
+#define F0900_VSTROUT2 0xf13a0004
+#define F0900_VDPN2 0xf13a0002
+#define F0900_VERROR2 0xf13a0001
+
+/*IOPVALUE3*/
+#define R0900_IOPVALUE3 0xf13b
+#define F0900_VDATA1_7 0xf13b0080
+#define F0900_VCLKOUT1 0xf13b0040
+#define F0900_VSTROUT1 0xf13b0020
+#define F0900_VDPN1 0xf13b0010
+#define F0900_VERROR1 0xf13b0008
+#define F0900_VCLKOUT27 0xf13b0004
+#define F0900_VDISEQCOUT2 0xf13b0002
+#define F0900_VSCLT2 0xf13b0001
+
+/*IOPVALUE2*/
+#define R0900_IOPVALUE2 0xf13c
+#define F0900_VSDAT2 0xf13c0080
+#define F0900_VAGCRF2 0xf13c0040
+#define F0900_VDISEQCOUT1 0xf13c0020
+#define F0900_VSCLT1 0xf13c0010
+#define F0900_VSDAT1 0xf13c0008
+#define F0900_VAGCRF1 0xf13c0004
+#define F0900_VDIRCLK 0xf13c0002
+#define F0900_VSTDBY 0xf13c0001
+
+/*IOPVALUE1*/
+#define R0900_IOPVALUE1 0xf13d
+#define F0900_VCS1 0xf13d0080
+#define F0900_VCS0 0xf13d0040
+#define F0900_VGPIO13 0xf13d0020
+#define F0900_VGPIO12 0xf13d0010
+#define F0900_VGPIO11 0xf13d0008
+#define F0900_VGPIO10 0xf13d0004
+#define F0900_VGPIO9 0xf13d0002
+#define F0900_VGPIO8 0xf13d0001
+
+/*IOPVALUE0*/
+#define R0900_IOPVALUE0 0xf13e
+#define F0900_VGPIO7 0xf13e0080
+#define F0900_VGPIO6 0xf13e0040
+#define F0900_VGPIO5 0xf13e0020
+#define F0900_VGPIO4 0xf13e0010
+#define F0900_VGPIO3 0xf13e0008
+#define F0900_VGPIO2 0xf13e0004
+#define F0900_VGPIO1 0xf13e0002
+#define F0900_VCLKI2 0xf13e0001
 
 /*CLKI2CFG*/
-#define R0900_CLKI2CFG  0xf140
-#define F0900_CLKI2_OPD  0xf1400080
-#define F0900_CLKI2_CONFIG  0xf140007e
-#define F0900_CLKI2_XOR  0xf1400001
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#define R0900_DATA73CFG 0xf169
+#define F0900_DATA73_OPD 0xf1690080
+#define F0900_DATA73_CONFIG 0xf169007e
+#define F0900_DATA73_XOR 0xf1690001
+
+/*STRSTATUS1*/
+#define R0900_STRSTATUS1 0xf16a
+#define F0900_STRSTATUS_SEL2 0xf16a00f0
+#define F0900_STRSTATUS_SEL1 0xf16a000f
+
+/*STRSTATUS2*/
+#define R0900_STRSTATUS2 0xf16b
+#define F0900_STRSTATUS_SEL4 0xf16b00f0
+#define F0900_STRSTATUS_SEL3 0xf16b000f
+
+/*STRSTATUS3*/
+#define R0900_STRSTATUS3 0xf16c
+#define F0900_STRSTATUS_SEL6 0xf16c00f0
+#define F0900_STRSTATUS_SEL5 0xf16c000f
 
 /*FSKTFC2*/
-#define R0900_FSKTFC2  0xf170
-#define F0900_FSKT_KMOD  0xf17000fc
-#define F0900_FSKT_CAR2  0xf1700003
+#define R0900_FSKTFC2 0xf170
+#define F0900_FSKT_KMOD 0xf17000fc
+#define F0900_FSKT_CAR2 0xf1700003
 
 /*FSKTFC1*/
-#define R0900_FSKTFC1  0xf171
-#define F0900_FSKT_CAR1  0xf17100ff
+#define R0900_FSKTFC1 0xf171
+#define F0900_FSKT_CAR1 0xf17100ff
 
 /*FSKTFC0*/
-#define R0900_FSKTFC0  0xf172
-#define F0900_FSKT_CAR0  0xf17200ff
+#define R0900_FSKTFC0 0xf172
+#define F0900_FSKT_CAR0 0xf17200ff
 
 /*FSKTDELTAF1*/
-#define R0900_FSKTDELTAF1  0xf173
-#define F0900_FSKT_DELTAF1  0xf173000f
+#define R0900_FSKTDELTAF1 0xf173
+#define F0900_FSKT_DELTAF1 0xf173000f
 
 /*FSKTDELTAF0*/
-#define R0900_FSKTDELTAF0  0xf174
-#define F0900_FSKT_DELTAF0  0xf17400ff
+#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
+#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
+#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
+#define R0900_FSKRFC1 0xf177
+#define F0900_FSKR_CAR1 0xf17700ff
 
 /*FSKRFC0*/
-#define R0900_FSKRFC0  0xf178
-#define F0900_FSKR_CAR0  0xf17800ff
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#define R0900_FSKRDF1 0xf180
+#define F0900_FSKR_OUT 0xf1800080
+#define F0900_FSKR_DELTAF1 0xf180001f
 
 /*FSKRDF0*/
-#define R0900_FSKRDF0  0xf181
-#define F0900_FSKR_DELTAF0  0xf18100ff
+#define R0900_FSKRDF0 0xf181
+#define F0900_FSKR_DELTAF0 0xf18100ff
 
 /*FSKRSTEPP*/
-#define R0900_FSKRSTEPP  0xf182
-#define F0900_FSKR_STEP_PLUS  0xf18200ff
+#define R0900_FSKRSTEPP 0xf182
+#define F0900_FSKR_STEP_PLUS 0xf18200ff
 
 /*FSKRSTEPM*/
-#define R0900_FSKRSTEPM  0xf183
-#define F0900_FSKR_STEP_MINUS  0xf18300ff
+#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
+#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
+#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
+#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
+#define R0900_FSKRDTH0 0xf187
+#define F0900_FSKR_CARDET_THRESH0 0xf18700ff
 
 /*FSKRLOSS*/
-#define R0900_FSKRLOSS  0xf188
-#define F0900_FSKR_CARLOSS_THRESH0  0xf18800ff
+#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
+#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
+#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_SELECT0 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
+#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
+#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
+#define R0900_P2_DISRXDATA 0xf196
+#define F0900_P2_DISRX_DATA 0xf19600ff
 
 /*P2_DISTXDATA*/
-#define R0900_P2_DISTXDATA  0xf197
-#define F0900_P2_DISEQC_FIFO  0xf19700ff
+#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
+#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
+#define R0900_P2_F22TX 0xf199
+#define F0900_P2_F22_REG 0xf19900ff
 
 /*P2_F22RX*/
-#define R0900_P2_F22RX  0xf19a
-#define F0900_P2_F22RX_REG  0xf19a00ff
+#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
+#define R0900_P2_ACRPRESC 0xf19c
+#define F0900_P2_ACR_PRESC 0xf19c0007
 
 /*P2_ACRDIV*/
-#define R0900_P2_ACRDIV  0xf19d
-#define F0900_P2_ACR_DIV  0xf19d00ff
+#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
+#define R0900_P1_DISTXCTL 0xf1a0
+#define DISTXCTL shiftx(R0900_P1_DISTXCTL, demod, 0x10)
+#define F0900_P1_TIM_OFF 0xf1a00080
+#define F0900_P1_DISEQC_RESET 0xf1a00040
+#define DISEQC_RESET shiftx(F0900_P1_DISEQC_RESET, demod, 0x100000)
+#define F0900_P1_TIM_CMD 0xf1a00030
+#define F0900_P1_DIS_PRECHARGE 0xf1a00008
+#define DIS_PRECHARGE shiftx(F0900_P1_DIS_PRECHARGE, demod, 0x100000)
+#define F0900_P1_DISTX_MODE 0xf1a00007
+#define DISTX_MODE shiftx(F0900_P1_DISTX_MODE, demod, 0x100000)
 
 /*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
+#define R0900_P1_DISRXCTL 0xf1a1
+#define DISRXCTL shiftx(R0900_P1_DISRXCTL, demod, 0x10)
+#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_SELECT0 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
+#define R0900_P1_DISRX_ST0 0xf1a4
+#define DISRX_ST0 shiftx(R0900_P1_DISRX_ST0, demod, 0x10)
+#define F0900_P1_RX_END 0xf1a40080
+#define RX_END shiftx(F0900_P1_RX_END, demod, 0x100000)
+#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
+#define R0900_P1_DISRX_ST1 0xf1a5
+#define DISRX_ST1 shiftx(R0900_P1_DISRX_ST1, demod, 0x10)
+#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
+#define FIFO_BYTENBR shiftx(F0900_P1_FIFO_BYTENBR, demod, 0x100000)
 
 /*P1_DISRXDATA*/
-#define R0900_P1_DISRXDATA  0xf1a6
-#define F0900_P1_DISRX_DATA  0xf1a600ff
+#define R0900_P1_DISRXDATA 0xf1a6
+#define DISRXDATA shiftx(R0900_P1_DISRXDATA, demod, 0x10)
+#define F0900_P1_DISRX_DATA 0xf1a600ff
 
 /*P1_DISTXDATA*/
-#define R0900_P1_DISTXDATA  0xf1a7
-#define F0900_P1_DISEQC_FIFO  0xf1a700ff
+#define R0900_P1_DISTXDATA 0xf1a7
+#define DISTXDATA shiftx(R0900_P1_DISTXDATA, demod, 0x10)
+#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
+#define R0900_P1_DISTXSTATUS 0xf1a8
+#define F0900_P1_TX_FAIL 0xf1a80080
+#define F0900_P1_FIFO_FULL 0xf1a80040
+#define FIFO_FULL shiftx(F0900_P1_FIFO_FULL, demod, 0x100000)
+#define F0900_P1_TX_IDLE 0xf1a80020
+#define TX_IDLE shiftx(F0900_P1_TX_IDLE, demod, 0x100000)
+#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
+#define R0900_P1_F22TX 0xf1a9
+#define F22TX shiftx(R0900_P1_F22TX, demod, 0x10)
+#define F0900_P1_F22_REG 0xf1a900ff
 
 /*P1_F22RX*/
-#define R0900_P1_F22RX  0xf1aa
-#define F0900_P1_F22RX_REG  0xf1aa00ff
+#define R0900_P1_F22RX 0xf1aa
+#define F22RX shiftx(R0900_P1_F22RX, demod, 0x10)
+#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
+#define R0900_P1_ACRPRESC 0xf1ac
+#define ACRPRESC shiftx(R0900_P1_ACRPRESC, demod, 0x10)
+#define F0900_P1_ACR_PRESC 0xf1ac0007
 
 /*P1_ACRDIV*/
-#define R0900_P1_ACRDIV  0xf1ad
-#define F0900_P1_ACR_DIV  0xf1ad00ff
+#define R0900_P1_ACRDIV 0xf1ad
+#define ACRDIV shiftx(R0900_P1_ACRDIV, demod, 0x10)
+#define F0900_P1_ACR_DIV 0xf1ad00ff
 
 /*NCOARSE*/
-#define R0900_NCOARSE  0xf1b3
-#define F0900_M_DIV  0xf1b300ff
+#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
+#define R0900_SYNTCTRL 0xf1b6
+#define F0900_STANDBY 0xf1b60080
+#define F0900_BYPASSPLLCORE 0xf1b60040
+#define F0900_SELX1RATIO 0xf1b60020
+#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
+#define R0900_FILTCTRL 0xf1b7
+#define F0900_INV_CLK135 0xf1b70080
+#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
+#define R0900_PLLSTAT 0xf1b8
+#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
+#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
+#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 STOP_CLKVIT shiftx(F0900_STOP_CLKVIT1, demod, -2)
+#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
+#define R0900_TSTTNR0 0xf1df
+#define F0900_SEL_FSK 0xf1df0080
+#define F0900_FSK_PON 0xf1df0004
 
 /*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
+#define R0900_TSTTNR1 0xf1e0
+#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
+#define R0900_TSTTNR2 0xf1e1
+#define F0900_DISEQC1_PON 0xf1e10020
 
 /*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
+#define R0900_TSTTNR3 0xf1e2
+#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
+#define R0900_TSTTNR4 0xf1e3
+#define F0900_DISEQC2_PON 0xf1e30020
 
 /*P2_IQCONST*/
-#define R0900_P2_IQCONST  0xf200
-#define F0900_P2_CONSTEL_SELECT  0xf2000060
-#define F0900_P2_IQSYMB_SEL  0xf200001f
+#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
+#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
+#define R0900_P2_ISYMB 0xf202
+#define F0900_P2_I_SYMBOL 0xf20201ff
 
 /*P2_QSYMB*/
-#define R0900_P2_QSYMB  0xf203
-#define F0900_P2_Q_SYMBOL  0xf20301ff
+#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
+#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
 
 /*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
+#define R0900_P2_AGC1CN 0xf206
+#define F0900_P2_AGC1_LOCKED 0xf2060080
+#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
+#define R0900_P2_AGC1REF 0xf207
+#define F0900_P2_AGCIQ_REF 0xf20700ff
 
 /*P2_IDCCOMP*/
-#define R0900_P2_IDCCOMP  0xf208
-#define F0900_P2_IAVERAGE_ADJ  0xf20801ff
+#define R0900_P2_IDCCOMP 0xf208
+#define F0900_P2_IAVERAGE_ADJ 0xf20801ff
 
 /*P2_QDCCOMP*/
-#define R0900_P2_QDCCOMP  0xf209
-#define F0900_P2_QAVERAGE_ADJ  0xf20901ff
+#define R0900_P2_QDCCOMP 0xf209
+#define F0900_P2_QAVERAGE_ADJ 0xf20901ff
 
 /*P2_POWERI*/
-#define R0900_P2_POWERI  0xf20a
-#define F0900_P2_POWER_I  0xf20a00ff
+#define R0900_P2_POWERI 0xf20a
+#define F0900_P2_POWER_I 0xf20a00ff
 
 /*P2_POWERQ*/
-#define R0900_P2_POWERQ  0xf20b
-#define F0900_P2_POWER_Q  0xf20b00ff
+#define R0900_P2_POWERQ 0xf20b
+#define F0900_P2_POWER_Q 0xf20b00ff
 
 /*P2_AGC1AMM*/
-#define R0900_P2_AGC1AMM  0xf20c
-#define F0900_P2_AMM_VALUE  0xf20c00ff
+#define R0900_P2_AGC1AMM 0xf20c
+#define F0900_P2_AMM_VALUE 0xf20c00ff
 
 /*P2_AGC1QUAD*/
-#define R0900_P2_AGC1QUAD  0xf20d
-#define F0900_P2_QUAD_VALUE  0xf20d01ff
+#define R0900_P2_AGC1QUAD 0xf20d
+#define F0900_P2_QUAD_VALUE 0xf20d01ff
 
 /*P2_AGCIQIN1*/
-#define R0900_P2_AGCIQIN1  0xf20e
-#define F0900_P2_AGCIQ_VALUE1  0xf20e00ff
+#define R0900_P2_AGCIQIN1 0xf20e
+#define F0900_P2_AGCIQ_VALUE1 0xf20e00ff
 
 /*P2_AGCIQIN0*/
-#define R0900_P2_AGCIQIN0  0xf20f
-#define F0900_P2_AGCIQ_VALUE0  0xf20f00ff
+#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
+#define R0900_P2_DEMOD 0xf210
+#define F0900_P2_MANUALS2_ROLLOFF 0xf2100080
+#define F0900_P2_SPECINV_CONTROL 0xf2100030
+#define F0900_P2_FORCE_ENASAMP 0xf2100008
+#define F0900_P2_MANUALSX_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
+#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
+#define R0900_P2_DSTATUS 0xf212
+#define F0900_P2_CAR_LOCK 0xf2120080
+#define F0900_P2_TMGLOCK_QUALITY 0xf2120060
+#define F0900_P2_LOCK_DEFINITIF 0xf2120008
+#define F0900_P2_OVADC_DETECT 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
+#define R0900_P2_DSTATUS2 0xf213
+#define F0900_P2_DEMOD_DELOCK 0xf2130080
+#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
+#define R0900_P2_DMDCFGMD 0xf214
+#define F0900_P2_DVBS2_ENABLE 0xf2140080
+#define F0900_P2_DVBS1_ENABLE 0xf2140040
+#define F0900_P2_SCAN_ENABLE 0xf2140010
+#define F0900_P2_CFR_AUTOSCAN 0xf2140008
+#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
+#define R0900_P2_DMDCFG2 0xf215
+#define F0900_P2_S1S2_SEQUENTIAL 0xf2150040
+#define F0900_P2_INFINITE_RELOCK 0xf2150010
 
 /*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
+#define R0900_P2_DMDISTATE 0xf216
+#define F0900_P2_I2C_DEMOD_MODE 0xf216001f
 
 /*P2_DMDT0M*/
-#define R0900_P2_DMDT0M  0xf217
-#define F0900_P2_DMDT0_MIN  0xf21700ff
+#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
+#define R0900_P2_DMDSTATE 0xf21b
+#define F0900_P2_HEADER_MODE 0xf21b0060
 
 /*P2_DMDFLYW*/
-#define R0900_P2_DMDFLYW  0xf21c
-#define F0900_P2_I2C_IRQVAL  0xf21c00f0
-#define F0900_P2_FLYWHEEL_CPT  0xf21c000f
+#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
+#define R0900_P2_DSTATUS3 0xf21d
+#define F0900_P2_DEMOD_CFGMODE 0xf21d0060
 
 /*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
+#define R0900_P2_DMDCFG3 0xf21e
+#define F0900_P2_NOSTOP_FIFOFULL 0xf21e0008
 
 /*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
+#define R0900_P2_DMDCFG4 0xf21f
+#define F0900_P2_TUNER_NRELAUNCH 0xf21f0008
 
 /*P2_CORRELMANT*/
-#define R0900_P2_CORRELMANT  0xf220
-#define F0900_P2_CORREL_MANT  0xf22000ff
+#define R0900_P2_CORRELMANT 0xf220
+#define F0900_P2_CORREL_MANT 0xf22000ff
 
 /*P2_CORRELABS*/
-#define R0900_P2_CORRELABS  0xf221
-#define F0900_P2_CORREL_ABS  0xf22100ff
+#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
+#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
+#define R0900_P2_PLHMODCOD 0xf224
+#define F0900_P2_SPECINV_DEMOD 0xf2240080
+#define F0900_P2_PLH_MODCOD 0xf224007c
+#define F0900_P2_PLH_TYPE 0xf2240003
+
+/*P2_DMDREG*/
+#define R0900_P2_DMDREG 0xf225
+#define F0900_P2_DECIM_PLFRAMES 0xf2250001
 
 /*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
+#define R0900_P2_AGC2O 0xf22c
+#define F0900_P2_AGC2_COEF 0xf22c0007
 
 /*P2_AGC2REF*/
-#define R0900_P2_AGC2REF  0xf22d
-#define F0900_P2_AGC2_REF  0xf22d00ff
+#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
+#define R0900_P2_AGC1ADJ 0xf22e
+#define F0900_P2_AGC1_ADJUSTED 0xf22e007f
 
 /*P2_AGC2I1*/
-#define R0900_P2_AGC2I1  0xf236
-#define F0900_P2_AGC2_INTEGRATOR1  0xf23600ff
+#define R0900_P2_AGC2I1 0xf236
+#define F0900_P2_AGC2_INTEGRATOR1 0xf23600ff
 
 /*P2_AGC2I0*/
-#define R0900_P2_AGC2I0  0xf237
-#define F0900_P2_AGC2_INTEGRATOR0  0xf23700ff
+#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
+#define R0900_P2_CARCFG 0xf238
+#define F0900_P2_CFRUPLOW_AUTO 0xf2380080
+#define F0900_P2_CFRUPLOW_TEST 0xf2380040
+#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
+#define R0900_P2_ACLC 0xf239
+#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
+#define R0900_P2_BCLC 0xf23a
+#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
+#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
+#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
+#define R0900_P2_LDT 0xf23f
+#define F0900_P2_CARLOCK_THRES 0xf23f01ff
 
 /*P2_LDT2*/
-#define R0900_P2_LDT2  0xf240
-#define F0900_P2_CARLOCK_THRES2  0xf24001ff
+#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
+#define R0900_P2_CFRICFG 0xf241
+#define F0900_P2_NEG_CFRSTEP 0xf2410001
 
 /*P2_CFRUP1*/
-#define R0900_P2_CFRUP1  0xf242
-#define F0900_P2_CFR_UP1  0xf24201ff
+#define R0900_P2_CFRUP1 0xf242
+#define F0900_P2_CFR_UP1 0xf24201ff
 
 /*P2_CFRUP0*/
-#define R0900_P2_CFRUP0  0xf243
-#define F0900_P2_CFR_UP0  0xf24300ff
+#define R0900_P2_CFRUP0 0xf243
+#define F0900_P2_CFR_UP0 0xf24300ff
 
 /*P2_CFRLOW1*/
-#define R0900_P2_CFRLOW1  0xf246
-#define F0900_P2_CFR_LOW1  0xf24601ff
+#define R0900_P2_CFRLOW1 0xf246
+#define F0900_P2_CFR_LOW1 0xf24601ff
 
 /*P2_CFRLOW0*/
-#define R0900_P2_CFRLOW0  0xf247
-#define F0900_P2_CFR_LOW0  0xf24700ff
+#define R0900_P2_CFRLOW0 0xf247
+#define F0900_P2_CFR_LOW0 0xf24700ff
 
 /*P2_CFRINIT1*/
-#define R0900_P2_CFRINIT1  0xf248
-#define F0900_P2_CFR_INIT1  0xf24801ff
+#define R0900_P2_CFRINIT1 0xf248
+#define F0900_P2_CFR_INIT1 0xf24801ff
 
 /*P2_CFRINIT0*/
-#define R0900_P2_CFRINIT0  0xf249
-#define F0900_P2_CFR_INIT0  0xf24900ff
+#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
+#define R0900_P2_CFRINC1 0xf24a
+#define F0900_P2_MANUAL_CFRINC 0xf24a0080
+#define F0900_P2_CFR_INC1 0xf24a003f
 
 /*P2_CFRINC0*/
-#define R0900_P2_CFRINC0  0xf24b
-#define F0900_P2_CFR_INC0  0xf24b00f0
+#define R0900_P2_CFRINC0 0xf24b
+#define F0900_P2_CFR_INC0 0xf24b00f8
 
 /*P2_CFR2*/
-#define R0900_P2_CFR2  0xf24c
-#define F0900_P2_CAR_FREQ2  0xf24c01ff
+#define R0900_P2_CFR2 0xf24c
+#define F0900_P2_CAR_FREQ2 0xf24c01ff
 
 /*P2_CFR1*/
-#define R0900_P2_CFR1  0xf24d
-#define F0900_P2_CAR_FREQ1  0xf24d00ff
+#define R0900_P2_CFR1 0xf24d
+#define F0900_P2_CAR_FREQ1 0xf24d00ff
 
 /*P2_CFR0*/
-#define R0900_P2_CFR0  0xf24e
-#define F0900_P2_CAR_FREQ0  0xf24e00ff
+#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
+#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
+#define R0900_P2_TMGCFG 0xf250
+#define F0900_P2_TMGLOCK_BETA 0xf25000c0
+#define F0900_P2_DO_TIMING_CORR 0xf2500010
+#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
+#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
+#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
+#define R0900_P2_TMGTHRISE 0xf253
+#define F0900_P2_TMGLOCK_THRISE 0xf25300ff
 
 /*P2_TMGTHFALL*/
-#define R0900_P2_TMGTHFALL  0xf254
-#define F0900_P2_TMGLOCK_THFALL  0xf25400ff
+#define R0900_P2_TMGTHFALL 0xf254
+#define F0900_P2_TMGLOCK_THFALL 0xf25400ff
 
 /*P2_SFRUPRATIO*/
-#define R0900_P2_SFRUPRATIO  0xf255
-#define F0900_P2_SFR_UPRATIO  0xf25500ff
+#define R0900_P2_SFRUPRATIO 0xf255
+#define F0900_P2_SFR_UPRATIO 0xf25500ff
 
 /*P2_SFRLOWRATIO*/
-#define R0900_P2_SFRLOWRATIO  0xf256
-#define F0900_P2_SFR_LOWRATIO  0xf25600ff
+#define R0900_P2_SFRLOWRATIO 0xf256
+#define F0900_P2_SFR_LOWRATIO 0xf25600ff
 
 /*P2_KREFTMG*/
-#define R0900_P2_KREFTMG  0xf258
-#define F0900_P2_KREF_TMG  0xf25800ff
+#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
+#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
+#define R0900_P2_TMGCFG2 0xf25a
+#define F0900_P2_SFRRATIO_FINE 0xf25a0001
+
+/*P2_KREFTMG2*/
+#define R0900_P2_KREFTMG2 0xf25b
+#define F0900_P2_KREF_TMG2 0xf25b00ff
 
 /*P2_SFRINIT1*/
-#define R0900_P2_SFRINIT1  0xf25e
-#define F0900_P2_SFR_INIT1  0xf25e00ff
+#define R0900_P2_SFRINIT1 0xf25e
+#define F0900_P2_SFR_INIT1 0xf25e007f
 
 /*P2_SFRINIT0*/
-#define R0900_P2_SFRINIT0  0xf25f
-#define F0900_P2_SFR_INIT0  0xf25f00ff
+#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
+#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
+#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
+#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
+#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
+#define R0900_P2_SFR3 0xf264
+#define F0900_P2_SYMB_FREQ3 0xf26400ff
 
 /*P2_SFR2*/
-#define R0900_P2_SFR2  0xf265
-#define F0900_P2_SYMB_FREQ2  0xf26500ff
+#define R0900_P2_SFR2 0xf265
+#define F0900_P2_SYMB_FREQ2 0xf26500ff
 
 /*P2_SFR1*/
-#define R0900_P2_SFR1  0xf266
-#define F0900_P2_SYMB_FREQ1  0xf26600ff
+#define R0900_P2_SFR1 0xf266
+#define F0900_P2_SYMB_FREQ1 0xf26600ff
 
 /*P2_SFR0*/
-#define R0900_P2_SFR0  0xf267
-#define F0900_P2_SYMB_FREQ0  0xf26700ff
+#define R0900_P2_SFR0 0xf267
+#define F0900_P2_SYMB_FREQ0 0xf26700ff
 
 /*P2_TMGREG2*/
-#define R0900_P2_TMGREG2  0xf268
-#define F0900_P2_TMGREG2  0xf26800ff
+#define R0900_P2_TMGREG2 0xf268
+#define F0900_P2_TMGREG2 0xf26800ff
 
 /*P2_TMGREG1*/
-#define R0900_P2_TMGREG1  0xf269
-#define F0900_P2_TMGREG1  0xf26900ff
+#define R0900_P2_TMGREG1 0xf269
+#define F0900_P2_TMGREG1 0xf26900ff
 
 /*P2_TMGREG0*/
-#define R0900_P2_TMGREG0  0xf26a
-#define F0900_P2_TMGREG0  0xf26a00ff
+#define R0900_P2_TMGREG0 0xf26a
+#define F0900_P2_TMGREG0 0xf26a00ff
 
 /*P2_TMGLOCK1*/
-#define R0900_P2_TMGLOCK1  0xf26b
-#define F0900_P2_TMGLOCK_LEVEL1  0xf26b01ff
+#define R0900_P2_TMGLOCK1 0xf26b
+#define F0900_P2_TMGLOCK_LEVEL1 0xf26b01ff
 
 /*P2_TMGLOCK0*/
-#define R0900_P2_TMGLOCK0  0xf26c
-#define F0900_P2_TMGLOCK_LEVEL0  0xf26c00ff
+#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
+#define R0900_P2_TMGOBS 0xf26d
+#define F0900_P2_ROLLOFF_STATUS 0xf26d00c0
 
 /*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
+#define R0900_P2_EQUALCFG 0xf26f
+#define F0900_P2_EQUAL_ON 0xf26f0040
+#define F0900_P2_MU_EQUALDFE 0xf26f0007
 
 /*P2_EQUAI1*/
-#define R0900_P2_EQUAI1  0xf270
-#define F0900_P2_EQUA_ACCI1  0xf27001ff
+#define R0900_P2_EQUAI1 0xf270
+#define F0900_P2_EQUA_ACCI1 0xf27001ff
 
 /*P2_EQUAQ1*/
-#define R0900_P2_EQUAQ1  0xf271
-#define F0900_P2_EQUA_ACCQ1  0xf27101ff
+#define R0900_P2_EQUAQ1 0xf271
+#define F0900_P2_EQUA_ACCQ1 0xf27101ff
 
 /*P2_EQUAI2*/
-#define R0900_P2_EQUAI2  0xf272
-#define F0900_P2_EQUA_ACCI2  0xf27201ff
+#define R0900_P2_EQUAI2 0xf272
+#define F0900_P2_EQUA_ACCI2 0xf27201ff
 
 /*P2_EQUAQ2*/
-#define R0900_P2_EQUAQ2  0xf273
-#define F0900_P2_EQUA_ACCQ2  0xf27301ff
+#define R0900_P2_EQUAQ2 0xf273
+#define F0900_P2_EQUA_ACCQ2 0xf27301ff
 
 /*P2_EQUAI3*/
-#define R0900_P2_EQUAI3  0xf274
-#define F0900_P2_EQUA_ACCI3  0xf27401ff
+#define R0900_P2_EQUAI3 0xf274
+#define F0900_P2_EQUA_ACCI3 0xf27401ff
 
 /*P2_EQUAQ3*/
-#define R0900_P2_EQUAQ3  0xf275
-#define F0900_P2_EQUA_ACCQ3  0xf27501ff
+#define R0900_P2_EQUAQ3 0xf275
+#define F0900_P2_EQUA_ACCQ3 0xf27501ff
 
 /*P2_EQUAI4*/
-#define R0900_P2_EQUAI4  0xf276
-#define F0900_P2_EQUA_ACCI4  0xf27601ff
+#define R0900_P2_EQUAI4 0xf276
+#define F0900_P2_EQUA_ACCI4 0xf27601ff
 
 /*P2_EQUAQ4*/
-#define R0900_P2_EQUAQ4  0xf277
-#define F0900_P2_EQUA_ACCQ4  0xf27701ff
+#define R0900_P2_EQUAQ4 0xf277
+#define F0900_P2_EQUA_ACCQ4 0xf27701ff
 
 /*P2_EQUAI5*/
-#define R0900_P2_EQUAI5  0xf278
-#define F0900_P2_EQUA_ACCI5  0xf27801ff
+#define R0900_P2_EQUAI5 0xf278
+#define F0900_P2_EQUA_ACCI5 0xf27801ff
 
 /*P2_EQUAQ5*/
-#define R0900_P2_EQUAQ5  0xf279
-#define F0900_P2_EQUA_ACCQ5  0xf27901ff
+#define R0900_P2_EQUAQ5 0xf279
+#define F0900_P2_EQUA_ACCQ5 0xf27901ff
 
 /*P2_EQUAI6*/
-#define R0900_P2_EQUAI6  0xf27a
-#define F0900_P2_EQUA_ACCI6  0xf27a01ff
+#define R0900_P2_EQUAI6 0xf27a
+#define F0900_P2_EQUA_ACCI6 0xf27a01ff
 
 /*P2_EQUAQ6*/
-#define R0900_P2_EQUAQ6  0xf27b
-#define F0900_P2_EQUA_ACCQ6  0xf27b01ff
+#define R0900_P2_EQUAQ6 0xf27b
+#define F0900_P2_EQUA_ACCQ6 0xf27b01ff
 
 /*P2_EQUAI7*/
-#define R0900_P2_EQUAI7  0xf27c
-#define F0900_P2_EQUA_ACCI7  0xf27c01ff
+#define R0900_P2_EQUAI7 0xf27c
+#define F0900_P2_EQUA_ACCI7 0xf27c01ff
 
 /*P2_EQUAQ7*/
-#define R0900_P2_EQUAQ7  0xf27d
-#define F0900_P2_EQUA_ACCQ7  0xf27d01ff
+#define R0900_P2_EQUAQ7 0xf27d
+#define F0900_P2_EQUA_ACCQ7 0xf27d01ff
 
 /*P2_EQUAI8*/
-#define R0900_P2_EQUAI8  0xf27e
-#define F0900_P2_EQUA_ACCI8  0xf27e01ff
+#define R0900_P2_EQUAI8 0xf27e
+#define F0900_P2_EQUA_ACCI8 0xf27e01ff
 
 /*P2_EQUAQ8*/
-#define R0900_P2_EQUAQ8  0xf27f
-#define F0900_P2_EQUA_ACCQ8  0xf27f01ff
+#define R0900_P2_EQUAQ8 0xf27f
+#define F0900_P2_EQUA_ACCQ8 0xf27f01ff
 
 /*P2_NNOSDATAT1*/
-#define R0900_P2_NNOSDATAT1  0xf280
-#define F0900_P2_NOSDATAT_NORMED1  0xf28000ff
+#define R0900_P2_NNOSDATAT1 0xf280
+#define F0900_P2_NOSDATAT_NORMED1 0xf28000ff
 
 /*P2_NNOSDATAT0*/
-#define R0900_P2_NNOSDATAT0  0xf281
-#define F0900_P2_NOSDATAT_NORMED0  0xf28100ff
+#define R0900_P2_NNOSDATAT0 0xf281
+#define F0900_P2_NOSDATAT_NORMED0 0xf28100ff
 
 /*P2_NNOSDATA1*/
-#define R0900_P2_NNOSDATA1  0xf282
-#define F0900_P2_NOSDATA_NORMED1  0xf28200ff
+#define R0900_P2_NNOSDATA1 0xf282
+#define F0900_P2_NOSDATA_NORMED1 0xf28200ff
 
 /*P2_NNOSDATA0*/
-#define R0900_P2_NNOSDATA0  0xf283
-#define F0900_P2_NOSDATA_NORMED0  0xf28300ff
+#define R0900_P2_NNOSDATA0 0xf283
+#define F0900_P2_NOSDATA_NORMED0 0xf28300ff
 
 /*P2_NNOSPLHT1*/
-#define R0900_P2_NNOSPLHT1  0xf284
-#define F0900_P2_NOSPLHT_NORMED1  0xf28400ff
+#define R0900_P2_NNOSPLHT1 0xf284
+#define F0900_P2_NOSPLHT_NORMED1 0xf28400ff
 
 /*P2_NNOSPLHT0*/
-#define R0900_P2_NNOSPLHT0  0xf285
-#define F0900_P2_NOSPLHT_NORMED0  0xf28500ff
+#define R0900_P2_NNOSPLHT0 0xf285
+#define F0900_P2_NOSPLHT_NORMED0 0xf28500ff
 
 /*P2_NNOSPLH1*/
-#define R0900_P2_NNOSPLH1  0xf286
-#define F0900_P2_NOSPLH_NORMED1  0xf28600ff
+#define R0900_P2_NNOSPLH1 0xf286
+#define F0900_P2_NOSPLH_NORMED1 0xf28600ff
 
 /*P2_NNOSPLH0*/
-#define R0900_P2_NNOSPLH0  0xf287
-#define F0900_P2_NOSPLH_NORMED0  0xf28700ff
+#define R0900_P2_NNOSPLH0 0xf287
+#define F0900_P2_NOSPLH_NORMED0 0xf28700ff
 
 /*P2_NOSDATAT1*/
-#define R0900_P2_NOSDATAT1  0xf288
-#define F0900_P2_NOSDATAT_UNNORMED1  0xf28800ff
+#define R0900_P2_NOSDATAT1 0xf288
+#define F0900_P2_NOSDATAT_UNNORMED1 0xf28800ff
 
 /*P2_NOSDATAT0*/
-#define R0900_P2_NOSDATAT0  0xf289
-#define F0900_P2_NOSDATAT_UNNORMED0  0xf28900ff
+#define R0900_P2_NOSDATAT0 0xf289
+#define F0900_P2_NOSDATAT_UNNORMED0 0xf28900ff
 
 /*P2_NOSDATA1*/
-#define R0900_P2_NOSDATA1  0xf28a
-#define F0900_P2_NOSDATA_UNNORMED1  0xf28a00ff
+#define R0900_P2_NOSDATA1 0xf28a
+#define F0900_P2_NOSDATA_UNNORMED1 0xf28a00ff
 
 /*P2_NOSDATA0*/
-#define R0900_P2_NOSDATA0  0xf28b
-#define F0900_P2_NOSDATA_UNNORMED0  0xf28b00ff
+#define R0900_P2_NOSDATA0 0xf28b
+#define F0900_P2_NOSDATA_UNNORMED0 0xf28b00ff
 
 /*P2_NOSPLHT1*/
-#define R0900_P2_NOSPLHT1  0xf28c
-#define F0900_P2_NOSPLHT_UNNORMED1  0xf28c00ff
+#define R0900_P2_NOSPLHT1 0xf28c
+#define F0900_P2_NOSPLHT_UNNORMED1 0xf28c00ff
 
 /*P2_NOSPLHT0*/
-#define R0900_P2_NOSPLHT0  0xf28d
-#define F0900_P2_NOSPLHT_UNNORMED0  0xf28d00ff
+#define R0900_P2_NOSPLHT0 0xf28d
+#define F0900_P2_NOSPLHT_UNNORMED0 0xf28d00ff
 
 /*P2_NOSPLH1*/
-#define R0900_P2_NOSPLH1  0xf28e
-#define F0900_P2_NOSPLH_UNNORMED1  0xf28e00ff
+#define R0900_P2_NOSPLH1 0xf28e
+#define F0900_P2_NOSPLH_UNNORMED1 0xf28e00ff
 
 /*P2_NOSPLH0*/
-#define R0900_P2_NOSPLH0  0xf28f
-#define F0900_P2_NOSPLH_UNNORMED0  0xf28f00ff
+#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
+#define R0900_P2_CAR2CFG 0xf290
+#define F0900_P2_CARRIER3_DISABLE 0xf2900040
+#define F0900_P2_ROTA2ON 0xf2900004
+#define F0900_P2_PH_DET_ALGO2 0xf2900003
+
+/*P2_CFR2CFR1*/
+#define R0900_P2_CFR2CFR1 0xf291
+#define F0900_P2_CFR2TOCFR1_DVBS1 0xf29100c0
+#define F0900_P2_EN_S2CAR2CENTER 0xf2910020
+#define F0900_P2_DIS_BCHERRCFR2 0xf2910010
+#define F0900_P2_CFR2TOCFR1_BETA 0xf2910007
 
 /*P2_CFR22*/
-#define R0900_P2_CFR22  0xf293
-#define F0900_P2_CAR2_FREQ2  0xf29301ff
+#define R0900_P2_CFR22 0xf293
+#define F0900_P2_CAR2_FREQ2 0xf29301ff
 
 /*P2_CFR21*/
-#define R0900_P2_CFR21  0xf294
-#define F0900_P2_CAR2_FREQ1  0xf29400ff
+#define R0900_P2_CFR21 0xf294
+#define F0900_P2_CAR2_FREQ1 0xf29400ff
 
 /*P2_CFR20*/
-#define R0900_P2_CFR20  0xf295
-#define F0900_P2_CAR2_FREQ0  0xf29500ff
+#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
+#define R0900_P2_ACLC2S2Q 0xf297
+#define F0900_P2_ENAB_SPSKSYMB 0xf2970080
+#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
+#define R0900_P2_ACLC2S28 0xf298
+#define F0900_P2_OLDI3Q_MODE 0xf2980080
+#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
+#define R0900_P2_ACLC2S216A 0xf299
+#define F0900_P2_DIS_C3STOPA2 0xf2990080
+#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
+#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
+#define R0900_P2_BCLC2S2Q 0xf29c
+#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
+#define R0900_P2_BCLC2S28 0xf29d
+#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
+#define R0900_P2_BCLC2S216A 0xf29e
 
 /*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
+#define R0900_P2_BCLC2S232A 0xf29f
 
 /*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
+#define R0900_P2_PLROOT2 0xf2ac
+#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
+#define R0900_P2_PLROOT1 0xf2ad
+#define F0900_P2_PLSCRAMB_ROOT1 0xf2ad00ff
 
 /*P2_PLROOT0*/
-#define R0900_P2_PLROOT0  0xf2ae
-#define F0900_P2_PLSCRAMB_ROOT0  0xf2ae00ff
+#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
+#define R0900_P2_MODCODLST0 0xf2b0
 
 /*P2_MODCODLST1*/
-#define R0900_P2_MODCODLST1  0xf2b1
-#define F0900_P2_DIS_MODCOD29  0xf2b100f0
-#define F0900_P2_DIS_32PSK_9_10  0xf2b1000f
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#define R0900_P2_MODCODLSTF 0xf2bf
+#define F0900_P2_DIS_QP_1_4 0xf2bf00f0
+
+/*P2_GAUSSR0*/
+#define R0900_P2_GAUSSR0 0xf2c0
+#define F0900_P2_EN_CCIMODE 0xf2c00080
+#define F0900_P2_R0_GAUSSIEN 0xf2c0007f
+
+/*P2_CCIR0*/
+#define R0900_P2_CCIR0 0xf2c1
+#define F0900_P2_CCIDETECT_PLHONLY 0xf2c10080
+#define F0900_P2_R0_CCI 0xf2c1007f
+
+/*P2_CCIQUANT*/
+#define R0900_P2_CCIQUANT 0xf2c2
+#define F0900_P2_CCI_BETA 0xf2c200e0
+#define F0900_P2_CCI_QUANT 0xf2c2001f
+
+/*P2_CCITHRES*/
+#define R0900_P2_CCITHRES 0xf2c3
+#define F0900_P2_CCI_THRESHOLD 0xf2c300ff
+
+/*P2_CCIACC*/
+#define R0900_P2_CCIACC 0xf2c4
+#define F0900_P2_CCI_VALUE 0xf2c400ff
 
 /*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
+#define R0900_P2_DMDRESCFG 0xf2c6
+#define F0900_P2_DMDRES_RESET 0xf2c60080
+#define F0900_P2_DMDRES_STRALL 0xf2c60008
+#define F0900_P2_DMDRES_NEWONLY 0xf2c60004
+#define F0900_P2_DMDRES_NOSTORE 0xf2c60002
 
 /*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
+#define R0900_P2_DMDRESADR 0xf2c7
+#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
+#define R0900_P2_DMDRESDATA7 0xf2c8
+#define F0900_P2_DMDRES_DATA7 0xf2c800ff
 
 /*P2_DMDRESDATA6*/
-#define R0900_P2_DMDRESDATA6  0xf2c9
-#define F0900_P2_DMDRES_DATA6  0xf2c900ff
+#define R0900_P2_DMDRESDATA6 0xf2c9
+#define F0900_P2_DMDRES_DATA6 0xf2c900ff
 
 /*P2_DMDRESDATA5*/
-#define R0900_P2_DMDRESDATA5  0xf2ca
-#define F0900_P2_DMDRES_DATA5  0xf2ca00ff
+#define R0900_P2_DMDRESDATA5 0xf2ca
+#define F0900_P2_DMDRES_DATA5 0xf2ca00ff
 
 /*P2_DMDRESDATA4*/
-#define R0900_P2_DMDRESDATA4  0xf2cb
-#define F0900_P2_DMDRES_DATA4  0xf2cb00ff
+#define R0900_P2_DMDRESDATA4 0xf2cb
+#define F0900_P2_DMDRES_DATA4 0xf2cb00ff
 
 /*P2_DMDRESDATA3*/
-#define R0900_P2_DMDRESDATA3  0xf2cc
-#define F0900_P2_DMDRES_DATA3  0xf2cc00ff
+#define R0900_P2_DMDRESDATA3 0xf2cc
+#define F0900_P2_DMDRES_DATA3 0xf2cc00ff
 
 /*P2_DMDRESDATA2*/
-#define R0900_P2_DMDRESDATA2  0xf2cd
-#define F0900_P2_DMDRES_DATA2  0xf2cd00ff
+#define R0900_P2_DMDRESDATA2 0xf2cd
+#define F0900_P2_DMDRES_DATA2 0xf2cd00ff
 
 /*P2_DMDRESDATA1*/
-#define R0900_P2_DMDRESDATA1  0xf2ce
-#define F0900_P2_DMDRES_DATA1  0xf2ce00ff
+#define R0900_P2_DMDRESDATA1 0xf2ce
+#define F0900_P2_DMDRES_DATA1 0xf2ce00ff
 
 /*P2_DMDRESDATA0*/
-#define R0900_P2_DMDRESDATA0  0xf2cf
-#define F0900_P2_DMDRES_DATA0  0xf2cf00ff
+#define R0900_P2_DMDRESDATA0 0xf2cf
+#define F0900_P2_DMDRES_DATA0 0xf2cf00ff
 
 /*P2_FFEI1*/
-#define R0900_P2_FFEI1  0xf2d0
-#define F0900_P2_FFE_ACCI1  0xf2d001ff
+#define R0900_P2_FFEI1 0xf2d0
+#define F0900_P2_FFE_ACCI1 0xf2d001ff
 
 /*P2_FFEQ1*/
-#define R0900_P2_FFEQ1  0xf2d1
-#define F0900_P2_FFE_ACCQ1  0xf2d101ff
+#define R0900_P2_FFEQ1 0xf2d1
+#define F0900_P2_FFE_ACCQ1 0xf2d101ff
 
 /*P2_FFEI2*/
-#define R0900_P2_FFEI2  0xf2d2
-#define F0900_P2_FFE_ACCI2  0xf2d201ff
+#define R0900_P2_FFEI2 0xf2d2
+#define F0900_P2_FFE_ACCI2 0xf2d201ff
 
 /*P2_FFEQ2*/
-#define R0900_P2_FFEQ2  0xf2d3
-#define F0900_P2_FFE_ACCQ2  0xf2d301ff
+#define R0900_P2_FFEQ2 0xf2d3
+#define F0900_P2_FFE_ACCQ2 0xf2d301ff
 
 /*P2_FFEI3*/
-#define R0900_P2_FFEI3  0xf2d4
-#define F0900_P2_FFE_ACCI3  0xf2d401ff
+#define R0900_P2_FFEI3 0xf2d4
+#define F0900_P2_FFE_ACCI3 0xf2d401ff
 
 /*P2_FFEQ3*/
-#define R0900_P2_FFEQ3  0xf2d5
-#define F0900_P2_FFE_ACCQ3  0xf2d501ff
+#define R0900_P2_FFEQ3 0xf2d5
+#define F0900_P2_FFE_ACCQ3 0xf2d501ff
 
 /*P2_FFEI4*/
-#define R0900_P2_FFEI4  0xf2d6
-#define F0900_P2_FFE_ACCI4  0xf2d601ff
+#define R0900_P2_FFEI4 0xf2d6
+#define F0900_P2_FFE_ACCI4 0xf2d601ff
 
 /*P2_FFEQ4*/
-#define R0900_P2_FFEQ4  0xf2d7
-#define F0900_P2_FFE_ACCQ4  0xf2d701ff
+#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
+#define R0900_P2_FFECFG 0xf2d8
+#define F0900_P2_EQUALFFE_ON 0xf2d80040
+#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
+#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
+#define R0900_P2_TNRCFG2 0xf2e1
+#define F0900_P2_TUN_IQSWAP 0xf2e10080
+#define F0900_P2_DIS_BWCALC 0xf2e10004
+#define F0900_P2_SHORT_WAITSTATES 0xf2e10002
 
 /*P2_TNRXTAL*/
-#define R0900_P2_TNRXTAL  0xf2e4
-#define F0900_P2_TUN_MCLKDECIMAL  0xf2e400e0
-#define F0900_P2_TUN_XTALFREQ  0xf2e4001f
+#define R0900_P2_TNRXTAL 0xf2e4
+#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
+#define R0900_P2_TNRSTEPS 0xf2e7
+#define F0900_P2_TUNER_BW0P125 0xf2e70080
+#define F0900_P2_BWINC_OFFSET 0xf2e70170
+#define F0900_P2_SOFTSTEP_RNG 0xf2e70008
+#define F0900_P2_TUN_BWOFFSET 0xf2e70007
 
 /*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
+#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
+#define R0900_P2_TNRRF1 0xf2e9
+#define F0900_P2_TUN_RFFREQ2 0xf2e900ff
 
 /*P2_TNRRF0*/
-#define R0900_P2_TNRRF0  0xf2ea
-#define F0900_P2_TUN_RFFREQ1  0xf2ea00ff
+#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
+#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
+#define R0900_P2_TNRADJ 0xf2ec
+#define F0900_P2_STB61X0_CALTIME 0xf2ec0040
 
 /*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
+#define R0900_P2_TNRCTL2 0xf2ed
+#define F0900_P2_STB61X0_RCCKOFF 0xf2ed0080
+#define F0900_P2_STB61X0_ICP_SDOFF 0xf2ed0040
+#define F0900_P2_STB61X0_DCLOOPOFF 0xf2ed0020
+#define F0900_P2_STB61X0_REFOUTSEL 0xf2ed0010
+#define F0900_P2_STB61X0_CALOFF 0xf2ed0008
+#define F0900_P2_STB6XX0_LPT_BEN 0xf2ed0004
+#define F0900_P2_STB6XX0_RX_OSCP 0xf2ed0002
+#define F0900_P2_STB6XX0_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
+#define R0900_P2_TNRCFG3 0xf2ee
+#define F0900_P2_TUN_PLLFREQ 0xf2ee001c
+#define F0900_P2_TUN_I2CFREQ_MODE 0xf2ee0003
 
 /*P2_TNRLAUNCH*/
-#define R0900_P2_TNRLAUNCH  0xf2f0
+#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
+#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
+#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
+#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
+#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
+#define R0900_P2_SMAPCOEF6 0xf301
+#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
+#define R0900_P2_SMAPCOEF5 0xf302
+#define F0900_P2_DIS_8SCALE 0xf3020080
+#define F0900_P2_SMAPCOEF_8P_LLR23 0xf302017f
+
+/*P2_NCO2MAX1*/
+#define R0900_P2_NCO2MAX1 0xf314
+#define F0900_P2_TETA2_MAXVABS1 0xf31400ff
+
+/*P2_NCO2MAX0*/
+#define R0900_P2_NCO2MAX0 0xf315
+#define F0900_P2_TETA2_MAXVABS0 0xf31500ff
+
+/*P2_NCO2FR1*/
+#define R0900_P2_NCO2FR1 0xf316
+#define F0900_P2_NCO2FINAL_ANGLE1 0xf31600ff
+
+/*P2_NCO2FR0*/
+#define R0900_P2_NCO2FR0 0xf317
+#define F0900_P2_NCO2FINAL_ANGLE0 0xf31700ff
+
+/*P2_CFR2AVRGE1*/
+#define R0900_P2_CFR2AVRGE1 0xf318
+#define F0900_P2_I2C_CFR2AVERAGE1 0xf31800ff
+
+/*P2_CFR2AVRGE0*/
+#define R0900_P2_CFR2AVRGE0 0xf319
+#define F0900_P2_I2C_CFR2AVERAGE0 0xf31900ff
 
 /*P2_DMDPLHSTAT*/
-#define R0900_P2_DMDPLHSTAT  0xf320
-#define F0900_P2_PLH_STATISTIC  0xf32000ff
+#define R0900_P2_DMDPLHSTAT 0xf320
+#define F0900_P2_PLH_STATISTIC 0xf32000ff
 
 /*P2_LOCKTIME3*/
-#define R0900_P2_LOCKTIME3  0xf322
-#define F0900_P2_DEMOD_LOCKTIME3  0xf32200ff
+#define R0900_P2_LOCKTIME3 0xf322
+#define F0900_P2_DEMOD_LOCKTIME3 0xf32200ff
 
 /*P2_LOCKTIME2*/
-#define R0900_P2_LOCKTIME2  0xf323
-#define F0900_P2_DEMOD_LOCKTIME2  0xf32300ff
+#define R0900_P2_LOCKTIME2 0xf323
+#define F0900_P2_DEMOD_LOCKTIME2 0xf32300ff
 
 /*P2_LOCKTIME1*/
-#define R0900_P2_LOCKTIME1  0xf324
-#define F0900_P2_DEMOD_LOCKTIME1  0xf32400ff
+#define R0900_P2_LOCKTIME1 0xf324
+#define F0900_P2_DEMOD_LOCKTIME1 0xf32400ff
 
 /*P2_LOCKTIME0*/
-#define R0900_P2_LOCKTIME0  0xf325
-#define F0900_P2_DEMOD_LOCKTIME0  0xf32500ff
+#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
+#define R0900_P2_VITSCALE 0xf332
+#define F0900_P2_NVTH_NOSRANGE 0xf3320080
+#define F0900_P2_VERROR_MAXMODE 0xf3320040
+#define F0900_P2_NSLOWSN_LOCKED 0xf3320008
+#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
+#define R0900_P2_FECM 0xf333
+#define F0900_P2_DSS_DVB 0xf3330080
+#define F0900_P2_DSS_SRCH 0xf3330010
+#define F0900_P2_SYNCVIT 0xf3330002
+#define F0900_P2_IQINV 0xf3330001
 
 /*P2_VTH12*/
-#define R0900_P2_VTH12  0xf334
-#define F0900_P2_VTH12  0xf33400ff
+#define R0900_P2_VTH12 0xf334
+#define F0900_P2_VTH12 0xf33400ff
 
 /*P2_VTH23*/
-#define R0900_P2_VTH23  0xf335
-#define F0900_P2_VTH23  0xf33500ff
+#define R0900_P2_VTH23 0xf335
+#define F0900_P2_VTH23 0xf33500ff
 
 /*P2_VTH34*/
-#define R0900_P2_VTH34  0xf336
-#define F0900_P2_VTH34  0xf33600ff
+#define R0900_P2_VTH34 0xf336
+#define F0900_P2_VTH34 0xf33600ff
 
 /*P2_VTH56*/
-#define R0900_P2_VTH56  0xf337
-#define F0900_P2_VTH56  0xf33700ff
+#define R0900_P2_VTH56 0xf337
+#define F0900_P2_VTH56 0xf33700ff
 
 /*P2_VTH67*/
-#define R0900_P2_VTH67  0xf338
-#define F0900_P2_VTH67  0xf33800ff
+#define R0900_P2_VTH67 0xf338
+#define F0900_P2_VTH67 0xf33800ff
 
 /*P2_VTH78*/
-#define R0900_P2_VTH78  0xf339
-#define F0900_P2_VTH78  0xf33900ff
+#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
+#define R0900_P2_VITCURPUN 0xf33a
+#define F0900_P2_VIT_CURPUN 0xf33a001f
 
 /*P2_VERROR*/
-#define R0900_P2_VERROR  0xf33b
-#define F0900_P2_REGERR_VIT  0xf33b00ff
+#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
+#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
+#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
+#define R0900_P2_VSTATUSVIT 0xf33e
+#define F0900_P2_PRFVIT 0xf33e0010
+#define F0900_P2_LOCKEDVIT 0xf33e0008
 
 /*P2_VTHINUSE*/
-#define R0900_P2_VTHINUSE  0xf33f
-#define F0900_P2_VIT_INUSE  0xf33f00ff
+#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
+#define R0900_P2_KDIV12 0xf340
+#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
+#define R0900_P2_KDIV23 0xf341
+#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
+#define R0900_P2_KDIV34 0xf342
+#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
+#define R0900_P2_KDIV56 0xf343
+#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
+#define R0900_P2_KDIV67 0xf344
+#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
+#define R0900_P2_KDIV78 0xf345
+#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
+#define R0900_P2_PDELCTRL1 0xf350
+#define F0900_P2_INV_MISMASK 0xf3500080
+#define F0900_P2_FILTER_EN 0xf3500020
+#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
+#define R0900_P2_PDELCTRL2 0xf351
+#define F0900_P2_RESET_UPKO_COUNT 0xf3510040
+#define F0900_P2_FRAME_MODE 0xf3510002
+#define F0900_P2_NOBCHERRFLG_USE 0xf3510001
 
 /*P2_HYSTTHRESH*/
-#define R0900_P2_HYSTTHRESH  0xf354
-#define F0900_P2_UNLCK_THRESH  0xf35400f0
-#define F0900_P2_DELIN_LCK_THRESH  0xf354000f
+#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
+#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
+#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
+#define R0900_P2_MATSTR1 0xf360
+#define F0900_P2_MATYPE_CURRENT1 0xf36000ff
 
 /*P2_MATSTR0*/
-#define R0900_P2_MATSTR0  0xf361
-#define F0900_P2_MATYPE_CURRENT0  0xf36100ff
+#define R0900_P2_MATSTR0 0xf361
+#define F0900_P2_MATYPE_CURRENT0 0xf36100ff
 
 /*P2_UPLSTR1*/
-#define R0900_P2_UPLSTR1  0xf362
-#define F0900_P2_UPL_CURRENT1  0xf36200ff
+#define R0900_P2_UPLSTR1 0xf362
+#define F0900_P2_UPL_CURRENT1 0xf36200ff
 
 /*P2_UPLSTR0*/
-#define R0900_P2_UPLSTR0  0xf363
-#define F0900_P2_UPL_CURRENT0  0xf36300ff
+#define R0900_P2_UPLSTR0 0xf363
+#define F0900_P2_UPL_CURRENT0 0xf36300ff
 
 /*P2_DFLSTR1*/
-#define R0900_P2_DFLSTR1  0xf364
-#define F0900_P2_DFL_CURRENT1  0xf36400ff
+#define R0900_P2_DFLSTR1 0xf364
+#define F0900_P2_DFL_CURRENT1 0xf36400ff
 
 /*P2_DFLSTR0*/
-#define R0900_P2_DFLSTR0  0xf365
-#define F0900_P2_DFL_CURRENT0  0xf36500ff
+#define R0900_P2_DFLSTR0 0xf365
+#define F0900_P2_DFL_CURRENT0 0xf36500ff
 
 /*P2_SYNCSTR*/
-#define R0900_P2_SYNCSTR  0xf366
-#define F0900_P2_SYNC_CURRENT  0xf36600ff
+#define R0900_P2_SYNCSTR 0xf366
+#define F0900_P2_SYNC_CURRENT 0xf36600ff
 
 /*P2_SYNCDSTR1*/
-#define R0900_P2_SYNCDSTR1  0xf367
-#define F0900_P2_SYNCD_CURRENT1  0xf36700ff
+#define R0900_P2_SYNCDSTR1 0xf367
+#define F0900_P2_SYNCD_CURRENT1 0xf36700ff
 
 /*P2_SYNCDSTR0*/
-#define R0900_P2_SYNCDSTR0  0xf368
-#define F0900_P2_SYNCD_CURRENT0  0xf36800ff
+#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
+#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_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
+#define R0900_P2_PDELSTATUS2 0xf36a
+#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
+#define R0900_P2_BBFCRCKO1 0xf36b
+#define F0900_P2_BBHCRC_KOCNT1 0xf36b00ff
 
 /*P2_BBFCRCKO0*/
-#define R0900_P2_BBFCRCKO0  0xf36c
-#define F0900_P2_BBHCRC_KOCNT0  0xf36c00ff
+#define R0900_P2_BBFCRCKO0 0xf36c
+#define F0900_P2_BBHCRC_KOCNT0 0xf36c00ff
 
 /*P2_UPCRCKO1*/
-#define R0900_P2_UPCRCKO1  0xf36d
-#define F0900_P2_PKTCRC_KOCNT1  0xf36d00ff
+#define R0900_P2_UPCRCKO1 0xf36d
+#define F0900_P2_PKTCRC_KOCNT1 0xf36d00ff
 
 /*P2_UPCRCKO0*/
-#define R0900_P2_UPCRCKO0  0xf36e
-#define F0900_P2_PKTCRC_KOCNT0  0xf36e00ff
+#define R0900_P2_UPCRCKO0 0xf36e
+#define F0900_P2_PKTCRC_KOCNT0 0xf36e00ff
+
+/*P2_PDELCTRL3*/
+#define R0900_P2_PDELCTRL3 0xf36f
+#define F0900_P2_PKTDEL_CONTFAIL 0xf36f0080
+#define F0900_P2_NOFIFO_BCHERR 0xf36f0020
 
 /*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
+#define R0900_P2_TSSTATEM 0xf370
+#define F0900_P2_TSDIL_ON 0xf3700080
+#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_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
+#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
+#define R0900_P2_TSCFGM 0xf373
+#define F0900_P2_TSFIFO_MANSPEED 0xf37300c0
+#define F0900_P2_TSFIFO_PERMDATA 0xf3730020
+#define F0900_P2_TSFIFO_DPUNACT 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
+#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_BITSPEED 0xf3740003
 
 /*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
+#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_TSDIVN*/
+#define R0900_P2_TSDIVN 0xf379
+#define F0900_P2_TSFIFO_SPEEDMODE 0xf37900c0
+
+/*P2_TSCFG4*/
+#define R0900_P2_TSCFG4 0xf37a
+#define F0900_P2_TSFIFO_TSSPEEDMODE 0xf37a00c0
 
 /*P2_TSSPEED*/
-#define R0900_P2_TSSPEED  0xf380
-#define F0900_P2_TSFIFO_OUTSPEED  0xf38000ff
+#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
+#define R0900_P2_TSSTATUS 0xf381
+#define F0900_P2_TSFIFO_LINEOK 0xf3810080
+#define F0900_P2_TSFIFO_ERROR 0xf3810040
+#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
+#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_SCRAMBDETECT 0xf3820002
 
 /*P2_TSBITRATE1*/
-#define R0900_P2_TSBITRATE1  0xf383
-#define F0900_P2_TSFIFO_BITRATE1  0xf38300ff
+#define R0900_P2_TSBITRATE1 0xf383
+#define F0900_P2_TSFIFO_BITRATE1 0xf38300ff
 
 /*P2_TSBITRATE0*/
-#define R0900_P2_TSBITRATE0  0xf384
-#define F0900_P2_TSFIFO_BITRATE0  0xf38400ff
+#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
+#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
+#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
+#define R0900_P2_ERRCNT11 0xf39a
+#define F0900_P2_ERR_CNT11 0xf39a00ff
 
 /*P2_ERRCNT10*/
-#define R0900_P2_ERRCNT10  0xf39b
-#define F0900_P2_ERR_CNT10  0xf39b00ff
+#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
+#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
+#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
+#define R0900_P2_ERRCNT21 0xf39e
+#define F0900_P2_ERR_CNT21 0xf39e00ff
 
 /*P2_ERRCNT20*/
-#define R0900_P2_ERRCNT20  0xf39f
-#define F0900_P2_ERR_CNT20  0xf39f00ff
+#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
+#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_BERMETER_DATAMODE 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
+#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
+#define R0900_P2_FSPYDATA 0xf3a2
+#define F0900_P2_SPY_STUFFING 0xf3a20080
+#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
+#define R0900_P2_FSPYOUT 0xf3a3
+#define F0900_P2_FSPY_DIRECT 0xf3a30080
+#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
+#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
+#define R0900_P2_FBERCPT4 0xf3a8
+#define F0900_P2_FBERMETER_CPT4 0xf3a800ff
 
 /*P2_FBERCPT3*/
-#define R0900_P2_FBERCPT3  0xf3a9
-#define F0900_P2_FBERMETER_CPT3  0xf3a900ff
+#define R0900_P2_FBERCPT3 0xf3a9
+#define F0900_P2_FBERMETER_CPT3 0xf3a900ff
 
 /*P2_FBERCPT2*/
-#define R0900_P2_FBERCPT2  0xf3aa
-#define F0900_P2_FBERMETER_CPT2  0xf3aa00ff
+#define R0900_P2_FBERCPT2 0xf3aa
+#define F0900_P2_FBERMETER_CPT2 0xf3aa00ff
 
 /*P2_FBERCPT1*/
-#define R0900_P2_FBERCPT1  0xf3ab
-#define F0900_P2_FBERMETER_CPT1  0xf3ab00ff
+#define R0900_P2_FBERCPT1 0xf3ab
+#define F0900_P2_FBERMETER_CPT1 0xf3ab00ff
 
 /*P2_FBERCPT0*/
-#define R0900_P2_FBERCPT0  0xf3ac
-#define F0900_P2_FBERMETER_CPT0  0xf3ac00ff
+#define R0900_P2_FBERCPT0 0xf3ac
+#define F0900_P2_FBERMETER_CPT0 0xf3ac00ff
 
 /*P2_FBERERR2*/
-#define R0900_P2_FBERERR2  0xf3ad
-#define F0900_P2_FBERMETER_ERR2  0xf3ad00ff
+#define R0900_P2_FBERERR2 0xf3ad
+#define F0900_P2_FBERMETER_ERR2 0xf3ad00ff
 
 /*P2_FBERERR1*/
-#define R0900_P2_FBERERR1  0xf3ae
-#define F0900_P2_FBERMETER_ERR1  0xf3ae00ff
+#define R0900_P2_FBERERR1 0xf3ae
+#define F0900_P2_FBERMETER_ERR1 0xf3ae00ff
 
 /*P2_FBERERR0*/
-#define R0900_P2_FBERERR0  0xf3af
-#define F0900_P2_FBERMETER_ERR0  0xf3af00ff
+#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
+#define R0900_P2_FSPYBER 0xf3b2
+#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
+#define R0900_P1_IQCONST 0xf400
+#define IQCONST REGx(R0900_P1_IQCONST)
+#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
+#define R0900_P1_NOSCFG 0xf401
+#define NOSCFG REGx(R0900_P1_NOSCFG)
+#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
+#define R0900_P1_ISYMB 0xf402
+#define ISYMB REGx(R0900_P1_ISYMB)
+#define F0900_P1_I_SYMBOL 0xf40201ff
 
 /*P1_QSYMB*/
-#define R0900_P1_QSYMB  0xf403
-#define F0900_P1_Q_SYMBOL  0xf40301ff
+#define R0900_P1_QSYMB 0xf403
+#define QSYMB REGx(R0900_P1_QSYMB)
+#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
+#define R0900_P1_AGC1CFG 0xf404
+#define AGC1CFG REGx(R0900_P1_AGC1CFG)
+#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
 
 /*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
+#define R0900_P1_AGC1CN 0xf406
+#define AGC1CN REGx(R0900_P1_AGC1CN)
+#define F0900_P1_AGC1_LOCKED 0xf4060080
+#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
+#define R0900_P1_AGC1REF 0xf407
+#define AGC1REF REGx(R0900_P1_AGC1REF)
+#define F0900_P1_AGCIQ_REF 0xf40700ff
 
 /*P1_IDCCOMP*/
-#define R0900_P1_IDCCOMP  0xf408
-#define F0900_P1_IAVERAGE_ADJ  0xf40801ff
+#define R0900_P1_IDCCOMP 0xf408
+#define IDCCOMP REGx(R0900_P1_IDCCOMP)
+#define F0900_P1_IAVERAGE_ADJ 0xf40801ff
 
 /*P1_QDCCOMP*/
-#define R0900_P1_QDCCOMP  0xf409
-#define F0900_P1_QAVERAGE_ADJ  0xf40901ff
+#define R0900_P1_QDCCOMP 0xf409
+#define QDCCOMP REGx(R0900_P1_QDCCOMP)
+#define F0900_P1_QAVERAGE_ADJ 0xf40901ff
 
 /*P1_POWERI*/
-#define R0900_P1_POWERI  0xf40a
-#define F0900_P1_POWER_I  0xf40a00ff
+#define R0900_P1_POWERI 0xf40a
+#define POWERI REGx(R0900_P1_POWERI)
+#define F0900_P1_POWER_I 0xf40a00ff
+#define POWER_I FLDx(F0900_P1_POWER_I)
 
 /*P1_POWERQ*/
-#define R0900_P1_POWERQ  0xf40b
-#define F0900_P1_POWER_Q  0xf40b00ff
+#define R0900_P1_POWERQ 0xf40b
+#define POWERQ REGx(R0900_P1_POWERQ)
+#define F0900_P1_POWER_Q 0xf40b00ff
+#define POWER_Q FLDx(F0900_P1_POWER_Q)
 
 /*P1_AGC1AMM*/
-#define R0900_P1_AGC1AMM  0xf40c
-#define F0900_P1_AMM_VALUE  0xf40c00ff
+#define R0900_P1_AGC1AMM 0xf40c
+#define AGC1AMM REGx(R0900_P1_AGC1AMM)
+#define F0900_P1_AMM_VALUE 0xf40c00ff
 
 /*P1_AGC1QUAD*/
-#define R0900_P1_AGC1QUAD  0xf40d
-#define F0900_P1_QUAD_VALUE  0xf40d01ff
+#define R0900_P1_AGC1QUAD 0xf40d
+#define AGC1QUAD REGx(R0900_P1_AGC1QUAD)
+#define F0900_P1_QUAD_VALUE 0xf40d01ff
 
 /*P1_AGCIQIN1*/
-#define R0900_P1_AGCIQIN1  0xf40e
-#define F0900_P1_AGCIQ_VALUE1  0xf40e00ff
+#define R0900_P1_AGCIQIN1 0xf40e
+#define AGCIQIN1 REGx(R0900_P1_AGCIQIN1)
+#define F0900_P1_AGCIQ_VALUE1 0xf40e00ff
+#define AGCIQ_VALUE1 FLDx(F0900_P1_AGCIQ_VALUE1)
 
 /*P1_AGCIQIN0*/
-#define R0900_P1_AGCIQIN0  0xf40f
-#define F0900_P1_AGCIQ_VALUE0  0xf40f00ff
+#define R0900_P1_AGCIQIN0 0xf40f
+#define AGCIQIN0 REGx(R0900_P1_AGCIQIN0)
+#define F0900_P1_AGCIQ_VALUE0 0xf40f00ff
+#define AGCIQ_VALUE0 FLDx(F0900_P1_AGCIQ_VALUE0)
 
 /*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
+#define R0900_P1_DEMOD 0xf410
+#define DEMOD REGx(R0900_P1_DEMOD)
+#define F0900_P1_MANUALS2_ROLLOFF 0xf4100080
+#define MANUALS2_ROLLOFF FLDx(F0900_P1_MANUALS2_ROLLOFF)
+
+#define F0900_P1_SPECINV_CONTROL 0xf4100030
+#define SPECINV_CONTROL FLDx(F0900_P1_SPECINV_CONTROL)
+#define F0900_P1_FORCE_ENASAMP 0xf4100008
+#define F0900_P1_MANUALSX_ROLLOFF 0xf4100004
+#define MANUALSX_ROLLOFF FLDx(F0900_P1_MANUALSX_ROLLOFF)
+#define F0900_P1_ROLLOFF_CONTROL 0xf4100003
+#define ROLLOFF_CONTROL FLDx(F0900_P1_ROLLOFF_CONTROL)
 
 /*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
+#define R0900_P1_DMDMODCOD 0xf411
+#define DMDMODCOD REGx(R0900_P1_DMDMODCOD)
+#define F0900_P1_MANUAL_MODCOD 0xf4110080
+#define F0900_P1_DEMOD_MODCOD 0xf411007c
+#define DEMOD_MODCOD FLDx(F0900_P1_DEMOD_MODCOD)
+#define F0900_P1_DEMOD_TYPE 0xf4110003
+#define DEMOD_TYPE FLDx(F0900_P1_DEMOD_TYPE)
 
 /*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
+#define R0900_P1_DSTATUS 0xf412
+#define DSTATUS REGx(R0900_P1_DSTATUS)
+#define F0900_P1_CAR_LOCK 0xf4120080
+#define F0900_P1_TMGLOCK_QUALITY 0xf4120060
+#define TMGLOCK_QUALITY FLDx(F0900_P1_TMGLOCK_QUALITY)
+#define F0900_P1_LOCK_DEFINITIF 0xf4120008
+#define LOCK_DEFINITIF FLDx(F0900_P1_LOCK_DEFINITIF)
+#define F0900_P1_OVADC_DETECT 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
+#define R0900_P1_DSTATUS2 0xf413
+#define DSTATUS2 REGx(R0900_P1_DSTATUS2)
+#define F0900_P1_DEMOD_DELOCK 0xf4130080
+#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
+#define R0900_P1_DMDCFGMD 0xf414
+#define DMDCFGMD REGx(R0900_P1_DMDCFGMD)
+#define F0900_P1_DVBS2_ENABLE 0xf4140080
+#define DVBS2_ENABLE FLDx(F0900_P1_DVBS2_ENABLE)
+#define F0900_P1_DVBS1_ENABLE 0xf4140040
+#define DVBS1_ENABLE FLDx(F0900_P1_DVBS1_ENABLE)
+#define F0900_P1_SCAN_ENABLE 0xf4140010
+#define SCAN_ENABLE FLDx(F0900_P1_SCAN_ENABLE)
+#define F0900_P1_CFR_AUTOSCAN 0xf4140008
+#define CFR_AUTOSCAN FLDx(F0900_P1_CFR_AUTOSCAN)
+#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
+#define R0900_P1_DMDCFG2 0xf415
+#define DMDCFG2 REGx(R0900_P1_DMDCFG2)
+#define F0900_P1_S1S2_SEQUENTIAL 0xf4150040
+#define S1S2_SEQUENTIAL FLDx(F0900_P1_S1S2_SEQUENTIAL)
+#define F0900_P1_INFINITE_RELOCK 0xf4150010
 
 /*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
+#define R0900_P1_DMDISTATE 0xf416
+#define DMDISTATE REGx(R0900_P1_DMDISTATE)
+#define F0900_P1_I2C_DEMOD_MODE 0xf416001f
+#define DEMOD_MODE FLDx(F0900_P1_I2C_DEMOD_MODE)
 
 /*P1_DMDT0M*/
-#define R0900_P1_DMDT0M  0xf417
-#define F0900_P1_DMDT0_MIN  0xf41700ff
+#define R0900_P1_DMDT0M 0xf417
+#define DMDT0M REGx(R0900_P1_DMDT0M)
+#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
+#define R0900_P1_DMDSTATE 0xf41b
+#define DMDSTATE REGx(R0900_P1_DMDSTATE)
+#define F0900_P1_HEADER_MODE 0xf41b0060
+#define HEADER_MODE FLDx(F0900_P1_HEADER_MODE)
 
 /*P1_DMDFLYW*/
-#define R0900_P1_DMDFLYW  0xf41c
-#define F0900_P1_I2C_IRQVAL  0xf41c00f0
-#define F0900_P1_FLYWHEEL_CPT  0xf41c000f
+#define R0900_P1_DMDFLYW 0xf41c
+#define DMDFLYW REGx(R0900_P1_DMDFLYW)
+#define F0900_P1_I2C_IRQVAL 0xf41c00f0
+#define F0900_P1_FLYWHEEL_CPT 0xf41c000f
+#define FLYWHEEL_CPT FLDx(F0900_P1_FLYWHEEL_CPT)
 
 /*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
+#define R0900_P1_DSTATUS3 0xf41d
+#define DSTATUS3 REGx(R0900_P1_DSTATUS3)
+#define F0900_P1_DEMOD_CFGMODE 0xf41d0060
 
 /*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
+#define R0900_P1_DMDCFG3 0xf41e
+#define DMDCFG3 REGx(R0900_P1_DMDCFG3)
+#define F0900_P1_NOSTOP_FIFOFULL 0xf41e0008
 
 /*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
+#define R0900_P1_DMDCFG4 0xf41f
+#define DMDCFG4 REGx(R0900_P1_DMDCFG4)
+#define F0900_P1_TUNER_NRELAUNCH 0xf41f0008
 
 /*P1_CORRELMANT*/
-#define R0900_P1_CORRELMANT  0xf420
-#define F0900_P1_CORREL_MANT  0xf42000ff
+#define R0900_P1_CORRELMANT 0xf420
+#define CORRELMANT REGx(R0900_P1_CORRELMANT)
+#define F0900_P1_CORREL_MANT 0xf42000ff
 
 /*P1_CORRELABS*/
-#define R0900_P1_CORRELABS  0xf421
-#define F0900_P1_CORREL_ABS  0xf42100ff
+#define R0900_P1_CORRELABS 0xf421
+#define CORRELABS REGx(R0900_P1_CORRELABS)
+#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
+#define R0900_P1_CORRELEXP 0xf422
+#define CORRELEXP REGx(R0900_P1_CORRELEXP)
+#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
+#define R0900_P1_PLHMODCOD 0xf424
+#define PLHMODCOD REGx(R0900_P1_PLHMODCOD)
+#define F0900_P1_SPECINV_DEMOD 0xf4240080
+#define SPECINV_DEMOD FLDx(F0900_P1_SPECINV_DEMOD)
+#define F0900_P1_PLH_MODCOD 0xf424007c
+#define F0900_P1_PLH_TYPE 0xf4240003
+
+/*P1_DMDREG*/
+#define R0900_P1_DMDREG 0xf425
+#define DMDREG REGx(R0900_P1_DMDREG)
+#define F0900_P1_DECIM_PLFRAMES 0xf4250001
 
 /*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
+#define R0900_P1_AGC2O 0xf42c
+#define AGC2O REGx(R0900_P1_AGC2O)
+#define F0900_P1_AGC2_COEF 0xf42c0007
 
 /*P1_AGC2REF*/
-#define R0900_P1_AGC2REF  0xf42d
-#define F0900_P1_AGC2_REF  0xf42d00ff
+#define R0900_P1_AGC2REF 0xf42d
+#define AGC2REF REGx(R0900_P1_AGC2REF)
+#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
+#define R0900_P1_AGC1ADJ 0xf42e
+#define AGC1ADJ REGx(R0900_P1_AGC1ADJ)
+#define F0900_P1_AGC1_ADJUSTED 0xf42e007f
 
 /*P1_AGC2I1*/
-#define R0900_P1_AGC2I1  0xf436
-#define F0900_P1_AGC2_INTEGRATOR1  0xf43600ff
+#define R0900_P1_AGC2I1 0xf436
+#define AGC2I1 REGx(R0900_P1_AGC2I1)
+#define F0900_P1_AGC2_INTEGRATOR1 0xf43600ff
 
 /*P1_AGC2I0*/
-#define R0900_P1_AGC2I0  0xf437
-#define F0900_P1_AGC2_INTEGRATOR0  0xf43700ff
+#define R0900_P1_AGC2I0 0xf437
+#define AGC2I0 REGx(R0900_P1_AGC2I0)
+#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
+#define R0900_P1_CARCFG 0xf438
+#define CARCFG REGx(R0900_P1_CARCFG)
+#define F0900_P1_CFRUPLOW_AUTO 0xf4380080
+#define F0900_P1_CFRUPLOW_TEST 0xf4380040
+#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
+#define R0900_P1_ACLC 0xf439
+#define ACLC REGx(R0900_P1_ACLC)
+#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
+#define R0900_P1_BCLC 0xf43a
+#define BCLC REGx(R0900_P1_BCLC)
+#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
+#define R0900_P1_CARFREQ 0xf43d
+#define CARFREQ REGx(R0900_P1_CARFREQ)
+#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
+#define R0900_P1_CARHDR 0xf43e
+#define CARHDR REGx(R0900_P1_CARHDR)
+#define F0900_P1_K_FREQ_HDR 0xf43e00ff
 
 /*P1_LDT*/
-#define R0900_P1_LDT  0xf43f
-#define F0900_P1_CARLOCK_THRES  0xf43f01ff
+#define R0900_P1_LDT 0xf43f
+#define LDT REGx(R0900_P1_LDT)
+#define F0900_P1_CARLOCK_THRES 0xf43f01ff
 
 /*P1_LDT2*/
-#define R0900_P1_LDT2  0xf440
-#define F0900_P1_CARLOCK_THRES2  0xf44001ff
+#define R0900_P1_LDT2 0xf440
+#define LDT2 REGx(R0900_P1_LDT2)
+#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
+#define R0900_P1_CFRICFG 0xf441
+#define CFRICFG REGx(R0900_P1_CFRICFG)
+#define F0900_P1_NEG_CFRSTEP 0xf4410001
 
 /*P1_CFRUP1*/
-#define R0900_P1_CFRUP1  0xf442
-#define F0900_P1_CFR_UP1  0xf44201ff
+#define R0900_P1_CFRUP1 0xf442
+#define CFRUP1 REGx(R0900_P1_CFRUP1)
+#define F0900_P1_CFR_UP1 0xf44201ff
+#define CFR_UP1 FLDx(F0900_P1_CFR_UP1)
 
 /*P1_CFRUP0*/
-#define R0900_P1_CFRUP0  0xf443
-#define F0900_P1_CFR_UP0  0xf44300ff
+#define R0900_P1_CFRUP0 0xf443
+#define CFRUP0 REGx(R0900_P1_CFRUP0)
+#define F0900_P1_CFR_UP0 0xf44300ff
+#define CFR_UP0 FLDx(F0900_P1_CFR_UP0)
 
 /*P1_CFRLOW1*/
-#define R0900_P1_CFRLOW1  0xf446
-#define F0900_P1_CFR_LOW1  0xf44601ff
+#define R0900_P1_CFRLOW1 0xf446
+#define CFRLOW1 REGx(R0900_P1_CFRLOW1)
+#define F0900_P1_CFR_LOW1 0xf44601ff
+#define CFR_LOW1 FLDx(F0900_P1_CFR_LOW1)
 
 /*P1_CFRLOW0*/
-#define R0900_P1_CFRLOW0  0xf447
-#define F0900_P1_CFR_LOW0  0xf44700ff
+#define R0900_P1_CFRLOW0 0xf447
+#define CFRLOW0 REGx(R0900_P1_CFRLOW0)
+#define F0900_P1_CFR_LOW0 0xf44700ff
+#define CFR_LOW0 FLDx(F0900_P1_CFR_LOW0)
 
 /*P1_CFRINIT1*/
-#define R0900_P1_CFRINIT1  0xf448
-#define F0900_P1_CFR_INIT1  0xf44801ff
+#define R0900_P1_CFRINIT1 0xf448
+#define CFRINIT1 REGx(R0900_P1_CFRINIT1)
+#define F0900_P1_CFR_INIT1 0xf44801ff
+#define CFR_INIT1 FLDx(F0900_P1_CFR_INIT1)
 
 /*P1_CFRINIT0*/
-#define R0900_P1_CFRINIT0  0xf449
-#define F0900_P1_CFR_INIT0  0xf44900ff
+#define R0900_P1_CFRINIT0 0xf449
+#define CFRINIT0 REGx(R0900_P1_CFRINIT0)
+#define F0900_P1_CFR_INIT0 0xf44900ff
+#define CFR_INIT0 FLDx(F0900_P1_CFR_INIT0)
 
 /*P1_CFRINC1*/
-#define R0900_P1_CFRINC1  0xf44a
-#define F0900_P1_MANUAL_CFRINC  0xf44a0080
-#define F0900_P1_CFR_INC1  0xf44a017f
+#define R0900_P1_CFRINC1 0xf44a
+#define CFRINC1 REGx(R0900_P1_CFRINC1)
+#define F0900_P1_MANUAL_CFRINC 0xf44a0080
+#define F0900_P1_CFR_INC1 0xf44a003f
 
 /*P1_CFRINC0*/
-#define R0900_P1_CFRINC0  0xf44b
-#define F0900_P1_CFR_INC0  0xf44b00f0
+#define R0900_P1_CFRINC0 0xf44b
+#define CFRINC0 REGx(R0900_P1_CFRINC0)
+#define F0900_P1_CFR_INC0 0xf44b00f8
 
 /*P1_CFR2*/
-#define R0900_P1_CFR2  0xf44c
-#define F0900_P1_CAR_FREQ2  0xf44c01ff
+#define R0900_P1_CFR2 0xf44c
+#define CFR2 REGx(R0900_P1_CFR2)
+#define F0900_P1_CAR_FREQ2 0xf44c01ff
+#define CAR_FREQ2 FLDx(F0900_P1_CAR_FREQ2)
 
 /*P1_CFR1*/
-#define R0900_P1_CFR1  0xf44d
-#define F0900_P1_CAR_FREQ1  0xf44d00ff
+#define R0900_P1_CFR1 0xf44d
+#define CFR1 REGx(R0900_P1_CFR1)
+#define F0900_P1_CAR_FREQ1 0xf44d00ff
+#define CAR_FREQ1 FLDx(F0900_P1_CAR_FREQ1)
 
 /*P1_CFR0*/
-#define R0900_P1_CFR0  0xf44e
-#define F0900_P1_CAR_FREQ0  0xf44e00ff
+#define R0900_P1_CFR0 0xf44e
+#define CFR0 REGx(R0900_P1_CFR0)
+#define F0900_P1_CAR_FREQ0 0xf44e00ff
+#define CAR_FREQ0 FLDx(F0900_P1_CAR_FREQ0)
 
 /*P1_LDI*/
-#define R0900_P1_LDI  0xf44f
-#define F0900_P1_LOCK_DET_INTEGR  0xf44f01ff
+#define R0900_P1_LDI 0xf44f
+#define LDI REGx(R0900_P1_LDI)
+#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
+#define R0900_P1_TMGCFG 0xf450
+#define TMGCFG REGx(R0900_P1_TMGCFG)
+#define F0900_P1_TMGLOCK_BETA 0xf45000c0
+#define F0900_P1_DO_TIMING_CORR 0xf4500010
+#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
+#define R0900_P1_RTC 0xf451
+#define RTC REGx(R0900_P1_RTC)
+#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
+#define R0900_P1_RTCS2 0xf452
+#define RTCS2 REGx(R0900_P1_RTCS2)
+#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
+#define R0900_P1_TMGTHRISE 0xf453
+#define TMGTHRISE REGx(R0900_P1_TMGTHRISE)
+#define F0900_P1_TMGLOCK_THRISE 0xf45300ff
 
 /*P1_TMGTHFALL*/
-#define R0900_P1_TMGTHFALL  0xf454
-#define F0900_P1_TMGLOCK_THFALL  0xf45400ff
+#define R0900_P1_TMGTHFALL 0xf454
+#define TMGTHFALL REGx(R0900_P1_TMGTHFALL)
+#define F0900_P1_TMGLOCK_THFALL 0xf45400ff
 
 /*P1_SFRUPRATIO*/
-#define R0900_P1_SFRUPRATIO  0xf455
-#define F0900_P1_SFR_UPRATIO  0xf45500ff
+#define R0900_P1_SFRUPRATIO 0xf455
+#define SFRUPRATIO REGx(R0900_P1_SFRUPRATIO)
+#define F0900_P1_SFR_UPRATIO 0xf45500ff
 
 /*P1_SFRLOWRATIO*/
-#define R0900_P1_SFRLOWRATIO  0xf456
-#define F0900_P1_SFR_LOWRATIO  0xf45600ff
+#define R0900_P1_SFRLOWRATIO 0xf456
+#define F0900_P1_SFR_LOWRATIO 0xf45600ff
 
 /*P1_KREFTMG*/
-#define R0900_P1_KREFTMG  0xf458
-#define F0900_P1_KREF_TMG  0xf45800ff
+#define R0900_P1_KREFTMG 0xf458
+#define KREFTMG REGx(R0900_P1_KREFTMG)
+#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
+#define R0900_P1_SFRSTEP 0xf459
+#define SFRSTEP REGx(R0900_P1_SFRSTEP)
+#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
+#define R0900_P1_TMGCFG2 0xf45a
+#define TMGCFG2 REGx(R0900_P1_TMGCFG2)
+#define F0900_P1_SFRRATIO_FINE 0xf45a0001
+
+/*P1_KREFTMG2*/
+#define R0900_P1_KREFTMG2 0xf45b
+#define KREFTMG2 REGx(R0900_P1_KREFTMG2)
+#define F0900_P1_KREF_TMG2 0xf45b00ff
 
 /*P1_SFRINIT1*/
-#define R0900_P1_SFRINIT1  0xf45e
-#define F0900_P1_SFR_INIT1  0xf45e00ff
+#define R0900_P1_SFRINIT1 0xf45e
+#define SFRINIT1 REGx(R0900_P1_SFRINIT1)
+#define F0900_P1_SFR_INIT1 0xf45e007f
 
 /*P1_SFRINIT0*/
-#define R0900_P1_SFRINIT0  0xf45f
-#define F0900_P1_SFR_INIT0  0xf45f00ff
+#define R0900_P1_SFRINIT0 0xf45f
+#define SFRINIT0 REGx(R0900_P1_SFRINIT0)
+#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
+#define R0900_P1_SFRUP1 0xf460
+#define SFRUP1 REGx(R0900_P1_SFRUP1)
+#define F0900_P1_AUTO_GUP 0xf4600080
+#define AUTO_GUP FLDx(F0900_P1_AUTO_GUP)
+#define F0900_P1_SYMB_FREQ_UP1 0xf460007f
 
 /*P1_SFRUP0*/
-#define R0900_P1_SFRUP0  0xf461
-#define F0900_P1_SYMB_FREQ_UP0  0xf46100ff
+#define R0900_P1_SFRUP0 0xf461
+#define SFRUP0 REGx(R0900_P1_SFRUP0)
+#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
+#define R0900_P1_SFRLOW1 0xf462
+#define SFRLOW1 REGx(R0900_P1_SFRLOW1)
+#define F0900_P1_AUTO_GLOW 0xf4620080
+#define AUTO_GLOW FLDx(F0900_P1_AUTO_GLOW)
+#define F0900_P1_SYMB_FREQ_LOW1 0xf462007f
 
 /*P1_SFRLOW0*/
-#define R0900_P1_SFRLOW0  0xf463
-#define F0900_P1_SYMB_FREQ_LOW0  0xf46300ff
+#define R0900_P1_SFRLOW0 0xf463
+#define SFRLOW0 REGx(R0900_P1_SFRLOW0)
+#define F0900_P1_SYMB_FREQ_LOW0 0xf46300ff
 
 /*P1_SFR3*/
-#define R0900_P1_SFR3  0xf464
-#define F0900_P1_SYMB_FREQ3  0xf46400ff
+#define R0900_P1_SFR3 0xf464
+#define SFR3 REGx(R0900_P1_SFR3)
+#define F0900_P1_SYMB_FREQ3 0xf46400ff
+#define SYMB_FREQ3 FLDx(F0900_P1_SYMB_FREQ3)
 
 /*P1_SFR2*/
-#define R0900_P1_SFR2  0xf465
-#define F0900_P1_SYMB_FREQ2  0xf46500ff
+#define R0900_P1_SFR2 0xf465
+#define SFR2 REGx(R0900_P1_SFR2)
+#define F0900_P1_SYMB_FREQ2 0xf46500ff
+#define SYMB_FREQ2 FLDx(F0900_P1_SYMB_FREQ2)
 
 /*P1_SFR1*/
-#define R0900_P1_SFR1  0xf466
-#define F0900_P1_SYMB_FREQ1  0xf46600ff
+#define R0900_P1_SFR1 0xf466
+#define SFR1 REGx(R0900_P1_SFR1)
+#define F0900_P1_SYMB_FREQ1 0xf46600ff
+#define SYMB_FREQ1 FLDx(F0900_P1_SYMB_FREQ1)
 
 /*P1_SFR0*/
-#define R0900_P1_SFR0  0xf467
-#define F0900_P1_SYMB_FREQ0  0xf46700ff
+#define R0900_P1_SFR0 0xf467
+#define SFR0 REGx(R0900_P1_SFR0)
+#define F0900_P1_SYMB_FREQ0 0xf46700ff
+#define SYMB_FREQ0 FLDx(F0900_P1_SYMB_FREQ0)
 
 /*P1_TMGREG2*/
-#define R0900_P1_TMGREG2  0xf468
-#define F0900_P1_TMGREG2  0xf46800ff
+#define R0900_P1_TMGREG2 0xf468
+#define TMGREG2 REGx(R0900_P1_TMGREG2)
+#define F0900_P1_TMGREG2 0xf46800ff
 
 /*P1_TMGREG1*/
-#define R0900_P1_TMGREG1  0xf469
-#define F0900_P1_TMGREG1  0xf46900ff
+#define R0900_P1_TMGREG1 0xf469
+#define TMGREG1 REGx(R0900_P1_TMGREG1)
+#define F0900_P1_TMGREG1 0xf46900ff
 
 /*P1_TMGREG0*/
-#define R0900_P1_TMGREG0  0xf46a
-#define F0900_P1_TMGREG0  0xf46a00ff
+#define R0900_P1_TMGREG0 0xf46a
+#define TMGREG0 REGx(R0900_P1_TMGREG0)
+#define F0900_P1_TMGREG0 0xf46a00ff
 
 /*P1_TMGLOCK1*/
-#define R0900_P1_TMGLOCK1  0xf46b
-#define F0900_P1_TMGLOCK_LEVEL1  0xf46b01ff
+#define R0900_P1_TMGLOCK1 0xf46b
+#define TMGLOCK1 REGx(R0900_P1_TMGLOCK1)
+#define F0900_P1_TMGLOCK_LEVEL1 0xf46b01ff
 
 /*P1_TMGLOCK0*/
-#define R0900_P1_TMGLOCK0  0xf46c
-#define F0900_P1_TMGLOCK_LEVEL0  0xf46c00ff
+#define R0900_P1_TMGLOCK0 0xf46c
+#define TMGLOCK0 REGx(R0900_P1_TMGLOCK0)
+#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
+#define R0900_P1_TMGOBS 0xf46d
+#define TMGOBS REGx(R0900_P1_TMGOBS)
+#define F0900_P1_ROLLOFF_STATUS 0xf46d00c0
+#define ROLLOFF_STATUS FLDx(F0900_P1_ROLLOFF_STATUS)
 
 /*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
+#define R0900_P1_EQUALCFG 0xf46f
+#define EQUALCFG REGx(R0900_P1_EQUALCFG)
+#define F0900_P1_EQUAL_ON 0xf46f0040
+#define F0900_P1_MU_EQUALDFE 0xf46f0007
 
 /*P1_EQUAI1*/
-#define R0900_P1_EQUAI1  0xf470
-#define F0900_P1_EQUA_ACCI1  0xf47001ff
+#define R0900_P1_EQUAI1 0xf470
+#define EQUAI1 REGx(R0900_P1_EQUAI1)
+#define F0900_P1_EQUA_ACCI1 0xf47001ff
 
 /*P1_EQUAQ1*/
-#define R0900_P1_EQUAQ1  0xf471
-#define F0900_P1_EQUA_ACCQ1  0xf47101ff
+#define R0900_P1_EQUAQ1 0xf471
+#define EQUAQ1 REGx(R0900_P1_EQUAQ1)
+#define F0900_P1_EQUA_ACCQ1 0xf47101ff
 
 /*P1_EQUAI2*/
-#define R0900_P1_EQUAI2  0xf472
-#define F0900_P1_EQUA_ACCI2  0xf47201ff
+#define R0900_P1_EQUAI2 0xf472
+#define EQUAI2 REGx(R0900_P1_EQUAI2)
+#define F0900_P1_EQUA_ACCI2 0xf47201ff
 
 /*P1_EQUAQ2*/
-#define R0900_P1_EQUAQ2  0xf473
-#define F0900_P1_EQUA_ACCQ2  0xf47301ff
+#define R0900_P1_EQUAQ2 0xf473
+#define EQUAQ2 REGx(R0900_P1_EQUAQ2)
+#define F0900_P1_EQUA_ACCQ2 0xf47301ff
 
 /*P1_EQUAI3*/
-#define R0900_P1_EQUAI3  0xf474
-#define F0900_P1_EQUA_ACCI3  0xf47401ff
+#define R0900_P1_EQUAI3 0xf474
+#define EQUAI3 REGx(R0900_P1_EQUAI3)
+#define F0900_P1_EQUA_ACCI3 0xf47401ff
 
 /*P1_EQUAQ3*/
-#define R0900_P1_EQUAQ3  0xf475
-#define F0900_P1_EQUA_ACCQ3  0xf47501ff
+#define R0900_P1_EQUAQ3 0xf475
+#define EQUAQ3 REGx(R0900_P1_EQUAQ3)
+#define F0900_P1_EQUA_ACCQ3 0xf47501ff
 
 /*P1_EQUAI4*/
-#define R0900_P1_EQUAI4  0xf476
-#define F0900_P1_EQUA_ACCI4  0xf47601ff
+#define R0900_P1_EQUAI4 0xf476
+#define EQUAI4 REGx(R0900_P1_EQUAI4)
+#define F0900_P1_EQUA_ACCI4 0xf47601ff
 
 /*P1_EQUAQ4*/
-#define R0900_P1_EQUAQ4  0xf477
-#define F0900_P1_EQUA_ACCQ4  0xf47701ff
+#define R0900_P1_EQUAQ4 0xf477
+#define EQUAQ4 REGx(R0900_P1_EQUAQ4)
+#define F0900_P1_EQUA_ACCQ4 0xf47701ff
 
 /*P1_EQUAI5*/
-#define R0900_P1_EQUAI5  0xf478
-#define F0900_P1_EQUA_ACCI5  0xf47801ff
+#define R0900_P1_EQUAI5 0xf478
+#define EQUAI5 REGx(R0900_P1_EQUAI5)
+#define F0900_P1_EQUA_ACCI5 0xf47801ff
 
 /*P1_EQUAQ5*/
-#define R0900_P1_EQUAQ5  0xf479
-#define F0900_P1_EQUA_ACCQ5  0xf47901ff
+#define R0900_P1_EQUAQ5 0xf479
+#define EQUAQ5 REGx(R0900_P1_EQUAQ5)
+#define F0900_P1_EQUA_ACCQ5 0xf47901ff
 
 /*P1_EQUAI6*/
-#define R0900_P1_EQUAI6  0xf47a
-#define F0900_P1_EQUA_ACCI6  0xf47a01ff
+#define R0900_P1_EQUAI6 0xf47a
+#define EQUAI6 REGx(R0900_P1_EQUAI6)
+#define F0900_P1_EQUA_ACCI6 0xf47a01ff
 
 /*P1_EQUAQ6*/
-#define R0900_P1_EQUAQ6  0xf47b
-#define F0900_P1_EQUA_ACCQ6  0xf47b01ff
+#define R0900_P1_EQUAQ6 0xf47b
+#define EQUAQ6 REGx(R0900_P1_EQUAQ6)
+#define F0900_P1_EQUA_ACCQ6 0xf47b01ff
 
 /*P1_EQUAI7*/
-#define R0900_P1_EQUAI7  0xf47c
-#define F0900_P1_EQUA_ACCI7  0xf47c01ff
+#define R0900_P1_EQUAI7 0xf47c
+#define EQUAI7 REGx(R0900_P1_EQUAI7)
+#define F0900_P1_EQUA_ACCI7 0xf47c01ff
 
 /*P1_EQUAQ7*/
-#define R0900_P1_EQUAQ7  0xf47d
-#define F0900_P1_EQUA_ACCQ7  0xf47d01ff
+#define R0900_P1_EQUAQ7 0xf47d
+#define EQUAQ7 REGx(R0900_P1_EQUAQ7)
+#define F0900_P1_EQUA_ACCQ7 0xf47d01ff
 
 /*P1_EQUAI8*/
-#define R0900_P1_EQUAI8  0xf47e
-#define F0900_P1_EQUA_ACCI8  0xf47e01ff
+#define R0900_P1_EQUAI8 0xf47e
+#define EQUAI8 REGx(R0900_P1_EQUAI8)
+#define F0900_P1_EQUA_ACCI8 0xf47e01ff
 
 /*P1_EQUAQ8*/
-#define R0900_P1_EQUAQ8  0xf47f
-#define F0900_P1_EQUA_ACCQ8  0xf47f01ff
+#define R0900_P1_EQUAQ8 0xf47f
+#define EQUAQ8 REGx(R0900_P1_EQUAQ8)
+#define F0900_P1_EQUA_ACCQ8 0xf47f01ff
 
 /*P1_NNOSDATAT1*/
-#define R0900_P1_NNOSDATAT1  0xf480
-#define F0900_P1_NOSDATAT_NORMED1  0xf48000ff
+#define R0900_P1_NNOSDATAT1 0xf480
+#define NNOSDATAT1 REGx(R0900_P1_NNOSDATAT1)
+#define F0900_P1_NOSDATAT_NORMED1 0xf48000ff
+#define NOSDATAT_NORMED1 FLDx(F0900_P1_NOSDATAT_NORMED1)
 
 /*P1_NNOSDATAT0*/
-#define R0900_P1_NNOSDATAT0  0xf481
-#define F0900_P1_NOSDATAT_NORMED0  0xf48100ff
+#define R0900_P1_NNOSDATAT0 0xf481
+#define NNOSDATAT0 REGx(R0900_P1_NNOSDATAT0)
+#define F0900_P1_NOSDATAT_NORMED0 0xf48100ff
+#define NOSDATAT_NORMED0 FLDx(F0900_P1_NOSDATAT_NORMED0)
 
 /*P1_NNOSDATA1*/
-#define R0900_P1_NNOSDATA1  0xf482
-#define F0900_P1_NOSDATA_NORMED1  0xf48200ff
+#define R0900_P1_NNOSDATA1 0xf482
+#define NNOSDATA1 REGx(R0900_P1_NNOSDATA1)
+#define F0900_P1_NOSDATA_NORMED1 0xf48200ff
 
 /*P1_NNOSDATA0*/
-#define R0900_P1_NNOSDATA0  0xf483
-#define F0900_P1_NOSDATA_NORMED0  0xf48300ff
+#define R0900_P1_NNOSDATA0 0xf483
+#define NNOSDATA0 REGx(R0900_P1_NNOSDATA0)
+#define F0900_P1_NOSDATA_NORMED0 0xf48300ff
 
 /*P1_NNOSPLHT1*/
-#define R0900_P1_NNOSPLHT1  0xf484
-#define F0900_P1_NOSPLHT_NORMED1  0xf48400ff
+#define R0900_P1_NNOSPLHT1 0xf484
+#define NNOSPLHT1 REGx(R0900_P1_NNOSPLHT1)
+#define F0900_P1_NOSPLHT_NORMED1 0xf48400ff
+#define NOSPLHT_NORMED1 FLDx(F0900_P1_NOSPLHT_NORMED1)
 
 /*P1_NNOSPLHT0*/
-#define R0900_P1_NNOSPLHT0  0xf485
-#define F0900_P1_NOSPLHT_NORMED0  0xf48500ff
+#define R0900_P1_NNOSPLHT0 0xf485
+#define NNOSPLHT0 REGx(R0900_P1_NNOSPLHT0)
+#define F0900_P1_NOSPLHT_NORMED0 0xf48500ff
+#define NOSPLHT_NORMED0 FLDx(F0900_P1_NOSPLHT_NORMED0)
 
 /*P1_NNOSPLH1*/
-#define R0900_P1_NNOSPLH1  0xf486
-#define F0900_P1_NOSPLH_NORMED1  0xf48600ff
+#define R0900_P1_NNOSPLH1 0xf486
+#define NNOSPLH1 REGx(R0900_P1_NNOSPLH1)
+#define F0900_P1_NOSPLH_NORMED1 0xf48600ff
 
 /*P1_NNOSPLH0*/
-#define R0900_P1_NNOSPLH0  0xf487
-#define F0900_P1_NOSPLH_NORMED0  0xf48700ff
+#define R0900_P1_NNOSPLH0 0xf487
+#define NNOSPLH0 REGx(R0900_P1_NNOSPLH0)
+#define F0900_P1_NOSPLH_NORMED0 0xf48700ff
 
 /*P1_NOSDATAT1*/
-#define R0900_P1_NOSDATAT1  0xf488
-#define F0900_P1_NOSDATAT_UNNORMED1  0xf48800ff
+#define R0900_P1_NOSDATAT1 0xf488
+#define NOSDATAT1 REGx(R0900_P1_NOSDATAT1)
+#define F0900_P1_NOSDATAT_UNNORMED1 0xf48800ff
 
 /*P1_NOSDATAT0*/
-#define R0900_P1_NOSDATAT0  0xf489
-#define F0900_P1_NOSDATAT_UNNORMED0  0xf48900ff
+#define R0900_P1_NOSDATAT0 0xf489
+#define NOSDATAT0 REGx(R0900_P1_NOSDATAT0)
+#define F0900_P1_NOSDATAT_UNNORMED0 0xf48900ff
 
 /*P1_NOSDATA1*/
-#define R0900_P1_NOSDATA1  0xf48a
-#define F0900_P1_NOSDATA_UNNORMED1  0xf48a00ff
+#define R0900_P1_NOSDATA1 0xf48a
+#define NOSDATA1 REGx(R0900_P1_NOSDATA1)
+#define F0900_P1_NOSDATA_UNNORMED1 0xf48a00ff
 
 /*P1_NOSDATA0*/
-#define R0900_P1_NOSDATA0  0xf48b
-#define F0900_P1_NOSDATA_UNNORMED0  0xf48b00ff
+#define R0900_P1_NOSDATA0 0xf48b
+#define NOSDATA0 REGx(R0900_P1_NOSDATA0)
+#define F0900_P1_NOSDATA_UNNORMED0 0xf48b00ff
 
 /*P1_NOSPLHT1*/
-#define R0900_P1_NOSPLHT1  0xf48c
-#define F0900_P1_NOSPLHT_UNNORMED1  0xf48c00ff
+#define R0900_P1_NOSPLHT1 0xf48c
+#define NOSPLHT1 REGx(R0900_P1_NOSPLHT1)
+#define F0900_P1_NOSPLHT_UNNORMED1 0xf48c00ff
 
 /*P1_NOSPLHT0*/
-#define R0900_P1_NOSPLHT0  0xf48d
-#define F0900_P1_NOSPLHT_UNNORMED0  0xf48d00ff
+#define R0900_P1_NOSPLHT0 0xf48d
+#define NOSPLHT0 REGx(R0900_P1_NOSPLHT0)
+#define F0900_P1_NOSPLHT_UNNORMED0 0xf48d00ff
 
 /*P1_NOSPLH1*/
-#define R0900_P1_NOSPLH1  0xf48e
-#define F0900_P1_NOSPLH_UNNORMED1  0xf48e00ff
+#define R0900_P1_NOSPLH1 0xf48e
+#define NOSPLH1 REGx(R0900_P1_NOSPLH1)
+#define F0900_P1_NOSPLH_UNNORMED1 0xf48e00ff
 
 /*P1_NOSPLH0*/
-#define R0900_P1_NOSPLH0  0xf48f
-#define F0900_P1_NOSPLH_UNNORMED0  0xf48f00ff
+#define R0900_P1_NOSPLH0 0xf48f
+#define NOSPLH0 REGx(R0900_P1_NOSPLH0)
+#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
+#define R0900_P1_CAR2CFG 0xf490
+#define CAR2CFG REGx(R0900_P1_CAR2CFG)
+#define F0900_P1_CARRIER3_DISABLE 0xf4900040
+#define F0900_P1_ROTA2ON 0xf4900004
+#define F0900_P1_PH_DET_ALGO2 0xf4900003
+
+/*P1_CFR2CFR1*/
+#define R0900_P1_CFR2CFR1 0xf491
+#define CFR2CFR1 REGx(R0900_P1_CFR2CFR1)
+#define F0900_P1_CFR2TOCFR1_DVBS1 0xf49100c0
+#define F0900_P1_EN_S2CAR2CENTER 0xf4910020
+#define F0900_P1_DIS_BCHERRCFR2 0xf4910010
+#define F0900_P1_CFR2TOCFR1_BETA 0xf4910007
 
 /*P1_CFR22*/
-#define R0900_P1_CFR22  0xf493
-#define F0900_P1_CAR2_FREQ2  0xf49301ff
+#define R0900_P1_CFR22 0xf493
+#define CFR22 REGx(R0900_P1_CFR22)
+#define F0900_P1_CAR2_FREQ2 0xf49301ff
 
 /*P1_CFR21*/
-#define R0900_P1_CFR21  0xf494
-#define F0900_P1_CAR2_FREQ1  0xf49400ff
+#define R0900_P1_CFR21 0xf494
+#define CFR21 REGx(R0900_P1_CFR21)
+#define F0900_P1_CAR2_FREQ1 0xf49400ff
 
 /*P1_CFR20*/
-#define R0900_P1_CFR20  0xf495
-#define F0900_P1_CAR2_FREQ0  0xf49500ff
+#define R0900_P1_CFR20 0xf495
+#define CFR20 REGx(R0900_P1_CFR20)
+#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
+#define R0900_P1_ACLC2S2Q 0xf497
+#define ACLC2S2Q REGx(R0900_P1_ACLC2S2Q)
+#define F0900_P1_ENAB_SPSKSYMB 0xf4970080
+#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
+#define R0900_P1_ACLC2S28 0xf498
+#define ACLC2S28 REGx(R0900_P1_ACLC2S28)
+#define F0900_P1_OLDI3Q_MODE 0xf4980080
+#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
+#define R0900_P1_ACLC2S216A 0xf499
+#define ACLC2S216A REGx(R0900_P1_ACLC2S216A)
+#define F0900_P1_DIS_C3STOPA2 0xf4990080
+#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
+#define R0900_P1_ACLC2S232A 0xf49a
+#define ACLC2S232A REGx(R0900_P1_ACLC2S232A)
+#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
+#define R0900_P1_BCLC2S2Q 0xf49c
+#define BCLC2S2Q REGx(R0900_P1_BCLC2S2Q)
+#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
+#define R0900_P1_BCLC2S28 0xf49d
+#define BCLC2S28 REGx(R0900_P1_BCLC2S28)
+#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
+#define R0900_P1_BCLC2S216A 0xf49e
+#define BCLC2S216A REGx(R0900_P1_BCLC2S216A)
 
 /*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
+#define R0900_P1_BCLC2S232A 0xf49f
+#define BCLC2S232A REGx(R0900_P1_BCLC2S232A)
 
 /*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
+#define R0900_P1_PLROOT2 0xf4ac
+#define PLROOT2 REGx(R0900_P1_PLROOT2)
+#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
+#define R0900_P1_PLROOT1 0xf4ad
+#define PLROOT1 REGx(R0900_P1_PLROOT1)
+#define F0900_P1_PLSCRAMB_ROOT1 0xf4ad00ff
 
 /*P1_PLROOT0*/
-#define R0900_P1_PLROOT0  0xf4ae
-#define F0900_P1_PLSCRAMB_ROOT0  0xf4ae00ff
+#define R0900_P1_PLROOT0 0xf4ae
+#define PLROOT0 REGx(R0900_P1_PLROOT0)
+#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
+#define R0900_P1_MODCODLST0 0xf4b0
+#define MODCODLST0 REGx(R0900_P1_MODCODLST0)
 
 /*P1_MODCODLST1*/
-#define R0900_P1_MODCODLST1  0xf4b1
-#define F0900_P1_DIS_MODCOD29  0xf4b100f0
-#define F0900_P1_DIS_32PSK_9_10  0xf4b1000f
+#define R0900_P1_MODCODLST1 0xf4b1
+#define MODCODLST1 REGx(R0900_P1_MODCODLST1)
+#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
+#define R0900_P1_MODCODLST2 0xf4b2
+#define MODCODLST2 REGx(R0900_P1_MODCODLST2)
+#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
+#define R0900_P1_MODCODLST3 0xf4b3
+#define MODCODLST3 REGx(R0900_P1_MODCODLST3)
+#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
+#define R0900_P1_MODCODLST4 0xf4b4
+#define MODCODLST4 REGx(R0900_P1_MODCODLST4)
+#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
+#define R0900_P1_MODCODLST5 0xf4b5
+#define MODCODLST5 REGx(R0900_P1_MODCODLST5)
+#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
+#define R0900_P1_MODCODLST6 0xf4b6
+#define MODCODLST6 REGx(R0900_P1_MODCODLST6)
+#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
+#define R0900_P1_MODCODLST7 0xf4b7
+#define MODCODLST7 REGx(R0900_P1_MODCODLST7)
+#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
+#define R0900_P1_MODCODLST8 0xf4b8
+#define MODCODLST8 REGx(R0900_P1_MODCODLST8)
+#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
+#define R0900_P1_MODCODLST9 0xf4b9
+#define MODCODLST9 REGx(R0900_P1_MODCODLST9)
+#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
+#define R0900_P1_MODCODLSTA 0xf4ba
+#define MODCODLSTA REGx(R0900_P1_MODCODLSTA)
+#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
+#define R0900_P1_MODCODLSTB 0xf4bb
+#define MODCODLSTB REGx(R0900_P1_MODCODLSTB)
+#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
+#define R0900_P1_MODCODLSTC 0xf4bc
+#define MODCODLSTC REGx(R0900_P1_MODCODLSTC)
+#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
+#define R0900_P1_MODCODLSTD 0xf4bd
+#define MODCODLSTD REGx(R0900_P1_MODCODLSTD)
+#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
+#define R0900_P1_MODCODLSTE 0xf4be
+#define MODCODLSTE REGx(R0900_P1_MODCODLSTE)
+#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
+#define R0900_P1_MODCODLSTF 0xf4bf
+#define MODCODLSTF REGx(R0900_P1_MODCODLSTF)
+#define F0900_P1_DIS_QP_1_4 0xf4bf00f0
+
+/*P1_GAUSSR0*/
+#define R0900_P1_GAUSSR0 0xf4c0
+#define GAUSSR0 REGx(R0900_P1_GAUSSR0)
+#define F0900_P1_EN_CCIMODE 0xf4c00080
+#define F0900_P1_R0_GAUSSIEN 0xf4c0007f
+
+/*P1_CCIR0*/
+#define R0900_P1_CCIR0 0xf4c1
+#define CCIR0 REGx(R0900_P1_CCIR0)
+#define F0900_P1_CCIDETECT_PLHONLY 0xf4c10080
+#define F0900_P1_R0_CCI 0xf4c1007f
+
+/*P1_CCIQUANT*/
+#define R0900_P1_CCIQUANT 0xf4c2
+#define CCIQUANT REGx(R0900_P1_CCIQUANT)
+#define F0900_P1_CCI_BETA 0xf4c200e0
+#define F0900_P1_CCI_QUANT 0xf4c2001f
+
+/*P1_CCITHRES*/
+#define R0900_P1_CCITHRES 0xf4c3
+#define CCITHRES REGx(R0900_P1_CCITHRES)
+#define F0900_P1_CCI_THRESHOLD 0xf4c300ff
+
+/*P1_CCIACC*/
+#define R0900_P1_CCIACC 0xf4c4
+#define CCIACC REGx(R0900_P1_CCIACC)
+#define F0900_P1_CCI_VALUE 0xf4c400ff
 
 /*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
+#define R0900_P1_DMDRESCFG 0xf4c6
+#define DMDRESCFG REGx(R0900_P1_DMDRESCFG)
+#define F0900_P1_DMDRES_RESET 0xf4c60080
+#define F0900_P1_DMDRES_STRALL 0xf4c60008
+#define F0900_P1_DMDRES_NEWONLY 0xf4c60004
+#define F0900_P1_DMDRES_NOSTORE 0xf4c60002
 
 /*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
+#define R0900_P1_DMDRESADR 0xf4c7
+#define DMDRESADR REGx(R0900_P1_DMDRESADR)
+#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
+#define R0900_P1_DMDRESDATA7 0xf4c8
+#define F0900_P1_DMDRES_DATA7 0xf4c800ff
 
 /*P1_DMDRESDATA6*/
-#define R0900_P1_DMDRESDATA6  0xf4c9
-#define F0900_P1_DMDRES_DATA6  0xf4c900ff
+#define R0900_P1_DMDRESDATA6 0xf4c9
+#define F0900_P1_DMDRES_DATA6 0xf4c900ff
 
 /*P1_DMDRESDATA5*/
-#define R0900_P1_DMDRESDATA5  0xf4ca
-#define F0900_P1_DMDRES_DATA5  0xf4ca00ff
+#define R0900_P1_DMDRESDATA5 0xf4ca
+#define F0900_P1_DMDRES_DATA5 0xf4ca00ff
 
 /*P1_DMDRESDATA4*/
-#define R0900_P1_DMDRESDATA4  0xf4cb
-#define F0900_P1_DMDRES_DATA4  0xf4cb00ff
+#define R0900_P1_DMDRESDATA4 0xf4cb
+#define F0900_P1_DMDRES_DATA4 0xf4cb00ff
 
 /*P1_DMDRESDATA3*/
-#define R0900_P1_DMDRESDATA3  0xf4cc
-#define F0900_P1_DMDRES_DATA3  0xf4cc00ff
+#define R0900_P1_DMDRESDATA3 0xf4cc
+#define F0900_P1_DMDRES_DATA3 0xf4cc00ff
 
 /*P1_DMDRESDATA2*/
-#define R0900_P1_DMDRESDATA2  0xf4cd
-#define F0900_P1_DMDRES_DATA2  0xf4cd00ff
+#define R0900_P1_DMDRESDATA2 0xf4cd
+#define F0900_P1_DMDRES_DATA2 0xf4cd00ff
 
 /*P1_DMDRESDATA1*/
-#define R0900_P1_DMDRESDATA1  0xf4ce
-#define F0900_P1_DMDRES_DATA1  0xf4ce00ff
+#define R0900_P1_DMDRESDATA1 0xf4ce
+#define F0900_P1_DMDRES_DATA1 0xf4ce00ff
 
 /*P1_DMDRESDATA0*/
-#define R0900_P1_DMDRESDATA0  0xf4cf
-#define F0900_P1_DMDRES_DATA0  0xf4cf00ff
+#define R0900_P1_DMDRESDATA0 0xf4cf
+#define F0900_P1_DMDRES_DATA0 0xf4cf00ff
 
 /*P1_FFEI1*/
-#define R0900_P1_FFEI1  0xf4d0
-#define F0900_P1_FFE_ACCI1  0xf4d001ff
+#define R0900_P1_FFEI1 0xf4d0
+#define FFEI1 REGx(R0900_P1_FFEI1)
+#define F0900_P1_FFE_ACCI1 0xf4d001ff
 
 /*P1_FFEQ1*/
-#define R0900_P1_FFEQ1  0xf4d1
-#define F0900_P1_FFE_ACCQ1  0xf4d101ff
+#define R0900_P1_FFEQ1 0xf4d1
+#define FFEQ1 REGx(R0900_P1_FFEQ1)
+#define F0900_P1_FFE_ACCQ1 0xf4d101ff
 
 /*P1_FFEI2*/
-#define R0900_P1_FFEI2  0xf4d2
-#define F0900_P1_FFE_ACCI2  0xf4d201ff
+#define R0900_P1_FFEI2 0xf4d2
+#define FFEI2 REGx(R0900_P1_FFEI2)
+#define F0900_P1_FFE_ACCI2 0xf4d201ff
 
 /*P1_FFEQ2*/
-#define R0900_P1_FFEQ2  0xf4d3
-#define F0900_P1_FFE_ACCQ2  0xf4d301ff
+#define R0900_P1_FFEQ2 0xf4d3
+#define FFEQ2 REGx(R0900_P1_FFEQ2)
+#define F0900_P1_FFE_ACCQ2 0xf4d301ff
 
 /*P1_FFEI3*/
-#define R0900_P1_FFEI3  0xf4d4
-#define F0900_P1_FFE_ACCI3  0xf4d401ff
+#define R0900_P1_FFEI3 0xf4d4
+#define FFEI3 REGx(R0900_P1_FFEI3)
+#define F0900_P1_FFE_ACCI3 0xf4d401ff
 
 /*P1_FFEQ3*/
-#define R0900_P1_FFEQ3  0xf4d5
-#define F0900_P1_FFE_ACCQ3  0xf4d501ff
+#define R0900_P1_FFEQ3 0xf4d5
+#define FFEQ3 REGx(R0900_P1_FFEQ3)
+#define F0900_P1_FFE_ACCQ3 0xf4d501ff
 
 /*P1_FFEI4*/
-#define R0900_P1_FFEI4  0xf4d6
-#define F0900_P1_FFE_ACCI4  0xf4d601ff
+#define R0900_P1_FFEI4 0xf4d6
+#define FFEI4 REGx(R0900_P1_FFEI4)
+#define F0900_P1_FFE_ACCI4 0xf4d601ff
 
 /*P1_FFEQ4*/
-#define R0900_P1_FFEQ4  0xf4d7
-#define F0900_P1_FFE_ACCQ4  0xf4d701ff
+#define R0900_P1_FFEQ4 0xf4d7
+#define FFEQ4 REGx(R0900_P1_FFEQ4)
+#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
+#define R0900_P1_FFECFG 0xf4d8
+#define FFECFG REGx(R0900_P1_FFECFG)
+#define F0900_P1_EQUALFFE_ON 0xf4d80040
+#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
+#define R0900_P1_TNRCFG 0xf4e0
+#define TNRCFG REGx(R0900_P1_TNRCFG)
+#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
+#define R0900_P1_TNRCFG2 0xf4e1
+#define TNRCFG2 REGx(R0900_P1_TNRCFG2)
+#define F0900_P1_TUN_IQSWAP 0xf4e10080
+#define F0900_P1_DIS_BWCALC 0xf4e10004
+#define F0900_P1_SHORT_WAITSTATES 0xf4e10002
 
 /*P1_TNRXTAL*/
-#define R0900_P1_TNRXTAL  0xf4e4
-#define F0900_P1_TUN_MCLKDECIMAL  0xf4e400e0
-#define F0900_P1_TUN_XTALFREQ  0xf4e4001f
+#define R0900_P1_TNRXTAL 0xf4e4
+#define TNRXTAL REGx(R0900_P1_TNRXTAL)
+#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
+#define R0900_P1_TNRSTEPS 0xf4e7
+#define TNRSTEPS REGx(R0900_P1_TNRSTEPS)
+#define F0900_P1_TUNER_BW0P125 0xf4e70080
+#define F0900_P1_BWINC_OFFSET 0xf4e70170
+#define F0900_P1_SOFTSTEP_RNG 0xf4e70008
+#define F0900_P1_TUN_BWOFFSET 0xf4e70007
 
 /*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
+#define R0900_P1_TNRGAIN 0xf4e8
+#define TNRGAIN REGx(R0900_P1_TNRGAIN)
+#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
+#define R0900_P1_TNRRF1 0xf4e9
+#define TNRRF1 REGx(R0900_P1_TNRRF1)
+#define F0900_P1_TUN_RFFREQ2 0xf4e900ff
 
 /*P1_TNRRF0*/
-#define R0900_P1_TNRRF0  0xf4ea
-#define F0900_P1_TUN_RFFREQ1  0xf4ea00ff
+#define R0900_P1_TNRRF0 0xf4ea
+#define TNRRF0 REGx(R0900_P1_TNRRF0)
+#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
+#define R0900_P1_TNRBW 0xf4eb
+#define TNRBW REGx(R0900_P1_TNRBW)
+#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
+#define R0900_P1_TNRADJ 0xf4ec
+#define TNRADJ REGx(R0900_P1_TNRADJ)
+#define F0900_P1_STB61X0_CALTIME 0xf4ec0040
 
 /*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
+#define R0900_P1_TNRCTL2 0xf4ed
+#define TNRCTL2 REGx(R0900_P1_TNRCTL2)
+#define F0900_P1_STB61X0_RCCKOFF 0xf4ed0080
+#define F0900_P1_STB61X0_ICP_SDOFF 0xf4ed0040
+#define F0900_P1_STB61X0_DCLOOPOFF 0xf4ed0020
+#define F0900_P1_STB61X0_REFOUTSEL 0xf4ed0010
+#define F0900_P1_STB61X0_CALOFF 0xf4ed0008
+#define F0900_P1_STB6XX0_LPT_BEN 0xf4ed0004
+#define F0900_P1_STB6XX0_RX_OSCP 0xf4ed0002
+#define F0900_P1_STB6XX0_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
+#define R0900_P1_TNRCFG3 0xf4ee
+#define TNRCFG3 REGx(R0900_P1_TNRCFG3)
+#define F0900_P1_TUN_PLLFREQ 0xf4ee001c
+#define F0900_P1_TUN_I2CFREQ_MODE 0xf4ee0003
 
 /*P1_TNRLAUNCH*/
-#define R0900_P1_TNRLAUNCH  0xf4f0
+#define R0900_P1_TNRLAUNCH 0xf4f0
+#define TNRLAUNCH REGx(R0900_P1_TNRLAUNCH)
 
 /*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
+#define R0900_P1_TNRLD 0xf4f0
+#define TNRLD REGx(R0900_P1_TNRLD)
+#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
+#define R0900_P1_TNROBSL 0xf4f6
+#define TNROBSL REGx(R0900_P1_TNROBSL)
+#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
+#define R0900_P1_TNRRESTE 0xf4f7
+#define TNRRESTE REGx(R0900_P1_TNRRESTE)
+#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
+#define R0900_P1_SMAPCOEF7 0xf500
+#define SMAPCOEF7 REGx(R0900_P1_SMAPCOEF7)
+#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
+#define R0900_P1_SMAPCOEF6 0xf501
+#define SMAPCOEF6 REGx(R0900_P1_SMAPCOEF6)
+#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
+#define R0900_P1_SMAPCOEF5 0xf502
+#define SMAPCOEF5 REGx(R0900_P1_SMAPCOEF5)
+#define F0900_P1_DIS_8SCALE 0xf5020080
+#define F0900_P1_SMAPCOEF_8P_LLR23 0xf502017f
+
+/*P1_NCO2MAX1*/
+#define R0900_P1_NCO2MAX1 0xf514
+#define NCO2MAX1 REGx(R0900_P1_NCO2MAX1)
+#define F0900_P1_TETA2_MAXVABS1 0xf51400ff
+
+/*P1_NCO2MAX0*/
+#define R0900_P1_NCO2MAX0 0xf515
+#define NCO2MAX0 REGx(R0900_P1_NCO2MAX0)
+#define F0900_P1_TETA2_MAXVABS0 0xf51500ff
+
+/*P1_NCO2FR1*/
+#define R0900_P1_NCO2FR1 0xf516
+#define NCO2FR1 REGx(R0900_P1_NCO2FR1)
+#define F0900_P1_NCO2FINAL_ANGLE1 0xf51600ff
+
+/*P1_NCO2FR0*/
+#define R0900_P1_NCO2FR0 0xf517
+#define NCO2FR0 REGx(R0900_P1_NCO2FR0)
+#define F0900_P1_NCO2FINAL_ANGLE0 0xf51700ff
+
+/*P1_CFR2AVRGE1*/
+#define R0900_P1_CFR2AVRGE1 0xf518
+#define CFR2AVRGE1 REGx(R0900_P1_CFR2AVRGE1)
+#define F0900_P1_I2C_CFR2AVERAGE1 0xf51800ff
+
+/*P1_CFR2AVRGE0*/
+#define R0900_P1_CFR2AVRGE0 0xf519
+#define CFR2AVRGE0 REGx(R0900_P1_CFR2AVRGE0)
+#define F0900_P1_I2C_CFR2AVERAGE0 0xf51900ff
 
 /*P1_DMDPLHSTAT*/
-#define R0900_P1_DMDPLHSTAT  0xf520
-#define F0900_P1_PLH_STATISTIC  0xf52000ff
+#define R0900_P1_DMDPLHSTAT 0xf520
+#define DMDPLHSTAT REGx(R0900_P1_DMDPLHSTAT)
+#define F0900_P1_PLH_STATISTIC 0xf52000ff
 
 /*P1_LOCKTIME3*/
-#define R0900_P1_LOCKTIME3  0xf522
-#define F0900_P1_DEMOD_LOCKTIME3  0xf52200ff
+#define R0900_P1_LOCKTIME3 0xf522
+#define LOCKTIME3 REGx(R0900_P1_LOCKTIME3)
+#define F0900_P1_DEMOD_LOCKTIME3 0xf52200ff
 
 /*P1_LOCKTIME2*/
-#define R0900_P1_LOCKTIME2  0xf523
-#define F0900_P1_DEMOD_LOCKTIME2  0xf52300ff
+#define R0900_P1_LOCKTIME2 0xf523
+#define LOCKTIME2 REGx(R0900_P1_LOCKTIME2)
+#define F0900_P1_DEMOD_LOCKTIME2 0xf52300ff
 
 /*P1_LOCKTIME1*/
-#define R0900_P1_LOCKTIME1  0xf524
-#define F0900_P1_DEMOD_LOCKTIME1  0xf52400ff
+#define R0900_P1_LOCKTIME1 0xf524
+#define LOCKTIME1 REGx(R0900_P1_LOCKTIME1)
+#define F0900_P1_DEMOD_LOCKTIME1 0xf52400ff
 
 /*P1_LOCKTIME0*/
-#define R0900_P1_LOCKTIME0  0xf525
-#define F0900_P1_DEMOD_LOCKTIME0  0xf52500ff
+#define R0900_P1_LOCKTIME0 0xf525
+#define LOCKTIME0 REGx(R0900_P1_LOCKTIME0)
+#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
+#define R0900_P1_VITSCALE 0xf532
+#define VITSCALE REGx(R0900_P1_VITSCALE)
+#define F0900_P1_NVTH_NOSRANGE 0xf5320080
+#define F0900_P1_VERROR_MAXMODE 0xf5320040
+#define F0900_P1_NSLOWSN_LOCKED 0xf5320008
+#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
+#define R0900_P1_FECM 0xf533
+#define FECM REGx(R0900_P1_FECM)
+#define F0900_P1_DSS_DVB 0xf5330080
+#define DSS_DVB FLDx(F0900_P1_DSS_DVB)
+#define F0900_P1_DSS_SRCH 0xf5330010
+#define F0900_P1_SYNCVIT 0xf5330002
+#define F0900_P1_IQINV 0xf5330001
+#define IQINV FLDx(F0900_P1_IQINV)
 
 /*P1_VTH12*/
-#define R0900_P1_VTH12  0xf534
-#define F0900_P1_VTH12  0xf53400ff
+#define R0900_P1_VTH12 0xf534
+#define VTH12 REGx(R0900_P1_VTH12)
+#define F0900_P1_VTH12 0xf53400ff
 
 /*P1_VTH23*/
-#define R0900_P1_VTH23  0xf535
-#define F0900_P1_VTH23  0xf53500ff
+#define R0900_P1_VTH23 0xf535
+#define VTH23 REGx(R0900_P1_VTH23)
+#define F0900_P1_VTH23 0xf53500ff
 
 /*P1_VTH34*/
-#define R0900_P1_VTH34  0xf536
-#define F0900_P1_VTH34  0xf53600ff
+#define R0900_P1_VTH34 0xf536
+#define VTH34 REGx(R0900_P1_VTH34)
+#define F0900_P1_VTH34 0xf53600ff
 
 /*P1_VTH56*/
-#define R0900_P1_VTH56  0xf537
-#define F0900_P1_VTH56  0xf53700ff
+#define R0900_P1_VTH56 0xf537
+#define VTH56 REGx(R0900_P1_VTH56)
+#define F0900_P1_VTH56 0xf53700ff
 
 /*P1_VTH67*/
-#define R0900_P1_VTH67  0xf538
-#define F0900_P1_VTH67  0xf53800ff
+#define R0900_P1_VTH67 0xf538
+#define VTH67 REGx(R0900_P1_VTH67)
+#define F0900_P1_VTH67 0xf53800ff
 
 /*P1_VTH78*/
-#define R0900_P1_VTH78  0xf539
-#define F0900_P1_VTH78  0xf53900ff
+#define R0900_P1_VTH78 0xf539
+#define VTH78 REGx(R0900_P1_VTH78)
+#define F0900_P1_VTH78 0xf53900ff
 
 /*P1_VITCURPUN*/
-#define R0900_P1_VITCURPUN  0xf53a
-#define F0900_P1_VIT_MAPPING  0xf53a00e0
-#define F0900_P1_VIT_CURPUN  0xf53a001f
+#define R0900_P1_VITCURPUN 0xf53a
+#define VITCURPUN REGx(R0900_P1_VITCURPUN)
+#define F0900_P1_VIT_CURPUN 0xf53a001f
+#define VIT_CURPUN FLDx(F0900_P1_VIT_CURPUN)
 
 /*P1_VERROR*/
-#define R0900_P1_VERROR  0xf53b
-#define F0900_P1_REGERR_VIT  0xf53b00ff
+#define R0900_P1_VERROR 0xf53b
+#define VERROR REGx(R0900_P1_VERROR)
+#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
+#define R0900_P1_PRVIT 0xf53c
+#define PRVIT REGx(R0900_P1_PRVIT)
+#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
+#define R0900_P1_VAVSRVIT 0xf53d
+#define VAVSRVIT REGx(R0900_P1_VAVSRVIT)
+#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
+#define R0900_P1_VSTATUSVIT 0xf53e
+#define VSTATUSVIT REGx(R0900_P1_VSTATUSVIT)
+#define F0900_P1_PRFVIT 0xf53e0010
+#define PRFVIT FLDx(F0900_P1_PRFVIT)
+#define F0900_P1_LOCKEDVIT 0xf53e0008
+#define LOCKEDVIT FLDx(F0900_P1_LOCKEDVIT)
 
 /*P1_VTHINUSE*/
-#define R0900_P1_VTHINUSE  0xf53f
-#define F0900_P1_VIT_INUSE  0xf53f00ff
+#define R0900_P1_VTHINUSE 0xf53f
+#define VTHINUSE REGx(R0900_P1_VTHINUSE)
+#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
+#define R0900_P1_KDIV12 0xf540
+#define KDIV12 REGx(R0900_P1_KDIV12)
+#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
+#define R0900_P1_KDIV23 0xf541
+#define KDIV23 REGx(R0900_P1_KDIV23)
+#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
+#define R0900_P1_KDIV34 0xf542
+#define KDIV34 REGx(R0900_P1_KDIV34)
+#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
+#define R0900_P1_KDIV56 0xf543
+#define KDIV56 REGx(R0900_P1_KDIV56)
+#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
+#define R0900_P1_KDIV67 0xf544
+#define KDIV67 REGx(R0900_P1_KDIV67)
+#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
+#define R0900_P1_KDIV78 0xf545
+#define KDIV78 REGx(R0900_P1_KDIV78)
+#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
+#define R0900_P1_PDELCTRL1 0xf550
+#define PDELCTRL1 REGx(R0900_P1_PDELCTRL1)
+#define F0900_P1_INV_MISMASK 0xf5500080
+#define F0900_P1_FILTER_EN 0xf5500020
+#define F0900_P1_EN_MIS00 0xf5500002
+#define F0900_P1_ALGOSWRST 0xf5500001
+#define ALGOSWRST FLDx(F0900_P1_ALGOSWRST)
 
 /*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
+#define R0900_P1_PDELCTRL2 0xf551
+#define PDELCTRL2 REGx(R0900_P1_PDELCTRL2)
+#define F0900_P1_RESET_UPKO_COUNT 0xf5510040
+#define RESET_UPKO_COUNT FLDx(F0900_P1_RESET_UPKO_COUNT)
+#define F0900_P1_FRAME_MODE 0xf5510002
+#define F0900_P1_NOBCHERRFLG_USE 0xf5510001
 
 /*P1_HYSTTHRESH*/
-#define R0900_P1_HYSTTHRESH  0xf554
-#define F0900_P1_UNLCK_THRESH  0xf55400f0
-#define F0900_P1_DELIN_LCK_THRESH  0xf554000f
+#define R0900_P1_HYSTTHRESH 0xf554
+#define HYSTTHRESH REGx(R0900_P1_HYSTTHRESH)
+#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
+#define R0900_P1_ISIENTRY 0xf55e
+#define ISIENTRY REGx(R0900_P1_ISIENTRY)
+#define F0900_P1_ISI_ENTRY 0xf55e00ff
 
 /*P1_ISIBITENA*/
-#define R0900_P1_ISIBITENA  0xf55f
-#define F0900_P1_ISI_BIT_EN  0xf55f00ff
+#define R0900_P1_ISIBITENA 0xf55f
+#define ISIBITENA REGx(R0900_P1_ISIBITENA)
+#define F0900_P1_ISI_BIT_EN 0xf55f00ff
 
 /*P1_MATSTR1*/
-#define R0900_P1_MATSTR1  0xf560
-#define F0900_P1_MATYPE_CURRENT1  0xf56000ff
+#define R0900_P1_MATSTR1 0xf560
+#define MATSTR1 REGx(R0900_P1_MATSTR1)
+#define F0900_P1_MATYPE_CURRENT1 0xf56000ff
 
 /*P1_MATSTR0*/
-#define R0900_P1_MATSTR0  0xf561
-#define F0900_P1_MATYPE_CURRENT0  0xf56100ff
+#define R0900_P1_MATSTR0 0xf561
+#define MATSTR0 REGx(R0900_P1_MATSTR0)
+#define F0900_P1_MATYPE_CURRENT0 0xf56100ff
 
 /*P1_UPLSTR1*/
-#define R0900_P1_UPLSTR1  0xf562
-#define F0900_P1_UPL_CURRENT1  0xf56200ff
+#define R0900_P1_UPLSTR1 0xf562
+#define UPLSTR1 REGx(R0900_P1_UPLSTR1)
+#define F0900_P1_UPL_CURRENT1 0xf56200ff
 
 /*P1_UPLSTR0*/
-#define R0900_P1_UPLSTR0  0xf563
-#define F0900_P1_UPL_CURRENT0  0xf56300ff
+#define R0900_P1_UPLSTR0 0xf563
+#define UPLSTR0 REGx(R0900_P1_UPLSTR0)
+#define F0900_P1_UPL_CURRENT0 0xf56300ff
 
 /*P1_DFLSTR1*/
-#define R0900_P1_DFLSTR1  0xf564
-#define F0900_P1_DFL_CURRENT1  0xf56400ff
+#define R0900_P1_DFLSTR1 0xf564
+#define DFLSTR1 REGx(R0900_P1_DFLSTR1)
+#define F0900_P1_DFL_CURRENT1 0xf56400ff
 
 /*P1_DFLSTR0*/
-#define R0900_P1_DFLSTR0  0xf565
-#define F0900_P1_DFL_CURRENT0  0xf56500ff
+#define R0900_P1_DFLSTR0 0xf565
+#define DFLSTR0 REGx(R0900_P1_DFLSTR0)
+#define F0900_P1_DFL_CURRENT0 0xf56500ff
 
 /*P1_SYNCSTR*/
-#define R0900_P1_SYNCSTR  0xf566
-#define F0900_P1_SYNC_CURRENT  0xf56600ff
+#define R0900_P1_SYNCSTR 0xf566
+#define SYNCSTR REGx(R0900_P1_SYNCSTR)
+#define F0900_P1_SYNC_CURRENT 0xf56600ff
 
 /*P1_SYNCDSTR1*/
-#define R0900_P1_SYNCDSTR1  0xf567
-#define F0900_P1_SYNCD_CURRENT1  0xf56700ff
+#define R0900_P1_SYNCDSTR1 0xf567
+#define SYNCDSTR1 REGx(R0900_P1_SYNCDSTR1)
+#define F0900_P1_SYNCD_CURRENT1 0xf56700ff
 
 /*P1_SYNCDSTR0*/
-#define R0900_P1_SYNCDSTR0  0xf568
-#define F0900_P1_SYNCD_CURRENT0  0xf56800ff
+#define R0900_P1_SYNCDSTR0 0xf568
+#define SYNCDSTR0 REGx(R0900_P1_SYNCDSTR0)
+#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
+#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_PKTDELIN_LOCK 0xf5690002
+#define PKTDELIN_LOCK FLDx(F0900_P1_PKTDELIN_LOCK)
+#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
+#define R0900_P1_PDELSTATUS2 0xf56a
+#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
+#define R0900_P1_BBFCRCKO1 0xf56b
+#define BBFCRCKO1 REGx(R0900_P1_BBFCRCKO1)
+#define F0900_P1_BBHCRC_KOCNT1 0xf56b00ff
 
 /*P1_BBFCRCKO0*/
-#define R0900_P1_BBFCRCKO0  0xf56c
-#define F0900_P1_BBHCRC_KOCNT0  0xf56c00ff
+#define R0900_P1_BBFCRCKO0 0xf56c
+#define BBFCRCKO0 REGx(R0900_P1_BBFCRCKO0)
+#define F0900_P1_BBHCRC_KOCNT0 0xf56c00ff
 
 /*P1_UPCRCKO1*/
-#define R0900_P1_UPCRCKO1  0xf56d
-#define F0900_P1_PKTCRC_KOCNT1  0xf56d00ff
+#define R0900_P1_UPCRCKO1 0xf56d
+#define UPCRCKO1 REGx(R0900_P1_UPCRCKO1)
+#define F0900_P1_PKTCRC_KOCNT1 0xf56d00ff
 
 /*P1_UPCRCKO0*/
-#define R0900_P1_UPCRCKO0  0xf56e
-#define F0900_P1_PKTCRC_KOCNT0  0xf56e00ff
+#define R0900_P1_UPCRCKO0 0xf56e
+#define UPCRCKO0 REGx(R0900_P1_UPCRCKO0)
+#define F0900_P1_PKTCRC_KOCNT0 0xf56e00ff
+
+/*P1_PDELCTRL3*/
+#define R0900_P1_PDELCTRL3 0xf56f
+#define PDELCTRL3 REGx(R0900_P1_PDELCTRL3)
+#define F0900_P1_PKTDEL_CONTFAIL 0xf56f0080
+#define F0900_P1_NOFIFO_BCHERR 0xf56f0020
 
 /*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
+#define R0900_P1_TSSTATEM 0xf570
+#define TSSTATEM REGx(R0900_P1_TSSTATEM)
+#define F0900_P1_TSDIL_ON 0xf5700080
+#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_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
+#define R0900_P1_TSCFGH 0xf572
+#define TSCFGH REGx(R0900_P1_TSCFGH)
+#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
+#define RST_HWARE FLDx(F0900_P1_RST_HWARE)
 
 /*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
+#define R0900_P1_TSCFGM 0xf573
+#define TSCFGM REGx(R0900_P1_TSCFGM)
+#define F0900_P1_TSFIFO_MANSPEED 0xf57300c0
+#define F0900_P1_TSFIFO_PERMDATA 0xf5730020
+#define F0900_P1_TSFIFO_DPUNACT 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
+#define R0900_P1_TSCFGL 0xf574
+#define TSCFGL REGx(R0900_P1_TSCFGL)
+#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_BITSPEED 0xf5740003
 
 /*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
+#define R0900_P1_TSINSDELH 0xf576
+#define TSINSDELH REGx(R0900_P1_TSINSDELH)
+#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_TSDIVN*/
+#define R0900_P1_TSDIVN 0xf579
+#define TSDIVN REGx(R0900_P1_TSDIVN)
+#define F0900_P1_TSFIFO_SPEEDMODE 0xf57900c0
+
+/*P1_TSCFG4*/
+#define R0900_P1_TSCFG4 0xf57a
+#define TSCFG4 REGx(R0900_P1_TSCFG4)
+#define F0900_P1_TSFIFO_TSSPEEDMODE 0xf57a00c0
 
 /*P1_TSSPEED*/
-#define R0900_P1_TSSPEED  0xf580
-#define F0900_P1_TSFIFO_OUTSPEED  0xf58000ff
+#define R0900_P1_TSSPEED 0xf580
+#define TSSPEED REGx(R0900_P1_TSSPEED)
+#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
+#define R0900_P1_TSSTATUS 0xf581
+#define TSSTATUS REGx(R0900_P1_TSSTATUS)
+#define F0900_P1_TSFIFO_LINEOK 0xf5810080
+#define TSFIFO_LINEOK FLDx(F0900_P1_TSFIFO_LINEOK)
+#define F0900_P1_TSFIFO_ERROR 0xf5810040
+#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
+#define R0900_P1_TSSTATUS2 0xf582
+#define TSSTATUS2 REGx(R0900_P1_TSSTATUS2)
+#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_SCRAMBDETECT 0xf5820002
 
 /*P1_TSBITRATE1*/
-#define R0900_P1_TSBITRATE1  0xf583
-#define F0900_P1_TSFIFO_BITRATE1  0xf58300ff
+#define R0900_P1_TSBITRATE1 0xf583
+#define TSBITRATE1 REGx(R0900_P1_TSBITRATE1)
+#define F0900_P1_TSFIFO_BITRATE1 0xf58300ff
 
 /*P1_TSBITRATE0*/
-#define R0900_P1_TSBITRATE0  0xf584
-#define F0900_P1_TSFIFO_BITRATE0  0xf58400ff
+#define R0900_P1_TSBITRATE0 0xf584
+#define TSBITRATE0 REGx(R0900_P1_TSBITRATE0)
+#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
+#define R0900_P1_ERRCTRL1 0xf598
+#define ERRCTRL1 REGx(R0900_P1_ERRCTRL1)
+#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
+#define R0900_P1_ERRCNT12 0xf599
+#define ERRCNT12 REGx(R0900_P1_ERRCNT12)
+#define F0900_P1_ERRCNT1_OLDVALUE 0xf5990080
+#define F0900_P1_ERR_CNT12 0xf599007f
+#define ERR_CNT12 FLDx(F0900_P1_ERR_CNT12)
 
 /*P1_ERRCNT11*/
-#define R0900_P1_ERRCNT11  0xf59a
-#define F0900_P1_ERR_CNT11  0xf59a00ff
+#define R0900_P1_ERRCNT11 0xf59a
+#define ERRCNT11 REGx(R0900_P1_ERRCNT11)
+#define F0900_P1_ERR_CNT11 0xf59a00ff
+#define ERR_CNT11 FLDx(F0900_P1_ERR_CNT11)
 
 /*P1_ERRCNT10*/
-#define R0900_P1_ERRCNT10  0xf59b
-#define F0900_P1_ERR_CNT10  0xf59b00ff
+#define R0900_P1_ERRCNT10 0xf59b
+#define ERRCNT10 REGx(R0900_P1_ERRCNT10)
+#define F0900_P1_ERR_CNT10 0xf59b00ff
+#define ERR_CNT10 FLDx(F0900_P1_ERR_CNT10)
 
 /*P1_ERRCTRL2*/
-#define R0900_P1_ERRCTRL2  0xf59c
-#define F0900_P1_ERR_SOURCE2  0xf59c00f0
-#define F0900_P1_NUM_EVENT2  0xf59c0007
+#define R0900_P1_ERRCTRL2 0xf59c
+#define ERRCTRL2 REGx(R0900_P1_ERRCTRL2)
+#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
+#define R0900_P1_ERRCNT22 0xf59d
+#define ERRCNT22 REGx(R0900_P1_ERRCNT22)
+#define F0900_P1_ERRCNT2_OLDVALUE 0xf59d0080
+#define F0900_P1_ERR_CNT22 0xf59d007f
+#define ERR_CNT22 FLDx(F0900_P1_ERR_CNT22)
 
 /*P1_ERRCNT21*/
-#define R0900_P1_ERRCNT21  0xf59e
-#define F0900_P1_ERR_CNT21  0xf59e00ff
+#define R0900_P1_ERRCNT21 0xf59e
+#define ERRCNT21 REGx(R0900_P1_ERRCNT21)
+#define F0900_P1_ERR_CNT21 0xf59e00ff
+#define ERR_CNT21 FLDx(F0900_P1_ERR_CNT21)
 
 /*P1_ERRCNT20*/
-#define R0900_P1_ERRCNT20  0xf59f
-#define F0900_P1_ERR_CNT20  0xf59f00ff
+#define R0900_P1_ERRCNT20 0xf59f
+#define ERRCNT20 REGx(R0900_P1_ERRCNT20)
+#define F0900_P1_ERR_CNT20 0xf59f00ff
+#define ERR_CNT20 FLDx(F0900_P1_ERR_CNT20)
 
 /*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
+#define R0900_P1_FECSPY 0xf5a0
+#define FECSPY REGx(R0900_P1_FECSPY)
+#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_BERMETER_DATAMODE 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
+#define R0900_P1_FSPYCFG 0xf5a1
+#define FSPYCFG REGx(R0900_P1_FSPYCFG)
+#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
+#define R0900_P1_FSPYDATA 0xf5a2
+#define FSPYDATA REGx(R0900_P1_FSPYDATA)
+#define F0900_P1_SPY_STUFFING 0xf5a20080
+#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
+#define R0900_P1_FSPYOUT 0xf5a3
+#define FSPYOUT REGx(R0900_P1_FSPYOUT)
+#define F0900_P1_FSPY_DIRECT 0xf5a30080
+#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
+#define R0900_P1_FSTATUS 0xf5a4
+#define FSTATUS REGx(R0900_P1_FSTATUS)
+#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
+#define R0900_P1_FBERCPT4 0xf5a8
+#define FBERCPT4 REGx(R0900_P1_FBERCPT4)
+#define F0900_P1_FBERMETER_CPT4 0xf5a800ff
 
 /*P1_FBERCPT3*/
-#define R0900_P1_FBERCPT3  0xf5a9
-#define F0900_P1_FBERMETER_CPT3  0xf5a900ff
+#define R0900_P1_FBERCPT3 0xf5a9
+#define FBERCPT3 REGx(R0900_P1_FBERCPT3)
+#define F0900_P1_FBERMETER_CPT3 0xf5a900ff
 
 /*P1_FBERCPT2*/
-#define R0900_P1_FBERCPT2  0xf5aa
-#define F0900_P1_FBERMETER_CPT2  0xf5aa00ff
+#define R0900_P1_FBERCPT2 0xf5aa
+#define FBERCPT2 REGx(R0900_P1_FBERCPT2)
+#define F0900_P1_FBERMETER_CPT2 0xf5aa00ff
 
 /*P1_FBERCPT1*/
-#define R0900_P1_FBERCPT1  0xf5ab
-#define F0900_P1_FBERMETER_CPT1  0xf5ab00ff
+#define R0900_P1_FBERCPT1 0xf5ab
+#define FBERCPT1 REGx(R0900_P1_FBERCPT1)
+#define F0900_P1_FBERMETER_CPT1 0xf5ab00ff
 
 /*P1_FBERCPT0*/
-#define R0900_P1_FBERCPT0  0xf5ac
-#define F0900_P1_FBERMETER_CPT0  0xf5ac00ff
+#define R0900_P1_FBERCPT0 0xf5ac
+#define FBERCPT0 REGx(R0900_P1_FBERCPT0)
+#define F0900_P1_FBERMETER_CPT0 0xf5ac00ff
 
 /*P1_FBERERR2*/
-#define R0900_P1_FBERERR2  0xf5ad
-#define F0900_P1_FBERMETER_ERR2  0xf5ad00ff
+#define R0900_P1_FBERERR2 0xf5ad
+#define FBERERR2 REGx(R0900_P1_FBERERR2)
+#define F0900_P1_FBERMETER_ERR2 0xf5ad00ff
 
 /*P1_FBERERR1*/
-#define R0900_P1_FBERERR1  0xf5ae
-#define F0900_P1_FBERMETER_ERR1  0xf5ae00ff
+#define R0900_P1_FBERERR1 0xf5ae
+#define FBERERR1 REGx(R0900_P1_FBERERR1)
+#define F0900_P1_FBERMETER_ERR1 0xf5ae00ff
 
 /*P1_FBERERR0*/
-#define R0900_P1_FBERERR0  0xf5af
-#define F0900_P1_FBERMETER_ERR0  0xf5af00ff
+#define R0900_P1_FBERERR0 0xf5af
+#define FBERERR0 REGx(R0900_P1_FBERERR0)
+#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
+#define R0900_P1_FSPYBER 0xf5b2
+#define FSPYBER REGx(R0900_P1_FSPYBER)
+#define F0900_P1_FSPYBER_SYNCBYTE 0xf5b20010
+#define F0900_P1_FSPYBER_UNSYNC 0xf5b20008
+#define F0900_P1_FSPYBER_CTIME 0xf5b20007
+
+/*RCCFG2*/
+#define R0900_RCCFG2 0xf600
 
 /*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
+#define R0900_TSGENERAL 0xf630
+#define F0900_TSFIFO_DISTS2PAR 0xf6300040
+#define F0900_MUXSTREAM_OUTMODE 0xf6300008
+#define F0900_TSFIFO_PERMPARAL 0xf6300006
 
 /*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
+#define R0900_TSGENERAL1X 0xf670
 
 /*NBITER_NF4*/
-#define R0900_NBITER_NF4  0xfa03
-#define F0900_NBITER_NF_QP_1_2  0xfa0300ff
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#define R0900_NBITER_NF17 0xfa10
+#define F0900_NBITER_NF_8P_9_10 0xfa1000ff
 
 /*NBITERNOERR*/
-#define R0900_NBITERNOERR  0xfa3f
-#define F0900_NBITER_STOP_CRIT  0xfa3f000f
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#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
+#define R0900_GENCFG 0xfa86
+#define F0900_BROADCAST 0xfa860010
+#define F0900_PRIORITY 0xfa860002
+#define F0900_DDEMOD 0xfa860001
 
 /*LDPCERR1*/
-#define R0900_LDPCERR1  0xfa96
-#define F0900_LDPC_ERRORS_COUNTER1  0xfa9600ff
+#define R0900_LDPCERR1 0xfa96
+#define F0900_LDPC_ERRORS_COUNTER1 0xfa9600ff
 
 /*LDPCERR0*/
-#define R0900_LDPCERR0  0xfa97
-#define F0900_LDPC_ERRORS_COUNTER0  0xfa9700ff
+#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
+#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
+#define R0900_TSTRES0 0xff11
+#define F0900_FRESFEC 0xff110080
+
+/*P2_TCTL4*/
+#define R0900_P2_TCTL4 0xff28
+#define F0900_P2_PN4_SELECT 0xff280020
+
+/*P1_TCTL4*/
+#define R0900_P1_TCTL4 0xff48
+#define TCTL4 shiftx(R0900_P1_TCTL4, demod, 0x20)
+#define F0900_P1_PN4_SELECT 0xff480020
 
 /*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
+#define R0900_P2_TSTDISRX 0xff65
+#define F0900_P2_PIN_SELECT1 0xff650008
 
 /*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
+#define R0900_P1_TSTDISRX 0xff67
+#define TSTDISRX shiftx(R0900_P1_TSTDISRX, demod, 2)
+#define F0900_P1_PIN_SELECT1 0xff670008
+#define PIN_SELECT1 shiftx(F0900_P1_PIN_SELECT1, demod, 0x20000)
+
+#define STV0900_NBREGS 723
+#define STV0900_NBFIELDS 1420
 
 #endif
 
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
index 962fde1437ce..b8da87fa637f 100644
--- a/drivers/media/dvb/frontends/stv0900_sw.c
+++ b/drivers/media/dvb/frontends/stv0900_sw.c
@@ -27,56 +27,45 @@
 #include "stv0900_reg.h"
 #include "stv0900_priv.h"
 
-int stv0900_check_signal_presence(struct stv0900_internal *i_params,
+s32 shiftx(s32 x, int demod, s32 shift)
+{
+	if (demod == 1)
+		return x - shift;
+
+	return x;
+}
+
+int stv0900_check_signal_presence(struct stv0900_internal *intp,
 					enum fe_stv0900_demod_num demod)
 {
-	s32 carr_offset,
-	agc2_integr,
-	max_carrier;
+	s32	carr_offset,
+		agc2_integr,
+		max_carrier;
 
-	int no_signal;
+	int no_signal = FALSE;
 
-	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;
-	}
+	carr_offset = (stv0900_read_reg(intp, CFR2) << 8)
+					| stv0900_read_reg(intp, CFR1);
+	carr_offset = ge2comp(carr_offset, 16);
+	agc2_integr = (stv0900_read_reg(intp, AGC2I1) << 8)
+					| stv0900_read_reg(intp, AGC2I0);
+	max_carrier = intp->srch_range[demod] / 1000;
 
 	max_carrier += (max_carrier / 10);
 	max_carrier = 65536 * (max_carrier / 2);
-	max_carrier /= i_params->mclk / 1000;
+	max_carrier /= intp->mclk / 1000;
 	if (max_carrier > 0x4000)
 		max_carrier = 0x4000;
 
 	if ((agc2_integr > 0x2000)
-			|| (carr_offset > + 2*max_carrier)
-			|| (carr_offset < -2*max_carrier))
+			|| (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,
+static void stv0900_get_sw_loop_params(struct stv0900_internal *intp,
 				s32 *frequency_inc, s32 *sw_timeout,
 				s32 *steps,
 				enum fe_stv0900_demod_num demod)
@@ -85,30 +74,19 @@ static void stv0900_get_sw_loop_params(struct stv0900_internal *i_params,
 
 	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;
-	}
+	srate = intp->symbol_rate[demod];
+	max_carrier = intp->srch_range[demod] / 1000;
+	max_carrier += max_carrier / 10;
+	standard = intp->srch_standard[demod];
 
 	max_carrier = 65536 * (max_carrier / 2);
-	max_carrier /= i_params->mclk / 1000;
+	max_carrier /= intp->mclk / 1000;
 
 	if (max_carrier > 0x4000)
 		max_carrier = 0x4000;
 
 	freq_inc = srate;
-	freq_inc /= i_params->mclk >> 10;
+	freq_inc /= intp->mclk >> 10;
 	freq_inc = freq_inc << 6;
 
 	switch (standard) {
@@ -154,7 +132,7 @@ static void stv0900_get_sw_loop_params(struct stv0900_internal *i_params,
 
 }
 
-static int stv0900_search_carr_sw_loop(struct stv0900_internal *i_params,
+static int stv0900_search_carr_sw_loop(struct stv0900_internal *intp,
 				s32 FreqIncr, s32 Timeout, int zigzag,
 				s32 MaxStep, enum fe_stv0900_demod_num demod)
 {
@@ -164,20 +142,11 @@ static int stv0900_search_carr_sw_loop(struct stv0900_internal *i_params,
 		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 = intp->srch_range[demod] / 1000;
+	max_carrier += (max_carrier / 10);
 
 	max_carrier = 65536 * (max_carrier / 2);
-	max_carrier /= i_params->mclk / 1000;
+	max_carrier /= intp->mclk / 1000;
 
 	if (max_carrier > 0x4000)
 		max_carrier = 0x4000;
@@ -190,40 +159,15 @@ static int stv0900_search_carr_sw_loop(struct stv0900_internal *i_params,
 	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;
+		stv0900_write_reg(intp, DMDISTATE, 0x1c);
+		stv0900_write_reg(intp, CFRINIT1, (freqOffset / 256) & 0xff);
+		stv0900_write_reg(intp, CFRINIT0, freqOffset & 0xff);
+		stv0900_write_reg(intp, DMDISTATE, 0x18);
+		stv0900_write_bits(intp, ALGOSWRST, 1);
+
+		if (intp->chip_id == 0x12) {
+			stv0900_write_bits(intp, RST_HWARE, 1);
+			stv0900_write_bits(intp, RST_HWARE, 0);
 		}
 
 		if (zigzag == TRUE) {
@@ -235,8 +179,8 @@ static int stv0900_search_carr_sw_loop(struct stv0900_internal *i_params,
 			freqOffset += + 2 * FreqIncr;
 
 		stepCpt++;
-		lock = stv0900_get_demod_lock(i_params, demod, Timeout);
-		no_signal = stv0900_check_signal_presence(i_params, demod);
+		lock = stv0900_get_demod_lock(intp, demod, Timeout);
+		no_signal = stv0900_check_signal_presence(intp, demod);
 
 	} while ((lock == FALSE)
 			&& (no_signal == FALSE)
@@ -244,269 +188,138 @@ static int stv0900_search_carr_sw_loop(struct stv0900_internal *i_params,
 			&& ((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;
-	}
+	stv0900_write_bits(intp, ALGOSWRST, 0);
 
 	return lock;
 }
 
-int stv0900_sw_algo(struct stv0900_internal *i_params,
+int stv0900_sw_algo(struct stv0900_internal *intp,
 				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,
+	int	lock = FALSE,
+		no_signal,
+		zigzag;
+	s32	s2fw,
+		fqc_inc,
+		sft_stp_tout,
+		trial_cntr,
+		max_steps;
+
+	stv0900_get_sw_loop_params(intp, &fqc_inc, &sft_stp_tout,
 					&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);
+	switch (intp->srch_standard[demod]) {
+	case STV0900_SEARCH_DVBS1:
+	case STV0900_SEARCH_DSS:
+		if (intp->chip_id >= 0x20)
+			stv0900_write_reg(intp, CARFREQ, 0x3b);
+		else
+			stv0900_write_reg(intp, CARFREQ, 0xef);
 
-			stv0900_write_reg(i_params, R0900_P1_DMDCFGMD,
-						0x89);
+		stv0900_write_reg(intp, DMDCFGMD, 0x49);
+		zigzag = FALSE;
+		break;
+	case STV0900_SEARCH_DVBS2:
+		if (intp->chip_id >= 0x20)
+			stv0900_write_reg(intp, CORRELABS, 0x79);
+		else
+			stv0900_write_reg(intp, CORRELABS, 0x68);
 
-			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(intp, DMDCFGMD, 0x89);
 
-			stv0900_write_reg(i_params, R0900_P1_DMDCFGMD,
-							0xc9);
-			zigzag = FALSE;
-			break;
+		zigzag = TRUE;
+		break;
+	case STV0900_AUTO_SEARCH:
+	default:
+		if (intp->chip_id >= 0x20) {
+			stv0900_write_reg(intp, CARFREQ, 0x3b);
+			stv0900_write_reg(intp, CORRELABS, 0x79);
+		} else {
+			stv0900_write_reg(intp, CARFREQ, 0xef);
+			stv0900_write_reg(intp, CORRELABS, 0x68);
 		}
 
-		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));
-
+		stv0900_write_reg(intp, DMDCFGMD, 0xc9);
+		zigzag = 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);
+	trial_cntr = 0;
+	do {
+		lock = stv0900_search_carr_sw_loop(intp,
+						fqc_inc,
+						sft_stp_tout,
+						zigzag,
+						max_steps,
+						demod);
+		no_signal = stv0900_check_signal_presence(intp, demod);
+		trial_cntr++;
+		if ((lock == TRUE)
+				|| (no_signal == TRUE)
+				|| (trial_cntr == 2)) {
+
+			if (intp->chip_id >= 0x20) {
+				stv0900_write_reg(intp, CARFREQ, 0x49);
+				stv0900_write_reg(intp, CORRELABS, 0x9e);
 			} else {
-				stv0900_write_reg(i_params, R0900_P2_CARFREQ,
-						0xef);
-				stv0900_write_reg(i_params, R0900_P2_CORRELABS,
-						0x68);
+				stv0900_write_reg(intp, CARFREQ, 0xed);
+				stv0900_write_reg(intp, CORRELABS, 0x88);
 			}
 
-			stv0900_write_reg(i_params, R0900_P2_DMDCFGMD, 0xc9);
-
-			zigzag = FALSE;
-			break;
-		}
+			if ((stv0900_get_bits(intp, HEADER_MODE) ==
+						STV0900_DVBS2_FOUND) &&
+							(lock == TRUE)) {
+				msleep(sft_stp_tout);
+				s2fw = stv0900_get_bits(intp, FLYWHEEL_CPT);
 
-		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 (s2fw < 0xd) {
+					msleep(sft_stp_tout);
+					s2fw = stv0900_get_bits(intp,
+								FLYWHEEL_CPT);
 				}
 
-				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 (s2fw < 0xd) {
+					lock = FALSE;
 
-					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);
+					if (trial_cntr < 2) {
+						if (intp->chip_id >= 0x20)
+							stv0900_write_reg(intp,
+								CORRELABS,
+								0x79);
+						else
+							stv0900_write_reg(intp,
+								CORRELABS,
+								0x68);
 
-							stv0900_write_reg(i_params, R0900_P2_DMDCFGMD, 0x89);
-						}
+						stv0900_write_reg(intp,
+								DMDCFGMD,
+								0x89);
 					}
 				}
 			}
+		}
 
-		} while ((lock == FALSE) && (trialCounter < 2) && (no_signal == FALSE));
-
-		break;
-	}
+	} while ((lock == FALSE)
+		&& (trial_cntr < 2)
+		&& (no_signal == FALSE));
 
 	return lock;
 }
 
-static u32 stv0900_get_symbol_rate(struct stv0900_internal *i_params,
+static u32 stv0900_get_symbol_rate(struct stv0900_internal *intp,
 					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));
+	s32	rem1, rem2, intval1, intval2, srate;
+
+	srate = (stv0900_get_bits(intp, SYMB_FREQ3) << 24) +
+		(stv0900_get_bits(intp, SYMB_FREQ2) << 16) +
+		(stv0900_get_bits(intp, SYMB_FREQ1) << 8) +
+		(stv0900_get_bits(intp, SYMB_FREQ0));
 	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));
+		srate, stv0900_get_bits(intp, SYMB_FREQ0),
+		stv0900_get_bits(intp, SYMB_FREQ1),
+		stv0900_get_bits(intp, SYMB_FREQ2),
+		stv0900_get_bits(intp, SYMB_FREQ3));
 
 	intval1 = (mclk) >> 16;
 	intval2 = (srate) >> 16;
@@ -520,18 +333,15 @@ static u32 stv0900_get_symbol_rate(struct stv0900_internal *i_params,
 	return srate;
 }
 
-static void stv0900_set_symbol_rate(struct stv0900_internal *i_params,
+static void stv0900_set_symbol_rate(struct stv0900_internal *intp,
 					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,
+	dprintk("%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);
@@ -543,19 +353,16 @@ static void stv0900_set_symbol_rate(struct stv0900_internal *i_params,
 		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));
+	stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0x7f);
+	stv0900_write_reg(intp, SFRINIT1 + 1, (symb & 0xff));
 }
 
-static void stv0900_set_max_symbol_rate(struct stv0900_internal *i_params,
+static void stv0900_set_max_symbol_rate(struct stv0900_internal *intp,
 					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) {
@@ -570,23 +377,20 @@ static void stv0900_set_max_symbol_rate(struct stv0900_internal *i_params,
 	}
 
 	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));
+		stv0900_write_reg(intp, SFRUP1, (symb >> 8) & 0x7f);
+		stv0900_write_reg(intp, SFRUP1 + 1, (symb & 0xff));
 	} else {
-		stv0900_write_reg(i_params, sfr_max_reg, 0x7F);
-		stv0900_write_reg(i_params, sfr_max_reg + 1, 0xFF);
+		stv0900_write_reg(intp, SFRUP1, 0x7f);
+		stv0900_write_reg(intp, SFRUP1 + 1, 0xff);
 	}
 }
 
-static void stv0900_set_min_symbol_rate(struct stv0900_internal *i_params,
+static void stv0900_set_min_symbol_rate(struct stv0900_internal *intp,
 					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;
@@ -601,22 +405,20 @@ static void stv0900_set_min_symbol_rate(struct stv0900_internal *i_params,
 		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));
+	stv0900_write_reg(intp, SFRLOW1, (symb >> 8) & 0xff);
+	stv0900_write_reg(intp, SFRLOW1 + 1, (symb & 0xff));
 }
 
-static s32 stv0900_get_timing_offst(struct stv0900_internal *i_params,
+static s32 stv0900_get_timing_offst(struct stv0900_internal *intp,
 					u32 srate,
 					enum fe_stv0900_demod_num demod)
 {
-	s32 tmgreg,
-	timingoffset;
+	s32 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 = (stv0900_read_reg(intp, TMGREG2) << 16) +
+		       (stv0900_read_reg(intp, TMGREG2 + 1) << 8) +
+		       (stv0900_read_reg(intp, TMGREG2 + 2));
 
 	timingoffset = ge2comp(timingoffset, 24);
 
@@ -630,22 +432,19 @@ static s32 stv0900_get_timing_offst(struct stv0900_internal *i_params,
 	return timingoffset;
 }
 
-static void stv0900_set_dvbs2_rolloff(struct stv0900_internal *i_params,
+static void stv0900_set_dvbs2_rolloff(struct stv0900_internal *intp,
 					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);
+	s32 rolloff;
+
+	if (intp->chip_id == 0x10) {
+		stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1);
+		rolloff = stv0900_read_reg(intp, MATSTR1) & 0x03;
+		stv0900_write_bits(intp, ROLLOFF_CONTROL, rolloff);
+	} else if (intp->chip_id <= 0x20)
+		stv0900_write_bits(intp, MANUALSX_ROLLOFF, 0);
+	else /* cut 3.0 */
+		stv0900_write_bits(intp, MANUALS2_ROLLOFF, 0);
 }
 
 static u32 stv0900_carrier_width(u32 srate, enum fe_stv0900_rolloff ro)
@@ -668,84 +467,47 @@ static u32 stv0900_carrier_width(u32 srate, enum fe_stv0900_rolloff ro)
 	return srate  + (srate * rolloff) / 100;
 }
 
-static int stv0900_check_timing_lock(struct stv0900_internal *i_params,
+static int stv0900_check_timing_lock(struct stv0900_internal *intp,
 				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++;
+	s32	i,
+		timingcpt = 0;
+	u8	car_freq,
+		tmg_th_high,
+		tmg_th_low;
+
+	car_freq = stv0900_read_reg(intp, CARFREQ);
+	tmg_th_high = stv0900_read_reg(intp, TMGTHRISE);
+	tmg_th_low = stv0900_read_reg(intp, TMGTHFALL);
+	stv0900_write_reg(intp, TMGTHRISE, 0x20);
+	stv0900_write_reg(intp, TMGTHFALL, 0x0);
+	stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+	stv0900_write_reg(intp, RTC, 0x80);
+	stv0900_write_reg(intp, RTCS2, 0x40);
+	stv0900_write_reg(intp, CARFREQ, 0x0);
+	stv0900_write_reg(intp, CFRINIT1, 0x0);
+	stv0900_write_reg(intp, CFRINIT0, 0x0);
+	stv0900_write_reg(intp, AGC2REF, 0x65);
+	stv0900_write_reg(intp, DMDISTATE, 0x18);
+	msleep(7);
+
+	for (i = 0; i < 10; i++) {
+		if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2)
+			timingcpt++;
+
+		msleep(1);
+	}
 
-			msleep(1);
-		}
+	if (timingcpt >= 3)
+		timingLock = TRUE;
 
-		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;
-	}
+	stv0900_write_reg(intp, AGC2REF, 0x38);
+	stv0900_write_reg(intp, RTC, 0x88);
+	stv0900_write_reg(intp, RTCS2, 0x68);
+	stv0900_write_reg(intp, CARFREQ, car_freq);
+	stv0900_write_reg(intp, TMGTHRISE, tmg_th_high);
+	stv0900_write_reg(intp, TMGTHFALL, tmg_th_low);
 
 	return	timingLock;
 }
@@ -754,142 +516,114 @@ 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;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_demod_num demod = state->demod;
+	int	lock = FALSE,
+		d = demod;
+	s32	srate,
+		search_range,
+		locktimeout,
+		currier_step,
+		nb_steps,
+		current_step,
+		direction,
+		tuner_freq,
+		timeout,
+		freq;
 
-	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;
-	}
+	srate = intp->symbol_rate[d];
+	search_range = intp->srch_range[d];
 
 	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(intp, d, locktimeout);
 
-				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;
+	if (lock != FALSE)
+		return lock;
+
+	if (srate >= 10000000) {
+		if (stv0900_check_timing_lock(intp, d) == TRUE) {
+			stv0900_write_reg(intp, DMDISTATE, 0x1f);
+			stv0900_write_reg(intp, DMDISTATE, 0x15);
+			lock = stv0900_get_demod_lock(intp, d, demod_timeout);
+		} else
+			lock = FALSE;
+
+		return lock;
+	}
+
+	if (intp->chip_id <= 0x20) {
+		if (srate <= 1000000)
+			currier_step = 500;
+		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;
+
+		if (srate >= 2000000) {
 			timeout = (demod_timeout / 3);
 			if (timeout > 1000)
 				timeout = 1000;
+		} else
+			timeout = (demod_timeout / 2);
+	} else {
+		/*cut 3.0 */
+		currier_step = srate / 4000;
+		timeout = (demod_timeout * 3) / 4;
+	}
 
-			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;
+	nb_steps = ((search_range / 1000) / currier_step);
 
-					while ((current_step <= nb_steps) && (lock == FALSE)) {
+	if ((nb_steps % 2) != 0)
+		nb_steps += 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->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;
+	if (nb_steps <= 0)
+		nb_steps = 2;
+	else if (nb_steps > 12)
+		nb_steps = 12;
 
-					while ((current_step <= nb_steps) && (lock == FALSE)) {
+	current_step = 1;
+	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);
-						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;
-			}
+	if (intp->chip_id <= 0x20) {
+		tuner_freq = intp->freq[d];
+		intp->bw[d] = stv0900_carrier_width(intp->symbol_rate[d],
+				intp->rolloff) + intp->symbol_rate[d];
+	} else
+		tuner_freq = 0;
+
+	while ((current_step <= nb_steps) && (lock == FALSE)) {
+		if (direction > 0)
+			tuner_freq += (current_step * currier_step);
+		else
+			tuner_freq -= (current_step * currier_step);
+
+		if (intp->chip_id <= 0x20) {
+			stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+			stv0900_write_reg(intp, DMDISTATE, 0x1c);
+			stv0900_write_reg(intp, CFRINIT1, 0);
+			stv0900_write_reg(intp, CFRINIT0, 0);
+			stv0900_write_reg(intp, DMDISTATE, 0x1f);
+			stv0900_write_reg(intp, DMDISTATE, 0x15);
+		} else {
+			stv0900_write_reg(intp, DMDISTATE, 0x1c);
+			freq = (tuner_freq * 65536) / (intp->mclk / 1000);
+			stv0900_write_bits(intp, CFR_INIT1, MSB(freq));
+			stv0900_write_bits(intp, CFR_INIT0, LSB(freq));
+			stv0900_write_reg(intp, DMDISTATE, 0x1f);
+			stv0900_write_reg(intp, DMDISTATE, 0x05);
 		}
+
+		lock = stv0900_get_demod_lock(intp, d, timeout);
+		direction *= -1;
+		current_step++;
 	}
 
 	return	lock;
@@ -931,9 +665,7 @@ static void stv0900_get_lock_timeout(s32 *demod_timeout, s32 *fec_timeout,
 		} else if (srate <= 20000000) {
 			(*demod_timeout) = 400;
 			(*fec_timeout) = 130;
-		}
-
-		else {
+		} else {
 			(*demod_timeout) = 300;
 			(*fec_timeout) = 100;
 		}
@@ -946,95 +678,77 @@ static void stv0900_get_lock_timeout(s32 *demod_timeout, s32 *fec_timeout,
 		(*demod_timeout) /= 2;
 }
 
-static void stv0900_set_viterbi_tracq(struct stv0900_internal *i_params,
+static void stv0900_set_viterbi_tracq(struct stv0900_internal *intp,
 					enum fe_stv0900_demod_num demod)
 {
 
-	s32 vth_reg;
+	s32 vth_reg = VTH12;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%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);
+	stv0900_write_reg(intp, vth_reg++, 0xd0);
+	stv0900_write_reg(intp, vth_reg++, 0x7d);
+	stv0900_write_reg(intp, vth_reg++, 0x53);
+	stv0900_write_reg(intp, vth_reg++, 0x2f);
+	stv0900_write_reg(intp, vth_reg++, 0x24);
+	stv0900_write_reg(intp, 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,
+static void stv0900_set_viterbi_standard(struct stv0900_internal *intp,
+				   enum fe_stv0900_search_standard standard,
+				   enum fe_stv0900_fec fec,
 				   enum fe_stv0900_demod_num demod)
 {
+	dprintk("%s: ViterbiStandard = ", __func__);
 
-	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) {
+	switch (standard) {
 	case STV0900_AUTO_SEARCH:
 		dprintk("Auto\n");
-		stv0900_write_reg(i_params, fecmReg, 0x10);
-		stv0900_write_reg(i_params, prvitReg, 0x3F);
+		stv0900_write_reg(intp, FECM, 0x10);
+		stv0900_write_reg(intp, PRVIT, 0x3f);
 		break;
 	case STV0900_SEARCH_DVBS1:
 		dprintk("DVBS1\n");
-		stv0900_write_reg(i_params, fecmReg, 0x00);
-		switch (PunctureRate) {
+		stv0900_write_reg(intp, FECM, 0x00);
+		switch (fec) {
 		case STV0900_FEC_UNKNOWN:
 		default:
-			stv0900_write_reg(i_params, prvitReg, 0x2F);
+			stv0900_write_reg(intp, PRVIT, 0x2f);
 			break;
 		case STV0900_FEC_1_2:
-			stv0900_write_reg(i_params, prvitReg, 0x01);
+			stv0900_write_reg(intp, PRVIT, 0x01);
 			break;
 		case STV0900_FEC_2_3:
-			stv0900_write_reg(i_params, prvitReg, 0x02);
+			stv0900_write_reg(intp, PRVIT, 0x02);
 			break;
 		case STV0900_FEC_3_4:
-			stv0900_write_reg(i_params, prvitReg, 0x04);
+			stv0900_write_reg(intp, PRVIT, 0x04);
 			break;
 		case STV0900_FEC_5_6:
-			stv0900_write_reg(i_params, prvitReg, 0x08);
+			stv0900_write_reg(intp, PRVIT, 0x08);
 			break;
 		case STV0900_FEC_7_8:
-			stv0900_write_reg(i_params, prvitReg, 0x20);
+			stv0900_write_reg(intp, PRVIT, 0x20);
 			break;
 		}
 
 		break;
 	case STV0900_SEARCH_DSS:
 		dprintk("DSS\n");
-		stv0900_write_reg(i_params, fecmReg, 0x80);
-		switch (PunctureRate) {
+		stv0900_write_reg(intp, FECM, 0x80);
+		switch (fec) {
 		case STV0900_FEC_UNKNOWN:
 		default:
-			stv0900_write_reg(i_params, prvitReg, 0x13);
+			stv0900_write_reg(intp, PRVIT, 0x13);
 			break;
 		case STV0900_FEC_1_2:
-			stv0900_write_reg(i_params, prvitReg, 0x01);
+			stv0900_write_reg(intp, PRVIT, 0x01);
 			break;
 		case STV0900_FEC_2_3:
-			stv0900_write_reg(i_params, prvitReg, 0x02);
+			stv0900_write_reg(intp, PRVIT, 0x02);
 			break;
 		case STV0900_FEC_6_7:
-			stv0900_write_reg(i_params, prvitReg, 0x10);
+			stv0900_write_reg(intp, PRVIT, 0x10);
 			break;
 		}
 		break;
@@ -1043,340 +757,277 @@ static void stv0900_set_viterbi_standard(struct stv0900_internal *i_params,
 	}
 }
 
-static void stv0900_track_optimization(struct dvb_frontend *fe)
+static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *intp,
+						enum fe_stv0900_demod_num demod)
 {
-	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_fec prate;
+	s32 rate_fld = stv0900_get_bits(intp, VIT_CURPUN);
 
-	s32 srate, pilots, aclc, freq1, freq0,
-		i = 0, timed, timef, blindTunSw = 0;
+	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;
+	}
 
-	enum fe_stv0900_rolloff rolloff;
-	enum fe_stv0900_modcode foundModcod;
+	return prate;
+}
 
-	dprintk(KERN_INFO "%s\n", __func__);
+void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp,
+					enum fe_stv0900_demod_num demod,
+					u32 srate)
+{
+	if (intp->chip_id >= 0x30) {
+		if (srate >= 15000000) {
+			stv0900_write_reg(intp, ACLC, 0x2b);
+			stv0900_write_reg(intp, BCLC, 0x1a);
+		} else if ((srate >= 7000000) && (15000000 > srate)) {
+			stv0900_write_reg(intp, ACLC, 0x0c);
+			stv0900_write_reg(intp, BCLC, 0x1b);
+		} else if (srate < 7000000) {
+			stv0900_write_reg(intp, ACLC, 0x2c);
+			stv0900_write_reg(intp, BCLC, 0x1c);
+		}
 
-	srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
-	srate += stv0900_get_timing_offst(i_params, srate, demod);
+	} else { /*cut 2.0 and 1.x*/
+		stv0900_write_reg(intp, ACLC, 0x1a);
+		stv0900_write_reg(intp, BCLC, 0x09);
+	}
 
-	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);
-			}
+static void stv0900_track_optimization(struct dvb_frontend *fe)
+{
+	struct stv0900_state *state = fe->demodulator_priv;
+	struct stv0900_internal *intp = state->internal;
+	enum fe_stv0900_demod_num demod = state->demod;
 
-			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);
-				}
+	s32	srate,
+		pilots,
+		aclc,
+		freq1,
+		freq0,
+		i = 0,
+		timed,
+		timef,
+		blind_tun_sw = 0,
+		modulation;
 
-				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);
-					}
-				}
+	enum fe_stv0900_rolloff rolloff;
+	enum fe_stv0900_modcode foundModcod;
 
-			} 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);
-				}
+	dprintk("%s\n", __func__);
 
-			}
+	srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
+	srate += stv0900_get_timing_offst(intp, srate, demod);
 
-			if (i_params->chip_id <= 0x11) {
-				if (i_params->demod_mode != STV0900_SINGLE)
-					stv0900_activate_s2_modcode(i_params, demod);
+	switch (intp->result[demod].standard) {
+	case STV0900_DVBS1_STANDARD:
+	case STV0900_DSS_STANDARD:
+		dprintk("%s: found DVB-S or DSS\n", __func__);
+		if (intp->srch_standard[demod] == STV0900_AUTO_SEARCH) {
+			stv0900_write_bits(intp, DVBS1_ENABLE, 1);
+			stv0900_write_bits(intp, DVBS2_ENABLE, 0);
+		}
 
-			}
+		stv0900_write_bits(intp, ROLLOFF_CONTROL, intp->rolloff);
+		stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1);
 
-			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);
+		if (intp->chip_id < 0x30) {
+			stv0900_write_reg(intp, ERRCTRL1, 0x75);
 			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 (stv0900_get_vit_fec(intp, demod) == STV0900_FEC_1_2) {
+			stv0900_write_reg(intp, GAUSSR0, 0x98);
+			stv0900_write_reg(intp, CCIR0, 0x18);
+		} else {
+			stv0900_write_reg(intp, GAUSSR0, 0x18);
+			stv0900_write_reg(intp, CCIR0, 0x18);
 		}
 
-		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);
+		stv0900_write_reg(intp, ERRCTRL1, 0x75);
+		break;
+	case STV0900_DVBS2_STANDARD:
+		dprintk("%s: found DVB-S2\n", __func__);
+		stv0900_write_bits(intp, DVBS1_ENABLE, 0);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
+		stv0900_write_reg(intp, ACLC, 0);
+		stv0900_write_reg(intp, BCLC, 0);
+		if (intp->result[demod].frame_len == STV0900_LONG_FRAME) {
+			foundModcod = stv0900_get_bits(intp, DEMOD_MODCOD);
+			pilots = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01;
+			aclc = stv0900_get_optim_carr_loop(srate,
+							foundModcod,
+							pilots,
+							intp->chip_id);
+			if (foundModcod <= STV0900_QPSK_910)
+				stv0900_write_reg(intp, ACLC2S2Q, aclc);
+			else if (foundModcod <= STV0900_8PSK_910) {
+				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+				stv0900_write_reg(intp, ACLC2S28, aclc);
 			}
-		}
-
-		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 ((intp->demod_mode == STV0900_SINGLE) &&
+					(foundModcod > STV0900_8PSK_910)) {
+				if (foundModcod <= STV0900_16APSK_910) {
+					stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+					stv0900_write_reg(intp, ACLC2S216A,
+									aclc);
+				} else if (foundModcod <= STV0900_32APSK_910) {
+					stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+					stv0900_write_reg(intp,	ACLC2S232A,
+									aclc);
+				}
 			}
 
-			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++;
-				}
+		} else {
+			modulation = intp->result[demod].modulation;
+			aclc = stv0900_get_optim_short_carr_loop(srate,
+					modulation, intp->chip_id);
+			if (modulation == STV0900_QPSK)
+				stv0900_write_reg(intp, ACLC2S2Q, aclc);
+			else if (modulation == STV0900_8PSK) {
+				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+				stv0900_write_reg(intp, ACLC2S28, aclc);
+			} else if (modulation == STV0900_16APSK) {
+				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+				stv0900_write_reg(intp, ACLC2S216A, aclc);
+			} else if (modulation == STV0900_32APSK) {
+				stv0900_write_reg(intp, ACLC2S2Q, 0x2a);
+				stv0900_write_reg(intp, ACLC2S232A, aclc);
 			}
 
 		}
 
-		if (i_params->chip_id >= 0x20)
-			stv0900_write_reg(i_params, R0900_P1_CARFREQ, 0x49);
+		if (intp->chip_id <= 0x11) {
+			if (intp->demod_mode != STV0900_SINGLE)
+				stv0900_activate_s2_modcod(intp, demod);
 
-		if ((i_params->dmd1_rslts.standard == STV0900_DVBS1_STANDARD) || (i_params->dmd1_rslts.standard == STV0900_DSS_STANDARD))
-			stv0900_set_viterbi_tracq(i_params, demod);
+		}
 
+		stv0900_write_reg(intp, ERRCTRL1, 0x67);
 		break;
+	case STV0900_UNKNOWN_STANDARD:
+	default:
+		dprintk("%s: found unknown standard\n", __func__);
+		stv0900_write_bits(intp, DVBS1_ENABLE, 1);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
+		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);
-				}
+	freq1 = stv0900_read_reg(intp, CFR2);
+	freq0 = stv0900_read_reg(intp, CFR1);
+	rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS);
+	if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) {
+		stv0900_write_reg(intp, SFRSTEP, 0x00);
+		stv0900_write_bits(intp, SCAN_ENABLE, 0);
+		stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+		stv0900_write_reg(intp, TMGCFG2, 0xc1);
+		stv0900_set_symbol_rate(intp, intp->mclk, srate, demod);
+		blind_tun_sw = 1;
+		if (intp->result[demod].standard != STV0900_DVBS2_STANDARD)
+			stv0900_set_dvbs1_track_car_loop(intp, demod, srate);
 
-				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);
-					}
+	}
 
-				}
+	if (intp->chip_id >= 0x20) {
+		if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) ||
+				(intp->srch_standard[demod] ==
+							STV0900_SEARCH_DSS) ||
+				(intp->srch_standard[demod] ==
+							STV0900_AUTO_SEARCH)) {
+			stv0900_write_reg(intp, VAVSRVIT, 0x0a);
+			stv0900_write_reg(intp, VITSCALE, 0x0);
+		}
+	}
 
-			} 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);
-				}
-			}
+	if (intp->chip_id < 0x20)
+		stv0900_write_reg(intp, CARHDR, 0x08);
 
-			stv0900_write_reg(i_params, R0900_P2_ERRCTRL1, 0x67);
+	if (intp->chip_id == 0x10)
+		stv0900_write_reg(intp, CORRELEXP, 0x0a);
 
-			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;
-		}
+	stv0900_write_reg(intp, AGC2REF, 0x38);
 
-		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 ((intp->chip_id >= 0x20) ||
+			(blind_tun_sw == 1) ||
+			(intp->symbol_rate[demod] < 10000000)) {
+		stv0900_write_reg(intp, CFRINIT1, freq1);
+		stv0900_write_reg(intp, CFRINIT0, freq0);
+		intp->bw[demod] = stv0900_carrier_width(srate,
+					intp->rolloff) + 10000000;
 
-		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 ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) {
+			if (intp->srch_algo[demod] != STV0900_WARM_START)
+				stv0900_set_bandwidth(fe, intp->bw[demod]);
 		}
 
-		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 ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) ||
+				(intp->symbol_rate[demod] < 10000000))
+			msleep(50);
+		else
+			msleep(5);
 
-			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);
-			}
+		stv0900_get_lock_timeout(&timed, &timef, srate,
+						STV0900_WARM_START);
 
-			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 (stv0900_get_demod_lock(intp, demod, timed / 2) == FALSE) {
+			stv0900_write_reg(intp, DMDISTATE, 0x1f);
+			stv0900_write_reg(intp, CFRINIT1, freq1);
+			stv0900_write_reg(intp, CFRINIT0, freq0);
+			stv0900_write_reg(intp, DMDISTATE, 0x18);
+			i = 0;
+			while ((stv0900_get_demod_lock(intp,
+							demod,
+							timed / 2) == FALSE) &&
+						(i <= 2)) {
+				stv0900_write_reg(intp, DMDISTATE, 0x1f);
+				stv0900_write_reg(intp, CFRINIT1, freq1);
+				stv0900_write_reg(intp, CFRINIT0, freq0);
+				stv0900_write_reg(intp, 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);
+	if (intp->chip_id >= 0x20)
+		stv0900_write_reg(intp, CARFREQ, 0x49);
+
+	if ((intp->result[demod].standard == STV0900_DVBS1_STANDARD) ||
+			(intp->result[demod].standard == STV0900_DSS_STANDARD))
+		stv0900_set_viterbi_tracq(intp, demod);
 
-		break;
-	}
 }
 
-static int stv0900_get_fec_lock(struct stv0900_internal *i_params, enum fe_stv0900_demod_num demod, s32 time_out)
+static int stv0900_get_fec_lock(struct stv0900_internal *intp,
+				enum fe_stv0900_demod_num demod, s32 time_out)
 {
-	s32 timer = 0, lock = 0, header_field, pktdelin_field, lock_vit_field;
+	s32 timer = 0, lock = 0;
 
 	enum fe_stv0900_search_state dmd_state;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%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);
+	dmd_state = stv0900_get_bits(intp, HEADER_MODE);
 
 	while ((timer < time_out) && (lock == 0)) {
 		switch (dmd_state) {
@@ -1386,10 +1037,10 @@ static int stv0900_get_fec_lock(struct stv0900_internal *i_params, enum fe_stv09
 			lock = 0;
 			break;
 		case STV0900_DVBS2_FOUND:
-			lock = stv0900_get_bits(i_params, pktdelin_field);
+			lock = stv0900_get_bits(intp, PKTDELIN_LOCK);
 			break;
 		case STV0900_DVBS_FOUND:
-			lock = stv0900_get_bits(i_params, lock_vit_field);
+			lock = stv0900_get_bits(intp, LOCKEDVIT);
 			break;
 		}
 
@@ -1400,46 +1051,44 @@ static int stv0900_get_fec_lock(struct stv0900_internal *i_params, enum fe_stv09
 	}
 
 	if (lock)
-		dprintk("DEMOD FEC LOCK OK\n");
+		dprintk("%s: DEMOD FEC LOCK OK\n", __func__);
 	else
-		dprintk("DEMOD FEC LOCK FAIL\n");
+		dprintk("%s: DEMOD FEC LOCK FAIL\n", __func__);
 
 	return lock;
 }
 
-static int stv0900_wait_for_lock(struct stv0900_internal *i_params,
+static int stv0900_wait_for_lock(struct stv0900_internal *intp,
 				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__);
+	s32 timer = 0, lock = 0;
 
-	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);
+	dprintk("%s\n", __func__);
 
-	lock = stv0900_get_demod_lock(i_params, demod, dmd_timeout);
+	lock = stv0900_get_demod_lock(intp, demod, dmd_timeout);
 
 	if (lock)
-		lock = lock && stv0900_get_fec_lock(i_params, demod, fec_timeout);
+		lock = lock && stv0900_get_fec_lock(intp, demod, fec_timeout);
 
 	if (lock) {
 		lock = 0;
 
-		dprintk(KERN_INFO "%s: Timer = %d, time_out = %d\n", __func__, timer, fec_timeout);
+		dprintk("%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);
+			lock = stv0900_get_bits(intp, TSFIFO_LINEOK);
 			msleep(1);
 			timer++;
 		}
 	}
 
 	if (lock)
-		dprintk(KERN_INFO "%s: DEMOD LOCK OK\n", __func__);
+		dprintk("%s: DEMOD LOCK OK\n", __func__);
 	else
-		dprintk(KERN_INFO "%s: DEMOD LOCK FAIL\n", __func__);
+		dprintk("%s: DEMOD LOCK FAIL\n", __func__);
 
 	if (lock)
 		return TRUE;
@@ -1451,43 +1100,43 @@ 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;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_tracking_standard fnd_standard;
-	s32 state_field,
-	dss_dvb_field;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	int hdr_mode = stv0900_get_bits(intp, HEADER_MODE);
 
-	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)
+	switch (hdr_mode) {
+	case 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)
+		break;
+	case 3:
+		if (stv0900_get_bits(intp, DSS_DVB) == 1)
 			fnd_standard = STV0900_DSS_STANDARD;
 		else
 			fnd_standard = STV0900_DVBS1_STANDARD;
-	} else
+
+		break;
+	default:
 		fnd_standard = STV0900_UNKNOWN_STANDARD;
+	}
+
+	dprintk("%s: standard %d\n", __func__, fnd_standard);
 
 	return fnd_standard;
 }
 
-static s32 stv0900_get_carr_freq(struct stv0900_internal *i_params, u32 mclk,
+static s32 stv0900_get_carr_freq(struct stv0900_internal *intp, u32 mclk,
 					enum fe_stv0900_demod_num demod)
 {
-	s32 cfr_field2, cfr_field1, cfr_field0,
-		derot, rem1, rem2, intval1, intval2;
+	s32	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 = (stv0900_get_bits(intp, CAR_FREQ2) << 16) +
+		(stv0900_get_bits(intp, CAR_FREQ1) << 8) +
+		(stv0900_get_bits(intp, CAR_FREQ0));
 
 	derot = ge2comp(derot, 24);
 	intval1 = mclk >> 12;
@@ -1505,7 +1154,7 @@ 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;
+	u32 freq = 0;
 
 	if (&fe->ops)
 		frontend_ops = &fe->ops;
@@ -1514,304 +1163,159 @@ static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe)
 		tuner_ops = &frontend_ops->tuner_ops;
 
 	if (tuner_ops->get_frequency) {
-		if ((tuner_ops->get_frequency(fe, &frequency)) < 0)
+		if ((tuner_ops->get_frequency(fe, &freq)) < 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;
+			dprintk("%s: Frequency=%d\n", __func__, freq);
 
-	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;
+	return freq;
 }
 
-static enum fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
+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;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_demod_num demod = state->demod;
 	enum fe_stv0900_signal_type range = STV0900_OUTOFRANGE;
-	s32 offsetFreq,
-	srate_offset,
-	i = 0;
+	struct stv0900_signal_info *result = &intp->result[demod];
+	s32	offsetFreq,
+		srate_offset;
+	int	i = 0,
+		d = demod;
 
 	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;
-			}
+	if (intp->srch_algo[d] == STV0900_BLIND_SEARCH) {
+		timing = stv0900_read_reg(intp, TMGREG2);
+		i = 0;
+		stv0900_write_reg(intp, SFRSTEP, 0x5c);
+
+		while ((i <= 50) && (timing != 0) && (timing != 0xff)) {
+			timing = stv0900_read_reg(intp, 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;
-		}
+	result->standard = stv0900_get_standard(fe, d);
+	result->frequency = stv0900_get_tuner_freq(fe);
+	offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000;
+	result->frequency += offsetFreq;
+	result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d);
+	srate_offset = stv0900_get_timing_offst(intp, result->symbol_rate, d);
+	result->symbol_rate += srate_offset;
+	result->fec = stv0900_get_vit_fec(intp, d);
+	result->modcode = stv0900_get_bits(intp, DEMOD_MODCOD);
+	result->pilot = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01;
+	result->frame_len = ((u32)stv0900_get_bits(intp, DEMOD_TYPE)) >> 1;
+	result->rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS);
+	switch (result->standard) {
+	case STV0900_DVBS2_STANDARD:
+		result->spectrum = stv0900_get_bits(intp, SPECINV_DEMOD);
+		if (result->modcode <= STV0900_QPSK_910)
+			result->modulation = STV0900_QPSK;
+		else if (result->modcode <= STV0900_8PSK_910)
+			result->modulation = STV0900_8PSK;
+		else if (result->modcode <= STV0900_16APSK_910)
+			result->modulation = STV0900_16APSK;
+		else if (result->modcode <= STV0900_32APSK_910)
+			result->modulation = STV0900_32APSK;
+		else
+			result->modulation = STV0900_UNKNOWN;
 		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;
-		}
+	case STV0900_DVBS1_STANDARD:
+	case STV0900_DSS_STANDARD:
+		result->spectrum = stv0900_get_bits(intp, IQINV);
+		result->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 ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) ||
+				(intp->symbol_rate[d] < 10000000)) {
+		offsetFreq = result->frequency - intp->freq[d];
+		intp->freq[d] = stv0900_get_tuner_freq(fe);
+		if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
+			range = STV0900_RANGEOK;
+		else if (ABS(offsetFreq) <=
+				(stv0900_carrier_width(result->symbol_rate,
+						result->rolloff) / 2000))
+			range = STV0900_RANGEOK;
 
-			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;
-		}
+	} else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
+		range = STV0900_RANGEOK;
 
-		break;
-	}
+	dprintk("%s: range %d\n", __func__, range);
 
 	return range;
 }
 
-static enum fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_frontend *fe)
+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;
+	struct stv0900_internal *intp = 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;
+	s32	srate,
+		demod_timeout,
+		fec_timeout,
+		freq1,
+		freq0;
+
+	intp->result[demod].locked = FALSE;
+
+	if (stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) {
+		srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
+		srate += stv0900_get_timing_offst(intp, srate, demod);
+		if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH)
+			stv0900_set_symbol_rate(intp, intp->mclk, srate, demod);
+
+		stv0900_get_lock_timeout(&demod_timeout, &fec_timeout,
+					srate, STV0900_WARM_START);
+		freq1 = stv0900_read_reg(intp, CFR2);
+		freq0 = stv0900_read_reg(intp, CFR1);
+		stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+		stv0900_write_bits(intp, SPECINV_CONTROL,
+					STV0900_IQ_FORCE_SWAPPED);
+		stv0900_write_reg(intp, DMDISTATE, 0x1c);
+		stv0900_write_reg(intp, CFRINIT1, freq1);
+		stv0900_write_reg(intp, CFRINIT0, freq0);
+		stv0900_write_reg(intp, DMDISTATE, 0x18);
+		if (stv0900_wait_for_lock(intp, demod,
+				demod_timeout, fec_timeout) == TRUE) {
+			intp->result[demod].locked = TRUE;
+			signal_type = stv0900_get_signal_params(fe);
+			stv0900_track_optimization(fe);
+		} else {
+			stv0900_write_bits(intp, SPECINV_CONTROL,
+					STV0900_IQ_FORCE_NORMAL);
+			stv0900_write_reg(intp, DMDISTATE, 0x1c);
+			stv0900_write_reg(intp, CFRINIT1, freq1);
+			stv0900_write_reg(intp, CFRINIT0, freq0);
+			stv0900_write_reg(intp, DMDISTATE, 0x18);
+			if (stv0900_wait_for_lock(intp, demod,
+					demod_timeout, fec_timeout) == TRUE) {
+				intp->result[demod].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;
-	}
+	} else
+		intp->result[demod].locked = FALSE;
 
 	return signal_type;
 }
 
-static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *i_params,
+static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *intp,
 					enum fe_stv0900_demod_num demod)
 {
 	u32 minagc2level = 0xffff,
@@ -1820,105 +1324,54 @@ static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *i_params,
 
 	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);
+	dprintk("%s\n", __func__);
 
-		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;
+	stv0900_write_reg(intp, AGC2REF, 0x38);
+	stv0900_write_bits(intp, SCAN_ENABLE, 0);
+	stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
 
-		if (nb_steps < 0)
-			nb_steps = 1;
+	stv0900_write_bits(intp, AUTO_GUP, 1);
+	stv0900_write_bits(intp, AUTO_GLOW, 1);
 
-		direction = 1;
+	stv0900_write_reg(intp, DMDT0M, 0x0);
 
-		freq_step = (1000000 << 8) / (i_params->mclk >> 8);
+	stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod);
+	nb_steps = -1 + (intp->srch_range[demod] / 1000000);
+	nb_steps /= 2;
+	nb_steps = (2 * nb_steps) + 1;
 
-		init_freq = 0;
+	if (nb_steps < 0)
+		nb_steps = 1;
 
-		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;
 
-			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;
+	freq_step = (1000000 << 8) / (intp->mclk >> 8);
 
-			for (j = 0; j < 10; j++)
-				agc2level += (stv0900_read_reg(i_params, R0900_P1_AGC2I1) << 8)
-						| stv0900_read_reg(i_params, R0900_P1_AGC2I0);
+	init_freq = 0;
 
-			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);
+	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;
+		direction *= -1;
+		stv0900_write_reg(intp, DMDISTATE, 0x5C);
+		stv0900_write_reg(intp, CFRINIT1, (init_freq >> 8) & 0xff);
+		stv0900_write_reg(intp, CFRINIT0, init_freq  & 0xff);
+		stv0900_write_reg(intp, DMDISTATE, 0x58);
+		msleep(10);
+		agc2level = 0;
 
-			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);
+		for (j = 0; j < 10; j++)
+			agc2level += (stv0900_read_reg(intp, AGC2I1) << 8)
+					| stv0900_read_reg(intp, AGC2I0);
 
-			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;
 
-			agc2level /= 10;
+		if (agc2level < minagc2level)
+			minagc2level = agc2level;
 
-			if (agc2level < minagc2level)
-				minagc2level = agc2level;
-		}
-		break;
 	}
 
 	return (u16)minagc2level;
@@ -1927,336 +1380,192 @@ static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *i_params,
 static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
 {
 	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *i_params = state->internal;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_demod_num demod = state->demod;
-	int timingLock = FALSE;
+	int timing_lck = FALSE;
 	s32 i, timingcpt = 0,
 		direction = 1,
 		nb_steps,
 		current_step = 0,
 		tuner_freq;
+	u32 agc2_th,
+		coarse_srate = 0,
+		agc2_integr = 0,
+		currier_step = 1200;
 
-	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 (intp->chip_id >= 0x30)
+		agc2_th = 0x2e00;
+	else
+		agc2_th = 0x1f00;
+
+	stv0900_write_bits(intp, DEMOD_MODE, 0x1f);
+	stv0900_write_reg(intp, TMGCFG, 0x12);
+	stv0900_write_reg(intp, TMGTHRISE, 0xf0);
+	stv0900_write_reg(intp, TMGTHFALL, 0xe0);
+	stv0900_write_bits(intp, SCAN_ENABLE, 1);
+	stv0900_write_bits(intp, CFR_AUTOSCAN, 1);
+	stv0900_write_reg(intp, SFRUP1, 0x83);
+	stv0900_write_reg(intp, SFRUP0, 0xc0);
+	stv0900_write_reg(intp, SFRLOW1, 0x82);
+	stv0900_write_reg(intp, SFRLOW0, 0xa0);
+	stv0900_write_reg(intp, DMDT0M, 0x0);
+	stv0900_write_reg(intp, AGC2REF, 0x50);
+
+	if (intp->chip_id >= 0x30) {
+		stv0900_write_reg(intp, CARFREQ, 0x99);
+		stv0900_write_reg(intp, SFRSTEP, 0x98);
+	} else if (intp->chip_id >= 0x20) {
+		stv0900_write_reg(intp, CARFREQ, 0x6a);
+		stv0900_write_reg(intp, SFRSTEP, 0x95);
+	} else {
+		stv0900_write_reg(intp, CARFREQ, 0xed);
+		stv0900_write_reg(intp, 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
+	if (intp->symbol_rate[demod] <= 2000000)
+		currier_step = 1000;
+	else if (intp->symbol_rate[demod] <= 5000000)
+		currier_step = 2000;
+	else if (intp->symbol_rate[demod] <= 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);
-
-			}
+	nb_steps = -1 + ((intp->srch_range[demod] / 1000) / currier_step);
+	nb_steps /= 2;
+	nb_steps = (2 * nb_steps) + 1;
 
-			agc2_integr /= 10;
-			coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
-			current_step++;
-			direction *= -1;
+	if (nb_steps < 0)
+		nb_steps = 1;
+	else if (nb_steps > 10) {
+		nb_steps = 11;
+		currier_step = (intp->srch_range[demod] / 1000) / 10;
+	}
 
-			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);
+	current_step = 0;
+	direction = 1;
 
-			if ((timingcpt >= 5) && (agc2_integr < 0x1F00) && (coarse_srate < 55000000) && (coarse_srate > 850000)) {
-				timingLock = TRUE;
-			}
+	tuner_freq = intp->freq[demod];
 
-			else if (current_step < nb_steps) {
-				if (direction > 0)
-					tuner_freq += (current_step * currier_step);
-				else
-					tuner_freq -= (current_step * currier_step);
+	while ((timing_lck == FALSE) && (current_step < nb_steps)) {
+		stv0900_write_reg(intp, DMDISTATE, 0x5f);
+		stv0900_write_bits(intp, DEMOD_MODE, 0);
 
-				stv0900_set_tuner(fe, tuner_freq, i_params->tuner1_bw);
-			}
-		}
+		msleep(50);
 
-		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;
+		for (i = 0; i < 10; i++) {
+			if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2)
+				timingcpt++;
 
-		if (nb_steps < 0)
-			nb_steps = 1;
-		else if (nb_steps > 10) {
-			nb_steps = 11;
-			currier_step = (i_params->dmd2_srch_range / 1000) / 10;
+			agc2_integr += (stv0900_read_reg(intp, AGC2I1) << 8) |
+					stv0900_read_reg(intp, AGC2I0);
 		}
 
-		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);
+		agc2_integr /= 10;
+		coarse_srate = stv0900_get_symbol_rate(intp, intp->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 < agc2_th) &&
+				(coarse_srate < 55000000) &&
+				(coarse_srate > 850000))
+			timing_lck = 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->tuner2_bw);
-			}
+			stv0900_set_tuner(fe, tuner_freq, intp->bw[demod]);
 		}
-
-		if (timingLock == FALSE)
-			coarse_srate = 0;
-		else
-			coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
-		break;
 	}
 
+	if (timing_lck == FALSE)
+		coarse_srate = 0;
+	else
+		coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
+
 	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;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_demod_num demod = state->demod;
-	u32 coarse_srate,
-	coarse_freq,
-	symb;
+	u32	coarse_srate,
+		coarse_freq,
+		symb,
+		symbmax,
+		symbmin,
+		symbcomp;
+
+	coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod);
+
+	if (coarse_srate > 3000000) {
+		symbmax = 13 * (coarse_srate / 10);
+		symbmax = (symbmax / 1000) * 65536;
+		symbmax /= (intp->mclk / 1000);
+
+		symbmin = 10 * (coarse_srate / 13);
+		symbmin = (symbmin / 1000)*65536;
+		symbmin /= (intp->mclk / 1000);
+
+		symb = (coarse_srate / 1000) * 65536;
+		symb /= (intp->mclk / 1000);
+	} else {
+		symbmax = 13 * (coarse_srate / 10);
+		symbmax = (symbmax / 100) * 65536;
+		symbmax /= (intp->mclk / 100);
 
-	coarse_srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod);
+		symbmin = 10 * (coarse_srate / 14);
+		symbmin = (symbmin / 100) * 65536;
+		symbmin /= (intp->mclk / 100);
 
-	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));
-			}
+		symb = (coarse_srate / 100) * 65536;
+		symb /= (intp->mclk / 100);
+	}
 
-			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));
-			}
+	symbcomp = 13 * (coarse_srate / 10);
+		coarse_freq = (stv0900_read_reg(intp, CFR2) << 8)
+					| stv0900_read_reg(intp, CFR1);
+
+	if (symbcomp < intp->symbol_rate[demod])
+		coarse_srate = 0;
+	else {
+		stv0900_write_reg(intp, DMDISTATE, 0x1f);
+		stv0900_write_reg(intp, TMGCFG2, 0xc1);
+		stv0900_write_reg(intp, TMGTHRISE, 0x20);
+		stv0900_write_reg(intp, TMGTHFALL, 0x00);
+		stv0900_write_reg(intp, TMGCFG, 0xd2);
+		stv0900_write_bits(intp, CFR_AUTOSCAN, 0);
+		stv0900_write_reg(intp, AGC2REF, 0x38);
+
+		if (intp->chip_id >= 0x30)
+			stv0900_write_reg(intp, CARFREQ, 0x79);
+		else if (intp->chip_id >= 0x20)
+			stv0900_write_reg(intp, CARFREQ, 0x49);
+		else
+			stv0900_write_reg(intp, CARFREQ, 0xed);
 
-			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);
-		}
+		stv0900_write_reg(intp, SFRUP1, (symbmax >> 8) & 0x7f);
+		stv0900_write_reg(intp, SFRUP0, (symbmax & 0xff));
 
-		break;
+		stv0900_write_reg(intp, SFRLOW1, (symbmin >> 8) & 0x7f);
+		stv0900_write_reg(intp, SFRLOW0, (symbmin & 0xff));
+
+		stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0xff);
+		stv0900_write_reg(intp, SFRINIT0, (symb & 0xff));
+
+		stv0900_write_reg(intp, DMDT0M, 0x20);
+		stv0900_write_reg(intp, CFRINIT1, (coarse_freq >> 8) & 0xff);
+		stv0900_write_reg(intp, CFRINIT0, coarse_freq  & 0xff);
+		stv0900_write_reg(intp, DMDISTATE, 0x15);
 	}
 
 	return coarse_srate;
@@ -2265,163 +1574,135 @@ static u32 stv0900_search_srate_fine(struct dvb_frontend *fe)
 static int stv0900_blind_search_algo(struct dvb_frontend *fe)
 {
 	struct stv0900_state *state = fe->demodulator_priv;
-	struct stv0900_internal *i_params = state->internal;
+	struct stv0900_internal *intp = 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) {
+	u8	k_ref_tmg,
+		k_ref_tmg_max,
+		k_ref_tmg_min;
+	u32	coarse_srate,
+		agc2_th;
+	int	lock = FALSE,
+		coarse_fail = FALSE;
+	s32	demod_timeout = 500,
+		fec_timeout = 50,
+		fail_cpt,
+		i,
+		agc2_overflow;
+	u16	agc2_int;
+	u8	dstatus2;
+
+	dprintk("%s\n", __func__);
+
+	if (intp->chip_id < 0x20) {
 		k_ref_tmg_max = 233;
 		k_ref_tmg_min = 143;
 	} else {
-		k_ref_tmg_max = 120;
-		k_ref_tmg_min = 30;
+		k_ref_tmg_max = 110;
+		k_ref_tmg_min = 10;
 	}
 
-	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);
+	if (intp->chip_id <= 0x20)
+		agc2_th = STV0900_BLIND_SEARCH_AGC2_TH;
+	else
+		agc2_th = STV0900_BLIND_SEARCH_AGC2_TH_CUT30;
 
-			stv0900_write_reg(i_params, R0900_P2_CARCFG, 0xC4);
-			stv0900_write_reg(i_params, R0900_P2_RTCS2, 0x44);
+	agc2_int = stv0900_blind_check_agc2_min_level(intp, demod);
 
-			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);
-			}
+	if (agc2_int > STV0900_BLIND_SEARCH_AGC2_TH)
+		return FALSE;
 
-			kref_tmg_reg = R0900_P2_KREFTMG;
-			break;
-		}
+	if (intp->chip_id == 0x10)
+		stv0900_write_reg(intp, CORRELEXP, 0xaa);
 
-		k_ref_tmg = k_ref_tmg_max;
+	if (intp->chip_id < 0x20)
+		stv0900_write_reg(intp, CARHDR, 0x55);
+	else
+		stv0900_write_reg(intp, CARHDR, 0x20);
 
-		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 (intp->chip_id <= 0x20)
+		stv0900_write_reg(intp, CARCFG, 0xc4);
+	else
+		stv0900_write_reg(intp, CARCFG, 0x6);
 
-				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;
+	stv0900_write_reg(intp, RTCS2, 0x44);
 
-				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 (intp->chip_id >= 0x20) {
+		stv0900_write_reg(intp, EQUALCFG, 0x41);
+		stv0900_write_reg(intp, FFECFG, 0x41);
+		stv0900_write_reg(intp, VITSCALE, 0x82);
+		stv0900_write_reg(intp, VAVSRVIT, 0x0);
+	}
 
-						if (agc2_integr >= 0xff00)
-							agc2_overflow++;
+	k_ref_tmg = k_ref_tmg_max;
 
-						dstatus2 = stv0900_read_reg(i_params, R0900_P1_DSTATUS2);
+	do {
+		stv0900_write_reg(intp, KREFTMG, 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(intp,
+							demod,
+							demod_timeout);
+			} else
+				lock = FALSE;
+		} else {
+			fail_cpt = 0;
+			agc2_overflow = 0;
 
-						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);
+			for (i = 0; i < 10; i++) {
+				agc2_int = (stv0900_read_reg(intp, AGC2I1) << 8)
+					| stv0900_read_reg(intp, AGC2I0);
 
-						if (agc2_integr >= 0xff00)
-							agc2_overflow++;
+				if (agc2_int >= 0xff00)
+					agc2_overflow++;
 
-						dstatus2 = stv0900_read_reg(i_params, R0900_P2_DSTATUS2);
+				dstatus2 = stv0900_read_reg(intp, DSTATUS2);
 
-						if (((dstatus2 & 0x1) == 0x1) && ((dstatus2 >> 7) == 1))
-							fail_cpt++;
-					}
-					break;
-				}
+				if (((dstatus2 & 0x1) == 0x1) &&
+						((dstatus2 >> 7) == 1))
+					fail_cpt++;
+			}
 
-				if ((fail_cpt > 7) || (agc2_overflow > 7))
-					coarse_fail = TRUE;
+			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));
-	}
+			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,
+static void stv0900_set_viterbi_acq(struct stv0900_internal *intp,
 					enum fe_stv0900_demod_num demod)
 {
-	s32 vth_reg;
+	s32 vth_reg = VTH12;
 
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%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);
+	stv0900_write_reg(intp, vth_reg++, 0x96);
+	stv0900_write_reg(intp, vth_reg++, 0x64);
+	stv0900_write_reg(intp, vth_reg++, 0x36);
+	stv0900_write_reg(intp, vth_reg++, 0x23);
+	stv0900_write_reg(intp, vth_reg++, 0x1e);
+	stv0900_write_reg(intp, vth_reg++, 0x19);
 }
 
-static void stv0900_set_search_standard(struct stv0900_internal *i_params,
+static void stv0900_set_search_standard(struct stv0900_internal *intp,
 					enum fe_stv0900_demod_num demod)
 {
 
-	int sstndrd;
-
-	dprintk(KERN_INFO "%s\n", __func__);
+	dprintk("%s\n", __func__);
 
-	sstndrd = i_params->dmd1_srch_standard;
-	if (demod == 1)
-		sstndrd = i_params->dmd2_srch_stndrd;
-
-	switch (sstndrd) {
+	switch (intp->srch_standard[demod]) {
 	case STV0900_SEARCH_DVBS1:
 		dprintk("Search Standard = DVBS1\n");
 		break;
@@ -2436,129 +1717,74 @@ static void stv0900_set_search_standard(struct stv0900_internal *i_params,
 		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);
+	switch (intp->srch_standard[demod]) {
+	case STV0900_SEARCH_DVBS1:
+	case STV0900_SEARCH_DSS:
+		stv0900_write_bits(intp, DVBS1_ENABLE, 1);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 0);
+		stv0900_write_bits(intp, STOP_CLKVIT, 0);
+		stv0900_set_dvbs1_track_car_loop(intp,
+						demod,
+						intp->symbol_rate[demod]);
+		stv0900_write_reg(intp, CAR2CFG, 0x22);
+
+		stv0900_set_viterbi_acq(intp, demod);
+		stv0900_set_viterbi_standard(intp,
+					intp->srch_standard[demod],
+					intp->fec[demod], demod);
 
-			} else
-				stv0900_activate_s2_modcode_single(i_params, demod);
+		break;
+	case STV0900_SEARCH_DVBS2:
+		stv0900_write_bits(intp, DVBS1_ENABLE, 0);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
+		stv0900_write_bits(intp, STOP_CLKVIT, 1);
+		stv0900_write_reg(intp, ACLC, 0x1a);
+		stv0900_write_reg(intp, BCLC, 0x09);
+		if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/
+			stv0900_write_reg(intp, CAR2CFG, 0x26);
+		else
+			stv0900_write_reg(intp, CAR2CFG, 0x66);
 
-			if (i_params->dmd1_symbol_rate >= 2000000)
-				stv0900_set_viterbi_acq(i_params, demod);
+		if (intp->demod_mode != STV0900_SINGLE) {
+			if (intp->chip_id <= 0x11)
+				stv0900_stop_all_s2_modcod(intp, demod);
 			else
-				stv0900_set_viterbi_tracq(i_params, demod);
+				stv0900_activate_s2_modcod(intp, demod);
 
-			stv0900_set_viterbi_standard(i_params, i_params->dmd1_srch_standard, i_params->dmd1_fec, demod);
+		} else
+			stv0900_activate_s2_modcod_single(intp, 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(intp, 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);
+		break;
+	case STV0900_AUTO_SEARCH:
+	default:
+		stv0900_write_bits(intp, DVBS1_ENABLE, 1);
+		stv0900_write_bits(intp, DVBS2_ENABLE, 1);
+		stv0900_write_bits(intp, STOP_CLKVIT, 0);
+		stv0900_write_reg(intp, ACLC, 0x1a);
+		stv0900_write_reg(intp, BCLC, 0x09);
+		stv0900_set_dvbs1_track_car_loop(intp,
+						demod,
+						intp->symbol_rate[demod]);
+		if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/
+			stv0900_write_reg(intp, CAR2CFG, 0x26);
+		else
+			stv0900_write_reg(intp, CAR2CFG, 0x66);
 
-			if (i_params->dmd2_symbol_rate >= 2000000)
-				stv0900_set_viterbi_acq(i_params, demod);
+		if (intp->demod_mode != STV0900_SINGLE) {
+			if (intp->chip_id <= 0x11)
+				stv0900_stop_all_s2_modcod(intp, demod);
 			else
-				stv0900_set_viterbi_tracq(i_params, demod);
+				stv0900_activate_s2_modcod(intp, demod);
 
-			stv0900_set_viterbi_standard(i_params, i_params->dmd2_srch_stndrd, i_params->dmd2_fec, demod);
+		} else
+			stv0900_activate_s2_modcod_single(intp, demod);
 
-			break;
-		}
+		stv0900_set_viterbi_tracq(intp, demod);
+		stv0900_set_viterbi_standard(intp,
+						intp->srch_standard[demod],
+						intp->fec[demod], demod);
 
 		break;
 	}
@@ -2567,10 +1793,11 @@ static void stv0900_set_search_standard(struct stv0900_internal *i_params,
 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;
+	struct stv0900_internal *intp = state->internal;
 	enum fe_stv0900_demod_num demod = state->demod;
 
-	s32 demod_timeout = 500, fec_timeout = 50, stream_merger_field;
+	s32 demod_timeout = 500, fec_timeout = 50;
+	s32 aq_power, agc1_power, i;
 
 	int lock = FALSE, low_sr = FALSE;
 
@@ -2578,157 +1805,117 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
 	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;
+	dprintk("%s\n", __func__);
 
-		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);
+	algo = intp->srch_algo[demod];
+	stv0900_write_bits(intp, RST_HWARE, 1);
+	stv0900_write_reg(intp, DMDISTATE, 0x5c);
+	if (intp->chip_id >= 0x20) {
+		if (intp->symbol_rate[demod] > 5000000)
+			stv0900_write_reg(intp, 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);
+			stv0900_write_reg(intp, CORRELABS, 0x82);
+	} else
+		stv0900_write_reg(intp, CORRELABS, 0x88);
 
-		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_get_lock_timeout(&demod_timeout, &fec_timeout,
+				intp->symbol_rate[demod],
+				intp->srch_algo[demod]);
 
-		stv0900_write_bits(i_params, F0900_P2_RST_HWARE, 1);
+	if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) {
+		intp->bw[demod] = 2 * 36000000;
 
-		stream_merger_field = F0900_P2_RST_HWARE;
+		stv0900_write_reg(intp, TMGCFG2, 0xc0);
+		stv0900_write_reg(intp, CORRELMANT, 0x70);
 
-		stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5C);
+		stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod);
+	} else {
+		stv0900_write_reg(intp, DMDT0M, 0x20);
+		stv0900_write_reg(intp, TMGCFG, 0xd2);
 
-		if (i_params->chip_id >= 0x20)
-			stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x9e);
+		if (intp->symbol_rate[demod] < 2000000)
+			stv0900_write_reg(intp, CORRELMANT, 0x63);
 		else
-			stv0900_write_reg(i_params, R0900_P2_CORRELABS, 0x88);
+			stv0900_write_reg(intp, CORRELMANT, 0x70);
 
-		stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, i_params->dmd2_symbol_rate, i_params->dmd2_srch_algo);
+		stv0900_write_reg(intp, AGC2REF, 0x38);
 
-		if (i_params->dmd2_srch_algo == STV0900_BLIND_SEARCH) {
-			i_params->tuner2_bw = 2 * 36000000;
+		intp->bw[demod] =
+				stv0900_carrier_width(intp->symbol_rate[demod],
+								intp->rolloff);
+		if (intp->chip_id >= 0x20) {
+			stv0900_write_reg(intp, KREFTMG, 0x5a);
 
-			stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x00);
-			stv0900_write_reg(i_params, R0900_P2_CORRELMANT, 0x70);
+			if (intp->srch_algo[demod] == STV0900_COLD_START) {
+				intp->bw[demod] += 10000000;
+				intp->bw[demod] *= 15;
+				intp->bw[demod] /= 10;
+			} else if (intp->srch_algo[demod] == STV0900_WARM_START)
+				intp->bw[demod] += 10000000;
 
-			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);
+			stv0900_write_reg(intp, KREFTMG, 0xc1);
+			intp->bw[demod] += 10000000;
+			intp->bw[demod] *= 15;
+			intp->bw[demod] /= 10;
+		}
 
-			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);
+		stv0900_write_reg(intp, TMGCFG2, 0xc1);
 
-			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);
+		stv0900_set_symbol_rate(intp, intp->mclk,
+					intp->symbol_rate[demod], demod);
+		stv0900_set_max_symbol_rate(intp, intp->mclk,
+					intp->symbol_rate[demod], demod);
+		stv0900_set_min_symbol_rate(intp, intp->mclk,
+					intp->symbol_rate[demod], demod);
+		if (intp->symbol_rate[demod] >= 10000000)
+			low_sr = FALSE;
+		else
+			low_sr = TRUE;
 
-			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_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
 
-			stv0900_write_reg(i_params, R0900_P2_TMGCFG2, 0x01);
+	agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
+				stv0900_get_bits(intp, AGCIQ_VALUE0));
 
-			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;
+	aq_power = 0;
 
-		}
+	if (agc1_power == 0) {
+		for (i = 0; i < 5; i++)
+			aq_power += (stv0900_get_bits(intp, POWER_I) +
+					stv0900_get_bits(intp, POWER_Q)) / 2;
 
-		stv0900_set_tuner(fe, i_params->tuner2_freq, i_params->tuner2_bw);
+		aq_power /= 5;
+	}
 
-		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);
+	if ((agc1_power == 0) && (aq_power < IQPOWER_THRESHOLD)) {
+		intp->result[demod].locked = FALSE;
+		signal_type = STV0900_NOAGC1;
+		dprintk("%s: NO AGC1, POWERI, POWERQ\n", __func__);
+	} else {
+		stv0900_write_bits(intp, SPECINV_CONTROL,
+					intp->srch_iq_inv[demod]);
+		if (intp->chip_id <= 0x20) /*cut 2.0*/
+			stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1);
+		else /*cut 3.0*/
+			stv0900_write_bits(intp, MANUALS2_ROLLOFF, 1);
 
-		stv0900_set_search_standard(i_params, demod);
+		stv0900_set_search_standard(intp, demod);
 
-		if (i_params->dmd2_srch_algo != STV0900_BLIND_SEARCH)
-			stv0900_start_search(i_params, demod);
-		break;
+		if (intp->srch_algo[demod] != STV0900_BLIND_SEARCH)
+			stv0900_start_search(intp, demod);
 	}
 
-	if (i_params->chip_id == 0x12) {
-		stv0900_write_bits(i_params, stream_merger_field, 0);
+	if (signal_type == STV0900_NOAGC1)
+		return signal_type;
+
+	if (intp->chip_id == 0x12) {
+		stv0900_write_bits(intp, RST_HWARE, 0);
 		msleep(3);
-		stv0900_write_bits(i_params, stream_merger_field, 1);
-		stv0900_write_bits(i_params, stream_merger_field, 0);
+		stv0900_write_bits(intp, RST_HWARE, 1);
+		stv0900_write_bits(intp, RST_HWARE, 0);
 	}
 
 	if (algo == STV0900_BLIND_SEARCH)
@@ -2736,12 +1923,12 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *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);
+		lock = stv0900_get_demod_lock(intp, 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 (stv0900_check_timing_lock(intp, demod) == TRUE)
+				lock = stv0900_sw_algo(intp, demod);
 		}
 	}
 
@@ -2750,98 +1937,64 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *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)) {
+		if (intp->chip_id <= 0x11) {
+			if ((stv0900_get_standard(fe, 0) ==
+						STV0900_DVBS1_STANDARD) &&
+			   (stv0900_get_standard(fe, 1) ==
+						STV0900_DVBS1_STANDARD)) {
 				msleep(20);
-				stv0900_write_bits(i_params, stream_merger_field, 0);
+				stv0900_write_bits(intp, RST_HWARE, 0);
 			} else {
-				stv0900_write_bits(i_params, stream_merger_field, 0);
+				stv0900_write_bits(intp, RST_HWARE, 0);
 				msleep(3);
-				stv0900_write_bits(i_params, stream_merger_field, 1);
-				stv0900_write_bits(i_params, stream_merger_field, 0);
+				stv0900_write_bits(intp, RST_HWARE, 1);
+				stv0900_write_bits(intp, RST_HWARE, 0);
 			}
-		} else if (i_params->chip_id == 0x20) {
-			stv0900_write_bits(i_params, stream_merger_field, 0);
+
+		} else if (intp->chip_id >= 0x20) {
+			stv0900_write_bits(intp, RST_HWARE, 0);
 			msleep(3);
-			stv0900_write_bits(i_params, stream_merger_field, 1);
-			stv0900_write_bits(i_params, stream_merger_field, 0);
+			stv0900_write_bits(intp, RST_HWARE, 1);
+			stv0900_write_bits(intp, RST_HWARE, 0);
 		}
 
-		if (stv0900_wait_for_lock(i_params, demod, fec_timeout, fec_timeout) == TRUE) {
+		if (stv0900_wait_for_lock(intp, 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;
+			intp->result[demod].locked = TRUE;
+			if (intp->result[demod].standard ==
+						STV0900_DVBS2_STANDARD) {
+				stv0900_set_dvbs2_rolloff(intp, demod);
+				stv0900_write_bits(intp, RESET_UPKO_COUNT, 1);
+				stv0900_write_bits(intp, RESET_UPKO_COUNT, 0);
+				stv0900_write_reg(intp, ERRCTRL1, 0x67);
+			} else {
+				stv0900_write_reg(intp, ERRCTRL1, 0x75);
 			}
+
+			stv0900_write_reg(intp, FBERCPT4, 0);
+			stv0900_write_reg(intp, ERRCTRL2, 0xc1);
 		} 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;
-			}
+			no_signal = stv0900_check_signal_presence(intp, demod);
+
+				intp->result[demod].locked = FALSE;
 		}
 	}
 
-	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;
+	if ((signal_type != STV0900_NODATA) || (no_signal != FALSE))
+		return signal_type;
 
-			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;
-		}
+	if (intp->chip_id > 0x11) {
+		intp->result[demod].locked = FALSE;
+		return signal_type;
 	}
 
+	if ((stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) &&
+	   (intp->srch_iq_inv[demod] <= STV0900_IQ_AUTO_NORMAL_FIRST))
+		signal_type = stv0900_dvbs1_acq_workaround(fe);
+
 	return signal_type;
 }
 
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index 488bdfb34fb3..48edd542242e 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -825,7 +825,7 @@ static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate
 		sym /= (state->mclk >> 7);
 	}
 
-	if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0xff)) < 0) /* MSB */
+	if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0x7f)) < 0) /* MSB */
 		goto err;
 	if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */
 		goto err;
@@ -1238,6 +1238,8 @@ static int stv090x_delivery_search(struct stv090x_state *state)
 				goto err;
 		}
 
+		if (stv090x_set_vit_thtracq(state) < 0)
+			goto err;
 		break;
 
 	case STV090x_SEARCH_AUTO:
@@ -1278,17 +1280,8 @@ static int stv090x_delivery_search(struct stv090x_state *state)
 				goto err;
 		}
 
-		if (state->srate >= 2000000) {
-			/* Srate >= 2MSPS, Viterbi threshold to acquire */
-			if (stv090x_set_vit_thacq(state) < 0)
-				goto err;
-		} else {
-			/* Srate < 2MSPS, Reset Viterbi thresholdto track
-			 * and then re-acquire
-			 */
-			if (stv090x_set_vit_thtracq(state) < 0)
-				goto err;
-		}
+		if (stv090x_set_vit_thacq(state) < 0)
+			goto err;
 
 		if (stv090x_set_viterbi(state) < 0)
 			goto err;
@@ -1317,7 +1310,7 @@ static int stv090x_start_search(struct stv090x_state *state)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0)
 				goto err;
-			if (STV090x_WRITE_DEMOD(state, CFRUP1, 0xff) < 0)
+			if (STV090x_WRITE_DEMOD(state, CFRUP0, 0xff) < 0)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0)
 				goto err;
@@ -1371,7 +1364,7 @@ static int stv090x_start_search(struct stv090x_state *state)
 
 		if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0)
 			goto err;
-		if (STV090x_WRITE_DEMOD(state, CFRUP1, LSB(freq)) < 0)
+		if (STV090x_WRITE_DEMOD(state, CFRUP0, LSB(freq)) < 0)
 			goto err;
 
 		freq *= -1;
@@ -1422,6 +1415,9 @@ static int stv090x_start_search(struct stv090x_state *state)
 	if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0)
 		goto err;
 
+	if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0)
+		goto err;
+
 	if (state->dev_ver >= 0x20) {
 		/*Frequency offset detector setting*/
 		if (state->srate < 2000000) {
@@ -1430,20 +1426,22 @@ static int stv090x_start_search(struct stv090x_state *state)
 				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0)
 					goto err;
 			} else {
-				/* Cut 2 */
+				/* Cut 3 */
 				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0)
 					goto err;
 			}
 			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0)
 				goto err;
-		}
-
-		if (state->srate < 10000000) {
+		} else if (state->srate < 10000000) {
 			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0)
 				goto err;
+			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0)
+				goto err;
 		} else {
 			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0)
 				goto err;
+			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0)
+				goto err;
 		}
 	} else {
 		if (state->srate < 10000000) {
@@ -1485,14 +1483,14 @@ err:
 
 static int stv090x_get_agc2_min_level(struct stv090x_state *state)
 {
-	u32 agc2_min = 0, agc2 = 0, freq_init, freq_step, reg;
+	u32 agc2_min = 0xffff, agc2 = 0, freq_init, freq_step, reg;
 	s32 i, j, steps, dir;
 
 	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
 		goto err;
 	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
-	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
+	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
 	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
 		goto err;
 
@@ -1509,10 +1507,8 @@ static int stv090x_get_agc2_min_level(struct stv090x_state *state)
 	if (stv090x_set_srate(state, 1000000) < 0)
 		goto err;
 
-	steps  = -1 + state->search_range / 1000000;
-	steps /= 2;
-	steps  = (2 * steps) + 1;
-	if (steps < 0)
+	steps  = state->search_range / 1000000;
+	if (steps <= 0)
 		steps = 1;
 
 	dir = 1;
@@ -1525,7 +1521,7 @@ static int stv090x_get_agc2_min_level(struct stv090x_state *state)
 		else
 			freq_init = freq_init - (freq_step * i);
 
-		dir = -1;
+		dir *= -1;
 
 		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */
 			goto err;
@@ -1536,13 +1532,14 @@ static int stv090x_get_agc2_min_level(struct stv090x_state *state)
 		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */
 			goto err;
 		msleep(10);
+
+		agc2 = 0;
 		for (j = 0; j < 10; j++) {
-			agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
-			agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+			agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
+				STV090x_READ_DEMOD(state, AGC2I0);
 		}
 		agc2 /= 10;
-		agc2_min = 0xffff;
-		if (agc2 < 0xffff)
+		if (agc2 < agc2_min)
 			agc2_min = agc2;
 	}
 
@@ -1584,6 +1581,12 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 	int tmg_lock = 0, i;
 	s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq;
 	u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg;
+	u32 agc2th;
+
+	if (state->dev_ver >= 0x30)
+		agc2th = 0x2e00;
+	else
+		agc2th = 0x1f00;
 
 	reg = STV090x_READ_DEMOD(state, DMDISTATE);
 	STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */
@@ -1591,13 +1594,15 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 		goto err;
 	if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0)
 		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0)
+		goto err;
 	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0)
 		goto err;
 	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0)
 		goto err;
 	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
 	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
-	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
 	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
 		goto err;
 
@@ -1611,13 +1616,13 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 		goto err;
 	if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0)
 		goto err;
-	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x60) < 0)
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x50) < 0)
 		goto err;
 
 	if (state->dev_ver >= 0x30) {
 		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0)
 			goto err;
-		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
+		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x98) < 0)
 			goto err;
 
 	} else if (state->dev_ver >= 0x20) {
@@ -1652,23 +1657,31 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 	while ((!tmg_lock) && (cur_step < steps)) {
 		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */
 			goto err;
-		reg = STV090x_READ_DEMOD(state, DMDISTATE);
-		STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x00); /* trigger acquisition */
-		if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRINIT1, 0x00) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRINIT0, 0x00) < 0)
+			goto err;
+		/* trigger acquisition */
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x40) < 0)
 			goto err;
 		msleep(50);
 		for (i = 0; i < 10; i++) {
 			reg = STV090x_READ_DEMOD(state, DSTATUS);
 			if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
 				tmg_cpt++;
-			agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
-			agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+			agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
+				STV090x_READ_DEMOD(state, AGC2I0);
 		}
 		agc2 /= 10;
 		srate_coarse = stv090x_get_srate(state, state->mclk);
 		cur_step++;
 		dir *= -1;
-		if ((tmg_cpt >= 5) && (agc2 < 0x1f00) && (srate_coarse < 55000000) && (srate_coarse > 850000))
+		if ((tmg_cpt >= 5) && (agc2 < agc2th) &&
+		    (srate_coarse < 50000000) && (srate_coarse > 850000))
 			tmg_lock = 1;
 		else if (cur_step < steps) {
 			if (dir > 0)
@@ -1681,7 +1694,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 				goto err;
 
 			if (state->config->tuner_set_frequency) {
-				if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+				if (state->config->tuner_set_frequency(fe, freq) < 0)
 					goto err;
 			}
 
@@ -1738,7 +1751,7 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
 	else {
 		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */
 			goto err;
-		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0x01) < 0)
+		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0)
 			goto err;
 		if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
 			goto err;
@@ -1751,6 +1764,9 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
 		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
 			goto err;
 
+		if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+			goto err;
+
 		if (state->dev_ver >= 0x30) {
 			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0)
 				goto err;
@@ -1856,12 +1872,12 @@ static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout)
 static int stv090x_blind_search(struct stv090x_state *state)
 {
 	u32 agc2, reg, srate_coarse;
-	s32 timeout_dmd = 500, cpt_fail, agc2_ovflw, i;
+	s32 cpt_fail, agc2_ovflw, i;
 	u8 k_ref, k_max, k_min;
 	int coarse_fail, lock;
 
-	k_max = 120;
-	k_min = 30;
+	k_max = 110;
+	k_min = 10;
 
 	agc2 = stv090x_get_agc2_min_level(state);
 
@@ -1900,7 +1916,8 @@ static int stv090x_blind_search(struct stv090x_state *state)
 				srate_coarse = stv090x_srate_srch_fine(state);
 				if (srate_coarse != 0) {
 					stv090x_get_lock_tmg(state);
-					lock = stv090x_get_dmdlock(state, timeout_dmd);
+					lock = stv090x_get_dmdlock(state,
+							state->DemodTimeout);
 				} else {
 					lock = 0;
 				}
@@ -1908,8 +1925,8 @@ static int stv090x_blind_search(struct stv090x_state *state)
 				cpt_fail = 0;
 				agc2_ovflw = 0;
 				for (i = 0; i < 10; i++) {
-					agc2  = STV090x_READ_DEMOD(state, AGC2I1) << 8;
-					agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+					agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
+						STV090x_READ_DEMOD(state, AGC2I0);
 					if (agc2 >= 0xff00)
 						agc2_ovflw++;
 					reg = STV090x_READ_DEMOD(state, DSTATUS2);
@@ -1923,7 +1940,7 @@ static int stv090x_blind_search(struct stv090x_state *state)
 
 				lock = 0;
 			}
-			k_ref -= 30;
+			k_ref -= 20;
 		} while ((k_ref >= k_min) && (!lock) && (!coarse_fail));
 	}
 
@@ -2062,7 +2079,7 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
 						goto err;
 
 					if (state->config->tuner_set_frequency) {
-						if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+						if (state->config->tuner_set_frequency(fe, freq) < 0)
 							goto err;
 					}
 
@@ -2093,17 +2110,6 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
 						goto err;
 
 					STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
-					if (state->delsys == STV090x_DVBS2) {
-						reg = STV090x_READ_DEMOD(state, DMDCFGMD);
-						STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
-						STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
-						if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-							goto err;
-						STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
-						STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
-						if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
-							goto err;
-					}
 					if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
 						goto err;
 					if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
@@ -2425,7 +2431,7 @@ static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk)
 
 	derot = (int_1 * int_2) +
 		((int_1 * tmp_2) >> 12) +
-		((int_1 * tmp_1) >> 12);
+		((int_2 * tmp_1) >> 12);
 
 	return derot;
 }
@@ -2732,7 +2738,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 	switch (state->delsys) {
 	case STV090x_DVBS1:
 	case STV090x_DSS:
-		if (state->algo == STV090x_SEARCH_AUTO) {
+		if (state->search_mode == STV090x_SEARCH_AUTO) {
 			reg = STV090x_READ_DEMOD(state, DMDCFGMD);
 			STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
 			STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
@@ -2857,6 +2863,9 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 		if (stv090x_set_srate(state, srate) < 0)
 			goto err;
 		blind_tune = 1;
+
+		if (stv090x_dvbs_track_crl(state) < 0)
+			goto err;
 	}
 
 	if (state->dev_ver >= 0x20) {
@@ -3042,7 +3051,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 	struct dvb_frontend *fe = &state->frontend;
 	enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
 	u32 reg;
-	s32 timeout_dmd = 500, timeout_fec = 50, agc1_power, power_iq = 0, i;
+	s32 agc1_power, power_iq = 0, i;
 	int lock = 0, low_sr = 0, no_signal = 0;
 
 	reg = STV090x_READ_DEMOD(state, TSCFGH);
@@ -3054,8 +3063,13 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 		goto err;
 
 	if (state->dev_ver >= 0x20) {
-		if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) /* cut 2.0 */
-			goto err;
+		if (state->srate > 5000000) {
+			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
+				goto err;
+		} else {
+			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x82) < 0)
+				goto err;
+		}
 	}
 
 	stv090x_get_lock_tmg(state);
@@ -3175,7 +3189,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 	if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) {
 		dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq);
 		lock = 0;
-
+		signal_state = STV090x_NOAGC1;
 	} else {
 		reg = STV090x_READ_DEMOD(state, DEMOD);
 		STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion);
@@ -3199,18 +3213,17 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 		}
 	}
 
-	/* need to check for AGC1 state */
-
-
+	if (signal_state == STV090x_NOAGC1)
+		return signal_state;
 
 	if (state->algo == STV090x_BLIND_SEARCH)
 		lock = stv090x_blind_search(state);
 
 	else if (state->algo == STV090x_COLD_SEARCH)
-		lock = stv090x_get_coldlock(state, timeout_dmd);
+		lock = stv090x_get_coldlock(state, state->DemodTimeout);
 
 	else if (state->algo == STV090x_WARM_SEARCH)
-		lock = stv090x_get_dmdlock(state, timeout_dmd);
+		lock = stv090x_get_dmdlock(state, state->DemodTimeout);
 
 	if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) {
 		if (!low_sr) {
@@ -3245,8 +3258,9 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 				goto err;
 		}
 
-		if (stv090x_get_lock(state, timeout_fec, timeout_fec)) {
-			lock = 1;
+		lock = stv090x_get_lock(state, state->FecTimeout,
+				state->FecTimeout);
+		if (lock) {
 			if (state->delsys == STV090x_DVBS2) {
 				stv090x_set_s2rolloff(state);
 
@@ -3273,7 +3287,6 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 			if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
 				goto err;
 		} else {
-			lock = 0;
 			signal_state = STV090x_NODATA;
 			no_signal = stv090x_chk_signal(state);
 		}
@@ -3296,7 +3309,13 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron
 	state->search_mode = STV090x_SEARCH_AUTO;
 	state->algo = STV090x_COLD_SEARCH;
 	state->fec = STV090x_PRERR;
-	state->search_range = 2000000;
+	if (state->srate > 10000000) {
+		dprintk(FE_DEBUG, 1, "Search range: 10 MHz");
+		state->search_range = 10000000;
+	} else {
+		dprintk(FE_DEBUG, 1, "Search range: 5 MHz");
+		state->search_range = 5000000;
+	}
 
 	if (stv090x_algo(state) == STV090x_RANGEOK) {
 		dprintk(FE_DEBUG, 1, "Search success!");
@@ -3309,7 +3328,6 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron
 	return DVBFE_ALGO_SEARCH_ERROR;
 }
 
-/* FIXME! */
 static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
 {
 	struct stv090x_state *state = fe->demodulator_priv;
@@ -3331,9 +3349,15 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
 		dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2");
 		reg = STV090x_READ_DEMOD(state, DSTATUS);
 		if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
-			reg = STV090x_READ_DEMOD(state, TSSTATUS);
-			if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
-				*status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
+			if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) {
+				reg = STV090x_READ_DEMOD(state, TSSTATUS);
+				if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
+					*status = FE_HAS_CARRIER |
+						  FE_HAS_VITERBI |
+						  FE_HAS_SYNC |
+						  FE_HAS_LOCK;
+				}
 			}
 		}
 		break;
@@ -3412,14 +3436,12 @@ static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val)
 	int res = 0;
 	int min = 0, med;
 
-	if (val < tab[min].read)
-		res = tab[min].real;
-	else if (val >= tab[max].read)
-		res = tab[max].real;
-	else {
+	if ((val >= tab[min].read && val < tab[max].read) ||
+	    (val >= tab[max].read && val < tab[min].read)) {
 		while ((max - min) > 1) {
 			med = (max + min) / 2;
-			if (val >= tab[min].read && val < tab[med].read)
+			if ((val >= tab[min].read && val < tab[med].read) ||
+			    (val >= tab[med].read && val < tab[min].read))
 				max = med;
 			else
 				min = med;
@@ -3428,6 +3450,18 @@ static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val)
 		       (tab[max].real - tab[min].real) /
 		       (tab[max].read - tab[min].read)) +
 			tab[min].real;
+	} else {
+		if (tab[min].read < tab[max].read) {
+			if (val < tab[min].read)
+				res = tab[min].real;
+			else if (val >= tab[max].read)
+				res = tab[max].real;
+		} else {
+			if (val >= tab[min].read)
+				res = tab[min].real;
+			else if (val < tab[max].read)
+				res = tab[max].real;
+		}
 	}
 
 	return res;
@@ -3437,16 +3471,22 @@ static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
 	struct stv090x_state *state = fe->demodulator_priv;
 	u32 reg;
-	s32 agc;
+	s32 agc_0, agc_1, agc;
+	s32 str;
 
 	reg = STV090x_READ_DEMOD(state, AGCIQIN1);
-	agc = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
+	agc_1 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
+	reg = STV090x_READ_DEMOD(state, AGCIQIN0);
+	agc_0 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
+	agc = MAKEWORD16(agc_1, agc_0);
 
-	*strength = stv090x_table_lookup(stv090x_rf_tab, ARRAY_SIZE(stv090x_rf_tab) - 1, agc);
+	str = stv090x_table_lookup(stv090x_rf_tab,
+		ARRAY_SIZE(stv090x_rf_tab) - 1, agc);
 	if (agc > stv090x_rf_tab[0].read)
-		*strength = 5;
+		str = 0;
 	else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read)
-		*strength = -100;
+		str = -100;
+	*strength = (str + 100) * 0xFFFF / 100;
 
 	return 0;
 }
@@ -3457,6 +3497,8 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
 	u32 reg_0, reg_1, reg, i;
 	s32 val_0, val_1, val = 0;
 	u8 lock_f;
+	s32 div;
+	u32 last;
 
 	switch (state->delsys) {
 	case STV090x_DVBS2:
@@ -3468,14 +3510,15 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
 				reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1);
 				val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
 				reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0);
-				val_0 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
+				val_0 = STV090x_GETFIELD_Px(reg_0, NOSPLHT_NORMED_FIELD);
 				val  += MAKEWORD16(val_1, val_0);
 				msleep(1);
 			}
 			val /= 16;
-			*cnr = stv090x_table_lookup(stv090x_s2cn_tab, ARRAY_SIZE(stv090x_s2cn_tab) - 1, val);
-			if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s2cn_tab) - 1].read)
-				*cnr = 1000;
+			last = ARRAY_SIZE(stv090x_s2cn_tab) - 1;
+			div = stv090x_s2cn_tab[0].read -
+			      stv090x_s2cn_tab[last].read;
+			*cnr = 0xFFFF - ((val * 0xFFFF) / div);
 		}
 		break;
 
@@ -3489,14 +3532,15 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
 				reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1);
 				val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
 				reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0);
-				val_0 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
+				val_0 = STV090x_GETFIELD_Px(reg_0, NOSDATAT_UNNORMED_FIELD);
 				val  += MAKEWORD16(val_1, val_0);
 				msleep(1);
 			}
 			val /= 16;
-			*cnr = stv090x_table_lookup(stv090x_s1cn_tab, ARRAY_SIZE(stv090x_s1cn_tab) - 1, val);
-			if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s1cn_tab) - 1].read)
-				*cnr = 1000;
+			last = ARRAY_SIZE(stv090x_s1cn_tab) - 1;
+			div = stv090x_s1cn_tab[0].read -
+			      stv090x_s1cn_tab[last].read;
+			*cnr = 0xFFFF - ((val * 0xFFFF) / div);
 		}
 		break;
 	default:
@@ -3732,6 +3776,8 @@ static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc
 {
 	u32 reg = 0;
 
+	reg = stv090x_read_reg(state, STV090x_GENCFG);
+
 	switch (ldpc_mode) {
 	case STV090x_DUAL:
 	default:
diff --git a/drivers/media/dvb/frontends/stv090x_priv.h b/drivers/media/dvb/frontends/stv090x_priv.h
index 5a4a01740d88..5921a8d6c89f 100644
--- a/drivers/media/dvb/frontends/stv090x_priv.h
+++ b/drivers/media/dvb/frontends/stv090x_priv.h
@@ -83,7 +83,7 @@
 
 #define STV090x_IQPOWER_THRESHOLD	  30
 #define STV090x_SEARCH_AGC2_TH_CUT20	 700
-#define STV090x_SEARCH_AGC2_TH_CUT30	1200
+#define STV090x_SEARCH_AGC2_TH_CUT30	1400
 
 #define STV090x_SEARCH_AGC2_TH(__ver)	\
 	((__ver <= 0x20) ?		\
@@ -91,6 +91,7 @@
 	STV090x_SEARCH_AGC2_TH_CUT30)
 
 enum stv090x_signal_state {
+	STV090x_NOAGC1,
 	STV090x_NOCARRIER,
 	STV090x_NODATA,
 	STV090x_DATAOK,
diff --git a/drivers/media/dvb/frontends/stv090x_reg.h b/drivers/media/dvb/frontends/stv090x_reg.h
index 57b6abbbd32d..2502855dd784 100644
--- a/drivers/media/dvb/frontends/stv090x_reg.h
+++ b/drivers/media/dvb/frontends/stv090x_reg.h
@@ -44,7 +44,7 @@
 #define STV090x_OFFST_OUTSERRS2_HZ_FIELD	5
 #define STV090x_WIDTH_OUTSERRS2_HZ_FIELD	1
 #define STV090x_OFFST_OUTSERRS3_HZ_FIELD	4
-#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD	1
+#define STV090x_WIDTH_OUTSERRS3_HZ_FIELD	1
 #define STV090x_OFFST_OUTPARRS3_HZ_FIELD	3
 #define STV090x_WIDTH_OUTPARRS3_HZ_FIELD	1
 
@@ -113,24 +113,24 @@
 #define STV090x_IRQMASK3			0xf124
 #define STV090x_OFFST_MPLL_LOCK_FIELD		5
 #define STV090x_WIDTH_MPLL_LOCK_FIELD		1
-#define STV090x_OFFST_MSTREAM_LCK_3_FIELD	2
-#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD	3
-#define STV090x_OFFST_MSTREAM_LCK_2_FIELD	2
-#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD	3
+#define STV090x_OFFST_MSTREAM_LCK_3_FIELD	4
+#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD	1
+#define STV090x_OFFST_MSTREAM_LCK_2_FIELD	3
+#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD	1
 #define STV090x_OFFST_MSTREAM_LCK_1_FIELD	2
-#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD	3
+#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD	1
 #define STV090x_OFFST_MDVBS1_PRF_2_FIELD	1
 #define STV090x_WIDTH_MDVBS1_PRF_2_FIELD	1
 #define STV090x_OFFST_MDVBS1_PRF_1_FIELD	0
 #define STV090x_WIDTH_MDVBS1_PRF_1_FIELD	1
 
 #define STV090x_IRQMASK2			0xf125
-#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD	5
-#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD	3
-#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD	5
-#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD	3
+#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD	7
+#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD	1
+#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD	6
+#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD	1
 #define STV090x_OFFST_MSPY_ENDSIM_1_FIELD	5
-#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD	3
+#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD	1
 #define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD	4
 #define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD	1
 #define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD	3
@@ -370,7 +370,7 @@
 #define STV090x_OFFST_SELX1RATIO_FIELD		5
 #define STV090x_WIDTH_SELX1RATIO_FIELD		1
 #define STV090x_OFFST_STOP_PLL_FIELD		3
-#define STV090x_WIDTH_SELX1RATIO_FIELD		1
+#define STV090x_WIDTH_STOP_PLL_FIELD		1
 #define STV090x_OFFST_BYPASSPLLFSK_FIELD	2
 #define STV090x_WIDTH_BYPASSPLLFSK_FIELD	1
 #define STV090x_OFFST_SELOSCI_FIELD		1
@@ -616,7 +616,7 @@
 #define STV090x_OFFST_Px_CONT_TONE_FIELD	4
 #define STV090x_WIDTH_Px_CONT_TONE_FIELD	1
 #define STV090x_OFFST_Px_FIFO_4BREADY_FIELD	3
-#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD	2
+#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD	1
 #define STV090x_OFFST_Px_FIFO_EMPTY_FIELD	2
 #define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD	1
 #define STV090x_OFFST_Px_ABORT_DISRX_FIELD	0
@@ -847,12 +847,10 @@
 #define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD	1
 #define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD	6
 #define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD	1
-#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD	5 /* check */
-#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD	1
-#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD	4 /* check */
+#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD	4
 #define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD	1
-#define STV090x_OFFST_Px_TUN_AUTOSCAN_FIELD	3
-#define STV090x_WIDTH_Px_TUN_AUTOSCAN_FIELD	1
+#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD	3
+#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD	1
 #define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD	2
 #define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD	1
 #define STV090x_OFFST_Px_TUN_RNG_FIELD		0
@@ -885,7 +883,7 @@
 #define STV090x_P2_DMDFLYW			STV090x_Px_DMDFLYW(2)
 #define STV090x_OFFST_Px_I2C_IRQVAL_FIELD	4
 #define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD	4
-#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD	0 /* check */
+#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD	0
 #define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD	4
 
 #define STV090x_Px_DSTATUS3(__x)		(0xF41D - (__x - 1) * 0x200)
@@ -1048,12 +1046,12 @@
 #define STV090x_P1_CFRINC1			STV090x_Px_CFRINC1(1)
 #define STV090x_P2_CFRINC1			STV090x_Px_CFRINC1(2)
 #define STV090x_OFFST_Px_CFR_INC1_FIELD		0
-#define STV090x_WIDTH_Px_CFR_INC1_FIELD		7
+#define STV090x_WIDTH_Px_CFR_INC1_FIELD		7 /* check */
 
 #define STV090x_Px_CFRINC0(__x)			(0xF44B - (__x - 1) * 0x200)
 #define STV090x_P1_CFRINC0			STV090x_Px_CFRINC0(1)
 #define STV090x_P2_CFRINC0			STV090x_Px_CFRINC0(2)
-#define STV090x_OFFST_Px_CFR_INC0_FIELD		4
+#define STV090x_OFFST_Px_CFR_INC0_FIELD		4 /* check */
 #define STV090x_WIDTH_Px_CFR_INC0_FIELD		4
 
 #define STV090x_Pn_CFRy(__x, __y)		(0xF44E - (__x - 1) * 0x200 - __y * 0x1)
@@ -1145,14 +1143,14 @@
 #define STV090x_Px_SFRINIT1(__x)		(0xF45E - (__x - 1) * 0x200)
 #define STV090x_P1_SFRINIT1			STV090x_Px_SFRINIT1(1)
 #define STV090x_P2_SFRINIT1			STV090x_Px_SFRINIT1(2)
-#define STV090x_OFFST_Px_SFR_INIT_FIELD		0
-#define STV090x_WIDTH_Px_SFR_INIT_FIELD		8
+#define STV090x_OFFST_Px_SFR_INIT1_FIELD	0
+#define STV090x_WIDTH_Px_SFR_INIT1_FIELD	7
 
 #define STV090x_Px_SFRINIT0(__x)		(0xF45F - (__x - 1) * 0x200)
 #define STV090x_P1_SFRINIT0			STV090x_Px_SFRINIT0(1)
 #define STV090x_P2_SFRINIT0			STV090x_Px_SFRINIT0(2)
-#define STV090x_OFFST_Px_SFR_INIT_FIELD		0
-#define STV090x_WIDTH_Px_SFR_INIT_FIELD		8
+#define STV090x_OFFST_Px_SFR_INIT0_FIELD	0
+#define STV090x_WIDTH_Px_SFR_INIT0_FIELD	8
 
 #define STV090x_Px_SFRUP1(__x)			(0xF460 - (__x - 1) * 0x200)
 #define STV090x_P1_SFRUP1			STV090x_Px_SFRUP1(1)
@@ -1178,7 +1176,7 @@
 #define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD	0
 #define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD	8
 
-#define STV090x_Px_SFRy(__x, __y)		(0xF464 - (__x-1) * 0x200 + (3 - __y))
+#define STV090x_Px_SFRy(__x, __y)		(0xF467 - (__x-1) * 0x200 - __y)
 #define STV090x_P1_SFR0				STV090x_Px_SFRy(1, 0)
 #define STV090x_P1_SFR1				STV090x_Px_SFRy(1, 1)
 #define STV090x_P1_SFR2				STV090x_Px_SFRy(1, 2)
@@ -1188,7 +1186,7 @@
 #define STV090x_P2_SFR2				STV090x_Px_SFRy(2, 2)
 #define STV090x_P2_SFR3				STV090x_Px_SFRy(2, 3)
 #define STV090x_OFFST_Px_SYMB_FREQ_FIELD	0
-#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD	32
+#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD	8
 
 #define STV090x_Px_TMGREG2(__x)			(0xF468 - (__x - 1) * 0x200)
 #define STV090x_P1_TMGREG2			STV090x_Px_TMGREG2(1)
@@ -1198,7 +1196,7 @@
 
 #define STV090x_Px_TMGREG1(__x)			(0xF469 - (__x - 1) * 0x200)
 #define STV090x_P1_TMGREG1			STV090x_Px_TMGREG1(1)
-#define STV090x_P2_TMGREG1				STV090x_Px_TMGREG1(2)
+#define STV090x_P2_TMGREG1			STV090x_Px_TMGREG1(2)
 #define STV090x_OFFST_Px_TMGREG_FIELD		0
 #define STV090x_WIDTH_Px_TMGREG_FIELD		8
 
@@ -1230,7 +1228,7 @@
 #define STV090x_OFFST_Px_MU_EQUALDFE_FIELD	0
 #define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD	3
 
-#define STV090x_Px_EQUAIy(__x, __y)		(0xf470 - (__x - 1) * 0x200 + (__y - 1))
+#define STV090x_Px_EQUAIy(__x, __y)	(0xf470 - (__x-1) * 0x200 + 2 * (__y-1))
 #define STV090x_P1_EQUAI1			STV090x_Px_EQUAIy(1, 1)
 #define STV090x_P1_EQUAI2			STV090x_Px_EQUAIy(1, 2)
 #define STV090x_P1_EQUAI3			STV090x_Px_EQUAIy(1, 3)
@@ -1251,7 +1249,7 @@
 #define STV090x_OFFST_Px_EQUA_ACCIy_FIELD	0
 #define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD	8
 
-#define STV090x_Px_EQUAQy(__x, __y)		(0xf471 - (__x - 1) * 0x200 + (__y - 1))
+#define STV090x_Px_EQUAQy(__x, __y)	(0xf471 - (__x-1) * 0x200 + 2 * (__y-1))
 #define STV090x_P1_EQUAQ1			STV090x_Px_EQUAQy(1, 1)
 #define STV090x_P1_EQUAQ2			STV090x_Px_EQUAQy(1, 2)
 #define STV090x_P1_EQUAQ3			STV090x_Px_EQUAQy(1, 3)
@@ -1390,7 +1388,7 @@
 #define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD	0
 #define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD	4
 
-#define STV090x_Px_ACLC2S232A(__x)		(0xf499 - (__x - 1) * 0x200)
+#define STV090x_Px_ACLC2S232A(__x)		(0xf49A - (__x - 1) * 0x200)
 #define STV090x_P1_ACLC2S232A			STV090x_Px_ACLC2S232A(1)
 #define STV090x_P2_ACLC2S232A			STV090x_Px_ACLC2S232A(2)
 #define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD	4
@@ -1414,7 +1412,7 @@
 #define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD	0
 #define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD	4
 
-#define STV090x_Px_BCLC2S216A(__x)		(0xf49d - (__x - 1) * 0x200)
+#define STV090x_Px_BCLC2S216A(__x)		(0xf49e - (__x - 1) * 0x200)
 #define STV090x_P1_BCLC2S216A			STV090x_Px_BCLC2S216A(1)
 #define STV090x_P2_BCLC2S216A			STV090x_Px_BCLC2S216A(1)
 #define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD	4
@@ -1422,7 +1420,7 @@
 #define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD	0
 #define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD	4
 
-#define STV090x_Px_BCLC2S232A(__x)		(0xf49d - (__x - 1) * 0x200)
+#define STV090x_Px_BCLC2S232A(__x)		(0xf49f - (__x - 1) * 0x200)
 #define STV090x_P1_BCLC2S232A			STV090x_Px_BCLC2S232A(1)
 #define STV090x_P2_BCLC2S232A			STV090x_Px_BCLC2S232A(1)
 #define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD	4
@@ -1458,7 +1456,7 @@
 #define STV090x_P1_MODCODLST1			STV090x_Px_MODCODLST1(1)
 #define STV090x_P2_MODCODLST1			STV090x_Px_MODCODLST1(2)
 #define STV090x_OFFST_Px_DIS_MODCOD29_FIELD	4
-#define STV090x_WIDTH_Px_DIS_MODCOD29T_FIELD	4
+#define STV090x_WIDTH_Px_DIS_MODCOD29_FIELD	4
 #define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD	0
 #define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD	4
 
@@ -2180,7 +2178,7 @@
 #define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD	1
 #define STV090x_OFFST_Px_DILXX_RESET_FIELD		5
 #define STV090x_WIDTH_Px_DILXX_RESET_FIELD		1
-#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD		5
+#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD		4
 #define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD		1
 #define STV090x_OFFST_Px_SCRAMBDETECT_FIELD		1
 #define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD		1
@@ -2190,7 +2188,7 @@
 #define STV090x_P1_TSBITRATE1				STV090x_Px_TSBITRATEy(1, 1)
 #define STV090x_P2_TSBITRATE0				STV090x_Px_TSBITRATEy(2, 0)
 #define STV090x_P2_TSBITRATE1				STV090x_Px_TSBITRATEy(2, 1)
-#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD		7
+#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD		0
 #define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD		8
 
 #define STV090x_Px_ERRCTRL1(__x)			(0xF598 - (__x - 1) * 0x200)
diff --git a/drivers/media/dvb/frontends/stv6110.c b/drivers/media/dvb/frontends/stv6110.c
index dcf1b21ea974..bef0cc838471 100644
--- a/drivers/media/dvb/frontends/stv6110.c
+++ b/drivers/media/dvb/frontends/stv6110.c
@@ -37,6 +37,7 @@ struct stv6110_priv {
 
 	u32 mclk;
 	u8 clk_div;
+	u8 gain;
 	u8 regs[8];
 };
 
@@ -255,7 +256,7 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
 	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;
+	s32 srate;
 
 	dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__,
 						frequency, priv->mclk);
@@ -273,15 +274,8 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
 	} 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);
+	priv->regs[RSTV6110_CTRL2] |= (priv->gain & 0x0f);
 
 	if (frequency <= 1023000) {
 		p = 1;
@@ -436,6 +430,7 @@ struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
 	priv->i2c = i2c;
 	priv->mclk = config->mclk;
 	priv->clk_div = config->clk_div;
+	priv->gain = config->gain;
 
 	memcpy(&priv->regs, &reg0[1], 8);
 
diff --git a/drivers/media/dvb/frontends/stv6110.h b/drivers/media/dvb/frontends/stv6110.h
index 9db2402410f6..fe71bba6a26e 100644
--- a/drivers/media/dvb/frontends/stv6110.h
+++ b/drivers/media/dvb/frontends/stv6110.h
@@ -41,6 +41,7 @@
 struct stv6110_config {
 	u8 i2c_address;
 	u32 mclk;
+	u8 gain;
 	u8 clk_div;	/* divisor value for the output clock */
 };
 
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c
index 3d8a2e01c9c4..bcfcb652464c 100644
--- a/drivers/media/dvb/frontends/stv6110x.c
+++ b/drivers/media/dvb/frontends/stv6110x.c
@@ -95,7 +95,7 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
 {
 	struct stv6110x_state *stv6110x = fe->tuner_priv;
 	u32 rDiv, divider;
-	s32 pVal, pCalc, rDivOpt = 0;
+	s32 pVal, pCalc, rDivOpt = 0, pCalcOpt = 1000;
 	u8 i;
 
 	STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
@@ -121,8 +121,10 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
 	for (rDiv = 0; rDiv <= 3; rDiv++) {
 		pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv);
 
-		if ((abs((s32)(pCalc - pVal))) < (abs((s32)(1000 - pVal))))
+		if ((abs((s32)(pCalc - pVal))) < (abs((s32)(pCalcOpt - pVal))))
 			rDivOpt = rDiv;
+
+		pCalcOpt = (REFCLOCK_kHz / 100) / R_DIV(rDivOpt);
 	}
 
 	divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c
index 1fd8306371e2..81e623a90f09 100644
--- a/drivers/media/dvb/pt1/pt1.c
+++ b/drivers/media/dvb/pt1/pt1.c
@@ -27,7 +27,6 @@
 #include <linux/pci.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
-#include <linux/vmalloc.h>
 
 #include "dvbdev.h"
 #include "dvb_demux.h"
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/dvb/pt1/va1j5jf8007s.c
index 2db940f8635f..fc6594996e79 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007s.c
+++ b/drivers/media/dvb/pt1/va1j5jf8007s.c
@@ -48,6 +48,60 @@ struct va1j5jf8007s_state {
 	enum va1j5jf8007s_tune_state tune_state;
 };
 
+static int va1j5jf8007s_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct va1j5jf8007s_state *state;
+	u8 addr;
+	int i;
+	u8 write_buf[1], read_buf[1];
+	struct i2c_msg msgs[2];
+	s32 word, x1, x2, x3, x4, x5, y;
+
+	state = fe->demodulator_priv;
+	addr = state->config->demod_address;
+
+	word = 0;
+	for (i = 0; i < 2; i++) {
+		write_buf[0] = 0xbc + i;
+
+		msgs[0].addr = addr;
+		msgs[0].flags = 0;
+		msgs[0].len = sizeof(write_buf);
+		msgs[0].buf = write_buf;
+
+		msgs[1].addr = addr;
+		msgs[1].flags = I2C_M_RD;
+		msgs[1].len = sizeof(read_buf);
+		msgs[1].buf = read_buf;
+
+		if (i2c_transfer(state->adap, msgs, 2) != 2)
+			return -EREMOTEIO;
+
+		word <<= 8;
+		word |= read_buf[0];
+	}
+
+	word -= 3000;
+	if (word < 0)
+		word = 0;
+
+	x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000);
+	x2 = (s64)x1 * x1 >> 31;
+	x3 = (s64)x2 * x1 >> 31;
+	x4 = (s64)x2 * x2 >> 31;
+	x5 = (s64)x4 * x1 >> 31;
+
+	y = (58857ll << 23) / 1000;
+	y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30;
+	y += (s64)x2 * ((88977ll << 24) / 1000) >> 28;
+	y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27;
+	y += (s64)x4 * ((14341ll << 27) / 1000) >> 27;
+	y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28;
+
+	*snr = y < 0 ? 0 : y >> 15;
+	return 0;
+}
+
 static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe)
 {
 	return DVBFE_ALGO_HW;
@@ -337,7 +391,7 @@ va1j5jf8007s_tune(struct dvb_frontend *fe,
 {
 	struct va1j5jf8007s_state *state;
 	int ret;
-	int lock;
+	int lock = 0;
 
 	state = fe->demodulator_priv;
 
@@ -536,6 +590,7 @@ static struct dvb_frontend_ops va1j5jf8007s_ops = {
 			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
 	},
 
+	.read_snr = va1j5jf8007s_read_snr,
 	.get_frontend_algo = va1j5jf8007s_get_frontend_algo,
 	.read_status = va1j5jf8007s_read_status,
 	.tune = va1j5jf8007s_tune,
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/dvb/pt1/va1j5jf8007t.c
index 71117f4ca7e6..3db4f3e34e8f 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007t.c
+++ b/drivers/media/dvb/pt1/va1j5jf8007t.c
@@ -46,6 +46,52 @@ struct va1j5jf8007t_state {
 	enum va1j5jf8007t_tune_state tune_state;
 };
 
+static int va1j5jf8007t_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct va1j5jf8007t_state *state;
+	u8 addr;
+	int i;
+	u8 write_buf[1], read_buf[1];
+	struct i2c_msg msgs[2];
+	s32 word, x, y;
+
+	state = fe->demodulator_priv;
+	addr = state->config->demod_address;
+
+	word = 0;
+	for (i = 0; i < 3; i++) {
+		write_buf[0] = 0x8b + i;
+
+		msgs[0].addr = addr;
+		msgs[0].flags = 0;
+		msgs[0].len = sizeof(write_buf);
+		msgs[0].buf = write_buf;
+
+		msgs[1].addr = addr;
+		msgs[1].flags = I2C_M_RD;
+		msgs[1].len = sizeof(read_buf);
+		msgs[1].buf = read_buf;
+
+		if (i2c_transfer(state->adap, msgs, 2) != 2)
+			return -EREMOTEIO;
+
+		word <<= 8;
+		word |= read_buf[0];
+	}
+
+	if (!word)
+		return -EIO;
+
+	x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24));
+	y = (24ll << 46) / 1000000;
+	y = ((s64)y * x >> 30) - (16ll << 40) / 10000;
+	y = ((s64)y * x >> 29) + (398ll << 35) / 10000;
+	y = ((s64)y * x >> 30) + (5491ll << 29) / 10000;
+	y = ((s64)y * x >> 30) + (30965ll << 23) / 10000;
+	*snr = y >> 15;
+	return 0;
+}
+
 static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe)
 {
 	return DVBFE_ALGO_HW;
@@ -224,7 +270,7 @@ va1j5jf8007t_tune(struct dvb_frontend *fe,
 {
 	struct va1j5jf8007t_state *state;
 	int ret;
-	int lock, retry;
+	int lock = 0, retry = 0;
 
 	state = fe->demodulator_priv;
 
@@ -393,6 +439,7 @@ static struct dvb_frontend_ops va1j5jf8007t_ops = {
 			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
 	},
 
+	.read_snr = va1j5jf8007t_read_snr,
 	.get_frontend_algo = va1j5jf8007t_get_frontend_algo,
 	.read_status = va1j5jf8007t_read_status,
 	.tune = va1j5jf8007t_tune,
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index 0420e2885e75..1067b22eb0c6 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -97,7 +97,7 @@ static struct sms_board sms_boards[] = {
 	},
 };
 
-struct sms_board *sms_get_board(int id)
+struct sms_board *sms_get_board(unsigned id)
 {
 	BUG_ON(id >= ARRAY_SIZE(sms_boards));
 
@@ -294,6 +294,8 @@ int sms_board_load_modules(int id)
 	case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
 	case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
 	case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+	case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
 		request_module("smsdvb");
 		break;
 	default:
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
index 38f062f6ad68..8f19fc000b46 100644
--- a/drivers/media/dvb/siano/sms-cards.h
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -81,7 +81,7 @@ struct sms_board {
 	int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
 };
 
-struct sms_board *sms_get_board(int id);
+struct sms_board *sms_get_board(unsigned id);
 
 extern struct smscore_device_t *coredev;
 
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index fa6a62369a78..ca758bcb48c9 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -1373,7 +1373,7 @@ static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
 
 	*pGroupCfg = 1;
 
-	if (PinNum >= 0 && PinNum <= 1)	{
+	if (PinNum <= 1)	{
 		*pTranslatedPinNum = 0;
 		*pGroupNum = 9;
 		*pGroupCfg = 2;
diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c
index d1d652e7f890..24206cbda264 100644
--- a/drivers/media/dvb/siano/smssdio.c
+++ b/drivers/media/dvb/siano/smssdio.c
@@ -78,7 +78,7 @@ struct smssdio_device {
 
 static int smssdio_sendrequest(void *context, void *buffer, size_t size)
 {
-	int ret;
+	int ret = 0;
 	struct smssdio_device *smsdev;
 
 	smsdev = context;
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 8ea915227674..983672aa2450 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1055,7 +1055,7 @@ static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = {
 	{ STB0899_TSCFGH		, 0x0c },
 	{ STB0899_TSCFGM		, 0x00 },
 	{ STB0899_TSCFGL		, 0x0c },
-	{ STB0899_TSOUT			, 0x0d }, /* 0x0d for CAM */
+	{ STB0899_TSOUT			, 0x4d }, /* 0x0d for CAM */
 	{ STB0899_RSSYNCDEL		, 0x00 },
 	{ STB0899_TSINHDELH		, 0x02 },
 	{ STB0899_TSINHDELM		, 0x00 },
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index b5c681372b6c..7d193ebc0aea 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -178,7 +178,7 @@ static void msp430_ir_interrupt(unsigned long data)
 	if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) {
 		ir_input_nokey(dev, &budget_ci->ir.state);
 		ir_input_keydown(dev, &budget_ci->ir.state,
-				 budget_ci->ir.ir_key, raw);
+				 budget_ci->ir.ir_key);
 		budget_ci->ir.last_raw = raw;
 	}
 
@@ -224,8 +224,10 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 	case 0x1011:
 	case 0x1012:
 		/* The hauppauge keymap is a superset of these remotes */
-		ir_input_init(input_dev, &budget_ci->ir.state,
+		error = ir_input_init(input_dev, &budget_ci->ir.state,
 			      IR_TYPE_RC5, &ir_codes_hauppauge_new_table);
+		if (error < 0)
+			goto out2;
 
 		if (rc5_device < 0)
 			budget_ci->ir.rc5_device = 0x1f;
@@ -236,8 +238,10 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 	case 0x1017:
 	case 0x101a:
 		/* for the Technotrend 1500 bundled remote */
-		ir_input_init(input_dev, &budget_ci->ir.state,
+		error = ir_input_init(input_dev, &budget_ci->ir.state,
 			      IR_TYPE_RC5, &ir_codes_tt_1500_table);
+		if (error < 0)
+			goto out2;
 
 		if (rc5_device < 0)
 			budget_ci->ir.rc5_device = IR_DEVICE_ANY;
@@ -246,8 +250,10 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 		break;
 	default:
 		/* unknown remote */
-		ir_input_init(input_dev, &budget_ci->ir.state,
+		error = ir_input_init(input_dev, &budget_ci->ir.state,
 			      IR_TYPE_RC5, &ir_codes_budget_ci_old_table);
+		if (error < 0)
+			goto out2;
 
 		if (rc5_device < 0)
 			budget_ci->ir.rc5_device = IR_DEVICE_ANY;
@@ -280,6 +286,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 	return 0;
 
 out2:
+	ir_input_free(input_dev);
 	input_free_device(input_dev);
 out1:
 	return error;
@@ -297,6 +304,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci)
 	del_timer_sync(&dev->timer);
 	ir_input_nokey(dev, &budget_ci->ir.state);
 
+	ir_input_free(dev);
 	input_unregister_device(dev);
 }
 
@@ -1248,7 +1256,7 @@ static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
 	{ STB0899_TSCFGH        	, 0x0c },
 	{ STB0899_TSCFGM        	, 0x00 },
 	{ STB0899_TSCFGL        	, 0x0c },
-	{ STB0899_TSOUT			, 0x0d }, /* 0x0d for CAM */
+	{ STB0899_TSOUT			, 0x4d }, /* 0x0d for CAM */
 	{ STB0899_RSSYNCDEL     	, 0x00 },
 	{ STB0899_TSINHDELH     	, 0x02 },
 	{ STB0899_TSINHDELM		, 0x00 },
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index d91e0638448f..53baccbab17f 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1198,7 +1198,7 @@ static int ttusb_init_rc( struct ttusb_dec *dec)
 	int err;
 
 	usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys));
-	strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
+	strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
 
 	input_dev = input_allocate_device();
 	if (!input_dev)
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index b134553eb3b5..d4389963b312 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -419,4 +419,16 @@ config RADIO_TEA5764_XTAL
 	  Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
 	  here if TEA5764 reference frequency is connected in FREQIN.
 
+config RADIO_TEF6862
+	tristate "TEF6862 Car Radio Enhanced Selectivity Tuner"
+	depends on I2C && VIDEO_V4L2
+	---help---
+	  Say Y here if you want to use the TEF6862 Car Radio Enhanced
+	  Selectivity Tuner, found for instance on the Russellville development
+	  board. On the russellville the device is connected to internal
+	  timberdale I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called TEF6862.
+
 endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 8a63d543ae41..01922ada6914 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -23,5 +23,6 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_RADIO_SI470X) += si470x/
 obj-$(CONFIG_USB_MR800) += radio-mr800.o
 obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
+obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
 
 EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 5f79acb56e48..949f60513d9e 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -85,6 +85,9 @@ MODULE_LICENSE("GPL");
 #define amradio_dev_warn(dev, fmt, arg...)				\
 		dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
 
+#define amradio_dev_err(dev, fmt, arg...) \
+		dev_err(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
+
 /* Probably USB_TIMEOUT should be modified in module parameter */
 #define BUFFER_LENGTH 8
 #define USB_TIMEOUT 500
@@ -129,18 +132,20 @@ static int usb_amradio_resume(struct usb_interface *intf);
 struct amradio_device {
 	/* reference to USB and video device */
 	struct usb_device *usbdev;
-	struct video_device *videodev;
+	struct usb_interface *intf;
+	struct video_device videodev;
 	struct v4l2_device v4l2_dev;
 
 	unsigned char *buffer;
 	struct mutex lock;	/* buffer locking */
 	int curfreq;
 	int stereo;
-	int users;
-	int removed;
 	int muted;
+	int initialized;
 };
 
+#define vdev_to_amradio(r) container_of(r, struct amradio_device, videodev)
+
 /* USB Device ID List */
 static struct usb_device_id usb_amradio_device_table[] = {
 	{USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
@@ -159,7 +164,7 @@ static struct usb_driver usb_amradio_driver = {
 	.resume			= usb_amradio_resume,
 	.reset_resume		= usb_amradio_resume,
 	.id_table		= usb_amradio_device_table,
-	.supports_autosuspend	= 0,
+	.supports_autosuspend	= 1,
 };
 
 /* switch on/off the radio. Send 8 bytes to device */
@@ -168,11 +173,7 @@ 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);
+	BUG_ON(!mutex_is_locked(&radio->lock));
 
 	radio->buffer[0] = 0x00;
 	radio->buffer[1] = 0x55;
@@ -187,14 +188,12 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
 		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
 
 	if (retval < 0 || size != BUFFER_LENGTH) {
-		mutex_unlock(&radio->lock);
+		amradio_dev_warn(&radio->videodev.dev, "set mute failed\n");
 		return retval;
 	}
 
 	radio->muted = argument;
 
-	mutex_unlock(&radio->lock);
-
 	return retval;
 }
 
@@ -205,11 +204,7 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
 	int size;
 	unsigned short freq_send = 0x10 + (freq >> 3) / 25;
 
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
-	mutex_lock(&radio->lock);
+	BUG_ON(!mutex_is_locked(&radio->lock));
 
 	radio->buffer[0] = 0x00;
 	radio->buffer[1] = 0x55;
@@ -223,10 +218,8 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
 	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;
-	}
+	if (retval < 0 || size != BUFFER_LENGTH)
+		goto out_err;
 
 	/* frequency is calculated from freq_send and placed in first 2 bytes */
 	radio->buffer[0] = (freq_send >> 8) & 0xff;
@@ -240,13 +233,15 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
 	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;
-	}
+	if (retval < 0 || size != BUFFER_LENGTH)
+		goto out_err;
 
-	mutex_unlock(&radio->lock);
+	radio->curfreq = freq;
+	goto out;
 
+out_err:
+	amradio_dev_warn(&radio->videodev.dev, "set frequency failed\n");
+out:
 	return retval;
 }
 
@@ -255,11 +250,7 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
 	int retval;
 	int size;
 
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
-	mutex_lock(&radio->lock);
+	BUG_ON(!mutex_is_locked(&radio->lock));
 
 	radio->buffer[0] = 0x00;
 	radio->buffer[1] = 0x55;
@@ -274,14 +265,14 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
 		(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
 
 	if (retval < 0 || size != BUFFER_LENGTH) {
-		radio->stereo = -1;
-		mutex_unlock(&radio->lock);
+		amradio_dev_warn(&radio->videodev.dev, "set stereo failed\n");
 		return retval;
 	}
 
-	radio->stereo = 1;
-
-	mutex_unlock(&radio->lock);
+	if (argument == WANT_STEREO)
+		radio->stereo = 1;
+	else
+		radio->stereo = 0;
 
 	return retval;
 }
@@ -296,19 +287,19 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
 	struct amradio_device *radio = usb_get_intfdata(intf);
 
 	mutex_lock(&radio->lock);
-	radio->removed = 1;
+	radio->usbdev = NULL;
 	mutex_unlock(&radio->lock);
 
 	usb_set_intfdata(intf, NULL);
-	video_unregister_device(radio->videodev);
 	v4l2_device_disconnect(&radio->v4l2_dev);
+	video_unregister_device(&radio->videodev);
 }
 
 /* vidioc_querycap - query device capabilities */
 static int vidioc_querycap(struct file *file, void *priv,
 					struct v4l2_capability *v)
 {
-	struct amradio_device *radio = video_drvdata(file);
+	struct amradio_device *radio = file->private_data;
 
 	strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
 	strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
@@ -322,13 +313,9 @@ static int vidioc_querycap(struct file *file, void *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *v)
 {
-	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+	struct amradio_device *radio = file->private_data;
 	int retval;
 
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
 	if (v->index > 0)
 		return -EINVAL;
 
@@ -341,9 +328,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
  * 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;
@@ -357,19 +341,16 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 		v->audmode = V4L2_TUNER_MODE_MONO;
 	v->signal = 0xffff;     /* Can't get the signal strength, sad.. */
 	v->afc = 0; /* Don't know what is this */
-	return 0;
+
+	return retval;
 }
 
 /* vidioc_s_tuner - set tuner attributes */
 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)
-		return -EIO;
+	struct amradio_device *radio = file->private_data;
+	int retval = -EINVAL;
 
 	if (v->index > 0)
 		return -EINVAL;
@@ -378,57 +359,33 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 	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;
+	return retval;
 }
 
 /* vidioc_s_frequency - set tuner radio frequency */
 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;
+	struct amradio_device *radio = file->private_data;
 
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
-
-	mutex_lock(&radio->lock);
-	radio->curfreq = f->frequency;
-	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;
+	return amradio_setfreq(radio, f->frequency);
 }
 
 /* vidioc_g_frequency - get tuner radio frequency */
 static int vidioc_g_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
-
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
+	struct amradio_device *radio = file->private_data;
 
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = radio->curfreq;
+
 	return 0;
 }
 
@@ -448,17 +405,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 amradio_device *radio = video_get_drvdata(video_devdata(file));
-
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
+	struct amradio_device *radio = file->private_data;
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 		ctrl->value = radio->muted;
 		return 0;
 	}
+
 	return -EINVAL;
 }
 
@@ -466,33 +420,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 amradio_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
-
-	/* safety check */
-	if (radio->removed)
-		return -EIO;
+	struct amradio_device *radio = file->private_data;
+	int retval = -EINVAL;
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value) {
+		if (ctrl->value)
 			retval = amradio_set_mute(radio, AMRADIO_STOP);
-			if (retval < 0) {
-				amradio_dev_warn(&radio->videodev->dev,
-					"amradio_stop failed\n");
-				return -1;
-			}
-		} else {
+		else
 			retval = amradio_set_mute(radio, AMRADIO_START);
-			if (retval < 0) {
-				amradio_dev_warn(&radio->videodev->dev,
-					"amradio_start failed\n");
-				return -1;
-			}
-		}
-		return 0;
+
+		break;
 	}
-	return -EINVAL;
+
+	return retval;
 }
 
 /* vidioc_g_audio - get audio attributes */
@@ -531,75 +472,108 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 	return 0;
 }
 
-/* open device - amradio_start() and amradio_setfreq() */
-static int usb_amradio_open(struct file *file)
+static int usb_amradio_init(struct amradio_device *radio)
 {
-	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
 	int retval;
 
-	lock_kernel();
+	retval = amradio_set_mute(radio, AMRADIO_STOP);
+	if (retval)
+		goto out_err;
 
-	radio->users = 1;
-	radio->muted = 1;
+	retval = amradio_set_stereo(radio, WANT_STEREO);
+	if (retval)
+		goto out_err;
 
-	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;
+	radio->initialized = 1;
+	goto out;
+
+out_err:
+	amradio_dev_err(&radio->videodev.dev, "initialization failed\n");
+out:
+	return retval;
+}
+
+/* open device - amradio_start() and amradio_setfreq() */
+static int usb_amradio_open(struct file *file)
+{
+	struct amradio_device *radio = vdev_to_amradio(video_devdata(file));
+	int retval = 0;
+
+	mutex_lock(&radio->lock);
+
+	if (!radio->usbdev) {
+		retval = -EIO;
+		goto unlock;
 	}
 
-	retval = amradio_set_stereo(radio, WANT_STEREO);
-	if (retval < 0)
-		amradio_dev_warn(&radio->videodev->dev,
-			"set stereo failed\n");
+	file->private_data = radio;
+	retval = usb_autopm_get_interface(radio->intf);
+	if (retval)
+		goto unlock;
 
-	retval = amradio_setfreq(radio, radio->curfreq);
-	if (retval < 0)
-		amradio_dev_warn(&radio->videodev->dev,
-			"set frequency failed\n");
+	if (unlikely(!radio->initialized)) {
+		retval = usb_amradio_init(radio);
+		if (retval)
+			usb_autopm_put_interface(radio->intf);
+	}
 
-	unlock_kernel();
-	return 0;
+unlock:
+	mutex_unlock(&radio->lock);
+	return retval;
 }
 
 /*close device */
 static int usb_amradio_close(struct file *file)
 {
-	struct amradio_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
-
-	if (!radio)
-		return -ENODEV;
+	struct amradio_device *radio = file->private_data;
+	int retval = 0;
 
 	mutex_lock(&radio->lock);
-	radio->users = 0;
+
+	if (!radio->usbdev)
+		retval = -EIO;
+	else
+		usb_autopm_put_interface(radio->intf);
+
 	mutex_unlock(&radio->lock);
+	return retval;
+}
 
-	if (!radio->removed) {
-		retval = amradio_set_mute(radio, AMRADIO_STOP);
-		if (retval < 0)
-			amradio_dev_warn(&radio->videodev->dev,
-				"amradio_stop failed\n");
+static long usb_amradio_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct amradio_device *radio = file->private_data;
+	long retval = 0;
+
+	mutex_lock(&radio->lock);
+
+	if (!radio->usbdev) {
+		retval = -EIO;
+		goto unlock;
 	}
 
-	return 0;
+	retval = video_ioctl2(file, cmd, arg);
+
+unlock:
+	mutex_unlock(&radio->lock);
+	return retval;
 }
 
 /* Suspend device - stop device. Need to be checked and fixed */
 static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct amradio_device *radio = usb_get_intfdata(intf);
-	int retval;
 
-	retval = amradio_set_mute(radio, AMRADIO_STOP);
-	if (retval < 0)
-		dev_warn(&intf->dev, "amradio_stop failed\n");
+	mutex_lock(&radio->lock);
+
+	if (!radio->muted && radio->initialized) {
+		amradio_set_mute(radio, AMRADIO_STOP);
+		radio->muted = 0;
+	}
 
 	dev_info(&intf->dev, "going into suspend..\n");
 
+	mutex_unlock(&radio->lock);
 	return 0;
 }
 
@@ -607,14 +581,26 @@ 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;
 
-	retval = amradio_set_mute(radio, AMRADIO_START);
-	if (retval < 0)
-		dev_warn(&intf->dev, "amradio_start failed\n");
+	mutex_lock(&radio->lock);
+
+	if (unlikely(!radio->initialized))
+		goto unlock;
+
+	if (radio->stereo)
+		amradio_set_stereo(radio, WANT_STEREO);
+	else
+		amradio_set_stereo(radio, WANT_MONO);
+
+	amradio_setfreq(radio, radio->curfreq);
 
+	if (!radio->muted)
+		amradio_set_mute(radio, AMRADIO_START);
+
+unlock:
 	dev_info(&intf->dev, "coming out of suspend..\n");
 
+	mutex_unlock(&radio->lock);
 	return 0;
 }
 
@@ -623,7 +609,7 @@ static const struct v4l2_file_operations usb_amradio_fops = {
 	.owner		= THIS_MODULE,
 	.open		= usb_amradio_open,
 	.release	= usb_amradio_close,
-	.ioctl		= video_ioctl2,
+	.ioctl		= usb_amradio_ioctl,
 };
 
 static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
@@ -643,10 +629,7 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
 
 static void usb_amradio_video_device_release(struct video_device *videodev)
 {
-	struct amradio_device *radio = video_get_drvdata(videodev);
-
-	/* we call v4l to free radio->videodev */
-	video_device_release(videodev);
+	struct amradio_device *radio = vdev_to_amradio(videodev);
 
 	v4l2_device_unregister(&radio->v4l2_dev);
 
@@ -660,70 +643,63 @@ static int usb_amradio_probe(struct usb_interface *intf,
 				const struct usb_device_id *id)
 {
 	struct amradio_device *radio;
-	struct v4l2_device *v4l2_dev;
-	int retval;
+	int retval = 0;
 
 	radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL);
 
 	if (!radio) {
 		dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
-		return -ENOMEM;
+		retval = -ENOMEM;
+		goto err;
 	}
 
 	radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
 
 	if (!radio->buffer) {
 		dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
-		kfree(radio);
-		return -ENOMEM;
+		retval = -ENOMEM;
+		goto err_nobuf;
 	}
 
-	v4l2_dev = &radio->v4l2_dev;
-	retval = v4l2_device_register(&intf->dev, v4l2_dev);
+	retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
 	if (retval < 0) {
 		dev_err(&intf->dev, "couldn't register v4l2_device\n");
-		kfree(radio->buffer);
-		kfree(radio);
-		return retval;
+		goto err_v4l2;
 	}
 
-	radio->videodev = video_device_alloc();
-
-	if (!radio->videodev) {
-		dev_err(&intf->dev, "video_device_alloc failed\n");
-		kfree(radio->buffer);
-		kfree(radio);
-		return -ENOMEM;
-	}
+	strlcpy(radio->videodev.name, radio->v4l2_dev.name,
+		sizeof(radio->videodev.name));
+	radio->videodev.v4l2_dev = &radio->v4l2_dev;
+	radio->videodev.fops = &usb_amradio_fops;
+	radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops;
+	radio->videodev.release = usb_amradio_video_device_release;
 
-	strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name));
-	radio->videodev->v4l2_dev = v4l2_dev;
-	radio->videodev->fops = &usb_amradio_fops;
-	radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops;
-	radio->videodev->release = usb_amradio_video_device_release;
-
-	radio->removed = 0;
-	radio->users = 0;
 	radio->usbdev = interface_to_usbdev(intf);
+	radio->intf = intf;
 	radio->curfreq = 95.16 * FREQ_MUL;
-	radio->stereo = -1;
 
 	mutex_init(&radio->lock);
 
-	video_set_drvdata(radio->videodev, radio);
+	video_set_drvdata(&radio->videodev, radio);
 
-	retval = video_register_device(radio->videodev,	VFL_TYPE_RADIO,	radio_nr);
+	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);
-		v4l2_device_unregister(v4l2_dev);
-		kfree(radio->buffer);
-		kfree(radio);
-		return -EIO;
+		goto err_vdev;
 	}
 
 	usb_set_intfdata(intf, radio);
 	return 0;
+
+err_vdev:
+	v4l2_device_unregister(&radio->v4l2_dev);
+err_v4l2:
+	kfree(radio->buffer);
+err_nobuf:
+	kfree(radio);
+err:
+	return retval;
 }
 
 static int __init amradio_init(void)
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
new file mode 100644
index 000000000000..6e607ff0c169
--- /dev/null
+++ b/drivers/media/radio/tef6862.c
@@ -0,0 +1,232 @@
+/*
+ * tef6862.c Philips TEF6862 Car Radio Enhanced Selectivity Tuner
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#define DRIVER_NAME "tef6862"
+
+#define FREQ_MUL 16000
+
+#define TEF6862_LO_FREQ (875 * FREQ_MUL / 10)
+#define TEF6862_HI_FREQ (108 * FREQ_MUL)
+
+/* Write mode sub addresses */
+#define WM_SUB_BANDWIDTH	0x0
+#define WM_SUB_PLLM		0x1
+#define WM_SUB_PLLL		0x2
+#define WM_SUB_DAA		0x3
+#define WM_SUB_AGC		0x4
+#define WM_SUB_BAND		0x5
+#define WM_SUB_CONTROL		0x6
+#define WM_SUB_LEVEL		0x7
+#define WM_SUB_IFCF		0x8
+#define WM_SUB_IFCAP		0x9
+#define WM_SUB_ACD		0xA
+#define WM_SUB_TEST		0xF
+
+/* Different modes of the MSA register */
+#define MODE_BUFFER		0x0
+#define MODE_PRESET		0x1
+#define MODE_SEARCH		0x2
+#define MODE_AF_UPDATE		0x3
+#define MODE_JUMP		0x4
+#define MODE_CHECK		0x5
+#define MODE_LOAD		0x6
+#define MODE_END		0x7
+#define MODE_SHIFT		5
+
+struct tef6862_state {
+	struct v4l2_subdev sd;
+	unsigned long freq;
+};
+
+static inline struct tef6862_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct tef6862_state, sd);
+}
+
+static u16 tef6862_sigstr(struct i2c_client *client)
+{
+	u8 buf[4];
+	int err = i2c_master_recv(client, buf, sizeof(buf));
+	if (err == sizeof(buf))
+		return buf[3] << 8;
+	return 0;
+}
+
+static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+
+	/* only support FM for now */
+	strlcpy(v->name, "FM", sizeof(v->name));
+	v->type = V4L2_TUNER_RADIO;
+	v->rangelow = TEF6862_LO_FREQ;
+	v->rangehigh = TEF6862_HI_FREQ;
+	v->rxsubchans = V4L2_TUNER_SUB_MONO;
+	v->capability = V4L2_TUNER_CAP_LOW;
+	v->audmode = V4L2_TUNER_MODE_STEREO;
+	v->signal = tef6862_sigstr(v4l2_get_subdevdata(sd));
+
+	return 0;
+}
+
+static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
+{
+	return v->index ? -EINVAL : 0;
+}
+
+static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+{
+	struct tef6862_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u16 pll;
+	u8 i2cmsg[3];
+	int err;
+
+	if (f->tuner != 0)
+		return -EINVAL;
+
+	pll = 1964 + ((f->frequency - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
+	i2cmsg[0] = (MODE_PRESET << MODE_SHIFT) | WM_SUB_PLLM;
+	i2cmsg[1] = (pll >> 8) & 0xff;
+	i2cmsg[2] = pll & 0xff;
+
+	err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg));
+	if (!err)
+		state->freq = f->frequency;
+	return err;
+}
+
+static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+{
+	struct tef6862_state *state = to_state(sd);
+
+	if (f->tuner != 0)
+		return -EINVAL;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = state->freq;
+	return 0;
+}
+
+static int tef6862_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_TEF6862, 0);
+}
+
+static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = {
+	.g_tuner = tef6862_g_tuner,
+	.s_tuner = tef6862_s_tuner,
+	.s_frequency = tef6862_s_frequency,
+	.g_frequency = tef6862_g_frequency,
+};
+
+static const struct v4l2_subdev_core_ops tef6862_core_ops = {
+	.g_chip_ident = tef6862_g_chip_ident,
+};
+
+static const struct v4l2_subdev_ops tef6862_ops = {
+	.core = &tef6862_core_ops,
+	.tuner = &tef6862_tuner_ops,
+};
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static int __devinit tef6862_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct tef6862_state *state;
+	struct v4l2_subdev *sd;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kmalloc(sizeof(struct tef6862_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+	state->freq = TEF6862_LO_FREQ;
+
+	sd = &state->sd;
+	v4l2_i2c_subdev_init(sd, client, &tef6862_ops);
+
+	return 0;
+}
+
+static int __devexit tef6862_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id tef6862_id[] = {
+	{DRIVER_NAME, 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, tef6862_id);
+
+static struct i2c_driver tef6862_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= DRIVER_NAME,
+	},
+	.probe		= tef6862_probe,
+	.remove		= tef6862_remove,
+	.id_table	= tef6862_id,
+};
+
+static __init int tef6862_init(void)
+{
+	return i2c_add_driver(&tef6862_driver);
+}
+
+static __exit void tef6862_exit(void)
+{
+	i2c_del_driver(&tef6862_driver);
+}
+
+module_init(tef6862_init);
+module_exit(tef6862_exit);
+
+MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner");
+MODULE_AUTHOR("Mocean Laboratories");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index e6186b338a12..9dc74c93bf24 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -600,7 +600,7 @@ source "drivers/media/video/bt8xx/Kconfig"
 
 config VIDEO_PMS
 	tristate "Mediavision Pro Movie Studio Video For Linux"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	help
 	  Say Y if you have such a thing.
 
@@ -847,6 +847,12 @@ config SOC_CAMERA_MT9V022
 	help
 	  This driver supports MT9V022 cameras from Micron
 
+config SOC_CAMERA_RJ54N1
+	tristate "rj54n1cb0c support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This is a rj54n1cb0c video driver
+
 config SOC_CAMERA_TW9910
 	tristate "tw9910 support"
 	depends on SOC_CAMERA && I2C
@@ -865,6 +871,12 @@ config SOC_CAMERA_OV772X
 	help
 	  This is a ov772x camera driver
 
+config SOC_CAMERA_OV9640
+	tristate "ov9640 camera support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This is a ov9640 camera driver
+
 config MX1_VIDEO
 	bool
 
@@ -939,9 +951,14 @@ source "drivers/media/video/usbvideo/Kconfig"
 source "drivers/media/video/et61x251/Kconfig"
 
 config VIDEO_OVCAMCHIP
-	tristate "OmniVision Camera Chip support"
+	tristate "OmniVision Camera Chip support (DEPRECATED)"
 	depends on I2C && VIDEO_V4L1
 	---help---
+	  This driver is DEPRECATED please use the gspca ov519 module
+	  instead. Note that for the ov511 / ov518 support of the gspca module
+	  you need atleast version 0.6.0 of libv4l and for the w9968cf
+	  atleast version 0.6.3 of libv4l.
+
 	  Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
 	  This driver is intended to be used with the ov511 and w9968cf USB
 	  camera drivers.
@@ -950,9 +967,13 @@ config VIDEO_OVCAMCHIP
 	  module will be called ovcamchip.
 
 config USB_W9968CF
-	tristate "USB W996[87]CF JPEG Dual Mode Camera support"
+	tristate "USB W996[87]CF JPEG Dual Mode Camera support (DEPRECATED)"
 	depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP
 	---help---
+	  This driver is DEPRECATED please use the gspca ov519 module
+	  instead. Note that for the w9968cf support of the gspca module
+	  you need atleast version 0.6.3 of libv4l.
+
 	  Say Y here if you want support for cameras based on OV681 or
 	  Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
 
@@ -995,9 +1016,13 @@ config USB_SE401
 source "drivers/media/video/sn9c102/Kconfig"
 
 config USB_STV680
-	tristate "USB STV680 (Pencam) Camera support"
+	tristate "USB STV680 (Pencam) Camera support (DEPRECATED)"
 	depends on VIDEO_V4L1
 	---help---
+	  This driver is DEPRECATED please use the gspca stv0680 module
+	  instead. Note that for the gspca stv0680 module you need
+	  atleast version 0.6.3 of libv4l.
+
 	  Say Y here if you want to connect this type of camera to your
 	  computer's USB port. This includes the Pencam line of cameras.
 	  See <file:Documentation/video4linux/stv680.txt> for more information
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index e541932a789b..7a2dcc34111c 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -77,6 +77,8 @@ obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
 obj-$(CONFIG_SOC_CAMERA_MT9T031)	+= mt9t031.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
 obj-$(CONFIG_SOC_CAMERA_OV772X)		+= ov772x.o
+obj-$(CONFIG_SOC_CAMERA_OV9640)		+= ov9640.o
+obj-$(CONFIG_SOC_CAMERA_RJ54N1)		+= rj54n1cb0c.o
 obj-$(CONFIG_SOC_CAMERA_TW9910)		+= tw9910.o
 
 # And now the v4l2 drivers:
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index 1b3cbd02a7fd..0826f0dabc17 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -27,17 +27,40 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <linux/mutex.h>
 
 #define DRIVER_NAME "adv7180"
 
-#define ADV7180_INPUT_CONTROL_REG	0x00
-#define ADV7180_INPUT_CONTROL_PAL_BG_NTSC_J_SECAM	0x00
-#define ADV7180_AUTODETECT_ENABLE_REG	0x07
-#define ADV7180_AUTODETECT_DEFAULT	0x7f
-
-
-#define ADV7180_STATUS1_REG 0x10
-#define ADV7180_STATUS1_AUTOD_MASK 0x70
+#define ADV7180_INPUT_CONTROL_REG			0x00
+#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM	0x00
+#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
+#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM	0x20
+#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM	0x30
+#define ADV7180_INPUT_CONTROL_NTSC_J			0x40
+#define ADV7180_INPUT_CONTROL_NTSC_M			0x50
+#define ADV7180_INPUT_CONTROL_PAL60			0x60
+#define ADV7180_INPUT_CONTROL_NTSC_443			0x70
+#define ADV7180_INPUT_CONTROL_PAL_BG			0x80
+#define ADV7180_INPUT_CONTROL_PAL_N			0x90
+#define ADV7180_INPUT_CONTROL_PAL_M			0xa0
+#define ADV7180_INPUT_CONTROL_PAL_M_PED			0xb0
+#define ADV7180_INPUT_CONTROL_PAL_COMB_N		0xc0
+#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED		0xd0
+#define ADV7180_INPUT_CONTROL_PAL_SECAM			0xe0
+#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED		0xf0
+
+#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG		0x04
+#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
+
+#define ADV7180_AUTODETECT_ENABLE_REG			0x07
+#define ADV7180_AUTODETECT_DEFAULT			0x7f
+
+#define ADV7180_ADI_CTRL_REG				0x0e
+#define ADV7180_ADI_CTRL_IRQ_SPACE			0x20
+
+#define ADV7180_STATUS1_REG				0x10
+#define ADV7180_STATUS1_IN_LOCK		0x01
+#define ADV7180_STATUS1_AUTOD_MASK	0x70
 #define ADV7180_STATUS1_AUTOD_NTSM_M_J	0x00
 #define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10
 #define ADV7180_STATUS1_AUTOD_PAL_M	0x20
@@ -50,18 +73,37 @@
 #define ADV7180_IDENT_REG 0x11
 #define ADV7180_ID_7180 0x18
 
+#define ADV7180_ICONF1_ADI		0x40
+#define ADV7180_ICONF1_ACTIVE_LOW	0x01
+#define ADV7180_ICONF1_PSYNC_ONLY	0x10
+#define ADV7180_ICONF1_ACTIVE_TO_CLR	0xC0
+
+#define ADV7180_IRQ1_LOCK	0x01
+#define ADV7180_IRQ1_UNLOCK	0x02
+#define ADV7180_ISR1_ADI	0x42
+#define ADV7180_ICR1_ADI	0x43
+#define ADV7180_IMR1_ADI	0x44
+#define ADV7180_IMR2_ADI	0x48
+#define ADV7180_IRQ3_AD_CHANGE	0x08
+#define ADV7180_ISR3_ADI	0x4A
+#define ADV7180_ICR3_ADI	0x4B
+#define ADV7180_IMR3_ADI	0x4C
+#define ADV7180_IMR4_ADI	0x50
 
 struct adv7180_state {
-	struct v4l2_subdev sd;
+	struct v4l2_subdev	sd;
+	struct work_struct	work;
+	struct mutex		mutex; /* mutual excl. when accessing chip */
+	int			irq;
+	v4l2_std_id		curr_norm;
+	bool			autodetect;
 };
 
-static v4l2_std_id determine_norm(struct i2c_client *client)
+static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
 {
-	u8 status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
-
 	switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
 	case ADV7180_STATUS1_AUTOD_NTSM_M_J:
-		return V4L2_STD_NTSC_M_JP;
+		return V4L2_STD_NTSC;
 	case ADV7180_STATUS1_AUTOD_NTSC_4_43:
 		return V4L2_STD_NTSC_443;
 	case ADV7180_STATUS1_AUTOD_PAL_M:
@@ -81,6 +123,53 @@ static v4l2_std_id determine_norm(struct i2c_client *client)
 	}
 }
 
+static int v4l2_std_to_adv7180(v4l2_std_id std)
+{
+	if (std == V4L2_STD_PAL_60)
+		return ADV7180_INPUT_CONTROL_PAL60;
+	if (std == V4L2_STD_NTSC_443)
+		return ADV7180_INPUT_CONTROL_NTSC_443;
+	if (std == V4L2_STD_PAL_N)
+		return ADV7180_INPUT_CONTROL_PAL_N;
+	if (std == V4L2_STD_PAL_M)
+		return ADV7180_INPUT_CONTROL_PAL_M;
+	if (std == V4L2_STD_PAL_Nc)
+		return ADV7180_INPUT_CONTROL_PAL_COMB_N;
+
+	if (std & V4L2_STD_PAL)
+		return ADV7180_INPUT_CONTROL_PAL_BG;
+	if (std & V4L2_STD_NTSC)
+		return ADV7180_INPUT_CONTROL_NTSC_M;
+	if (std & V4L2_STD_SECAM)
+		return ADV7180_INPUT_CONTROL_PAL_SECAM;
+
+	return -EINVAL;
+}
+
+static u32 adv7180_status_to_v4l2(u8 status1)
+{
+	if (!(status1 & ADV7180_STATUS1_IN_LOCK))
+		return V4L2_IN_ST_NO_SIGNAL;
+
+	return 0;
+}
+
+static int __adv7180_status(struct i2c_client *client, u32 *status,
+	v4l2_std_id *std)
+{
+	int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
+
+	if (status1 < 0)
+		return status1;
+
+	if (status)
+		*status = adv7180_status_to_v4l2(status1);
+	if (std)
+		*std = adv7180_std_to_v4l2(status1);
+
+	return 0;
+}
+
 static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
 {
 	return container_of(sd, struct adv7180_state, sd);
@@ -88,10 +177,31 @@ static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
 
 static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
 {
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct adv7180_state *state = to_state(sd);
+	int err = mutex_lock_interruptible(&state->mutex);
+	if (err)
+		return err;
+
+	/* when we are interrupt driven we know the state */
+	if (!state->autodetect || state->irq > 0)
+		*std = state->curr_norm;
+	else
+		err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
+
+	mutex_unlock(&state->mutex);
+	return err;
+}
 
-	*std = determine_norm(client);
-	return 0;
+static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	struct adv7180_state *state = to_state(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	if (ret)
+		return ret;
+
+	ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
+	mutex_unlock(&state->mutex);
+	return ret;
 }
 
 static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
@@ -102,12 +212,51 @@ static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
 	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0);
 }
 
+static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7180_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	if (ret)
+		return ret;
+
+	/* all standards -> autodetect */
+	if (std == V4L2_STD_ALL) {
+		ret = i2c_smbus_write_byte_data(client,
+			ADV7180_INPUT_CONTROL_REG,
+			ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
+		if (ret < 0)
+			goto out;
+
+		__adv7180_status(client, NULL, &state->curr_norm);
+		state->autodetect = true;
+	} else {
+		ret = v4l2_std_to_adv7180(std);
+		if (ret < 0)
+			goto out;
+
+		ret = i2c_smbus_write_byte_data(client,
+			ADV7180_INPUT_CONTROL_REG, ret);
+		if (ret < 0)
+			goto out;
+
+		state->curr_norm = std;
+		state->autodetect = false;
+	}
+	ret = 0;
+out:
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
 static const struct v4l2_subdev_video_ops adv7180_video_ops = {
 	.querystd = adv7180_querystd,
+	.g_input_status = adv7180_g_input_status,
 };
 
 static const struct v4l2_subdev_core_ops adv7180_core_ops = {
 	.g_chip_ident = adv7180_g_chip_ident,
+	.s_std = adv7180_s_std,
 };
 
 static const struct v4l2_subdev_ops adv7180_ops = {
@@ -115,12 +264,45 @@ static const struct v4l2_subdev_ops adv7180_ops = {
 	.video = &adv7180_video_ops,
 };
 
+static void adv7180_work(struct work_struct *work)
+{
+	struct adv7180_state *state = container_of(work, struct adv7180_state,
+		work);
+	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
+	u8 isr3;
+
+	mutex_lock(&state->mutex);
+	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
+		ADV7180_ADI_CTRL_IRQ_SPACE);
+	isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
+	/* clear */
+	i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
+	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
+
+	if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
+		__adv7180_status(client, NULL, &state->curr_norm);
+	mutex_unlock(&state->mutex);
+
+	enable_irq(state->irq);
+}
+
+static irqreturn_t adv7180_irq(int irq, void *devid)
+{
+	struct adv7180_state *state = devid;
+
+	schedule_work(&state->work);
+
+	disable_irq_nosync(state->irq);
+
+	return IRQ_HANDLED;
+}
+
 /*
  * Generic i2c probe
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static int adv7180_probe(struct i2c_client *client,
+static __devinit int adv7180_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
 	struct adv7180_state *state;
@@ -135,32 +317,111 @@ static int adv7180_probe(struct i2c_client *client,
 			client->addr << 1, client->adapter->name);
 
 	state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
-	if (state == NULL)
-		return -ENOMEM;
+	if (state == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	state->irq = client->irq;
+	INIT_WORK(&state->work, adv7180_work);
+	mutex_init(&state->mutex);
+	state->autodetect = true;
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
 
 	/* Initialize adv7180 */
-	/* enable autodetection */
+	/* Enable autodetection */
 	ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
-		ADV7180_INPUT_CONTROL_PAL_BG_NTSC_J_SECAM);
-	if (ret > 0)
-		ret = i2c_smbus_write_byte_data(client,
-			ADV7180_AUTODETECT_ENABLE_REG,
-			ADV7180_AUTODETECT_DEFAULT);
-	if (ret < 0) {
-		printk(KERN_ERR DRIVER_NAME
-			": Failed to communicate to chip: %d\n", ret);
-		return ret;
+		ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
+	if (ret < 0)
+		goto err_unreg_subdev;
+
+	ret = i2c_smbus_write_byte_data(client, ADV7180_AUTODETECT_ENABLE_REG,
+		ADV7180_AUTODETECT_DEFAULT);
+	if (ret < 0)
+		goto err_unreg_subdev;
+
+	/* ITU-R BT.656-4 compatible */
+	ret = i2c_smbus_write_byte_data(client,
+		ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
+		ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
+	if (ret < 0)
+		goto err_unreg_subdev;
+
+	/* read current norm */
+	__adv7180_status(client, NULL, &state->curr_norm);
+
+	/* register for interrupts */
+	if (state->irq > 0) {
+		ret = request_irq(state->irq, adv7180_irq, 0, DRIVER_NAME,
+			state);
+		if (ret)
+			goto err_unreg_subdev;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
+			ADV7180_ADI_CTRL_IRQ_SPACE);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* config the Interrupt pin to be active low */
+		ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
+			ADV7180_ICONF1_ACTIVE_LOW | ADV7180_ICONF1_PSYNC_ONLY);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* enable AD change interrupts interrupts */
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
+			ADV7180_IRQ3_AD_CHANGE);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
+			0);
+		if (ret < 0)
+			goto err_unreg_subdev;
 	}
 
 	return 0;
+
+err_unreg_subdev:
+	mutex_destroy(&state->mutex);
+	v4l2_device_unregister_subdev(sd);
+	kfree(state);
+err:
+	printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", ret);
+	return ret;
 }
 
-static int adv7180_remove(struct i2c_client *client)
+static __devexit int adv7180_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7180_state *state = to_state(sd);
+
+	if (state->irq > 0) {
+		free_irq(client->irq, state);
+		if (cancel_work_sync(&state->work)) {
+			/*
+			 * Work was pending, therefore we need to enable
+			 * IRQ here to balance the disable_irq() done in the
+			 * interrupt handler.
+			 */
+			enable_irq(state->irq);
+		}
+	}
 
+	mutex_destroy(&state->mutex);
 	v4l2_device_unregister_subdev(sd);
 	kfree(to_state(sd));
 	return 0;
@@ -179,7 +440,7 @@ static struct i2c_driver adv7180_driver = {
 		.name	= DRIVER_NAME,
 	},
 	.probe		= adv7180_probe,
-	.remove		= adv7180_remove,
+	.remove		= __devexit_p(adv7180_remove),
 	.id_table	= adv7180_id,
 };
 
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 51527d7b55a7..1485aee18d58 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -830,7 +830,7 @@ static int au0828_v4l2_close(struct file *filp)
 		au0828_uninit_isoc(dev);
 
 		/* Save some power by putting tuner to sleep */
-		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
 
 		/* When close the device, set the usb intf0 into alt0 to free
 		   USB bandwidth */
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index f9330e3529c3..5bb0f9e71583 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -299,7 +299,7 @@ static int bt819_s_routing(struct v4l2_subdev *sd,
 
 	v4l2_dbg(1, debug, sd, "set input %x\n", input);
 
-	if (input < 0 || input > 7)
+	if (input > 7)
 		return -EINVAL;
 
 	if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index ebd51afe8761..84a957e52c4b 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -73,12 +73,12 @@ static void ir_handle_key(struct bttv *btv)
 
 	if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
 	    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
-		ir_input_keydown(ir->dev,&ir->ir,data,data);
+		ir_input_keydown(ir->dev, &ir->ir, data);
 	} else {
 		/* HACK: Probably, ir->mask_keydown is missing
 		   for this board */
 		if (btv->c.type == BTTV_BOARD_WINFAST2000)
-			ir_input_keydown(ir->dev, &ir->ir, data, data);
+			ir_input_keydown(ir->dev, &ir->ir, data);
 
 		ir_input_nokey(ir->dev,&ir->ir);
 	}
@@ -104,7 +104,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
 			gpio, data,
 			(gpio & ir->mask_keyup) ? " up" : "up/down");
 
-		ir_input_keydown(ir->dev, &ir->ir, data, data);
+		ir_input_keydown(ir->dev, &ir->ir, data);
 		if (keyup)
 			ir_input_nokey(ir->dev, &ir->ir);
 	} else {
@@ -118,7 +118,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
 		if (keyup)
 			ir_input_nokey(ir->dev, &ir->ir);
 		else
-			ir_input_keydown(ir->dev, &ir->ir, data, data);
+			ir_input_keydown(ir->dev, &ir->ir, data);
 	}
 
 	ir->last_gpio = data | keyup;
@@ -368,7 +368,10 @@ int bttv_input_init(struct bttv *btv)
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
 		 pci_name(btv->c.pci));
 
-	ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
+	err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
+	if (err < 0)
+		goto err_out_free;
+
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
 	input_dev->id.bustype = BUS_PCI;
@@ -400,6 +403,7 @@ int bttv_input_init(struct bttv *btv)
 	bttv_ir_stop(btv);
 	btv->remote = NULL;
  err_out_free:
+	ir_input_free(input_dev);
 	input_free_device(input_dev);
 	kfree(ir);
 	return err;
@@ -411,6 +415,7 @@ void bttv_input_fini(struct bttv *btv)
 		return;
 
 	bttv_ir_stop(btv);
+	ir_input_free(btv->remote->dev);
 	input_unregister_device(btv->remote->dev);
 	kfree(btv->remote);
 	btv->remote = NULL;
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index 536dedb23ba3..4392c76af5df 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -99,10 +99,8 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
 			     or_value);
 }
 
-static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
+static void cx18_av_init(struct cx18 *cx)
 {
-	struct cx18 *cx = v4l2_get_subdevdata(sd);
-
 	/*
 	 * The crystal freq used in calculations in this driver will be
 	 * 28.636360 MHz.
@@ -125,7 +123,6 @@ static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
 
 	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
 	cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
-	return 0;
 }
 
 static void cx18_av_initialize(struct v4l2_subdev *sd)
@@ -198,7 +195,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
 	cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000);
 
 	/* Setup the Video and and Aux/Audio PLLs */
-	cx18_av_init(sd, 0);
+	cx18_av_init(cx);
 
 	/* set video to auto-detect */
 	/* Clear bits 11-12 to enable slow locking mode.  Set autodetect mode */
@@ -1355,7 +1352,6 @@ static int cx18_av_s_register(struct v4l2_subdev *sd,
 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,
 	.load_fw = cx18_av_load_fw,
 	.reset = cx18_av_reset,
 	.queryctrl = cx18_av_queryctrl,
@@ -1399,6 +1395,7 @@ int cx18_av_probe(struct cx18 *cx)
 {
 	struct cx18_av_state *state = &cx->av_state;
 	struct v4l2_subdev *sd;
+	int err;
 
 	state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff;
 	state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO)
@@ -1417,5 +1414,8 @@ int cx18_av_probe(struct cx18 *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);
+	err = v4l2_device_register_subdev(&cx->v4l2_dev, sd);
+	if (!err)
+		cx18_av_init(cx);
+	return err;
 }
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index 444e3c7c563e..af3d71607dc9 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -34,6 +34,9 @@
 #define CX18_HW_Z8F0811_IR_HAUP	(CX18_HW_Z8F0811_IR_RX_HAUP | \
 				 CX18_HW_Z8F0811_IR_TX_HAUP)
 
+#define CX18_HW_IR_ANY (CX18_HW_Z8F0811_IR_RX_HAUP | \
+			CX18_HW_Z8F0811_IR_TX_HAUP)
+
 /* video inputs */
 #define	CX18_CARD_INPUT_VID_TUNER	1
 #define	CX18_CARD_INPUT_SVIDEO1 	2
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index e12082b8a08d..7f65a47f12e1 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -87,7 +87,6 @@ static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE;
 static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE;
 static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE;
 static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE;
-/* VBI bufsize based on standards supported by card tuner for now */
 static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE;
 
 static int enc_ts_bufs = -1;
@@ -128,7 +127,6 @@ module_param(enc_ts_bufsize, int, 0644);
 module_param(enc_mpg_bufsize, int, 0644);
 module_param(enc_idx_bufsize, int, 0644);
 module_param(enc_yuv_bufsize, int, 0644);
-/* VBI bufsize based on standards supported by card tuner for now */
 module_param(enc_pcm_bufsize, int, 0644);
 
 module_param(enc_ts_bufs, int, 0644);
@@ -211,7 +209,9 @@ MODULE_PARM_DESC(enc_yuv_buffers,
 		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
 MODULE_PARM_DESC(enc_yuv_bufsize,
 		 "Size of an encoder YUV buffer (kB)\n"
-		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFSIZE));
+		 "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n"
+		 "\t\t\t(multiples of size required for 32 screen lines)\n"
+		 "\t\t\tDefault: 102");
 MODULE_PARM_DESC(enc_yuv_bufs,
 		 "Number of encoder YUV buffers\n"
 		 "\t\t\tDefault is computed from other enc_yuv_* parameters");
@@ -220,7 +220,7 @@ MODULE_PARM_DESC(enc_vbi_buffers,
 		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
 MODULE_PARM_DESC(enc_vbi_bufs,
 		 "Number of encoder VBI buffers\n"
-		 "\t\t\tDefault is computed from enc_vbi_buffers & tuner std");
+		 "\t\t\tDefault is computed from enc_vbi_buffers");
 MODULE_PARM_DESC(enc_pcm_buffers,
 		 "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n"
 		 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
@@ -499,10 +499,27 @@ static void cx18_process_options(struct cx18 *cx)
 			continue;
 		}
 		/*
+		 * YUV is a special case where the stream_buf_size needs to be
+		 * an integral multiple of 33.75 kB (storage for 32 screens
+		 * lines to maintain alignment in case of lost buffers
+		 */
+		if (i == CX18_ENC_STREAM_TYPE_YUV) {
+			cx->stream_buf_size[i] *= 1024;
+			cx->stream_buf_size[i] -=
+			   (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE);
+
+			if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE)
+				cx->stream_buf_size[i] =
+						CX18_UNIT_ENC_YUV_BUFSIZE;
+		}
+		/*
+		 * YUV is a special case where the stream_buf_size is
+		 * now in bytes.
 		 * VBI is a special case where the stream_buf_size is fixed
 		 * and already in bytes
 		 */
-		if (i == CX18_ENC_STREAM_TYPE_VBI) {
+		if (i == CX18_ENC_STREAM_TYPE_VBI ||
+		    i == CX18_ENC_STREAM_TYPE_YUV) {
 			if (cx->stream_buffers[i] < 0) {
 				cx->stream_buffers[i] =
 					cx->options.megabytes[i] * 1024 * 1024
@@ -513,18 +530,24 @@ static void cx18_process_options(struct cx18 *cx)
 					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];
 		} else {
-			/* N.B. This might round down to 0 */
-			cx->options.megabytes[i] =
-			  cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024;
+			/* All other streams have stream_buf_size in kB here */
+			if (cx->stream_buffers[i] < 0) {
+				cx->stream_buffers[i] =
+						cx->options.megabytes[i] * 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;
+			}
+			/* convert from kB to bytes */
+			cx->stream_buf_size[i] *= 1024;
 		}
-		cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */
+		CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, "
+				"%d bytes\n", i, cx->options.megabytes[i],
+				cx->stream_buffers[i], cx->stream_buf_size[i]);
 	}
 
 	cx->options.cardtype = cardtype[cx->instance];
@@ -669,6 +692,12 @@ 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;
 
+	/* IVTV style VBI insertion into MPEG streams */
+	INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list);
+	INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list);
+	INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list);
+	list_add(&cx->vbi.sliced_mpeg_buf.list,
+		 &cx->vbi.sliced_mpeg_mdl.buf_list);
 	return 0;
 }
 
@@ -883,7 +912,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
 		CX18_ERR("Could not register A/V decoder subdevice\n");
 		goto free_map;
 	}
-	cx18_call_hw(cx, CX18_HW_418_AV, core, init, 0);
 
 	/* Initialize GPIO Reset Controller to do chip resets during i2c init */
 	if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index c6a1e907f63a..e3f7911a7385 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -50,6 +50,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <media/tuner.h>
+#include <media/ir-kbd-i2c.h>
 #include "cx18-mailbox.h"
 #include "cx18-av-core.h"
 #include "cx23418.h"
@@ -120,12 +121,16 @@
 /* Maximum firmware DMA buffers per stream */
 #define CX18_MAX_FW_MDLS_PER_STREAM 63
 
+/* YUV buffer sizes in bytes to ensure integer # of frames per buffer */
+#define CX18_UNIT_ENC_YUV_BUFSIZE	(720 *  32 * 3 / 2) /* bytes */
+#define CX18_625_LINE_ENC_YUV_BUFSIZE	(CX18_UNIT_ENC_YUV_BUFSIZE * 576/32)
+#define CX18_525_LINE_ENC_YUV_BUFSIZE	(CX18_UNIT_ENC_YUV_BUFSIZE * 480/32)
+
 /* DMA buffer, default size in kB allocated */
 #define CX18_DEFAULT_ENC_TS_BUFSIZE   32
 #define CX18_DEFAULT_ENC_MPG_BUFSIZE  32
 #define CX18_DEFAULT_ENC_IDX_BUFSIZE  32
-#define CX18_DEFAULT_ENC_YUV_BUFSIZE 128
-/* Default VBI bufsize based on standards supported by card tuner for now */
+#define CX18_DEFAULT_ENC_YUV_BUFSIZE  (CX18_UNIT_ENC_YUV_BUFSIZE * 3 / 1024 + 1)
 #define CX18_DEFAULT_ENC_PCM_BUFSIZE   4
 
 /* i2c stuff */
@@ -246,8 +251,8 @@ struct cx18_options {
 	int radio;		/* enable/disable radio */
 };
 
-/* per-buffer bit flags */
-#define CX18_F_B_NEED_BUF_SWAP  0	/* this buffer should be byte swapped */
+/* per-mdl bit flags */
+#define CX18_F_M_NEED_SWAP  0	/* mdl buffer data must be endianess swapped */
 
 /* per-stream, s_flags */
 #define CX18_F_S_CLAIMED 	3	/* this stream is claimed */
@@ -274,18 +279,29 @@ struct cx18_options {
 struct cx18_buffer {
 	struct list_head list;
 	dma_addr_t dma_handle;
-	u32 id;
-	unsigned long b_flags;
-	unsigned skipped;
 	char *buf;
 
 	u32 bytesused;
 	u32 readpos;
 };
 
+struct cx18_mdl {
+	struct list_head list;
+	u32 id;		/* index into cx->scb->cpu_mdl[] of 1st cx18_mdl_ent */
+
+	unsigned int skipped;
+	unsigned long m_flags;
+
+	struct list_head buf_list;
+	struct cx18_buffer *curr_buf; /* current buffer in list for reading */
+
+	u32 bytesused;
+	u32 readpos;
+};
+
 struct cx18_queue {
 	struct list_head list;
-	atomic_t buffers;
+	atomic_t depth;
 	u32 bytesused;
 	spinlock_t lock;
 };
@@ -337,7 +353,7 @@ struct cx18_stream {
 	const char *name;		/* name of the stream */
 	int type;			/* stream type */
 	u32 handle;			/* task handle */
-	unsigned mdl_offset;
+	unsigned int mdl_base_idx;
 
 	u32 id;
 	unsigned long s_flags;	/* status flags, see above */
@@ -346,14 +362,20 @@ struct cx18_stream {
 				   PCI_DMA_NONE */
 	wait_queue_head_t waitq;
 
-	/* Buffer Stats */
-	u32 buffers;
-	u32 buf_size;
+	/* Buffers */
+	struct list_head buf_pool;	/* buffers not attached to an MDL */
+	u32 buffers;			/* total buffers owned by this stream */
+	u32 buf_size;			/* size in bytes of a single buffer */
+
+	/* MDL sizes - all stream MDLs are the same size */
+	u32 bufs_per_mdl;
+	u32 mdl_size;		/* total bytes in all buffers in a mdl */
 
-	/* Buffer Queues */
-	struct cx18_queue q_free;	/* free buffers */
-	struct cx18_queue q_busy;	/* busy buffers - in use by firmware */
-	struct cx18_queue q_full;	/* full buffers - data for user apps */
+	/* MDL Queues */
+	struct cx18_queue q_free;	/* free - in rotation, not committed */
+	struct cx18_queue q_busy;	/* busy - in use by firmware */
+	struct cx18_queue q_full;	/* full - data for user apps */
+	struct cx18_queue q_idle;	/* idle - not in rotation */
 
 	struct work_struct out_work_order;
 
@@ -481,10 +503,11 @@ struct vbi_info {
 	u32 inserted_frame;
 
 	/*
-	 * A dummy driver stream transfer buffer with a copy of the next
+	 * A dummy driver stream transfer mdl & 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_mdl sliced_mpeg_mdl;
 	struct cx18_buffer sliced_mpeg_buf;
 };
 
@@ -511,10 +534,9 @@ struct cx18 {
 	u8 is_60hz;
 	u8 nof_inputs;		/* number of video inputs */
 	u8 nof_audio_inputs;	/* number of audio inputs */
-	u16 buffer_id;		/* buffer ID counter */
 	u32 v4l2_cap;		/* V4L2 capabilities of card */
 	u32 hw_flags; 		/* Hardware description of the board */
-	unsigned mdl_offset;
+	unsigned int free_mdl_idx;
 	struct cx18_scb __iomem *scb; /* pointer to SCB */
 	struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/
 	struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/
@@ -585,6 +607,8 @@ struct cx18 {
 	struct i2c_algo_bit_data i2c_algo[2];
 	struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2];
 
+	struct IR_i2c_init_data ir_i2c_init_data;
+
 	/* gpio */
 	u32 gpio_dir;
 	u32 gpio_val;
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index 51a0c33b25b7..71ad2d1b4c2c 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -61,6 +61,7 @@ static struct mxl5005s_config hauppauge_hvr1600_tuner = {
 	.top		 = MXL5005S_TOP_25P2,
 	.mod_mode        = MXL_DIGITAL_MODE,
 	.if_mode         = MXL_ZERO_IF,
+	.qam_gain        = 0x02,
 	.AgcMasterByte   = 0x00,
 };
 
@@ -71,7 +72,8 @@ static struct s5h1409_config hauppauge_hvr1600_config = {
 	.qam_if        = 44000,
 	.inversion     = S5H1409_INVERSION_OFF,
 	.status_mode   = S5H1409_DEMODLOCKING,
-	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+	.hvr1600_opt   = S5H1409_HVR1600_OPTIMIZE
 };
 
 /*
@@ -360,9 +362,10 @@ int cx18_dvb_register(struct cx18_stream *stream)
 	dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
 
 	CX18_INFO("DVB Frontend registered\n");
-	CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n",
+	CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n",
 		  stream->dvb.dvb_adapter.num, stream->name,
-		  stream->buffers, stream->buf_size/1024);
+		  stream->buffers, stream->buf_size/1024,
+		  (stream->buf_size * 100 / 1024) % 100);
 
 	mutex_init(&dvb->feedlock);
 	dvb->enabled = 1;
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 04d9c2508b86..4e278db31cc9 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -166,11 +166,12 @@ static void cx18_dualwatch(struct cx18 *cx)
 }
 
 
-static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err)
+static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block,
+				     int *err)
 {
 	struct cx18 *cx = s->cx;
 	struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
-	struct cx18_buffer *buf;
+	struct cx18_mdl *mdl;
 	DEFINE_WAIT(wait);
 
 	*err = 0;
@@ -185,32 +186,33 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
 			}
 			if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
 			    !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
-				while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
+				while ((mdl = cx18_dequeue(s_vbi,
+							   &s_vbi->q_full))) {
 					/* byteswap and process VBI data */
-					cx18_process_vbi_data(cx, buf,
+					cx18_process_vbi_data(cx, mdl,
 							      s_vbi->type);
-					cx18_stream_put_buf_fw(s_vbi, buf);
+					cx18_stream_put_mdl_fw(s_vbi, mdl);
 				}
 			}
-			buf = &cx->vbi.sliced_mpeg_buf;
-			if (buf->readpos != buf->bytesused)
-				return buf;
+			mdl = &cx->vbi.sliced_mpeg_mdl;
+			if (mdl->readpos != mdl->bytesused)
+				return mdl;
 		}
 
 		/* do we have new data? */
-		buf = cx18_dequeue(s, &s->q_full);
-		if (buf) {
-			if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP,
-						&buf->b_flags))
-				return buf;
+		mdl = cx18_dequeue(s, &s->q_full);
+		if (mdl) {
+			if (!test_and_clear_bit(CX18_F_M_NEED_SWAP,
+						&mdl->m_flags))
+				return mdl;
 			if (s->type == CX18_ENC_STREAM_TYPE_MPG)
 				/* byteswap MPG data */
-				cx18_buf_swap(buf);
+				cx18_mdl_swap(mdl);
 			else {
 				/* byteswap and process VBI data */
-				cx18_process_vbi_data(cx, buf, s->type);
+				cx18_process_vbi_data(cx, mdl, s->type);
 			}
-			return buf;
+			return mdl;
 		}
 
 		/* return if end of stream */
@@ -229,7 +231,7 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
 		prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
 		/* New buffers might have become available before we were added
 		   to the waitqueue */
-		if (!atomic_read(&s->q_full.buffers))
+		if (!atomic_read(&s->q_full.depth))
 			schedule();
 		finish_wait(&s->waitq, &wait);
 		if (signal_pending(current)) {
@@ -241,21 +243,28 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
 	}
 }
 
-static void cx18_setup_sliced_vbi_buf(struct cx18 *cx)
+static void cx18_setup_sliced_vbi_mdl(struct cx18 *cx)
 {
+	struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl;
+	struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf;
 	int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
 
-	cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx];
-	cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx];
-	cx->vbi.sliced_mpeg_buf.readpos = 0;
+	buf->buf = cx->vbi.sliced_mpeg_data[idx];
+	buf->bytesused = cx->vbi.sliced_mpeg_size[idx];
+	buf->readpos = 0;
+
+	mdl->curr_buf = NULL;
+	mdl->bytesused = cx->vbi.sliced_mpeg_size[idx];
+	mdl->readpos = 0;
 }
 
 static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
-		struct cx18_buffer *buf, char __user *ubuf, size_t ucount)
+	struct cx18_buffer *buf, char __user *ubuf, size_t ucount, bool *stop)
 {
 	struct cx18 *cx = s->cx;
 	size_t len = buf->bytesused - buf->readpos;
 
+	*stop = false;
 	if (len > ucount)
 		len = ucount;
 	if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
@@ -335,7 +344,8 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
 				/* 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);
+				cx18_setup_sliced_vbi_mdl(cx);
+				*stop = true;
 				break;
 			}
 		}
@@ -352,6 +362,60 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
 	return len;
 }
 
+/**
+ * list_entry_is_past_end - check if a previous loop cursor is off list end
+ * @pos:	the type * previously used as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Check if the entry's list_head is the head of the list, thus it's not a
+ * real entry but was the loop cursor that walked past the end
+ */
+#define list_entry_is_past_end(pos, head, member) \
+	(&pos->member == (head))
+
+static size_t cx18_copy_mdl_to_user(struct cx18_stream *s,
+		struct cx18_mdl *mdl, char __user *ubuf, size_t ucount)
+{
+	size_t tot_written = 0;
+	int rc;
+	bool stop = false;
+
+	if (mdl->curr_buf == NULL)
+		mdl->curr_buf = list_first_entry(&mdl->buf_list,
+						 struct cx18_buffer, list);
+
+	if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {
+		/*
+		 * For some reason we've exhausted the buffers, but the MDL
+		 * object still said some data was unread.
+		 * Fix that and bail out.
+		 */
+		mdl->readpos = mdl->bytesused;
+		return 0;
+	}
+
+	list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) {
+
+		if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused)
+			continue;
+
+		rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written,
+					   ucount - tot_written, &stop);
+		if (rc < 0)
+			return rc;
+		mdl->readpos += rc;
+		tot_written += rc;
+
+		if (stop ||	/* Forced stopping point for VBI insertion */
+		    tot_written >= ucount ||	/* Reader request statisfied */
+		    mdl->curr_buf->readpos < mdl->curr_buf->bytesused ||
+		    mdl->readpos >= mdl->bytesused) /* MDL buffers drained */
+			break;
+	}
+	return tot_written;
+}
+
 static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
 		size_t tot_count, int non_block)
 {
@@ -373,12 +437,12 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
 		single_frame = 1;
 
 	for (;;) {
-		struct cx18_buffer *buf;
+		struct cx18_mdl *mdl;
 		int rc;
 
-		buf = cx18_get_buffer(s, non_block, &rc);
+		mdl = cx18_get_mdl(s, non_block, &rc);
 		/* if there is no data available... */
-		if (buf == NULL) {
+		if (mdl == NULL) {
 			/* if we got data, then return that regardless */
 			if (tot_written)
 				break;
@@ -392,20 +456,20 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
 			return rc;
 		}
 
-		rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written,
+		rc = cx18_copy_mdl_to_user(s, mdl, ubuf + tot_written,
 				tot_count - tot_written);
 
-		if (buf != &cx->vbi.sliced_mpeg_buf) {
-			if (buf->readpos == buf->bytesused)
-				cx18_stream_put_buf_fw(s, buf);
+		if (mdl != &cx->vbi.sliced_mpeg_mdl) {
+			if (mdl->readpos == mdl->bytesused)
+				cx18_stream_put_mdl_fw(s, mdl);
 			else
-				cx18_push(s, buf, &s->q_full);
-		} else if (buf->readpos == buf->bytesused) {
+				cx18_push(s, mdl, &s->q_full);
+		} else if (mdl->readpos == mdl->bytesused) {
 			int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
 
 			cx->vbi.sliced_mpeg_size[idx] = 0;
 			cx->vbi.inserted_frame++;
-			cx->vbi_data_inserted += buf->bytesused;
+			cx->vbi_data_inserted += mdl->bytesused;
 		}
 		if (rc < 0)
 			return rc;
@@ -543,7 +607,7 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
 	CX18_DEBUG_HI_FILE("Encoder poll\n");
 	poll_wait(filp, &s->waitq, wait);
 
-	if (atomic_read(&s->q_full.buffers))
+	if (atomic_read(&s->q_full.depth))
 		return POLLIN | POLLRDNORM;
 	if (eof)
 		return POLLHUP;
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 2477461e84d7..eecf29af916c 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -28,7 +28,6 @@
 #include "cx18-gpio.h"
 #include "cx18-i2c.h"
 #include "cx18-irq.h"
-#include <media/ir-kbd-i2c.h>
 
 #define CX18_REG_I2C_1_WR   0xf15000
 #define CX18_REG_I2C_1_RD   0xf15008
@@ -97,17 +96,11 @@ static const char * const hw_devicenames[] = {
 	"ir_rx_z8f0811_haup",
 };
 
-static const struct IR_i2c_init_data z8f0811_ir_init_data = {
-	.ir_codes = &ir_codes_hauppauge_new_table,
-	.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR,
-	.type = IR_TYPE_RC5,
-	.name = "CX23418 Z8F0811 Hauppauge",
-};
-
-static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type,
-			   u8 addr)
+static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
+			   const char *type, u8 addr)
 {
 	struct i2c_board_info info;
+	struct IR_i2c_init_data *init_data = &cx->ir_i2c_init_data;
 	unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
 
 	memset(&info, 0, sizeof(struct i2c_board_info));
@@ -116,9 +109,11 @@ static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type,
 	/* Our default information for ir-kbd-i2c.c to use */
 	switch (hw) {
 	case CX18_HW_Z8F0811_IR_RX_HAUP:
-		info.platform_data = (void *) &z8f0811_ir_init_data;
-		break;
-	default:
+		init_data->ir_codes = &ir_codes_hauppauge_new_table;
+		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+		init_data->type = IR_TYPE_RC5;
+		init_data->name = cx->card_name;
+		info.platform_data = init_data;
 		break;
 	}
 
@@ -154,8 +149,8 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
 		return sd != NULL ? 0 : -1;
 	}
 
-	if (hw & CX18_HW_Z8F0811_IR_HAUP)
-		return cx18_i2c_new_ir(adap, hw, type, hw_addrs[idx]);
+	if (hw & CX18_HW_IR_ANY)
+		return cx18_i2c_new_ir(cx, adap, hw, type, hw_addrs[idx]);
 
 	/* Is it not an I2C device or one we do not wish to register? */
 	if (!hw_addrs[idx])
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index fc76e4d6ffa7..3e4fc192fdec 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -910,7 +910,8 @@ static int cx18_log_status(struct file *file, void *fh)
 			continue;
 		CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
 			  s->name, s->s_flags,
-			  atomic_read(&s->q_full.buffers) * 100 / s->buffers,
+			  atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100
+			   / s->buffers,
 			  (s->buffers * s->buf_size) / 1024, s->buffers);
 	}
 	CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index afe46c3d4057..f231dd09c720 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -131,13 +131,39 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
  * Functions that run in a work_queue work handling context
  */
 
+static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
+{
+	struct cx18_buffer *buf;
+
+	if (!s->dvb.enabled || mdl->bytesused == 0)
+		return;
+
+	/* We ignore mdl and buf readpos accounting here - it doesn't matter */
+
+	/* The likely case */
+	if (list_is_singular(&mdl->buf_list)) {
+		buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
+				       list);
+		if (buf->bytesused)
+			dvb_dmx_swfilter(&s->dvb.demux,
+					 buf->buf, buf->bytesused);
+		return;
+	}
+
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		if (buf->bytesused == 0)
+			break;
+		dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused);
+	}
+}
+
 static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
 {
 	u32 handle, mdl_ack_count, id;
 	struct cx18_mailbox *mb;
 	struct cx18_mdl_ack *mdl_ack;
 	struct cx18_stream *s;
-	struct cx18_buffer *buf;
+	struct cx18_mdl *mdl;
 	int i;
 
 	mb = &order->mb;
@@ -158,7 +184,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
 		id = mdl_ack->id;
 		/*
 		 * Simple integrity check for processing a stale (and possibly
-		 * inconsistent mailbox): make sure the buffer id is in the
+		 * inconsistent mailbox): make sure the MDL id is in the
 		 * valid range for the stream.
 		 *
 		 * We go through the trouble of dealing with stale mailboxes
@@ -169,44 +195,42 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
 		 * There are occasions when we get a half changed mailbox,
 		 * which this check catches for a handle & id mismatch.  If the
 		 * handle and id do correspond, the worst case is that we
-		 * completely lost the old buffer, but pick up the new buffer
+		 * completely lost the old MDL, but pick up the new MDL
 		 * early (but the new mdl_ack is guaranteed to be good in this
 		 * case as the firmware wouldn't point us to a new mdl_ack until
 		 * it's filled in).
 		 *
-		 * cx18_queue_get buf() will detect the lost buffers
+		 * cx18_queue_get_mdl() will detect the lost MDLs
 		 * and send them back to q_free for fw rotation eventually.
 		 */
 		if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) &&
-		    !(id >= s->mdl_offset &&
-		      id < (s->mdl_offset + s->buffers))) {
+		    !(id >= s->mdl_base_idx &&
+		      id < (s->mdl_base_idx + s->buffers))) {
 			CX18_WARN("Fell behind! Ignoring stale mailbox with "
-				  " inconsistent data. Lost buffer for mailbox "
+				  " inconsistent data. Lost MDL for mailbox "
 				  "seq no %d\n", mb->request);
 			break;
 		}
-		buf = cx18_queue_get_buf(s, id, mdl_ack->data_used);
+		mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used);
 
-		CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
-		if (buf == NULL) {
-			CX18_WARN("Could not find buf %d for stream %s\n",
+		CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id);
+		if (mdl == NULL) {
+			CX18_WARN("Could not find MDL %d for stream %s\n",
 				  id, s->name);
 			continue;
 		}
 
 		CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n",
-				  s->name, buf->bytesused);
+				  s->name, mdl->bytesused);
 
 		if (s->type != CX18_ENC_STREAM_TYPE_TS)
-			cx18_enqueue(s, buf, &s->q_full);
+			cx18_enqueue(s, mdl, &s->q_full);
 		else {
-			if (s->dvb.enabled)
-				dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
-						 buf->bytesused);
-			cx18_enqueue(s, buf, &s->q_free);
+			cx18_mdl_send_to_dvb(s, mdl);
+			cx18_enqueue(s, mdl, &s->q_free);
 		}
 	}
-	/* Put as many buffers as possible back into fw use */
+	/* Put as many MDLs as possible back into fw use */
 	cx18_stream_load_fw_queue(s);
 
 	wake_up(&cx->dma_waitq);
@@ -616,7 +640,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
 
 	/*
 	 * Wait for XPU to perform extra actions for the caller in some cases.
-	 * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all buffers
+	 * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all MDLs
 	 * back in a burst shortly thereafter
 	 */
 	if (info->flags & API_SLOW)
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h
index 522ad534034c..33a3491c4537 100644
--- a/drivers/media/video/cx18/cx18-mailbox.h
+++ b/drivers/media/video/cx18/cx18-mailbox.h
@@ -39,14 +39,14 @@
 struct cx18;
 
 /*
- * This structure is used by CPU to provide completed buffers information
- * Its structure is dictrated by the layout of the SCB, required by the
+ * This structure is used by CPU to provide completed MDL & buffers information.
+ * Its structure is dictated by the layout of the SCB, required by the
  * firmware, but its definition needs to be here, instead of in cx18-scb.h,
  * for mailbox work order scheduling
  */
 struct cx18_mdl_ack {
     u32 id;        /* ID of a completed MDL */
-    u32 data_used; /* Total data filled in the MDL for buffer 'id' */
+    u32 data_used; /* Total data filled in the MDL with 'id' */
 };
 
 /* The cx18_mailbox struct is the mailbox structure which is used for passing
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index fa1ed7897d97..63304823cef5 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -26,6 +26,7 @@
 #include "cx18-queue.h"
 #include "cx18-streams.h"
 #include "cx18-scb.h"
+#include "cx18-io.h"
 
 void cx18_buf_swap(struct cx18_buffer *buf)
 {
@@ -35,151 +36,312 @@ void cx18_buf_swap(struct cx18_buffer *buf)
 		swab32s((u32 *)(buf->buf + i));
 }
 
+void _cx18_mdl_swap(struct cx18_mdl *mdl)
+{
+	struct cx18_buffer *buf;
+
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		if (buf->bytesused == 0)
+			break;
+		cx18_buf_swap(buf);
+	}
+}
+
 void cx18_queue_init(struct cx18_queue *q)
 {
 	INIT_LIST_HEAD(&q->list);
-	atomic_set(&q->buffers, 0);
+	atomic_set(&q->depth, 0);
 	q->bytesused = 0;
 }
 
-struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl,
 				 struct cx18_queue *q, int to_front)
 {
-	/* clear the buffer if it is not to be enqueued to the full queue */
+	/* clear the mdl if it is not to be enqueued to the full queue */
 	if (q != &s->q_full) {
-		buf->bytesused = 0;
-		buf->readpos = 0;
-		buf->b_flags = 0;
-		buf->skipped = 0;
+		mdl->bytesused = 0;
+		mdl->readpos = 0;
+		mdl->m_flags = 0;
+		mdl->skipped = 0;
+		mdl->curr_buf = NULL;
 	}
 
 	/* q_busy is restricted to a max buffer count imposed by firmware */
 	if (q == &s->q_busy &&
-	    atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM)
+	    atomic_read(&q->depth) >= CX18_MAX_FW_MDLS_PER_STREAM)
 		q = &s->q_free;
 
 	spin_lock(&q->lock);
 
 	if (to_front)
-		list_add(&buf->list, &q->list); /* LIFO */
+		list_add(&mdl->list, &q->list); /* LIFO */
 	else
-		list_add_tail(&buf->list, &q->list); /* FIFO */
-	q->bytesused += buf->bytesused - buf->readpos;
-	atomic_inc(&q->buffers);
+		list_add_tail(&mdl->list, &q->list); /* FIFO */
+	q->bytesused += mdl->bytesused - mdl->readpos;
+	atomic_inc(&q->depth);
 
 	spin_unlock(&q->lock);
 	return q;
 }
 
-struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
+struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
 {
-	struct cx18_buffer *buf = NULL;
+	struct cx18_mdl *mdl = NULL;
 
 	spin_lock(&q->lock);
 	if (!list_empty(&q->list)) {
-		buf = list_first_entry(&q->list, struct cx18_buffer, list);
-		list_del_init(&buf->list);
-		q->bytesused -= buf->bytesused - buf->readpos;
-		buf->skipped = 0;
-		atomic_dec(&q->buffers);
+		mdl = list_first_entry(&q->list, struct cx18_mdl, list);
+		list_del_init(&mdl->list);
+		q->bytesused -= mdl->bytesused - mdl->readpos;
+		mdl->skipped = 0;
+		atomic_dec(&q->depth);
 	}
 	spin_unlock(&q->lock);
-	return buf;
+	return mdl;
+}
+
+static void _cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s,
+					  struct cx18_mdl *mdl)
+{
+	struct cx18_buffer *buf;
+	u32 buf_size = s->buf_size;
+	u32 bytesused = mdl->bytesused;
+
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		buf->readpos = 0;
+		if (bytesused >= buf_size) {
+			buf->bytesused = buf_size;
+			bytesused -= buf_size;
+		} else {
+			buf->bytesused = bytesused;
+			bytesused = 0;
+		}
+		cx18_buf_sync_for_cpu(s, buf);
+	}
+}
+
+static inline void cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s,
+						struct cx18_mdl *mdl)
+{
+	struct cx18_buffer *buf;
+
+	if (list_is_singular(&mdl->buf_list)) {
+		buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
+				       list);
+		buf->bytesused = mdl->bytesused;
+		buf->readpos = 0;
+		cx18_buf_sync_for_cpu(s, buf);
+	} else {
+		_cx18_mdl_update_bufs_for_cpu(s, mdl);
+	}
 }
 
-struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
+struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id,
 	u32 bytesused)
 {
 	struct cx18 *cx = s->cx;
-	struct cx18_buffer *buf;
-	struct cx18_buffer *tmp;
-	struct cx18_buffer *ret = NULL;
+	struct cx18_mdl *mdl;
+	struct cx18_mdl *tmp;
+	struct cx18_mdl *ret = NULL;
 	LIST_HEAD(sweep_up);
 
 	/*
 	 * We don't have to acquire multiple q locks here, because we are
 	 * serialized by the single threaded work handler.
-	 * Buffers from the firmware will thus remain in order as
+	 * MDLs from the firmware will thus remain in order as
 	 * they are moved from q_busy to q_full or to the dvb ring buffer.
 	 */
 	spin_lock(&s->q_busy.lock);
-	list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) {
+	list_for_each_entry_safe(mdl, tmp, &s->q_busy.list, list) {
 		/*
 		 * We should find what the firmware told us is done,
 		 * right at the front of the queue.  If we don't, we likely have
-		 * missed a buffer done message from the firmware.
-		 * Once we skip a buffer repeatedly, relative to the size of
+		 * missed an mdl done message from the firmware.
+		 * Once we skip an mdl repeatedly, relative to the size of
 		 * q_busy, we have high confidence we've missed it.
 		 */
-		if (buf->id != id) {
-			buf->skipped++;
-			if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) {
-				/* buffer must have fallen out of rotation */
-				CX18_WARN("Skipped %s, buffer %d, %d "
+		if (mdl->id != id) {
+			mdl->skipped++;
+			if (mdl->skipped >= atomic_read(&s->q_busy.depth)-1) {
+				/* mdl must have fallen out of rotation */
+				CX18_WARN("Skipped %s, MDL %d, %d "
 					  "times - it must have dropped out of "
-					  "rotation\n", s->name, buf->id,
-					  buf->skipped);
+					  "rotation\n", s->name, mdl->id,
+					  mdl->skipped);
 				/* Sweep it up to put it back into rotation */
-				list_move_tail(&buf->list, &sweep_up);
-				atomic_dec(&s->q_busy.buffers);
+				list_move_tail(&mdl->list, &sweep_up);
+				atomic_dec(&s->q_busy.depth);
 			}
 			continue;
 		}
 		/*
-		 * We pull the desired buffer off of the queue here.  Something
+		 * We pull the desired mdl off of the queue here.  Something
 		 * will have to put it back on a queue later.
 		 */
-		list_del_init(&buf->list);
-		atomic_dec(&s->q_busy.buffers);
-		ret = buf;
+		list_del_init(&mdl->list);
+		atomic_dec(&s->q_busy.depth);
+		ret = mdl;
 		break;
 	}
 	spin_unlock(&s->q_busy.lock);
 
 	/*
-	 * We found the buffer for which we were looking.  Get it ready for
+	 * We found the mdl for which we were looking.  Get it ready for
 	 * the caller to put on q_full or in the dvb ring buffer.
 	 */
 	if (ret != NULL) {
 		ret->bytesused = bytesused;
 		ret->skipped = 0;
-		/* readpos and b_flags were 0'ed when the buf went on q_busy */
-		cx18_buf_sync_for_cpu(s, ret);
+		/* 0'ed readpos, m_flags & curr_buf when mdl went on q_busy */
+		cx18_mdl_update_bufs_for_cpu(s, ret);
 		if (s->type != CX18_ENC_STREAM_TYPE_TS)
-			set_bit(CX18_F_B_NEED_BUF_SWAP, &ret->b_flags);
+			set_bit(CX18_F_M_NEED_SWAP, &ret->m_flags);
 	}
 
-	/* Put any buffers the firmware is ignoring back into normal rotation */
-	list_for_each_entry_safe(buf, tmp, &sweep_up, list) {
-		list_del_init(&buf->list);
-		cx18_enqueue(s, buf, &s->q_free);
+	/* Put any mdls the firmware is ignoring back into normal rotation */
+	list_for_each_entry_safe(mdl, tmp, &sweep_up, list) {
+		list_del_init(&mdl->list);
+		cx18_enqueue(s, mdl, &s->q_free);
 	}
 	return ret;
 }
 
-/* Move all buffers of a queue to q_free, while flushing the buffers */
-static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
+/* Move all mdls of a queue, while flushing the mdl */
+static void cx18_queue_flush(struct cx18_stream *s,
+			     struct cx18_queue *q_src, struct cx18_queue *q_dst)
 {
-	struct cx18_buffer *buf;
+	struct cx18_mdl *mdl;
 
-	if (q == &s->q_free)
+	/* It only makes sense to flush to q_free or q_idle */
+	if (q_src == q_dst || q_dst == &s->q_full || q_dst == &s->q_busy)
 		return;
 
-	spin_lock(&q->lock);
-	while (!list_empty(&q->list)) {
-		buf = list_first_entry(&q->list, struct cx18_buffer, list);
-		list_move_tail(&buf->list, &s->q_free.list);
-		buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0;
-		atomic_inc(&s->q_free.buffers);
+	spin_lock(&q_src->lock);
+	spin_lock(&q_dst->lock);
+	while (!list_empty(&q_src->list)) {
+		mdl = list_first_entry(&q_src->list, struct cx18_mdl, list);
+		list_move_tail(&mdl->list, &q_dst->list);
+		mdl->bytesused = 0;
+		mdl->readpos = 0;
+		mdl->m_flags = 0;
+		mdl->skipped = 0;
+		mdl->curr_buf = NULL;
+		atomic_inc(&q_dst->depth);
 	}
-	cx18_queue_init(q);
-	spin_unlock(&q->lock);
+	cx18_queue_init(q_src);
+	spin_unlock(&q_src->lock);
+	spin_unlock(&q_dst->lock);
 }
 
 void cx18_flush_queues(struct cx18_stream *s)
 {
-	cx18_queue_flush(s, &s->q_busy);
-	cx18_queue_flush(s, &s->q_full);
+	cx18_queue_flush(s, &s->q_busy, &s->q_free);
+	cx18_queue_flush(s, &s->q_full, &s->q_free);
+}
+
+/*
+ * Note, s->buf_pool is not protected by a lock,
+ * the stream better not have *anything* going on when calling this
+ */
+void cx18_unload_queues(struct cx18_stream *s)
+{
+	struct cx18_queue *q_idle = &s->q_idle;
+	struct cx18_mdl *mdl;
+	struct cx18_buffer *buf;
+
+	/* Move all MDLS to q_idle */
+	cx18_queue_flush(s, &s->q_busy, q_idle);
+	cx18_queue_flush(s, &s->q_full, q_idle);
+	cx18_queue_flush(s, &s->q_free, q_idle);
+
+	/* Reset MDL id's and move all buffers back to the stream's buf_pool */
+	spin_lock(&q_idle->lock);
+	list_for_each_entry(mdl, &q_idle->list, list) {
+		while (!list_empty(&mdl->buf_list)) {
+			buf = list_first_entry(&mdl->buf_list,
+					       struct cx18_buffer, list);
+			list_move_tail(&buf->list, &s->buf_pool);
+			buf->bytesused = 0;
+			buf->readpos = 0;
+		}
+		mdl->id = s->mdl_base_idx; /* reset id to a "safe" value */
+		/* all other mdl fields were cleared by cx18_queue_flush() */
+	}
+	spin_unlock(&q_idle->lock);
+}
+
+/*
+ * Note, s->buf_pool is not protected by a lock,
+ * the stream better not have *anything* going on when calling this
+ */
+void cx18_load_queues(struct cx18_stream *s)
+{
+	struct cx18 *cx = s->cx;
+	struct cx18_mdl *mdl;
+	struct cx18_buffer *buf;
+	int mdl_id;
+	int i;
+	u32 partial_buf_size;
+
+	/*
+	 * Attach buffers to MDLs, give the MDLs ids, and add MDLs to q_free
+	 * Excess MDLs are left on q_idle
+	 * Excess buffers are left in buf_pool and/or on an MDL in q_idle
+	 */
+	mdl_id = s->mdl_base_idx;
+	for (mdl = cx18_dequeue(s, &s->q_idle), i = s->bufs_per_mdl;
+	     mdl != NULL && i == s->bufs_per_mdl;
+	     mdl = cx18_dequeue(s, &s->q_idle)) {
+
+		mdl->id = mdl_id;
+
+		for (i = 0; i < s->bufs_per_mdl; i++) {
+			if (list_empty(&s->buf_pool))
+				break;
+
+			buf = list_first_entry(&s->buf_pool, struct cx18_buffer,
+					       list);
+			list_move_tail(&buf->list, &mdl->buf_list);
+
+			/* update the firmware's MDL array with this buffer */
+			cx18_writel(cx, buf->dma_handle,
+				    &cx->scb->cpu_mdl[mdl_id + i].paddr);
+			cx18_writel(cx, s->buf_size,
+				    &cx->scb->cpu_mdl[mdl_id + i].length);
+		}
+
+		if (i == s->bufs_per_mdl) {
+			/*
+			 * The encoder doesn't honor s->mdl_size.  So in the
+			 * case of a non-integral number of buffers to meet
+			 * mdl_size, we lie about the size of the last buffer
+			 * in the MDL to get the encoder to really only send
+			 * us mdl_size bytes per MDL transfer.
+			 */
+			partial_buf_size = s->mdl_size % s->buf_size;
+			if (partial_buf_size) {
+				cx18_writel(cx, partial_buf_size,
+				      &cx->scb->cpu_mdl[mdl_id + i - 1].length);
+			}
+			cx18_enqueue(s, mdl, &s->q_free);
+		} else {
+			/* Not enough buffers for this MDL; we won't use it */
+			cx18_push(s, mdl, &s->q_idle);
+		}
+		mdl_id += i;
+	}
+}
+
+void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl)
+{
+	int dma = s->dma;
+	u32 buf_size = s->buf_size;
+	struct pci_dev *pci_dev = s->cx->pci_dev;
+	struct cx18_buffer *buf;
+
+	list_for_each_entry(buf, &mdl->buf_list, list)
+		pci_dma_sync_single_for_device(pci_dev, buf->dma_handle,
+					       buf_size, dma);
 }
 
 int cx18_stream_alloc(struct cx18_stream *s)
@@ -190,44 +352,62 @@ int cx18_stream_alloc(struct cx18_stream *s)
 	if (s->buffers == 0)
 		return 0;
 
-	CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n",
+	CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers "
+			"(%d.%02d kB total)\n",
 		s->name, s->buffers, s->buf_size,
-		s->buffers * s->buf_size / 1024);
+		s->buffers * s->buf_size / 1024,
+		(s->buffers * s->buf_size * 100 / 1024) % 100);
 
-	if (((char __iomem *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
+	if (((char __iomem *)&cx->scb->cpu_mdl[cx->free_mdl_idx + s->buffers] -
 				(char __iomem *)cx->scb) > SCB_RESERVED_SIZE) {
 		unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE -
 					((char __iomem *)cx->scb->cpu_mdl));
 
 		CX18_ERR("Too many buffers, cannot fit in SCB area\n");
 		CX18_ERR("Max buffers = %zd\n",
-			bufsz / sizeof(struct cx18_mdl));
+			bufsz / sizeof(struct cx18_mdl_ent));
 		return -ENOMEM;
 	}
 
-	s->mdl_offset = cx->mdl_offset;
+	s->mdl_base_idx = cx->free_mdl_idx;
 
-	/* allocate stream buffers. Initially all buffers are in q_free. */
+	/* allocate stream buffers and MDLs */
 	for (i = 0; i < s->buffers; i++) {
-		struct cx18_buffer *buf = kzalloc(sizeof(struct cx18_buffer),
-						GFP_KERNEL|__GFP_NOWARN);
+		struct cx18_mdl *mdl;
+		struct cx18_buffer *buf;
 
-		if (buf == NULL)
+		/* 1 MDL per buffer to handle the worst & also default case */
+		mdl = kzalloc(sizeof(struct cx18_mdl), GFP_KERNEL|__GFP_NOWARN);
+		if (mdl == NULL)
 			break;
+
+		buf = kzalloc(sizeof(struct cx18_buffer),
+				GFP_KERNEL|__GFP_NOWARN);
+		if (buf == NULL) {
+			kfree(mdl);
+			break;
+		}
+
 		buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN);
 		if (buf->buf == NULL) {
+			kfree(mdl);
 			kfree(buf);
 			break;
 		}
-		buf->id = cx->buffer_id++;
+
+		INIT_LIST_HEAD(&mdl->list);
+		INIT_LIST_HEAD(&mdl->buf_list);
+		mdl->id = s->mdl_base_idx; /* a somewhat safe value */
+		cx18_enqueue(s, mdl, &s->q_idle);
+
 		INIT_LIST_HEAD(&buf->list);
 		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);
+		list_add_tail(&buf->list, &s->buf_pool);
 	}
 	if (i == s->buffers) {
-		cx->mdl_offset += s->buffers;
+		cx->free_mdl_idx += s->buffers;
 		return 0;
 	}
 	CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name);
@@ -237,13 +417,21 @@ int cx18_stream_alloc(struct cx18_stream *s)
 
 void cx18_stream_free(struct cx18_stream *s)
 {
+	struct cx18_mdl *mdl;
 	struct cx18_buffer *buf;
 
-	/* move all buffers to q_free */
-	cx18_flush_queues(s);
+	/* move all buffers to buf_pool and all MDLs to q_idle */
+	cx18_unload_queues(s);
+
+	/* empty q_idle */
+	while ((mdl = cx18_dequeue(s, &s->q_idle)))
+		kfree(mdl);
+
+	/* empty buf_pool */
+	while (!list_empty(&s->buf_pool)) {
+		buf = list_first_entry(&s->buf_pool, struct cx18_buffer, list);
+		list_del_init(&buf->list);
 
-	/* empty q_free */
-	while ((buf = cx18_dequeue(s, &s->q_free))) {
 		pci_unmap_single(s->cx->pci_dev, buf->dma_handle,
 				s->buf_size, s->dma);
 		kfree(buf->buf);
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
index 4de06269d88f..88a6d34ad3bb 100644
--- a/drivers/media/video/cx18/cx18-queue.h
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -40,32 +40,59 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
 				s->buf_size, s->dma);
 }
 
+void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl);
+
+static inline void cx18_mdl_sync_for_device(struct cx18_stream *s,
+					    struct cx18_mdl *mdl)
+{
+	if (list_is_singular(&mdl->buf_list))
+		cx18_buf_sync_for_device(s, list_first_entry(&mdl->buf_list,
+							     struct cx18_buffer,
+							     list));
+	else
+		_cx18_mdl_sync_for_device(s, mdl);
+}
+
 void cx18_buf_swap(struct cx18_buffer *buf);
+void _cx18_mdl_swap(struct cx18_mdl *mdl);
+
+static inline void cx18_mdl_swap(struct cx18_mdl *mdl)
+{
+	if (list_is_singular(&mdl->buf_list))
+		cx18_buf_swap(list_first_entry(&mdl->buf_list,
+					       struct cx18_buffer, list));
+	else
+		_cx18_mdl_swap(mdl);
+}
 
 /* cx18_queue utility functions */
-struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl,
 				 struct cx18_queue *q, int to_front);
 
 static inline
-struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl,
 				struct cx18_queue *q)
 {
-	return _cx18_enqueue(s, buf, q, 0); /* FIFO */
+	return _cx18_enqueue(s, mdl, q, 0); /* FIFO */
 }
 
 static inline
-struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_buffer *buf,
+struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_mdl *mdl,
 			     struct cx18_queue *q)
 {
-	return _cx18_enqueue(s, buf, q, 1); /* LIFO */
+	return _cx18_enqueue(s, mdl, q, 1); /* LIFO */
 }
 
 void cx18_queue_init(struct cx18_queue *q);
-struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
-struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
+struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
+struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id,
 	u32 bytesused);
 void cx18_flush_queues(struct cx18_stream *s);
 
+/* queue MDL reconfiguration helpers */
+void cx18_unload_queues(struct cx18_stream *s);
+void cx18_load_queues(struct cx18_stream *s);
+
 /* cx18_stream utility functions */
 int cx18_stream_alloc(struct cx18_stream *s);
 void cx18_stream_free(struct cx18_stream *s);
diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h
index 1dc1c431f5a1..368f23d08709 100644
--- a/drivers/media/video/cx18/cx18-scb.h
+++ b/drivers/media/video/cx18/cx18-scb.h
@@ -81,7 +81,7 @@
 
 
 /* This structure is used by EPU to provide memory descriptors in its memory */
-struct cx18_mdl {
+struct cx18_mdl_ent {
     u32 paddr;  /* Physical address of a buffer segment */
     u32 length; /* Length of the buffer segment */
 };
@@ -272,7 +272,7 @@ struct cx18_scb {
 	struct cx18_mailbox  ppu2epu_mb;
 
 	struct cx18_mdl_ack  cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS];
-	struct cx18_mdl      cpu_mdl[1];
+	struct cx18_mdl_ent  cpu_mdl[1];
 };
 
 void cx18_init_scb(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 7df513a2dba8..c398651dd74c 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -115,6 +115,9 @@ static void cx18_stream_init(struct cx18 *cx, int type)
 	s->dma = cx18_stream_info[type].dma;
 	s->buffers = cx->stream_buffers[type];
 	s->buf_size = cx->stream_buf_size[type];
+	INIT_LIST_HEAD(&s->buf_pool);
+	s->bufs_per_mdl = 1;
+	s->mdl_size = s->buf_size * s->bufs_per_mdl;
 
 	init_waitqueue_head(&s->waitq);
 	s->id = -1;
@@ -124,6 +127,8 @@ static void cx18_stream_init(struct cx18 *cx, int type)
 	cx18_queue_init(&s->q_busy);
 	spin_lock_init(&s->q_full.lock);
 	cx18_queue_init(&s->q_full);
+	spin_lock_init(&s->q_idle.lock);
+	cx18_queue_init(&s->q_idle);
 
 	INIT_WORK(&s->out_work_order, cx18_out_work_handler);
 }
@@ -257,9 +262,11 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
 
 	switch (vfl_type) {
 	case VFL_TYPE_GRABBER:
-		CX18_INFO("Registered device video%d for %s (%d x %d kB)\n",
+		CX18_INFO("Registered device video%d for %s "
+			  "(%d x %d.%02d kB)\n",
 			  num, s->name, cx->stream_buffers[type],
-			  cx->stream_buf_size[type]/1024);
+			  cx->stream_buf_size[type] / 1024,
+			  (cx->stream_buf_size[type] * 100 / 1024) % 100);
 		break;
 
 	case VFL_TYPE_RADIO:
@@ -441,8 +448,8 @@ static void cx18_vbi_setup(struct cx18_stream *s)
 }
 
 static
-struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s,
-					   struct cx18_buffer *buf)
+struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s,
+					   struct cx18_mdl *mdl)
 {
 	struct cx18 *cx = s->cx;
 	struct cx18_queue *q;
@@ -451,16 +458,16 @@ struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s,
 	if (s->handle == CX18_INVALID_TASK_HANDLE ||
 	    test_bit(CX18_F_S_STOPPING, &s->s_flags) ||
 	    !test_bit(CX18_F_S_STREAMING, &s->s_flags))
-		return cx18_enqueue(s, buf, &s->q_free);
+		return cx18_enqueue(s, mdl, &s->q_free);
 
-	q = cx18_enqueue(s, buf, &s->q_busy);
+	q = cx18_enqueue(s, mdl, &s->q_busy);
 	if (q != &s->q_busy)
-		return q; /* The firmware has the max buffers it can handle */
+		return q; /* The firmware has the max MDLs it can handle */
 
-	cx18_buf_sync_for_device(s, buf);
+	cx18_mdl_sync_for_device(s, mdl);
 	cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
-		  (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
-		  1, buf->id, s->buf_size);
+		  (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem,
+		  s->bufs_per_mdl, mdl->id, s->mdl_size);
 	return q;
 }
 
@@ -468,19 +475,19 @@ static
 void _cx18_stream_load_fw_queue(struct cx18_stream *s)
 {
 	struct cx18_queue *q;
-	struct cx18_buffer *buf;
+	struct cx18_mdl *mdl;
 
-	if (atomic_read(&s->q_free.buffers) == 0 ||
-	    atomic_read(&s->q_busy.buffers) >= CX18_MAX_FW_MDLS_PER_STREAM)
+	if (atomic_read(&s->q_free.depth) == 0 ||
+	    atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM)
 		return;
 
 	/* Move from q_free to q_busy notifying the firmware, until the limit */
 	do {
-		buf = cx18_dequeue(s, &s->q_free);
-		if (buf == NULL)
+		mdl = cx18_dequeue(s, &s->q_free);
+		if (mdl == NULL)
 			break;
-		q = _cx18_stream_put_buf_fw(s, buf);
-	} while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM
+		q = _cx18_stream_put_mdl_fw(s, mdl);
+	} while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM
 		 && q == &s->q_busy);
 }
 
@@ -492,11 +499,51 @@ void cx18_out_work_handler(struct work_struct *work)
 	_cx18_stream_load_fw_queue(s);
 }
 
+static void cx18_stream_configure_mdls(struct cx18_stream *s)
+{
+	cx18_unload_queues(s);
+
+	switch (s->type) {
+	case CX18_ENC_STREAM_TYPE_YUV:
+		/*
+		 * Height should be a multiple of 32 lines.
+		 * Set the MDL size to the exact size needed for one frame.
+		 * Use enough buffers per MDL to cover the MDL size
+		 */
+		s->mdl_size = 720 * s->cx->params.height * 3 / 2;
+		s->bufs_per_mdl = s->mdl_size / s->buf_size;
+		if (s->mdl_size % s->buf_size)
+			s->bufs_per_mdl++;
+		break;
+	case CX18_ENC_STREAM_TYPE_VBI:
+		s->bufs_per_mdl = 1;
+		if  (cx18_raw_vbi(s->cx)) {
+			s->mdl_size = (s->cx->is_60hz ? 12 : 18)
+						       * 2 * vbi_active_samples;
+		} else {
+			/*
+			 * See comment in cx18_vbi_setup() below about the
+			 * extra lines we capture in sliced VBI mode due to
+			 * the lines on which EAV RP codes toggle.
+			*/
+			s->mdl_size = s->cx->is_60hz
+				   ? (21 - 4 + 1) * 2 * vbi_hblank_samples_60Hz
+				   : (23 - 2 + 1) * 2 * vbi_hblank_samples_50Hz;
+		}
+		break;
+	default:
+		s->bufs_per_mdl = 1;
+		s->mdl_size = s->buf_size * s->bufs_per_mdl;
+		break;
+	}
+
+	cx18_load_queues(s);
+}
+
 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 captype = 0;
 	struct cx18_api_func_private priv;
 
@@ -619,14 +666,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 		(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
 
 	/* Init all the cpu_mdls for this stream */
-	cx18_flush_queues(s);
-	spin_lock(&s->q_free.lock);
-	list_for_each_entry(buf, &s->q_free.list, list) {
-		cx18_writel(cx, buf->dma_handle,
-					&cx->scb->cpu_mdl[buf->id].paddr);
-		cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
-	}
-	spin_unlock(&s->q_free.lock);
+	cx18_stream_configure_mdls(s);
 	_cx18_stream_load_fw_queue(s);
 
 	/* begin_capture */
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
index 1afc3fd9d822..4a01db5e5a35 100644
--- a/drivers/media/video/cx18/cx18-streams.h
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -28,18 +28,18 @@ int cx18_streams_setup(struct cx18 *cx);
 int cx18_streams_register(struct cx18 *cx);
 void cx18_streams_cleanup(struct cx18 *cx, int unregister);
 
-/* Related to submission of buffers to firmware */
+/* Related to submission of mdls to firmware */
 static inline void cx18_stream_load_fw_queue(struct cx18_stream *s)
 {
 	struct cx18 *cx = s->cx;
 	queue_work(cx->out_work_queue, &s->out_work_order);
 }
 
-static inline void cx18_stream_put_buf_fw(struct cx18_stream *s,
-					  struct cx18_buffer *buf)
+static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s,
+					  struct cx18_mdl *mdl)
 {
-	/* Put buf on q_free; the out work handler will move buf(s) to q_busy */
-	cx18_enqueue(s, buf, &s->q_free);
+	/* Put mdl on q_free; the out work handler will move mdl(s) to q_busy */
+	cx18_enqueue(s, mdl, &s->q_free);
 	cx18_stream_load_fw_queue(s);
 }
 
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c
index c2aef4add31d..574c1c6974f8 100644
--- a/drivers/media/video/cx18/cx18-vbi.c
+++ b/drivers/media/video/cx18/cx18-vbi.c
@@ -105,6 +105,7 @@ 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 frame.  Returns new compressed size. */
+/* FIXME - this function ignores the input size. */
 static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size)
 {
 	u32 line_size = vbi_active_samples;
@@ -185,8 +186,7 @@ static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size,
 	return line;
 }
 
-void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
-			   int streamtype)
+static void _cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf)
 {
 	/*
 	 * The CX23418 provides a 12 byte header in its raw VBI buffers to us:
@@ -203,9 +203,6 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
 	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
@@ -250,3 +247,31 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
 		copy_vbi_data(cx, lines, pts);
 	cx->vbi.frame++;
 }
+
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl,
+			   int streamtype)
+{
+	struct cx18_buffer *buf;
+	u32 orig_used;
+
+	if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
+		return;
+
+	/*
+	 * Big assumption here:
+	 * Every buffer hooked to the MDL's buf_list is a complete VBI frame
+	 * that ends at the end of the buffer.
+	 *
+	 * To assume anything else would make the code in this file
+	 * more complex, or require extra memcpy()'s to make the
+	 * buffers satisfy the above assumption.  It's just simpler to set
+	 * up the encoder buffer transfers to make the assumption true.
+	 */
+	list_for_each_entry(buf, &mdl->buf_list, list) {
+		orig_used = buf->bytesused;
+		if (orig_used == 0)
+			break;
+		_cx18_process_vbi_data(cx, buf);
+		mdl->bytesused -= (orig_used - buf->bytesused);
+	}
+}
diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h
index e7e1ae427f34..b365cf4b4668 100644
--- a/drivers/media/video/cx18/cx18-vbi.h
+++ b/drivers/media/video/cx18/cx18-vbi.h
@@ -21,6 +21,6 @@
  *  02111-1307  USA
  */
 
-void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl,
 			   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 45494b094e7f..9c0b5bb1b019 100644
--- a/drivers/media/video/cx18/cx18-version.h
+++ b/drivers/media/video/cx18/cx18-version.h
@@ -24,7 +24,7 @@
 
 #define CX18_DRIVER_NAME "cx18"
 #define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 2
+#define CX18_DRIVER_VERSION_MINOR 3
 #define CX18_DRIVER_VERSION_PATCHLEVEL 0
 
 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 9956abf576c5..868806effdcf 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -363,7 +363,7 @@
 /* Description: This command provides the offset to a Memory Descriptor List
    IN[0] - Task handle. Handle of the task to start
    IN[1] - Offset of the MDL from the beginning of the local DDR.
-   IN[2] - Number of cx18_mdl structures in the array pointed to by IN[1]
+   IN[2] - Number of cx18_mdl_ent structures in the array pointed to by IN[1]
    IN[3] - Buffer ID
    IN[4] - Total buffer length
    ReturnCode - One of the ERR_DE_... */
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
index 48f22fa38e6c..cd135f01b9c1 100644
--- a/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/drivers/media/video/cx231xx/cx231xx-input.c
@@ -126,8 +126,7 @@ static void cx231xx_ir_handle_key(struct cx231xx_IR *ir)
 
 	if (do_sendkey) {
 		dprintk("sending keypress\n");
-		ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0],
-				 poll_result.rc_data[0]);
+		ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0]);
 		ir_input_nokey(ir->input, &ir->ir);
 	}
 
@@ -198,7 +197,11 @@ int cx231xx_ir_init(struct cx231xx *dev)
 	usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
 	strlcat(ir->phys, "/input0", sizeof(ir->phys));
 
-	ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->board.ir_codes);
+	err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER,
+			    dev->board.ir_codes);
+	if (err < 0)
+		goto err_out_free;
+
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
 	input_dev->id.bustype = BUS_USB;
@@ -223,6 +226,7 @@ err_out_stop:
 	cx231xx_ir_stop(ir);
 	dev->ir = NULL;
 err_out_free:
+	ir_input_free(input_dev);
 	input_free_device(input_dev);
 	kfree(ir);
 	return err;
@@ -237,6 +241,7 @@ int cx231xx_ir_fini(struct cx231xx *dev)
 		return 0;
 
 	cx231xx_ir_stop(ir);
+	ir_input_free(ir->input);
 	input_unregister_device(ir->input);
 	kfree(ir);
 
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 36503725d973..d095aa0d6d19 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -2106,7 +2106,7 @@ static int cx231xx_v4l2_close(struct file *filp)
 		}
 
 		/* Save some power by putting tuner to sleep */
-		call_all(dev, tuner, s_standby);
+		call_all(dev, core, s_power, 0);
 
 		/* do this before setting alternate! */
 		cx231xx_uninit_isoc(dev);
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index fd3fc3e3198a..bcdda9a9aa96 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -18,7 +18,9 @@ config VIDEO_CX23885
 	select DVB_TDA10048 if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	select DVB_STV6110 if !DVB_FE_CUSTOMISE
+	select DVB_CX24116 if !DVB_FE_CUSTOMISE
 	select DVB_STV0900 if !DVB_FE_CUSTOMISE
+	select DVB_DS3000 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
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
index ab8ea35c9bfb..5787ae243631 100644
--- a/drivers/media/video/cx23885/Makefile
+++ b/drivers/media/video/cx23885/Makefile
@@ -1,6 +1,7 @@
 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
+		    cx23885-ioctl.o cx23885-ir.o cx23885-input.o cx23888-ir.o \
+		    netup-init.o cimax2.o netup-eeprom.o cx23885-f300.o
 
 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
 
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index 6c3b51ce3372..0eed852c61e9 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -37,6 +37,7 @@
 #include <media/cx2341x.h>
 
 #include "cx23885.h"
+#include "cx23885-ioctl.h"
 
 #define CX23885_FIRM_IMAGE_SIZE 376836
 #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
@@ -318,7 +319,7 @@ static int mc417_wait_ready(struct cx23885_dev *dev)
 	}
 }
 
-static int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
+int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
 {
 	u32 regval;
 
@@ -382,7 +383,7 @@ static int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
 	return mc417_wait_ready(dev);
 }
 
-static int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
+int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
 {
 	int retval;
 	u32 regval;
@@ -1724,6 +1725,11 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
 	.vidioc_log_status	 = vidioc_log_status,
 	.vidioc_querymenu	 = vidioc_querymenu,
 	.vidioc_queryctrl	 = vidioc_queryctrl,
+	.vidioc_g_chip_ident	 = cx23885_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register	 = cx23885_g_register,
+	.vidioc_s_register	 = cx23885_s_register,
+#endif
 };
 
 static struct video_device cx23885_mpeg_template = {
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index bfdf79f1033c..1ec48169277d 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -28,6 +28,7 @@
 #include "cx23885.h"
 #include "tuner-xc2028.h"
 #include "netup-init.h"
+#include "cx23888-ir.h"
 
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
@@ -199,11 +200,61 @@ struct cx23885_board cx23885_boards[] = {
 	},
 	[CX23885_BOARD_MYGICA_X8506] = {
 		.name		= "Mygica X8506 DMB-TH",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.porta		= CX23885_ANALOG_VIDEO,
 		.portb		= CX23885_MPEG_DVB,
+		.input		= {
+			{
+				.type   = CX23885_VMUX_TELEVISION,
+				.vmux   = CX25840_COMPOSITE2,
+			},
+			{
+				.type   = CX23885_VMUX_COMPOSITE1,
+				.vmux   = CX25840_COMPOSITE8,
+			},
+			{
+				.type   = CX23885_VMUX_SVIDEO,
+				.vmux   = CX25840_SVIDEO_LUMA3 |
+						CX25840_SVIDEO_CHROMA4,
+			},
+			{
+				.type   = CX23885_VMUX_COMPONENT,
+				.vmux   = CX25840_COMPONENT_ON |
+					CX25840_VIN1_CH1 |
+					CX25840_VIN6_CH2 |
+					CX25840_VIN7_CH3,
+			},
+		},
 	},
 	[CX23885_BOARD_MAGICPRO_PROHDTVE2] = {
 		.name		= "Magic-Pro ProHDTV Extreme 2",
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
+		.porta		= CX23885_ANALOG_VIDEO,
 		.portb		= CX23885_MPEG_DVB,
+		.input		= {
+			{
+				.type   = CX23885_VMUX_TELEVISION,
+				.vmux   = CX25840_COMPOSITE2,
+			},
+			{
+				.type   = CX23885_VMUX_COMPOSITE1,
+				.vmux   = CX25840_COMPOSITE8,
+			},
+			{
+				.type   = CX23885_VMUX_SVIDEO,
+				.vmux   = CX25840_SVIDEO_LUMA3 |
+						CX25840_SVIDEO_CHROMA4,
+			},
+			{
+				.type   = CX23885_VMUX_COMPONENT,
+				.vmux   = CX25840_COMPONENT_ON |
+					CX25840_VIN1_CH1 |
+					CX25840_VIN6_CH2 |
+					CX25840_VIN7_CH3,
+			},
+		},
 	},
 	[CX23885_BOARD_HAUPPAUGE_HVR1850] = {
 		.name		= "Hauppauge WinTV-HVR1850",
@@ -214,6 +265,15 @@ struct cx23885_board cx23885_boards[] = {
 		.name		= "Compro VideoMate E800",
 		.portc		= CX23885_MPEG_DVB,
 	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1290] = {
+		.name		= "Hauppauge WinTV-HVR1290",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_MYGICA_X8558PRO] = {
+		.name		= "Mygica X8558 PRO DMB-TH",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+	},
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -349,6 +409,14 @@ struct cx23885_subid cx23885_subids[] = {
 		.subvendor = 0x1858,
 		.subdevice = 0xe800,
 		.card      = CX23885_BOARD_COMPRO_VIDEOMATE_E800,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8551,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1290,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8578,
+		.card      = CX23885_BOARD_MYGICA_X8558PRO,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -509,9 +577,13 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
 		 * DVB-T and MPEG2 HW Encoder */
 		break;
 	case 85021:
-		/* WinTV-HVR1850 (PCIe, OEM, RCA in, IR, FM,
+		/* WinTV-HVR1850 (PCIe, Retail, 3.5mm in, IR, FM,
 			Dual channel ATSC and MPEG2 HW Encoder */
 		break;
+	case 85721:
+		/* WinTV-HVR1290 (PCIe, OEM, RCA in, IR,
+			Dual channel ATSC and Basic analog */
+		break;
 	default:
 		printk(KERN_WARNING "%s: warning: "
 			"unknown hauppauge model #%d\n",
@@ -710,10 +782,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
 		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);
+		cx_set(MC417_RWD, 0x00000002);
+		mdelay(200);
+		cx_clear(MC417_RWD, 0x00000800);
+		mdelay(200);
+		cx_set(MC417_RWD, 0x00000800);
+		mdelay(200);
 		break;
 	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
 		/* GPIO-0 INTA from CiMax1
@@ -758,15 +834,26 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
 		break;
 	case CX23885_BOARD_MYGICA_X8506:
 	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+		/* GPIO-0 (0)Analog / (1)Digital TV */
 		/* GPIO-1 reset XC5000 */
 		/* GPIO-2 reset LGS8GL5 / LGS8G75 */
-		cx_set(GP0_IO, 0x00060000);
-		cx_clear(GP0_IO, 0x00000006);
+		cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1);
+		cx23885_gpio_clear(dev, GPIO_1 | GPIO_2);
 		mdelay(100);
-		cx_set(GP0_IO, 0x00060006);
+		cx23885_gpio_set(dev, GPIO_0 | GPIO_1 | GPIO_2);
+		mdelay(100);
+		break;
+	case CX23885_BOARD_MYGICA_X8558PRO:
+		/* GPIO-0 reset first ATBM8830 */
+		/* GPIO-1 reset second ATBM8830 */
+		cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1);
+		cx23885_gpio_clear(dev, GPIO_0 | GPIO_1);
+		mdelay(100);
+		cx23885_gpio_set(dev, GPIO_0 | GPIO_1);
 		mdelay(100);
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 		/* GPIO-0 656_CLK */
 		/* GPIO-1 656_D0 */
 		/* GPIO-2 Wake# */
@@ -801,6 +888,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
 
 int cx23885_ir_init(struct cx23885_dev *dev)
 {
+	int ret = 0;
 	switch (dev->board) {
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
@@ -812,15 +900,46 @@ int cx23885_ir_init(struct cx23885_dev *dev)
 	case CX23885_BOARD_HAUPPAUGE_HVR1275:
 	case CX23885_BOARD_HAUPPAUGE_HVR1255:
 	case CX23885_BOARD_HAUPPAUGE_HVR1210:
-	case CX23885_BOARD_HAUPPAUGE_HVR1850:
 		/* FIXME: Implement me */
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		ret = cx23888_ir_probe(dev);
+		if (ret)
+			break;
+		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
+		dev->pci_irqmask |= PCI_MSK_IR;
+		break;
 	case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
 		request_module("ir-kbd-i2c");
 		break;
 	}
 
-	return 0;
+	return ret;
+}
+
+void cx23885_ir_fini(struct cx23885_dev *dev)
+{
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		dev->pci_irqmask &= ~PCI_MSK_IR;
+		cx_clear(PCI_INT_MSK, PCI_MSK_IR);
+		cx23888_ir_remove(dev);
+		dev->sd_ir = NULL;
+		break;
+	}
+}
+
+void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
+{
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_IR))
+			cx_set(PCI_INT_MSK, PCI_MSK_IR);
+		break;
+	}
 }
 
 void cx23885_card_setup(struct cx23885_dev *dev)
@@ -853,6 +972,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 	case CX23885_BOARD_HAUPPAUGE_HVR1255:
 	case CX23885_BOARD_HAUPPAUGE_HVR1210:
 	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 		if (dev->i2c_bus[0].i2c_rc == 0)
 			hauppauge_eeprom(dev, eeprom+0xc0);
 		break;
@@ -886,8 +1006,12 @@ 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:
+		ts1->gen_ctrl_val  = 0x4; /* Parallel */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
+	case CX23885_BOARD_TEVII_S470:
 	case CX23885_BOARD_DVBWORLD_2005:
 		ts1->gen_ctrl_val  = 0x5; /* Parallel */
 		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -907,6 +1031,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
+	case CX23885_BOARD_MYGICA_X8558PRO:
+		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;
+		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:
@@ -922,6 +1054,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 	case CX23885_BOARD_HAUPPAUGE_HVR1210:
 	case CX23885_BOARD_HAUPPAUGE_HVR1850:
 	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 	default:
 		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -939,6 +1072,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 	case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
 	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
 	case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_MYGICA_X8506:
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
 				&dev->i2c_bus[2].i2c_adap,
 				"cx25840", "cx25840", 0x88 >> 1, NULL);
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index fa2d350e20fd..04b12d27bc13 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -32,6 +32,9 @@
 
 #include "cx23885.h"
 #include "cimax2.h"
+#include "cx23888-ir.h"
+#include "cx23885-ir.h"
+#include "cx23885-input.h"
 
 MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -753,6 +756,23 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
 			__func__, dev->hwrevision);
 }
 
+/* Find the first v4l2_subdev member of the group id in hw */
+struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw)
+{
+	struct v4l2_subdev *result = NULL;
+	struct v4l2_subdev *sd;
+
+	spin_lock(&dev->v4l2_dev.lock);
+	v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) {
+		if (sd->grp_id == hw) {
+			result = sd;
+			break;
+		}
+	}
+	spin_unlock(&dev->v4l2_dev.lock);
+	return result;
+}
+
 static int cx23885_dev_setup(struct cx23885_dev *dev)
 {
 	int i;
@@ -899,7 +919,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);
-	call_all(dev, tuner, s_standby);
+	call_all(dev, core, s_power, 0);
 	cx23885_ir_init(dev);
 
 	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
@@ -1637,6 +1657,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
 	u32 ts1_status, ts1_mask;
 	u32 ts2_status, ts2_mask;
 	int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
+	bool ir_handled = false;
 
 	pci_status = cx_read(PCI_INT_STAT);
 	pci_mask = cx_read(PCI_INT_MSK);
@@ -1662,18 +1683,12 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
 	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
 		ts2_status, ts2_mask, ts2_count);
 
-	if ((pci_status & PCI_MSK_RISC_RD) ||
-	    (pci_status & PCI_MSK_RISC_WR) ||
-	    (pci_status & PCI_MSK_AL_RD) ||
-	    (pci_status & PCI_MSK_AL_WR) ||
-	    (pci_status & PCI_MSK_APB_DMA) ||
-	    (pci_status & PCI_MSK_VID_C) ||
-	    (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_GPIO0) ||
-	    (pci_status & PCI_MSK_GPIO1)) {
+	if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR |
+			  PCI_MSK_AL_RD   | PCI_MSK_AL_WR   | PCI_MSK_APB_DMA |
+			  PCI_MSK_VID_C   | PCI_MSK_VID_B   | PCI_MSK_VID_A   |
+			  PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
+			  PCI_MSK_GPIO0   | PCI_MSK_GPIO1   |
+			  PCI_MSK_IR)) {
 
 		if (pci_status & PCI_MSK_RISC_RD)
 			dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n",
@@ -1722,6 +1737,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
 		if (pci_status & PCI_MSK_GPIO1)
 			dprintk(7, " (PCI_MSK_GPIO1     0x%08x)\n",
 				PCI_MSK_GPIO1);
+
+		if (pci_status & PCI_MSK_IR)
+			dprintk(7, " (PCI_MSK_IR        0x%08x)\n",
+				PCI_MSK_IR);
 	}
 
 	if (cx23885_boards[dev->board].cimax > 0 &&
@@ -1752,12 +1771,48 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
 	if (vida_status)
 		handled += cx23885_video_irq(dev, vida_status);
 
+	if (pci_status & PCI_MSK_IR) {
+		v4l2_subdev_call(dev->sd_ir, ir, interrupt_service_routine,
+				 pci_status, &ir_handled);
+		if (ir_handled)
+			handled++;
+	}
+
 	if (handled)
 		cx_write(PCI_INT_STAT, pci_status);
 out:
 	return IRQ_RETVAL(handled);
 }
 
+static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,
+				    unsigned int notification, void *arg)
+{
+	struct cx23885_dev *dev;
+
+	if (sd == NULL)
+		return;
+
+	dev = to_cx23885(sd->v4l2_dev);
+
+	switch (notification) {
+	case V4L2_SUBDEV_IR_RX_NOTIFY: /* Called in an IRQ context */
+		if (sd == dev->sd_ir)
+			cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg);
+		break;
+	case V4L2_SUBDEV_IR_TX_NOTIFY: /* Called in an IRQ context */
+		if (sd == dev->sd_ir)
+			cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg);
+		break;
+	}
+}
+
+static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev)
+{
+	INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler);
+	INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler);
+	dev->v4l2_dev.notify = cx23885_v4l2_dev_notify;
+}
+
 static inline int encoder_on_portb(struct cx23885_dev *dev)
 {
 	return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER;
@@ -1816,6 +1871,26 @@ void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask)
 		printk(KERN_INFO "%s: Unsupported\n", dev->name);
 }
 
+u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask)
+{
+	if (mask & 0x00000007)
+		return (cx_read(GP0_IO) >> 8) & mask & 0x7;
+
+	if (mask & 0x0007fff8) {
+		if (encoder_on_portb(dev) || encoder_on_portc(dev))
+			printk(KERN_ERR
+				"%s: Reading GPIO moving on encoder ports\n",
+				dev->name);
+		return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3;
+	}
+
+	/* TODO: 23-19 */
+	if (mask & 0x00f80000)
+		printk(KERN_INFO "%s: Unsupported\n", dev->name);
+
+	return 0;
+}
+
 void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
 {
 	if ((mask & 0x00000007) && asoutput)
@@ -1854,6 +1929,9 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
 	if (err < 0)
 		goto fail_free;
 
+	/* Prepare to handle notifications from subdevices */
+	cx23885_v4l2_dev_notify_init(dev);
+
 	/* pci init */
 	dev->pci = pci_dev;
 	if (pci_enable_device(pci_dev)) {
@@ -1896,6 +1974,14 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
 		break;
 	}
 
+	/*
+	 * The CX2388[58] IR controller can start firing interrupts when
+	 * enabled, so these have to take place after the cx23885_irq() handler
+	 * is hooked up by the call to request_irq() above.
+	 */
+	cx23885_ir_pci_int_enable(dev);
+	cx23885_input_init(dev);
+
 	return 0;
 
 fail_irq:
@@ -1912,6 +1998,9 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
 	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
 	struct cx23885_dev *dev = to_cx23885(v4l2_dev);
 
+	cx23885_input_fini(dev);
+	cx23885_ir_fini(dev);
+
 	cx23885_shutdown(dev);
 
 	pci_disable_device(pci_dev);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 16c6a921f40b..e45d2df08138 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -38,6 +38,7 @@
 #include "tda18271.h"
 #include "lgdt330x.h"
 #include "xc5000.h"
+#include "max2165.h"
 #include "tda10048.h"
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
@@ -54,6 +55,9 @@
 #include "netup-eeprom.h"
 #include "netup-init.h"
 #include "lgdt3305.h"
+#include "atbm8830.h"
+#include "ds3000.h"
+#include "cx23885-f300.h"
 
 static unsigned int debug;
 
@@ -400,6 +404,7 @@ static struct stv0900_reg stv0900_ts_regs[] = {
 
 static struct stv0900_config netup_stv0900_config = {
 	.demod_address = 0x68,
+	.demod_mode = 1, /* dual */
 	.xtal = 8000000,
 	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
 	.diseqc_mode = 2,/* 2/3 PWM */
@@ -414,34 +419,22 @@ static struct stv6110_config netup_stv6110_tunerconfig_a = {
 	.i2c_address = 0x60,
 	.mclk = 16000000,
 	.clk_div = 1,
+	.gain = 8, /* +16 dB  - maximum gain */
 };
 
 static struct stv6110_config netup_stv6110_tunerconfig_b = {
 	.i2c_address = 0x63,
 	.mclk = 16000000,
 	.clk_div = 1,
+	.gain = 8, /* +16 dB  - maximum gain */
 };
 
-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,
+	.demod_address = 0x55,
 };
 
-static struct cx24116_config tevii_cx24116_config = {
-	.demod_address = 0x55,
+static struct ds3000_config tevii_ds3000_config = {
+	.demod_address = 0x68,
 };
 
 static struct cx24116_config dvbworld_cx24116_config = {
@@ -486,11 +479,40 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
 			break;
 		}
 		break;
+	case CX23885_BOARD_MYGICA_X8506:
+	case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+		/* Select Digital TV */
+		cx23885_gpio_set(dev, GPIO_0);
+		break;
 	}
-	return (port->set_frontend_save) ?
-		port->set_frontend_save(fe, param) : -ENODEV;
+	return 0;
 }
 
+static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe,
+					 unsigned int cmd, void *parg,
+					 unsigned int stage)
+{
+	int err = 0;
+
+	switch (stage) {
+	case DVB_FE_IOCTL_PRE:
+
+		switch (cmd) {
+		case FE_SET_FRONTEND:
+			err = cx23885_dvb_set_frontend(fe,
+				(struct dvb_frontend_parameters *) parg);
+			break;
+		}
+		break;
+
+	case DVB_FE_IOCTL_POST:
+		/* no post-ioctl handling required */
+		break;
+	}
+	return err;
+};
+
+
 static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
 	.prod = LGS8GXX_PROD_LGS8G75,
 	.demod_address = 0x19,
@@ -511,6 +533,38 @@ static struct xc5000_config magicpro_prohdtve2_xc5000_config = {
 	.if_khz = 6500,
 };
 
+static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = {
+	.prod = ATBM8830_PROD_8830,
+	.demod_address = 0x44,
+	.serial_ts = 0,
+	.ts_sampling_edge = 1,
+	.ts_clk_gated = 0,
+	.osc_clk_freq = 30400, /* in kHz */
+	.if_freq = 0, /* zero IF */
+	.zif_swap_iq = 1,
+};
+
+static struct max2165_config mygic_x8558pro_max2165_cfg1 = {
+	.i2c_address = 0x60,
+	.osc_clk = 20
+};
+
+static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = {
+	.prod = ATBM8830_PROD_8830,
+	.demod_address = 0x44,
+	.serial_ts = 1,
+	.ts_sampling_edge = 1,
+	.ts_clk_gated = 0,
+	.osc_clk_freq = 30400, /* in kHz */
+	.if_freq = 0, /* zero IF */
+	.zif_swap_iq = 1,
+};
+
+static struct max2165_config mygic_x8558pro_max2165_cfg2 = {
+	.i2c_address = 0x60,
+	.osc_clk = 20
+};
+
 static int dvb_register(struct cx23885_tsport *port)
 {
 	struct cx23885_dev *dev = port->dev;
@@ -550,12 +604,6 @@ static int dvb_register(struct cx23885_tsport *port)
 				   0x60, &dev->i2c_bus[1].i2c_adap,
 				   &hauppauge_hvr127x_config);
 		}
-
-		/* FIXME: temporary hack */
-		/* define bridge override to set_frontend */
-		port->set_frontend_save = fe0->dvb.frontend->ops.set_frontend;
-		fe0->dvb.frontend->ops.set_frontend = cx23885_dvb_set_frontend;
-
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1255:
 		i2c_bus = &dev->i2c_bus[0];
@@ -772,23 +820,23 @@ static int dvb_register(struct cx23885_tsport *port)
 		}
 		break;
 	case CX23885_BOARD_TBS_6920:
-		i2c_bus = &dev->i2c_bus[0];
+		i2c_bus = &dev->i2c_bus[1];
 
 		fe0->dvb.frontend = dvb_attach(cx24116_attach,
-			&tbs_cx24116_config,
-			&i2c_bus->i2c_adap);
+					&tbs_cx24116_config,
+					&i2c_bus->i2c_adap);
 		if (fe0->dvb.frontend != NULL)
-			fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage;
+			fe0->dvb.frontend->ops.set_voltage = f300_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);
+		fe0->dvb.frontend = dvb_attach(ds3000_attach,
+					&tevii_ds3000_config,
+					&i2c_bus->i2c_adap);
 		if (fe0->dvb.frontend != NULL)
-			fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage;
+			fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
 
 		break;
 	case CX23885_BOARD_DVBWORLD_2005:
@@ -814,8 +862,8 @@ static int dvb_register(struct cx23885_tsport *port)
 					if (!dvb_attach(lnbh24_attach,
 							fe0->dvb.frontend,
 							&i2c_bus->i2c_adap,
-							LNBH24_PCL,
-							LNBH24_TTX, 0x09))
+							LNBH24_PCL | LNBH24_TTX,
+							LNBH24_TEN, 0x09))
 						printk(KERN_ERR
 							"No LNBH24 found!\n");
 
@@ -835,8 +883,8 @@ static int dvb_register(struct cx23885_tsport *port)
 					if (!dvb_attach(lnbh24_attach,
 							fe0->dvb.frontend,
 							&i2c_bus->i2c_adap,
-							LNBH24_PCL,
-							LNBH24_TTX, 0x0a))
+							LNBH24_PCL | LNBH24_TTX,
+							LNBH24_TEN, 0x0a))
 						printk(KERN_ERR
 							"No LNBH24 found!\n");
 
@@ -872,6 +920,7 @@ static int dvb_register(struct cx23885_tsport *port)
 		}
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 		i2c_bus = &dev->i2c_bus[0];
 		fe0->dvb.frontend = dvb_attach(s5h1411_attach,
 			&hcw_s5h1411_config,
@@ -881,6 +930,36 @@ static int dvb_register(struct cx23885_tsport *port)
 				0x60, &dev->i2c_bus[0].i2c_adap,
 				&hauppauge_tda18271_config);
 		break;
+	case CX23885_BOARD_MYGICA_X8558PRO:
+		switch (port->nr) {
+		/* port B */
+		case 1:
+			i2c_bus = &dev->i2c_bus[0];
+			fe0->dvb.frontend = dvb_attach(atbm8830_attach,
+				&mygica_x8558pro_atbm8830_cfg1,
+				&i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL) {
+				dvb_attach(max2165_attach,
+					fe0->dvb.frontend,
+					&i2c_bus->i2c_adap,
+					&mygic_x8558pro_max2165_cfg1);
+			}
+			break;
+		/* port C */
+		case 2:
+			i2c_bus = &dev->i2c_bus[1];
+			fe0->dvb.frontend = dvb_attach(atbm8830_attach,
+				&mygica_x8558pro_atbm8830_cfg2,
+				&i2c_bus->i2c_adap);
+			if (fe0->dvb.frontend != NULL) {
+				dvb_attach(max2165_attach,
+					fe0->dvb.frontend,
+					&i2c_bus->i2c_adap,
+					&mygic_x8558pro_max2165_cfg2);
+			}
+			break;
+		}
+		break;
 
 	default:
 		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
@@ -897,14 +976,15 @@ 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 */
-	call_all(dev, tuner, s_standby);
+	call_all(dev, core, s_power, 0);
 
 	if (fe0->dvb.frontend->ops.analog_ops.standby)
 		fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
 
 	/* register everything */
 	ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
-		&dev->pci->dev, adapter_nr, 0);
+					&dev->pci->dev, adapter_nr, 0,
+					cx23885_dvb_fe_ioctl_override);
 
 	/* init CI & MAC */
 	switch (dev->board) {
diff --git a/drivers/media/video/cx23885/cx23885-f300.c b/drivers/media/video/cx23885/cx23885-f300.c
new file mode 100644
index 000000000000..93998f220986
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-f300.c
@@ -0,0 +1,177 @@
+/*
+ * Driver for Silicon Labs C8051F300 microcontroller.
+ *
+ * It is used for LNB power control in TeVii S470,
+ * TBS 6920 PCIe DVB-S2 cards.
+ *
+ * Microcontroller connected to cx23885 GPIO pins:
+ * GPIO0 - data		- P0.3 F300
+ * GPIO1 - reset	- P0.2 F300
+ * GPIO2 - clk		- P0.1 F300
+ * GPIO3 - busy		- P0.0 F300
+ *
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@me.by>
+ *
+ * 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"
+
+#define F300_DATA	GPIO_0
+#define F300_RESET	GPIO_1
+#define F300_CLK	GPIO_2
+#define F300_BUSY	GPIO_3
+
+static void f300_set_line(struct cx23885_dev *dev, u32 line, u8 lvl)
+{
+	cx23885_gpio_enable(dev, line, 1);
+	if (lvl == 1)
+		cx23885_gpio_set(dev, line);
+	else
+		cx23885_gpio_clear(dev, line);
+}
+
+static u8 f300_get_line(struct cx23885_dev *dev, u32 line)
+{
+	cx23885_gpio_enable(dev, line, 0);
+
+	return cx23885_gpio_get(dev, line);
+}
+
+static void f300_send_byte(struct cx23885_dev *dev, u8 dta)
+{
+	u8 i;
+
+	for (i = 0; i < 8; i++) {
+		f300_set_line(dev, F300_CLK, 0);
+		udelay(30);
+		f300_set_line(dev, F300_DATA, (dta & 0x80) >> 7);/* msb first */
+		udelay(30);
+		dta <<= 1;
+		f300_set_line(dev, F300_CLK, 1);
+		udelay(30);
+	}
+}
+
+static u8 f300_get_byte(struct cx23885_dev *dev)
+{
+	u8 i, dta = 0;
+
+	for (i = 0; i < 8; i++) {
+		f300_set_line(dev, F300_CLK, 0);
+		udelay(30);
+		dta <<= 1;
+		f300_set_line(dev, F300_CLK, 1);
+		udelay(30);
+		dta |= f300_get_line(dev, F300_DATA);/* msb first */
+
+	}
+
+	return dta;
+}
+
+static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf)
+{
+	struct cx23885_tsport *port = fe->dvb->priv;
+	struct cx23885_dev *dev = port->dev;
+	u8 i, temp, ret = 0;
+
+	temp = buf[0];
+	for (i = 0; i < buf[0]; i++)
+		temp += buf[i + 1];
+	temp = (~temp + 1);/* get check sum */
+	buf[1 + buf[0]] = temp;
+
+	f300_set_line(dev, F300_RESET, 1);
+	f300_set_line(dev, F300_CLK, 1);
+	udelay(30);
+	f300_set_line(dev, F300_DATA, 1);
+	msleep(1);
+
+	/* question: */
+	f300_set_line(dev, F300_RESET, 0);/* begin to send data */
+	msleep(1);
+
+	f300_send_byte(dev, 0xe0);/* the slave address is 0xe0, write */
+	msleep(1);
+
+	temp = buf[0];
+	temp += 2;
+	for (i = 0; i < temp; i++)
+		f300_send_byte(dev, buf[i]);
+
+	f300_set_line(dev, F300_RESET, 1);/* sent data over */
+	f300_set_line(dev, F300_DATA, 1);
+
+	/* answer: */
+	temp = 0;
+	for (i = 0; ((i < 8) & (temp == 0)); i++) {
+		msleep(1);
+		if (f300_get_line(dev, F300_BUSY) == 0)
+			temp = 1;
+	}
+
+	if (i > 7) {
+		printk(KERN_ERR "%s: timeout, the slave no response\n",
+								__func__);
+		ret = 1; /* timeout, the slave no response */
+	} else { /* the slave not busy, prepare for getting data */
+		f300_set_line(dev, F300_RESET, 0);/*ready...*/
+		msleep(1);
+		f300_send_byte(dev, 0xe1);/* 0xe1 is Read */
+		msleep(1);
+		temp = f300_get_byte(dev);/*get the data length */
+		if (temp > 14)
+			temp = 14;
+
+		for (i = 0; i < (temp + 1); i++)
+			f300_get_byte(dev);/* get data to empty buffer */
+
+		f300_set_line(dev, F300_RESET, 1);/* received data over */
+		f300_set_line(dev, F300_DATA, 1);
+	}
+
+	return ret;
+}
+
+int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	u8 buf[16];
+
+	buf[0] = 0x05;
+	buf[1] = 0x38;/* write port */
+	buf[2] = 0x01;/* A port, lnb power */
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		buf[3] = 0x01;/* power on */
+		buf[4] = 0x02;/* B port, H/V */
+		buf[5] = 0x00;/*13V v*/
+		break;
+	case SEC_VOLTAGE_18:
+		buf[3] = 0x01;
+		buf[4] = 0x02;
+		buf[5] = 0x01;/* 18V h*/
+		break;
+	case SEC_VOLTAGE_OFF:
+		buf[3] = 0x00;/* power off */
+		buf[4] = 0x00;
+		buf[5] = 0x00;
+		break;
+	}
+
+	return f300_xfer(fe, buf);
+}
diff --git a/drivers/media/video/cx23885/cx23885-f300.h b/drivers/media/video/cx23885/cx23885-f300.h
new file mode 100644
index 000000000000..e73344c94963
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-f300.h
@@ -0,0 +1,2 @@
+extern int f300_set_voltage(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage);
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
new file mode 100644
index 000000000000..469e083dd5f8
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -0,0 +1,427 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Infrared remote control input device
+ *
+ *  Most of this file is
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@radix.net>
+ *
+ *  However, the cx23885_input_{init,fini} functions contained herein are
+ *  derived from Linux kernel files linux/media/video/.../...-input.c marked as:
+ *
+ *  Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
+ *  Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ *		       Markus Rechberger <mrechberger@gmail.com>
+ *		       Mauro Carvalho Chehab <mchehab@infradead.org>
+ *		       Sascha Sommer <saschasommer@freenet.de>
+ *  Copyright (C) 2004, 2005 Chris Pascoe
+ *  Copyright (C) 2003, 2004 Gerd Knorr
+ *  Copyright (C) 2003 Pavel Machek
+ *
+ *  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.
+ */
+
+#include <linux/input.h>
+#include <media/ir-common.h>
+#include <media/v4l2-subdev.h>
+
+#include "cx23885.h"
+
+#define RC5_BITS		14
+#define RC5_HALF_BITS		(2*RC5_BITS)
+#define RC5_HALF_BITS_MASK	((1 << RC5_HALF_BITS) - 1)
+
+#define RC5_START_BITS_NORMAL	0x3 /* Command range  0 -  63 */
+#define RC5_START_BITS_EXTENDED	0x2 /* Command range 64 - 127 */
+
+#define RC5_EXTENDED_COMMAND_OFFSET	64
+
+static inline unsigned int rc5_command(u32 rc5_baseband)
+{
+	return RC5_INSTR(rc5_baseband) +
+		((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED)
+			? RC5_EXTENDED_COMMAND_OFFSET : 0);
+}
+
+static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev)
+{
+	struct card_ir *ir_input = dev->ir_input;
+	unsigned int code, command;
+	u32 rc5;
+
+	/* Ignore codes that are too short to be valid RC-5 */
+	if (ir_input->last_bit < (RC5_HALF_BITS - 1))
+		return;
+
+	/* The library has the manchester coding backwards; XOR to adapt. */
+	code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK;
+	rc5 = ir_rc5_decode(code);
+
+	switch (RC5_START(rc5)) {
+	case RC5_START_BITS_NORMAL:
+		break;
+	case RC5_START_BITS_EXTENDED:
+		/* Don't allow if the remote only emits standard commands */
+		if (ir_input->start == RC5_START_BITS_NORMAL)
+			return;
+		break;
+	default:
+		return;
+	}
+
+	if (ir_input->addr != RC5_ADDR(rc5))
+		return;
+
+	/* Don't generate a keypress for RC-5 auto-repeated keypresses */
+	command = rc5_command(rc5);
+	if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) ||
+	    command != rc5_command(ir_input->last_rc5) ||
+	    /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */
+	    RC5_START(ir_input->last_rc5) == 0) {
+		/* This keypress is differnet: not an auto repeat */
+		ir_input_nokey(ir_input->dev, &ir_input->ir);
+		ir_input_keydown(ir_input->dev, &ir_input->ir, command);
+	}
+	ir_input->last_rc5 = rc5;
+
+	/* Schedule when we should do the key up event: ir_input_nokey() */
+	mod_timer(&ir_input->timer_keyup,
+		  jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout));
+}
+
+static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev,
+					       u32 ns_pulse)
+{
+	const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */
+	struct card_ir *ir_input = dev->ir_input;
+	int i, level, quarterbits, halfbits;
+
+	if (!ir_input->active) {
+		ir_input->active = 1;
+		/* assume an initial space that we may not detect or measure */
+		ir_input->code = 0;
+		ir_input->last_bit = 0;
+	}
+
+	if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) {
+		ir_input->last_bit++; /* Account for the final space */
+		ir_input->active = 0;
+		cx23885_input_process_raw_rc5(dev);
+		return;
+	}
+
+	level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0;
+
+	/* Skip any leading space to sync to the start bit */
+	if (ir_input->last_bit == 0 && level == 0)
+		return;
+
+	/*
+	 * With valid RC-5 we can get up to two consecutive half-bits in a
+	 * single pulse measurment.  Experiments have shown that the duration
+	 * of a half-bit can vary.  Make sure we always end up with an even
+	 * number of quarter bits at the same level (mark or space).
+	 */
+	ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
+	quarterbits = ns_pulse / rc5_quarterbit_ns;
+	if (quarterbits & 1)
+		quarterbits++;
+	halfbits = quarterbits / 2;
+
+	for (i = 0; i < halfbits; i++) {
+		ir_input->last_bit++;
+		ir_input->code |= (level << ir_input->last_bit);
+
+		if (ir_input->last_bit >= RC5_HALF_BITS-1) {
+			ir_input->active = 0;
+			cx23885_input_process_raw_rc5(dev);
+			/*
+			 * If level is 1, a leading mark is invalid for RC5.
+			 * If level is 0, we scan past extra intial space.
+			 * Either way we don't want to reactivate collecting
+			 * marks or spaces here with any left over half-bits.
+			 */
+			break;
+		}
+	}
+}
+
+static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev,
+						   bool add_eom)
+{
+	struct card_ir *ir_input = dev->ir_input;
+	struct ir_input_state *ir_input_state = &ir_input->ir;
+
+	u32 ns_pulse[RC5_HALF_BITS+1];
+	ssize_t num = 0;
+	int count, i;
+
+	do {
+		v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse,
+				 sizeof(ns_pulse), &num);
+
+		count = num / sizeof(u32);
+
+		/* Append an end of Rx seq, if the caller requested */
+		if (add_eom && count < ARRAY_SIZE(ns_pulse)) {
+			ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END;
+			count++;
+		}
+
+		/* Just drain the Rx FIFO, if we're called, but not RC-5 */
+		if (ir_input_state->ir_type != IR_TYPE_RC5)
+			continue;
+
+		for (i = 0; i < count; i++)
+			cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]);
+	} while (num != 0);
+}
+
+void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
+{
+	struct v4l2_subdev_ir_parameters params;
+	int overrun, data_available;
+
+	if (dev->sd_ir == NULL || events == 0)
+		return;
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		/*
+		 * The only board we handle right now.  However other boards
+		 * using the CX2388x integrated IR controller should be similar
+		 */
+		break;
+	default:
+		return;
+	}
+
+	overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN |
+			    V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN);
+
+	data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED |
+				   V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ);
+
+	if (overrun) {
+		/* If there was a FIFO overrun, stop the device */
+		v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+		params.enable = false;
+		/* Mitigate race with cx23885_input_ir_stop() */
+		params.shutdown = atomic_read(&dev->ir_input_stopping);
+		v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+	}
+
+	if (data_available)
+		cx23885_input_process_pulse_widths_rc5(dev, overrun);
+
+	if (overrun) {
+		/* If there was a FIFO overrun, clear & restart the device */
+		params.enable = true;
+		/* Mitigate race with cx23885_input_ir_stop() */
+		params.shutdown = atomic_read(&dev->ir_input_stopping);
+		v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+	}
+}
+
+static void cx23885_input_ir_start(struct cx23885_dev *dev)
+{
+	struct card_ir *ir_input = dev->ir_input;
+	struct ir_input_state *ir_input_state = &ir_input->ir;
+	struct v4l2_subdev_ir_parameters params;
+
+	if (dev->sd_ir == NULL)
+		return;
+
+	atomic_set(&dev->ir_input_stopping, 0);
+
+	/* keyup timer set up, if needed */
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		setup_timer(&ir_input->timer_keyup,
+			    ir_rc5_timer_keyup,	/* Not actually RC-5 specific */
+			    (unsigned long) ir_input);
+		if (ir_input_state->ir_type == IR_TYPE_RC5) {
+			/*
+			 * RC-5 repeats a held key every
+			 * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms
+			 */
+			ir_input->rc5_key_timeout = 115;
+		}
+		break;
+	}
+
+	v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		/*
+		 * The IR controller on this board only returns pulse widths.
+		 * Any other mode setting will fail to set up the device.
+		*/
+		params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+		params.enable = true;
+		params.interrupt_enable = true;
+		params.shutdown = false;
+
+		/* Setup for baseband compatible with both RC-5 and RC-6A */
+		params.modulation = false;
+		/* RC-5:  2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/
+		/* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/
+		params.max_pulse_width = 3333333; /* ns */
+		/* RC-5:    666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
+		/* RC-6A:   333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
+		params.noise_filter_min_width = 333333; /* ns */
+		/*
+		 * This board has inverted receive sense:
+		 * mark is received as low logic level;
+		 * falling edges are detected as rising edges; etc.
+		 */
+		params.invert = true;
+		break;
+	}
+	v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+}
+
+static void cx23885_input_ir_stop(struct cx23885_dev *dev)
+{
+	struct card_ir *ir_input = dev->ir_input;
+	struct v4l2_subdev_ir_parameters params;
+
+	if (dev->sd_ir == NULL)
+		return;
+
+	/*
+	 * Stop the sd_ir subdevice from generating notifications and
+	 * scheduling work.
+	 * It is shutdown this way in order to mitigate a race with
+	 * cx23885_input_rx_work_handler() in the overrun case, which could
+	 * re-enable the subdevice.
+	 */
+	atomic_set(&dev->ir_input_stopping, 1);
+	v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+	while (params.shutdown == false) {
+		params.enable = false;
+		params.interrupt_enable = false;
+		params.shutdown = true;
+		v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+		v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
+	}
+
+	flush_scheduled_work();
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		del_timer_sync(&ir_input->timer_keyup);
+		break;
+	}
+}
+
+int cx23885_input_init(struct cx23885_dev *dev)
+{
+	struct card_ir *ir;
+	struct input_dev *input_dev;
+	struct ir_scancode_table *ir_codes = NULL;
+	int ir_type, ir_addr, ir_start;
+	int ret;
+
+	/*
+	 * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't
+	 * encapsulated in a v4l2_subdev, then I'm not going to deal with it.
+	 */
+	if (dev->sd_ir == NULL)
+		return -ENODEV;
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1850:
+	case CX23885_BOARD_HAUPPAUGE_HVR1290:
+		/* Parameters for the grey Hauppauge remote for the HVR-1850 */
+		ir_codes = &ir_codes_hauppauge_new_table;
+		ir_type = IR_TYPE_RC5;
+		ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */
+		ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */
+		break;
+	}
+	if (ir_codes == NULL)
+		return -ENODEV;
+
+	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ir || !input_dev) {
+		ret = -ENOMEM;
+		goto err_out_free;
+	}
+
+	ir->dev = input_dev;
+	ir->addr = ir_addr;
+	ir->start = ir_start;
+
+	/* init input device */
+	snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)",
+		 cx23885_boards[dev->board].name);
+	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci));
+
+	ret = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
+	if (ret < 0)
+		goto err_out_free;
+
+	input_dev->name = ir->name;
+	input_dev->phys = ir->phys;
+	input_dev->id.bustype = BUS_PCI;
+	input_dev->id.version = 1;
+	if (dev->pci->subsystem_vendor) {
+		input_dev->id.vendor  = dev->pci->subsystem_vendor;
+		input_dev->id.product = dev->pci->subsystem_device;
+	} else {
+		input_dev->id.vendor  = dev->pci->vendor;
+		input_dev->id.product = dev->pci->device;
+	}
+	input_dev->dev.parent = &dev->pci->dev;
+
+	dev->ir_input = ir;
+	cx23885_input_ir_start(dev);
+
+	ret = input_register_device(ir->dev);
+	if (ret)
+		goto err_out_stop;
+
+	return 0;
+
+err_out_stop:
+	cx23885_input_ir_stop(dev);
+	dev->ir_input = NULL;
+err_out_free:
+	ir_input_free(input_dev);
+	input_free_device(input_dev);
+	kfree(ir);
+	return ret;
+}
+
+void cx23885_input_fini(struct cx23885_dev *dev)
+{
+	/* Always stop the IR hardware from generating interrupts */
+	cx23885_input_ir_stop(dev);
+
+	if (dev->ir_input == NULL)
+		return;
+	ir_input_free(dev->ir_input->dev);
+	input_unregister_device(dev->ir_input->dev);
+	kfree(dev->ir_input);
+	dev->ir_input = NULL;
+}
diff --git a/drivers/media/video/cx23885/cx23885-input.h b/drivers/media/video/cx23885/cx23885-input.h
new file mode 100644
index 000000000000..3572cb1ecfc2
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-input.h
@@ -0,0 +1,30 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Infrared remote control input device
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _CX23885_INPUT_H_
+#define _CX23885_INPUT_H_
+int cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events);
+
+int cx23885_input_init(struct cx23885_dev *dev);
+void cx23885_input_fini(struct cx23885_dev *dev);
+#endif
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.c b/drivers/media/video/cx23885/cx23885-ioctl.c
new file mode 100644
index 000000000000..dfb4627fb340
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-ioctl.c
@@ -0,0 +1,208 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Various common ioctl() support functions
+ *
+ *  Copyright (c) 2009 Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx23885.h"
+#include <media/v4l2-chip-ident.h>
+
+int cx23885_g_chip_ident(struct file *file, void *fh,
+			 struct v4l2_dbg_chip_ident *chip)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+	int err = 0;
+	u8 rev;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	switch (chip->match.type) {
+	case V4L2_CHIP_MATCH_HOST:
+		switch (chip->match.addr) {
+		case 0:
+			rev = cx_read(RDR_CFG2) & 0xff;
+			switch (dev->pci->device) {
+			case 0x8852:
+				/* rev 0x04 could be '885 or '888. Pick '888. */
+				if (rev == 0x04)
+					chip->ident = V4L2_IDENT_CX23888;
+				else
+					chip->ident = V4L2_IDENT_CX23885;
+				break;
+			case 0x8880:
+				if (rev == 0x0e || rev == 0x0f)
+					chip->ident = V4L2_IDENT_CX23887;
+				else
+					chip->ident = V4L2_IDENT_CX23888;
+				break;
+			default:
+				chip->ident = V4L2_IDENT_UNKNOWN;
+				break;
+			}
+			chip->revision = (dev->pci->device << 16) | (rev << 8) |
+					 (dev->hwrevision & 0xff);
+			break;
+		case 1:
+			if (dev->v4l_device != NULL) {
+				chip->ident = V4L2_IDENT_CX23417;
+				chip->revision = 0;
+			}
+			break;
+		case 2:
+			/*
+			 * The integrated IR controller on the CX23888 is
+			 * host chip 2.  It may not be used/initialized or sd_ir
+			 * may be pointing at the cx25840 subdevice for the
+			 * IR controller on the CX23885.  Thus we find it
+			 * without using the dev->sd_ir pointer.
+			 */
+			call_hw(dev, CX23885_HW_888_IR, core, g_chip_ident,
+				chip);
+			break;
+		default:
+			err = -EINVAL; /* per V4L2 spec */
+			break;
+		}
+		break;
+	case V4L2_CHIP_MATCH_I2C_DRIVER:
+		/* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
+		call_all(dev, 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.
+		 */
+		call_all(dev, core, g_chip_ident, chip);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cx23885_g_host_register(struct cx23885_dev *dev,
+				   struct v4l2_dbg_register *reg)
+{
+	if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
+		return -EINVAL;
+
+	reg->size = 4;
+	reg->val = cx_read(reg->reg);
+	return 0;
+}
+
+static int cx23417_g_register(struct cx23885_dev *dev,
+			      struct v4l2_dbg_register *reg)
+{
+	u32 value;
+
+	if (dev->v4l_device == NULL)
+		return -EINVAL;
+
+	if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000)
+		return -EINVAL;
+
+	if (mc417_register_read(dev, (u16) reg->reg, &value))
+		return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */
+
+	reg->size = 4;
+	reg->val = value;
+	return 0;
+}
+
+int cx23885_g_register(struct file *file, void *fh,
+		       struct v4l2_dbg_register *reg)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (reg->match.type == V4L2_CHIP_MATCH_HOST) {
+		switch (reg->match.addr) {
+		case 0:
+			return cx23885_g_host_register(dev, reg);
+		case 1:
+			return cx23417_g_register(dev, reg);
+		default:
+			break;
+		}
+	}
+
+	/* FIXME - any error returns should not be ignored */
+	call_all(dev, core, g_register, reg);
+	return 0;
+}
+
+static int cx23885_s_host_register(struct cx23885_dev *dev,
+				   struct v4l2_dbg_register *reg)
+{
+	if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
+		return -EINVAL;
+
+	reg->size = 4;
+	cx_write(reg->reg, reg->val);
+	return 0;
+}
+
+static int cx23417_s_register(struct cx23885_dev *dev,
+			      struct v4l2_dbg_register *reg)
+{
+	if (dev->v4l_device == NULL)
+		return -EINVAL;
+
+	if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000)
+		return -EINVAL;
+
+	if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val))
+		return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */
+
+	reg->size = 4;
+	return 0;
+}
+
+int cx23885_s_register(struct file *file, void *fh,
+		       struct v4l2_dbg_register *reg)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (reg->match.type == V4L2_CHIP_MATCH_HOST) {
+		switch (reg->match.addr) {
+		case 0:
+			return cx23885_s_host_register(dev, reg);
+		case 1:
+			return cx23417_s_register(dev, reg);
+		default:
+			break;
+		}
+	}
+
+	/* FIXME - any error returns should not be ignored */
+	call_all(dev, core, s_register, reg);
+	return 0;
+}
+#endif
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.h b/drivers/media/video/cx23885/cx23885-ioctl.h
new file mode 100644
index 000000000000..80b0f4923c6a
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-ioctl.h
@@ -0,0 +1,39 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Various common ioctl() support functions
+ *
+ *  Copyright (c) 2009 Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX23885_IOCTL_H_
+#define _CX23885_IOCTL_H_
+
+int cx23885_g_chip_ident(struct file *file, void *fh,
+			 struct v4l2_dbg_chip_ident *chip);
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int cx23885_g_register(struct file *file, void *fh,
+		       struct v4l2_dbg_register *reg);
+
+
+int cx23885_s_register(struct file *file, void *fh,
+		       struct v4l2_dbg_register *reg);
+
+#endif
+#endif
diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c
new file mode 100644
index 000000000000..6ae982cc9856
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-ir.c
@@ -0,0 +1,101 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Infrared device support routines - non-input, non-vl42_subdev routines
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include <media/v4l2-device.h>
+
+#include "cx23885.h"
+#include "cx23885-input.h"
+
+#define CX23885_IR_RX_FIFO_SERVICE_REQ		0
+#define CX23885_IR_RX_END_OF_RX_DETECTED	1
+#define CX23885_IR_RX_HW_FIFO_OVERRUN		2
+#define CX23885_IR_RX_SW_FIFO_OVERRUN		3
+
+#define CX23885_IR_TX_FIFO_SERVICE_REQ		0
+
+
+void cx23885_ir_rx_work_handler(struct work_struct *work)
+{
+	struct cx23885_dev *dev =
+			     container_of(work, struct cx23885_dev, ir_rx_work);
+	u32 events = 0;
+	unsigned long *notifications = &dev->ir_rx_notifications;
+
+	if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications))
+		events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
+	if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications))
+		events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
+	if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications))
+		events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
+	if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications))
+		events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+
+	if (events == 0)
+		return;
+
+	if (dev->ir_input)
+		cx23885_input_rx_work_handler(dev, events);
+}
+
+void cx23885_ir_tx_work_handler(struct work_struct *work)
+{
+	struct cx23885_dev *dev =
+			     container_of(work, struct cx23885_dev, ir_tx_work);
+	u32 events = 0;
+	unsigned long *notifications = &dev->ir_tx_notifications;
+
+	if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications))
+		events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
+
+	if (events == 0)
+		return;
+
+}
+
+/* Called in an IRQ context */
+void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
+{
+	struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
+	unsigned long *notifications = &dev->ir_rx_notifications;
+
+	if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ)
+		set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications);
+	if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED)
+		set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications);
+	if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN)
+		set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications);
+	if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN)
+		set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications);
+	schedule_work(&dev->ir_rx_work);
+}
+
+/* Called in an IRQ context */
+void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
+{
+	struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
+	unsigned long *notifications = &dev->ir_tx_notifications;
+
+	if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ)
+		set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications);
+	schedule_work(&dev->ir_tx_work);
+}
diff --git a/drivers/media/video/cx23885/cx23885-ir.h b/drivers/media/video/cx23885/cx23885-ir.h
new file mode 100644
index 000000000000..9b8a6d5d1ef6
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-ir.h
@@ -0,0 +1,31 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Infrared device support routines - non-input, non-vl42_subdev routines
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _CX23885_IR_H_
+#define _CX23885_IR_H_
+void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events);
+void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events);
+
+void cx23885_ir_rx_work_handler(struct work_struct *work);
+void cx23885_ir_tx_work_handler(struct work_struct *work);
+#endif
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
index eafbe5226bae..c0bc9a068954 100644
--- a/drivers/media/video/cx23885/cx23885-reg.h
+++ b/drivers/media/video/cx23885/cx23885-reg.h
@@ -212,8 +212,9 @@ 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_IR        (1 << 28)
+#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 654cc253cd50..8b372b4f0de2 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -35,6 +35,7 @@
 #include "cx23885.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include "cx23885-ioctl.h"
 
 MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -401,6 +402,13 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
 		INPUT(input)->gpio2, INPUT(input)->gpio3);
 	dev->input = input;
 
+	if (dev->board == CX23885_BOARD_MYGICA_X8506 ||
+		dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) {
+		/* Select Analog TV */
+		if (INPUT(input)->type == CX23885_VMUX_TELEVISION)
+			cx23885_gpio_clear(dev, GPIO_0);
+	}
+
 	/* Tell the internal A/V decoder */
 	v4l2_subdev_call(dev->sd_cx25840, video, s_routing,
 			INPUT(input)->vmux, 0, 0);
@@ -1144,6 +1152,7 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
 		[CX23885_VMUX_COMPOSITE3] = "Composite3",
 		[CX23885_VMUX_COMPOSITE4] = "Composite4",
 		[CX23885_VMUX_SVIDEO]     = "S-Video",
+		[CX23885_VMUX_COMPONENT]  = "Component",
 		[CX23885_VMUX_TELEVISION] = "Television",
 		[CX23885_VMUX_CABLE]      = "Cable TV",
 		[CX23885_VMUX_DVB]        = "DVB",
@@ -1312,34 +1321,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 		cx23885_set_freq(dev, f);
 }
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vidioc_g_register(struct file *file, void *fh,
-				struct v4l2_dbg_register *reg)
-{
-	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
-
-	if (!v4l2_chip_match_host(&reg->match))
-		return -EINVAL;
-
-	call_all(dev, core, g_register, reg);
-
-	return 0;
-}
-
-static int vidioc_s_register(struct file *file, void *fh,
-				struct v4l2_dbg_register *reg)
-{
-	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
-
-	if (!v4l2_chip_match_host(&reg->match))
-		return -EINVAL;
-
-	call_all(dev, core, s_register, reg);
-
-	return 0;
-}
-#endif
-
 /* ----------------------------------------------------------- */
 
 static void cx23885_vid_timeout(unsigned long data)
@@ -1449,9 +1430,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 	.vidioc_s_tuner       = vidioc_s_tuner,
 	.vidioc_g_frequency   = vidioc_g_frequency,
 	.vidioc_s_frequency   = vidioc_s_frequency,
+	.vidioc_g_chip_ident  = cx23885_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register    = vidioc_g_register,
-	.vidioc_s_register    = vidioc_s_register,
+	.vidioc_g_register    = cx23885_g_register,
+	.vidioc_s_register    = cx23885_s_register,
 #endif
 };
 
@@ -1529,9 +1511,11 @@ int cx23885_video_register(struct cx23885_dev *dev)
 		if (sd) {
 			struct tuner_setup tun_setup;
 
+			memset(&tun_setup, 0, sizeof(tun_setup));
 			tun_setup.mode_mask = T_ANALOG_TV;
 			tun_setup.type = dev->tuner_type;
 			tun_setup.addr = v4l2_i2c_subdev_addr(sd);
+			tun_setup.tuner_callback = cx23885_tuner_callback;
 
 			v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup);
 		}
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index cc7a165561ff..fa744764dc8b 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -79,6 +79,8 @@
 #define CX23885_BOARD_MAGICPRO_PROHDTVE2       23
 #define CX23885_BOARD_HAUPPAUGE_HVR1850        24
 #define CX23885_BOARD_COMPRO_VIDEOMATE_E800    25
+#define CX23885_BOARD_HAUPPAUGE_HVR1290        26
+#define CX23885_BOARD_MYGICA_X8558PRO          27
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -157,6 +159,7 @@ enum cx23885_itype {
 	CX23885_VMUX_COMPOSITE3,
 	CX23885_VMUX_COMPOSITE4,
 	CX23885_VMUX_SVIDEO,
+	CX23885_VMUX_COMPONENT,
 	CX23885_VMUX_TELEVISION,
 	CX23885_VMUX_CABLE,
 	CX23885_VMUX_DVB,
@@ -297,10 +300,6 @@ struct cx23885_tsport {
 	/* Allow a single tsport to have multiple frontends */
 	u32                        num_frontends;
 	void                       *port_priv;
-
-	/* FIXME: temporary hack */
-	int (*set_frontend_save) (struct dvb_frontend *,
-				  struct dvb_frontend_parameters *);
 };
 
 struct cx23885_dev {
@@ -356,6 +355,16 @@ struct cx23885_dev {
 	unsigned int               has_radio;
 	struct v4l2_subdev 	   *sd_cx25840;
 
+	/* Infrared */
+	struct v4l2_subdev         *sd_ir;
+	struct work_struct	   ir_rx_work;
+	unsigned long		   ir_rx_notifications;
+	struct work_struct	   ir_tx_work;
+	unsigned long		   ir_tx_notifications;
+
+	struct card_ir		   *ir_input;
+	atomic_t		   ir_input_stopping;
+
 	/* V4l */
 	u32                        freq;
 	struct video_device        *video_dev;
@@ -383,6 +392,13 @@ static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev)
 #define call_all(dev, o, f, args...) \
 	v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
 
+#define CX23885_HW_888_IR (1 << 0)
+
+#define call_hw(dev, grpid, o, f, args...) \
+	v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args)
+
+extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw);
+
 extern struct list_head cx23885_devlist;
 
 #define SRAM_CH01  0 /* Video A */
@@ -455,6 +471,7 @@ extern void cx23885_wakeup(struct cx23885_tsport *port,
 
 extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask);
 extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask);
+extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask);
 extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask,
 	int asoutput);
 
@@ -471,6 +488,8 @@ extern int cx23885_tuner_callback(void *priv, int component,
 	int command, int arg);
 extern void cx23885_card_list(struct cx23885_dev *dev);
 extern int  cx23885_ir_init(struct cx23885_dev *dev);
+extern void cx23885_ir_pci_int_enable(struct cx23885_dev *dev);
+extern void cx23885_ir_fini(struct cx23885_dev *dev);
 extern void cx23885_gpio_setup(struct cx23885_dev *dev);
 extern void cx23885_card_setup(struct cx23885_dev *dev);
 extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
@@ -515,6 +534,10 @@ extern void cx23885_417_check_encoder(struct cx23885_dev *dev);
 extern void cx23885_mc417_init(struct cx23885_dev *dev);
 extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value);
 extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value);
+extern int mc417_register_read(struct cx23885_dev *dev,
+				u16 address, u32 *value);
+extern int mc417_register_write(struct cx23885_dev *dev,
+				u16 address, u32 value);
 extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask);
 extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask);
 extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput);
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
new file mode 100644
index 000000000000..3ccc8afeccf3
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -0,0 +1,1239 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  CX23888 Integrated Consumer Infrared Controller
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include <linux/kfifo.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "cx23885.h"
+
+static unsigned int ir_888_debug;
+module_param(ir_888_debug, int, 0644);
+MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]");
+
+#define CX23888_IR_REG_BASE 	0x170000
+/*
+ * These CX23888 register offsets have a straightforward one to one mapping
+ * to the CX23885 register offsets of 0x200 through 0x218
+ */
+#define CX23888_IR_CNTRL_REG	0x170000
+#define CNTRL_WIN_3_3	0x00000000
+#define CNTRL_WIN_4_3	0x00000001
+#define CNTRL_WIN_3_4	0x00000002
+#define CNTRL_WIN_4_4	0x00000003
+#define CNTRL_WIN	0x00000003
+#define CNTRL_EDG_NONE	0x00000000
+#define CNTRL_EDG_FALL	0x00000004
+#define CNTRL_EDG_RISE	0x00000008
+#define CNTRL_EDG_BOTH	0x0000000C
+#define CNTRL_EDG	0x0000000C
+#define CNTRL_DMD	0x00000010
+#define CNTRL_MOD	0x00000020
+#define CNTRL_RFE	0x00000040
+#define CNTRL_TFE	0x00000080
+#define CNTRL_RXE	0x00000100
+#define CNTRL_TXE	0x00000200
+#define CNTRL_RIC	0x00000400
+#define CNTRL_TIC	0x00000800
+#define CNTRL_CPL	0x00001000
+#define CNTRL_LBM	0x00002000
+#define CNTRL_R		0x00004000
+
+#define CX23888_IR_TXCLK_REG	0x170004
+#define TXCLK_TCD	0x0000FFFF
+
+#define CX23888_IR_RXCLK_REG	0x170008
+#define RXCLK_RCD	0x0000FFFF
+
+#define CX23888_IR_CDUTY_REG	0x17000C
+#define CDUTY_CDC	0x0000000F
+
+#define CX23888_IR_STATS_REG	0x170010
+#define STATS_RTO	0x00000001
+#define STATS_ROR	0x00000002
+#define STATS_RBY	0x00000004
+#define STATS_TBY	0x00000008
+#define STATS_RSR	0x00000010
+#define STATS_TSR	0x00000020
+
+#define CX23888_IR_IRQEN_REG	0x170014
+#define IRQEN_RTE	0x00000001
+#define IRQEN_ROE	0x00000002
+#define IRQEN_RSE	0x00000010
+#define IRQEN_TSE	0x00000020
+
+#define CX23888_IR_FILTR_REG	0x170018
+#define FILTR_LPF	0x0000FFFF
+
+/* This register doesn't follow the pattern; it's 0x23C on a CX23885 */
+#define CX23888_IR_FIFO_REG	0x170040
+#define FIFO_RXTX	0x0000FFFF
+#define FIFO_RXTX_LVL	0x00010000
+#define FIFO_RXTX_RTO	0x0001FFFF
+#define FIFO_RX_NDV	0x00020000
+#define FIFO_RX_DEPTH	8
+#define FIFO_TX_DEPTH	8
+
+/* CX23888 unique registers */
+#define CX23888_IR_SEEDP_REG	0x17001C
+#define CX23888_IR_TIMOL_REG	0x170020
+#define CX23888_IR_WAKE0_REG	0x170024
+#define CX23888_IR_WAKE1_REG	0x170028
+#define CX23888_IR_WAKE2_REG	0x17002C
+#define CX23888_IR_MASK0_REG	0x170030
+#define CX23888_IR_MASK1_REG	0x170034
+#define CX23888_IR_MAKS2_REG	0x170038
+#define CX23888_IR_DPIPG_REG	0x17003C
+#define CX23888_IR_LEARN_REG	0x170044
+
+#define CX23888_VIDCLK_FREQ	108000000 /* 108 MHz, BT.656 */
+#define CX23888_IR_REFCLK_FREQ	(CX23888_VIDCLK_FREQ / 2)
+
+#define CX23888_IR_RX_KFIFO_SIZE	(512 * sizeof(u32))
+#define CX23888_IR_TX_KFIFO_SIZE	(512 * sizeof(u32))
+
+struct cx23888_ir_state {
+	struct v4l2_subdev sd;
+	struct cx23885_dev *dev;
+	u32 id;
+	u32 rev;
+
+	struct v4l2_subdev_ir_parameters rx_params;
+	struct mutex rx_params_lock;
+	atomic_t rxclk_divider;
+	atomic_t rx_invert;
+
+	struct kfifo *rx_kfifo;
+	spinlock_t rx_kfifo_lock;
+
+	struct v4l2_subdev_ir_parameters tx_params;
+	struct mutex tx_params_lock;
+	atomic_t txclk_divider;
+
+	struct kfifo *tx_kfifo;
+	spinlock_t tx_kfifo_lock;
+};
+
+static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd)
+{
+	return v4l2_get_subdevdata(sd);
+}
+
+/*
+ * IR register block read and write functions
+ */
+static
+inline int cx23888_ir_write4(struct cx23885_dev *dev, u32 addr, u32 value)
+{
+	cx_write(addr, value);
+	return 0;
+}
+
+static inline u32 cx23888_ir_read4(struct cx23885_dev *dev, u32 addr)
+{
+	return cx_read(addr);
+}
+
+static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr,
+				     u32 and_mask, u32 or_value)
+{
+	cx_andor(addr, ~and_mask, or_value);
+	return 0;
+}
+
+/*
+ * Rx and Tx Clock Divider register computations
+ *
+ * Note the largest clock divider value of 0xffff corresponds to:
+ * 	(0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns
+ * which fits in 21 bits, so we'll use unsigned int for time arguments.
+ */
+static inline u16 count_to_clock_divider(unsigned int d)
+{
+	if (d > RXCLK_RCD + 1)
+		d = RXCLK_RCD;
+	else if (d < 2)
+		d = 1;
+	else
+		d--;
+	return (u16) d;
+}
+
+static inline u16 ns_to_clock_divider(unsigned int ns)
+{
+	return count_to_clock_divider(
+		DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000));
+}
+
+static inline unsigned int clock_divider_to_ns(unsigned int divider)
+{
+	/* Period of the Rx or Tx clock in ns */
+	return DIV_ROUND_CLOSEST((divider + 1) * 1000,
+				 CX23888_IR_REFCLK_FREQ / 1000000);
+}
+
+static inline u16 carrier_freq_to_clock_divider(unsigned int freq)
+{
+	return count_to_clock_divider(
+			  DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * 16));
+}
+
+static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider)
+{
+	return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16);
+}
+
+static inline u16 freq_to_clock_divider(unsigned int freq,
+					unsigned int rollovers)
+{
+	return count_to_clock_divider(
+		   DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * rollovers));
+}
+
+static inline unsigned int clock_divider_to_freq(unsigned int divider,
+						 unsigned int rollovers)
+{
+	return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ,
+				 (divider + 1) * rollovers);
+}
+
+/*
+ * Low Pass Filter register calculations
+ *
+ * Note the largest count value of 0xffff corresponds to:
+ * 	0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns
+ * which fits in 21 bits, so we'll use unsigned int for time arguments.
+ */
+static inline u16 count_to_lpf_count(unsigned int d)
+{
+	if (d > FILTR_LPF)
+		d = FILTR_LPF;
+	else if (d < 4)
+		d = 0;
+	return (u16) d;
+}
+
+static inline u16 ns_to_lpf_count(unsigned int ns)
+{
+	return count_to_lpf_count(
+		DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000));
+}
+
+static inline unsigned int lpf_count_to_ns(unsigned int count)
+{
+	/* Duration of the Low Pass Filter rejection window in ns */
+	return DIV_ROUND_CLOSEST(count * 1000,
+				 CX23888_IR_REFCLK_FREQ / 1000000);
+}
+
+static inline unsigned int lpf_count_to_us(unsigned int count)
+{
+	/* Duration of the Low Pass Filter rejection window in us */
+	return DIV_ROUND_CLOSEST(count, CX23888_IR_REFCLK_FREQ / 1000000);
+}
+
+/*
+ * FIFO register pulse width count compuations
+ */
+static u32 clock_divider_to_resolution(u16 divider)
+{
+	/*
+	 * Resolution is the duration of 1 tick of the readable portion of
+	 * of the pulse width counter as read from the FIFO.  The two lsb's are
+	 * not readable, hence the << 2.  This function returns ns.
+	 */
+	return DIV_ROUND_CLOSEST((1 << 2)  * ((u32) divider + 1) * 1000,
+				 CX23888_IR_REFCLK_FREQ / 1000000);
+}
+
+static u64 pulse_width_count_to_ns(u16 count, u16 divider)
+{
+	u64 n;
+	u32 rem;
+
+	/*
+	 * The 2 lsb's of the pulse width timer count are not readable, hence
+	 * the (count << 2) | 0x3
+	 */
+	n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */
+	rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000);     /* / MHz => ns */
+	if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2)
+		n++;
+	return n;
+}
+
+static unsigned int pulse_width_count_to_us(u16 count, u16 divider)
+{
+	u64 n;
+	u32 rem;
+
+	/*
+	 * The 2 lsb's of the pulse width timer count are not readable, hence
+	 * the (count << 2) | 0x3
+	 */
+	n = (((u64) count << 2) | 0x3) * (divider + 1);    /* cycles      */
+	rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => us */
+	if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2)
+		n++;
+	return (unsigned int) n;
+}
+
+/*
+ * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts
+ *
+ * The total pulse clock count is an 18 bit pulse width timer count as the most
+ * significant part and (up to) 16 bit clock divider count as a modulus.
+ * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse
+ * width timer count's least significant bit.
+ */
+static u64 ns_to_pulse_clocks(u32 ns)
+{
+	u64 clocks;
+	u32 rem;
+	clocks = CX23888_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles  */
+	rem = do_div(clocks, 1000);                         /* /1000 = cycles */
+	if (rem >= 1000 / 2)
+		clocks++;
+	return clocks;
+}
+
+static u16 pulse_clocks_to_clock_divider(u64 count)
+{
+	u32 rem;
+
+	rem = do_div(count, (FIFO_RXTX << 2) | 0x3);
+
+	/* net result needs to be rounded down and decremented by 1 */
+	if (count > RXCLK_RCD + 1)
+		count = RXCLK_RCD;
+	else if (count < 2)
+		count = 1;
+	else
+		count--;
+	return (u16) count;
+}
+
+/*
+ * IR Control Register helpers
+ */
+enum tx_fifo_watermark {
+	TX_FIFO_HALF_EMPTY = 0,
+	TX_FIFO_EMPTY      = CNTRL_TIC,
+};
+
+enum rx_fifo_watermark {
+	RX_FIFO_HALF_FULL = 0,
+	RX_FIFO_NOT_EMPTY = CNTRL_RIC,
+};
+
+static inline void control_tx_irq_watermark(struct cx23885_dev *dev,
+					    enum tx_fifo_watermark level)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_TIC, level);
+}
+
+static inline void control_rx_irq_watermark(struct cx23885_dev *dev,
+					    enum rx_fifo_watermark level)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_RIC, level);
+}
+
+static inline void control_tx_enable(struct cx23885_dev *dev, bool enable)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE),
+			   enable ? (CNTRL_TXE | CNTRL_TFE) : 0);
+}
+
+static inline void control_rx_enable(struct cx23885_dev *dev, bool enable)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE),
+			   enable ? (CNTRL_RXE | CNTRL_RFE) : 0);
+}
+
+static inline void control_tx_modulation_enable(struct cx23885_dev *dev,
+						bool enable)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_MOD,
+			   enable ? CNTRL_MOD : 0);
+}
+
+static inline void control_rx_demodulation_enable(struct cx23885_dev *dev,
+						  bool enable)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_DMD,
+			   enable ? CNTRL_DMD : 0);
+}
+
+static inline void control_rx_s_edge_detection(struct cx23885_dev *dev,
+					       u32 edge_types)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_EDG_BOTH,
+			   edge_types & CNTRL_EDG_BOTH);
+}
+
+static void control_rx_s_carrier_window(struct cx23885_dev *dev,
+					unsigned int carrier,
+					unsigned int *carrier_range_low,
+					unsigned int *carrier_range_high)
+{
+	u32 v;
+	unsigned int c16 = carrier * 16;
+
+	if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) {
+		v = CNTRL_WIN_3_4;
+		*carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4);
+	} else {
+		v = CNTRL_WIN_3_3;
+		*carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3);
+	}
+
+	if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) {
+		v |= CNTRL_WIN_4_3;
+		*carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4);
+	} else {
+		v |= CNTRL_WIN_3_3;
+		*carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3);
+	}
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_WIN, v);
+}
+
+static inline void control_tx_polarity_invert(struct cx23885_dev *dev,
+					      bool invert)
+{
+	cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_CPL,
+			   invert ? CNTRL_CPL : 0);
+}
+
+/*
+ * IR Rx & Tx Clock Register helpers
+ */
+static unsigned int txclk_tx_s_carrier(struct cx23885_dev *dev,
+				       unsigned int freq,
+				       u16 *divider)
+{
+	*divider = carrier_freq_to_clock_divider(freq);
+	cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider);
+	return clock_divider_to_carrier_freq(*divider);
+}
+
+static unsigned int rxclk_rx_s_carrier(struct cx23885_dev *dev,
+				       unsigned int freq,
+				       u16 *divider)
+{
+	*divider = carrier_freq_to_clock_divider(freq);
+	cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider);
+	return clock_divider_to_carrier_freq(*divider);
+}
+
+static u32 txclk_tx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns,
+				      u16 *divider)
+{
+	u64 pulse_clocks;
+
+	if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
+		ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
+	pulse_clocks = ns_to_pulse_clocks(ns);
+	*divider = pulse_clocks_to_clock_divider(pulse_clocks);
+	cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider);
+	return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
+}
+
+static u32 rxclk_rx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns,
+				      u16 *divider)
+{
+	u64 pulse_clocks;
+
+	if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
+		ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
+	pulse_clocks = ns_to_pulse_clocks(ns);
+	*divider = pulse_clocks_to_clock_divider(pulse_clocks);
+	cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider);
+	return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
+}
+
+/*
+ * IR Tx Carrier Duty Cycle register helpers
+ */
+static unsigned int cduty_tx_s_duty_cycle(struct cx23885_dev *dev,
+					  unsigned int duty_cycle)
+{
+	u32 n;
+	n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */
+	if (n != 0)
+		n--;
+	if (n > 15)
+		n = 15;
+	cx23888_ir_write4(dev, CX23888_IR_CDUTY_REG, n);
+	return DIV_ROUND_CLOSEST((n + 1) * 100, 16);
+}
+
+/*
+ * IR Filter Register helpers
+ */
+static u32 filter_rx_s_min_width(struct cx23885_dev *dev, u32 min_width_ns)
+{
+	u32 count = ns_to_lpf_count(min_width_ns);
+	cx23888_ir_write4(dev, CX23888_IR_FILTR_REG, count);
+	return lpf_count_to_ns(count);
+}
+
+/*
+ * IR IRQ Enable Register helpers
+ */
+static inline void irqenable_rx(struct cx23885_dev *dev, u32 mask)
+{
+	mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE);
+	cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG,
+			   ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask);
+}
+
+static inline void irqenable_tx(struct cx23885_dev *dev, u32 mask)
+{
+	mask &= IRQEN_TSE;
+	cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, ~IRQEN_TSE, mask);
+}
+
+/*
+ * V4L2 Subdevice IR Ops
+ */
+static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
+				  bool *handled)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+
+	u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG);
+	u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG);
+	u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG);
+
+	u32 rx_data[FIFO_RX_DEPTH];
+	int i, j, k;
+	u32 events, v;
+	int tsr, rsr, rto, ror, tse, rse, rte, roe, kror;
+
+	tsr = stats & STATS_TSR; /* Tx FIFO Service Request */
+	rsr = stats & STATS_RSR; /* Rx FIFO Service Request */
+	rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */
+	ror = stats & STATS_ROR; /* Rx FIFO Over Run */
+
+	tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */
+	rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */
+	rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */
+	roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */
+
+	*handled = false;
+	v4l2_dbg(2, ir_888_debug, sd, "IRQ Status:  %s %s %s %s %s %s\n",
+		 tsr ? "tsr" : "   ", rsr ? "rsr" : "   ",
+		 rto ? "rto" : "   ", ror ? "ror" : "   ",
+		 stats & STATS_TBY ? "tby" : "   ",
+		 stats & STATS_RBY ? "rby" : "   ");
+
+	v4l2_dbg(2, ir_888_debug, sd, "IRQ Enables: %s %s %s %s\n",
+		 tse ? "tse" : "   ", rse ? "rse" : "   ",
+		 rte ? "rte" : "   ", roe ? "roe" : "   ");
+
+	/*
+	 * Transmitter interrupt service
+	 */
+	if (tse && tsr) {
+		/*
+		 * TODO:
+		 * Check the watermark threshold setting
+		 * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo
+		 * Push the data to the hardware FIFO.
+		 * If there was nothing more to send in the tx_kfifo, disable
+		 *	the TSR IRQ and notify the v4l2_device.
+		 * If there was something in the tx_kfifo, check the tx_kfifo
+		 *      level and notify the v4l2_device, if it is low.
+		 */
+		/* For now, inhibit TSR interrupt until Tx is implemented */
+		irqenable_tx(dev, 0);
+		events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events);
+		*handled = true;
+	}
+
+	/*
+	 * Receiver interrupt service
+	 */
+	kror = 0;
+	if ((rse && rsr) || (rte && rto)) {
+		/*
+		 * Receive data on RSR to clear the STATS_RSR.
+		 * Receive data on RTO, since we may not have yet hit the RSR
+		 * watermark when we receive the RTO.
+		 */
+		for (i = 0, v = FIFO_RX_NDV;
+		     (v & FIFO_RX_NDV) && !kror; i = 0) {
+			for (j = 0;
+			     (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) {
+				v = cx23888_ir_read4(dev, CX23888_IR_FIFO_REG);
+				rx_data[i++] = v & ~FIFO_RX_NDV;
+			}
+			if (i == 0)
+				break;
+			j = i * sizeof(u32);
+			k = kfifo_put(state->rx_kfifo,
+				      (unsigned char *) rx_data, j);
+			if (k != j)
+				kror++; /* rx_kfifo over run */
+		}
+		*handled = true;
+	}
+
+	events = 0;
+	v = 0;
+	if (kror) {
+		events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
+		v4l2_err(sd, "IR receiver software FIFO overrun\n");
+	}
+	if (roe && ror) {
+		/*
+		 * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear
+		 * the Rx FIFO Over Run status (STATS_ROR)
+		 */
+		v |= CNTRL_RFE;
+		events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
+		v4l2_err(sd, "IR receiver hardware FIFO overrun\n");
+	}
+	if (rte && rto) {
+		/*
+		 * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear
+		 * the Rx Pulse Width Timer Time Out (STATS_RTO)
+		 */
+		v |= CNTRL_RXE;
+		events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
+	}
+	if (v) {
+		/* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */
+		cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl & ~v);
+		cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl);
+		*handled = true;
+	}
+	if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2)
+		events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+
+	if (events)
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
+	return 0;
+}
+
+/* Receiver */
+static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
+			      ssize_t *num)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	bool invert = (bool) atomic_read(&state->rx_invert);
+	u16 divider = (u16) atomic_read(&state->rxclk_divider);
+
+	unsigned int i, n;
+	u32 *p;
+	u32 u, v;
+
+	n = count / sizeof(u32) * sizeof(u32);
+	if (n == 0) {
+		*num = 0;
+		return 0;
+	}
+
+	n = kfifo_get(state->rx_kfifo, buf, n);
+
+	n /= sizeof(u32);
+	*num = n * sizeof(u32);
+
+	for (p = (u32 *) buf, i = 0; i < n; p++, i++) {
+		if ((*p & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
+			*p = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END;
+			v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n");
+			continue;
+		}
+
+		u = (*p & FIFO_RXTX_LVL) ? V4L2_SUBDEV_IR_PULSE_LEVEL_MASK : 0;
+		if (invert)
+			u = u ? 0 : V4L2_SUBDEV_IR_PULSE_LEVEL_MASK;
+
+		v = (u32) pulse_width_count_to_ns((u16) (*p & FIFO_RXTX),
+						  divider);
+		if (v >= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
+			v = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS - 1;
+
+		*p = u | v;
+
+		v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns  %s\n",
+			 v, u ? "mark" : "space");
+	}
+	return 0;
+}
+
+static int cx23888_ir_rx_g_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	mutex_lock(&state->rx_params_lock);
+	memcpy(p, &state->rx_params, sizeof(struct v4l2_subdev_ir_parameters));
+	mutex_unlock(&state->rx_params_lock);
+	return 0;
+}
+
+static int cx23888_ir_rx_shutdown(struct v4l2_subdev *sd)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+
+	mutex_lock(&state->rx_params_lock);
+
+	/* Disable or slow down all IR Rx circuits and counters */
+	irqenable_rx(dev, 0);
+	control_rx_enable(dev, false);
+	control_rx_demodulation_enable(dev, false);
+	control_rx_s_edge_detection(dev, CNTRL_EDG_NONE);
+	filter_rx_s_min_width(dev, 0);
+	cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, RXCLK_RCD);
+
+	state->rx_params.shutdown = true;
+
+	mutex_unlock(&state->rx_params_lock);
+	return 0;
+}
+
+static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+	struct v4l2_subdev_ir_parameters *o = &state->rx_params;
+	u16 rxclk_divider;
+
+	if (p->shutdown)
+		return cx23888_ir_rx_shutdown(sd);
+
+	if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
+		return -ENOSYS;
+
+	mutex_lock(&state->rx_params_lock);
+
+	o->shutdown = p->shutdown;
+
+	o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+
+	o->bytes_per_data_element = p->bytes_per_data_element = sizeof(u32);
+
+	/* Before we tweak the hardware, we have to disable the receiver */
+	irqenable_rx(dev, 0);
+	control_rx_enable(dev, false);
+
+	control_rx_demodulation_enable(dev, p->modulation);
+	o->modulation = p->modulation;
+
+	if (p->modulation) {
+		p->carrier_freq = rxclk_rx_s_carrier(dev, p->carrier_freq,
+						     &rxclk_divider);
+
+		o->carrier_freq = p->carrier_freq;
+
+		o->duty_cycle = p->duty_cycle = 50;
+
+		control_rx_s_carrier_window(dev, p->carrier_freq,
+					    &p->carrier_range_lower,
+					    &p->carrier_range_upper);
+		o->carrier_range_lower = p->carrier_range_lower;
+		o->carrier_range_upper = p->carrier_range_upper;
+	} else {
+		p->max_pulse_width =
+			    rxclk_rx_s_max_pulse_width(dev, p->max_pulse_width,
+						       &rxclk_divider);
+		o->max_pulse_width = p->max_pulse_width;
+	}
+	atomic_set(&state->rxclk_divider, rxclk_divider);
+
+	p->noise_filter_min_width =
+			  filter_rx_s_min_width(dev, p->noise_filter_min_width);
+	o->noise_filter_min_width = p->noise_filter_min_width;
+
+	p->resolution = clock_divider_to_resolution(rxclk_divider);
+	o->resolution = p->resolution;
+
+	/* FIXME - make this dependent on resolution for better performance */
+	control_rx_irq_watermark(dev, RX_FIFO_HALF_FULL);
+
+	control_rx_s_edge_detection(dev, CNTRL_EDG_BOTH);
+
+	o->invert = p->invert;
+	atomic_set(&state->rx_invert, p->invert);
+
+	o->interrupt_enable = p->interrupt_enable;
+	o->enable = p->enable;
+	if (p->enable) {
+		kfifo_reset(state->rx_kfifo);
+		if (p->interrupt_enable)
+			irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
+		control_rx_enable(dev, p->enable);
+	}
+
+	mutex_unlock(&state->rx_params_lock);
+	return 0;
+}
+
+/* Transmitter */
+static int cx23888_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count,
+			       ssize_t *num)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+	/* For now enable the Tx FIFO Service interrupt & pretend we did work */
+	irqenable_tx(dev, IRQEN_TSE);
+	*num = count;
+	return 0;
+}
+
+static int cx23888_ir_tx_g_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	mutex_lock(&state->tx_params_lock);
+	memcpy(p, &state->tx_params, sizeof(struct v4l2_subdev_ir_parameters));
+	mutex_unlock(&state->tx_params_lock);
+	return 0;
+}
+
+static int cx23888_ir_tx_shutdown(struct v4l2_subdev *sd)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+
+	mutex_lock(&state->tx_params_lock);
+
+	/* Disable or slow down all IR Tx circuits and counters */
+	irqenable_tx(dev, 0);
+	control_tx_enable(dev, false);
+	control_tx_modulation_enable(dev, false);
+	cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, TXCLK_TCD);
+
+	state->tx_params.shutdown = true;
+
+	mutex_unlock(&state->tx_params_lock);
+	return 0;
+}
+
+static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_ir_parameters *p)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+	struct v4l2_subdev_ir_parameters *o = &state->tx_params;
+	u16 txclk_divider;
+
+	if (p->shutdown)
+		return cx23888_ir_tx_shutdown(sd);
+
+	if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
+		return -ENOSYS;
+
+	mutex_lock(&state->tx_params_lock);
+
+	o->shutdown = p->shutdown;
+
+	o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+
+	o->bytes_per_data_element = p->bytes_per_data_element = sizeof(u32);
+
+	/* Before we tweak the hardware, we have to disable the transmitter */
+	irqenable_tx(dev, 0);
+	control_tx_enable(dev, false);
+
+	control_tx_modulation_enable(dev, p->modulation);
+	o->modulation = p->modulation;
+
+	if (p->modulation) {
+		p->carrier_freq = txclk_tx_s_carrier(dev, p->carrier_freq,
+						     &txclk_divider);
+		o->carrier_freq = p->carrier_freq;
+
+		p->duty_cycle = cduty_tx_s_duty_cycle(dev, p->duty_cycle);
+		o->duty_cycle = p->duty_cycle;
+	} else {
+		p->max_pulse_width =
+			    txclk_tx_s_max_pulse_width(dev, p->max_pulse_width,
+						       &txclk_divider);
+		o->max_pulse_width = p->max_pulse_width;
+	}
+	atomic_set(&state->txclk_divider, txclk_divider);
+
+	p->resolution = clock_divider_to_resolution(txclk_divider);
+	o->resolution = p->resolution;
+
+	/* FIXME - make this dependent on resolution for better performance */
+	control_tx_irq_watermark(dev, TX_FIFO_HALF_EMPTY);
+
+	control_tx_polarity_invert(dev, p->invert);
+	o->invert = p->invert;
+
+	o->interrupt_enable = p->interrupt_enable;
+	o->enable = p->enable;
+	if (p->enable) {
+		kfifo_reset(state->tx_kfifo);
+		if (p->interrupt_enable)
+			irqenable_tx(dev, IRQEN_TSE);
+		control_tx_enable(dev, p->enable);
+	}
+
+	mutex_unlock(&state->tx_params_lock);
+	return 0;
+}
+
+
+/*
+ * V4L2 Subdevice Core Ops
+ */
+static int cx23888_ir_log_status(struct v4l2_subdev *sd)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	struct cx23885_dev *dev = state->dev;
+	char *s;
+	int i, j;
+
+	u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG);
+	u32 txclk = cx23888_ir_read4(dev, CX23888_IR_TXCLK_REG) & TXCLK_TCD;
+	u32 rxclk = cx23888_ir_read4(dev, CX23888_IR_RXCLK_REG) & RXCLK_RCD;
+	u32 cduty = cx23888_ir_read4(dev, CX23888_IR_CDUTY_REG) & CDUTY_CDC;
+	u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG);
+	u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG);
+	u32 filtr = cx23888_ir_read4(dev, CX23888_IR_FILTR_REG) & FILTR_LPF;
+
+	v4l2_info(sd, "IR Receiver:\n");
+	v4l2_info(sd, "\tEnabled:                           %s\n",
+		  cntrl & CNTRL_RXE ? "yes" : "no");
+	v4l2_info(sd, "\tDemodulation from a carrier:       %s\n",
+		  cntrl & CNTRL_DMD ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO:                              %s\n",
+		  cntrl & CNTRL_RFE ? "enabled" : "disabled");
+	switch (cntrl & CNTRL_EDG) {
+	case CNTRL_EDG_NONE:
+		s = "disabled";
+		break;
+	case CNTRL_EDG_FALL:
+		s = "falling edge";
+		break;
+	case CNTRL_EDG_RISE:
+		s = "rising edge";
+		break;
+	case CNTRL_EDG_BOTH:
+		s = "rising & falling edges";
+		break;
+	default:
+		s = "??? edge";
+		break;
+	}
+	v4l2_info(sd, "\tPulse timers' start/stop trigger:  %s\n", s);
+	v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n",
+		  cntrl & CNTRL_R ? "not loaded" : "overflow marker");
+	v4l2_info(sd, "\tFIFO interrupt watermark:          %s\n",
+		  cntrl & CNTRL_RIC ? "not empty" : "half full or greater");
+	v4l2_info(sd, "\tLoopback mode:                     %s\n",
+		  cntrl & CNTRL_LBM ? "loopback active" : "normal receive");
+	if (cntrl & CNTRL_DMD) {
+		v4l2_info(sd, "\tExpected carrier (16 clocks):      %u Hz\n",
+			  clock_divider_to_carrier_freq(rxclk));
+		switch (cntrl & CNTRL_WIN) {
+		case CNTRL_WIN_3_3:
+			i = 3;
+			j = 3;
+			break;
+		case CNTRL_WIN_4_3:
+			i = 4;
+			j = 3;
+			break;
+		case CNTRL_WIN_3_4:
+			i = 3;
+			j = 4;
+			break;
+		case CNTRL_WIN_4_4:
+			i = 4;
+			j = 4;
+			break;
+		default:
+			i = 0;
+			j = 0;
+			break;
+		}
+		v4l2_info(sd, "\tNext carrier edge window:          16 clocks "
+			  "-%1d/+%1d, %u to %u Hz\n", i, j,
+			  clock_divider_to_freq(rxclk, 16 + j),
+			  clock_divider_to_freq(rxclk, 16 - i));
+	} else {
+		v4l2_info(sd, "\tMax measurable pulse width:        %u us, "
+			  "%llu ns\n",
+			  pulse_width_count_to_us(FIFO_RXTX, rxclk),
+			  pulse_width_count_to_ns(FIFO_RXTX, rxclk));
+	}
+	v4l2_info(sd, "\tLow pass filter:                   %s\n",
+		  filtr ? "enabled" : "disabled");
+	if (filtr)
+		v4l2_info(sd, "\tMin acceptable pulse width (LPF):  %u us, "
+			  "%u ns\n",
+			  lpf_count_to_us(filtr),
+			  lpf_count_to_ns(filtr));
+	v4l2_info(sd, "\tPulse width timer timed-out:       %s\n",
+		  stats & STATS_RTO ? "yes" : "no");
+	v4l2_info(sd, "\tPulse width timer time-out intr:   %s\n",
+		  irqen & IRQEN_RTE ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO overrun:                      %s\n",
+		  stats & STATS_ROR ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO overrun interrupt:            %s\n",
+		  irqen & IRQEN_ROE ? "enabled" : "disabled");
+	v4l2_info(sd, "\tBusy:                              %s\n",
+		  stats & STATS_RBY ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service requested:            %s\n",
+		  stats & STATS_RSR ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service request interrupt:    %s\n",
+		  irqen & IRQEN_RSE ? "enabled" : "disabled");
+
+	v4l2_info(sd, "IR Transmitter:\n");
+	v4l2_info(sd, "\tEnabled:                           %s\n",
+		  cntrl & CNTRL_TXE ? "yes" : "no");
+	v4l2_info(sd, "\tModulation onto a carrier:         %s\n",
+		  cntrl & CNTRL_MOD ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO:                              %s\n",
+		  cntrl & CNTRL_TFE ? "enabled" : "disabled");
+	v4l2_info(sd, "\tFIFO interrupt watermark:          %s\n",
+		  cntrl & CNTRL_TIC ? "not empty" : "half full or less");
+	v4l2_info(sd, "\tSignal polarity:                   %s\n",
+		  cntrl & CNTRL_CPL ? "0:mark 1:space" : "0:space 1:mark");
+	if (cntrl & CNTRL_MOD) {
+		v4l2_info(sd, "\tCarrier (16 clocks):               %u Hz\n",
+			  clock_divider_to_carrier_freq(txclk));
+		v4l2_info(sd, "\tCarrier duty cycle:                %2u/16\n",
+			  cduty + 1);
+	} else {
+		v4l2_info(sd, "\tMax pulse width:                   %u us, "
+			  "%llu ns\n",
+			  pulse_width_count_to_us(FIFO_RXTX, txclk),
+			  pulse_width_count_to_ns(FIFO_RXTX, txclk));
+	}
+	v4l2_info(sd, "\tBusy:                              %s\n",
+		  stats & STATS_TBY ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service requested:            %s\n",
+		  stats & STATS_TSR ? "yes" : "no");
+	v4l2_info(sd, "\tFIFO service request interrupt:    %s\n",
+		  irqen & IRQEN_TSE ? "enabled" : "disabled");
+
+	return 0;
+}
+
+static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match)
+{
+	return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2;
+}
+
+static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd,
+				   struct v4l2_dbg_chip_ident *chip)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+
+	if (cx23888_ir_dbg_match(&chip->match)) {
+		chip->ident = state->id;
+		chip->revision = state->rev;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cx23888_ir_g_register(struct v4l2_subdev *sd,
+				 struct v4l2_dbg_register *reg)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
+
+	if (!cx23888_ir_dbg_match(&reg->match))
+		return -EINVAL;
+	if ((addr & 0x3) != 0)
+		return -EINVAL;
+	if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->size = 4;
+	reg->val = cx23888_ir_read4(state->dev, addr);
+	return 0;
+}
+
+static int cx23888_ir_s_register(struct v4l2_subdev *sd,
+				 struct v4l2_dbg_register *reg)
+{
+	struct cx23888_ir_state *state = to_state(sd);
+	u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
+
+	if (!cx23888_ir_dbg_match(&reg->match))
+		return -EINVAL;
+	if ((addr & 0x3) != 0)
+		return -EINVAL;
+	if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	cx23888_ir_write4(state->dev, addr, reg->val);
+	return 0;
+}
+#endif
+
+static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = {
+	.g_chip_ident = cx23888_ir_g_chip_ident,
+	.log_status = cx23888_ir_log_status,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = cx23888_ir_g_register,
+	.s_register = cx23888_ir_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = {
+	.interrupt_service_routine = cx23888_ir_irq_handler,
+
+	.rx_read = cx23888_ir_rx_read,
+	.rx_g_parameters = cx23888_ir_rx_g_parameters,
+	.rx_s_parameters = cx23888_ir_rx_s_parameters,
+
+	.tx_write = cx23888_ir_tx_write,
+	.tx_g_parameters = cx23888_ir_tx_g_parameters,
+	.tx_s_parameters = cx23888_ir_tx_s_parameters,
+};
+
+static const struct v4l2_subdev_ops cx23888_ir_controller_ops = {
+	.core = &cx23888_ir_core_ops,
+	.ir = &cx23888_ir_ir_ops,
+};
+
+static const struct v4l2_subdev_ir_parameters default_rx_params = {
+	.bytes_per_data_element = sizeof(u32),
+	.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
+
+	.enable = false,
+	.interrupt_enable = false,
+	.shutdown = true,
+
+	.modulation = true,
+	.carrier_freq = 36000, /* 36 kHz - RC-5, RC-6, and RC-6A carrier */
+
+	/* RC-5:    666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
+	/* RC-6A:   333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
+	.noise_filter_min_width = 333333, /* ns */
+	.carrier_range_lower = 35000,
+	.carrier_range_upper = 37000,
+	.invert = false,
+};
+
+static const struct v4l2_subdev_ir_parameters default_tx_params = {
+	.bytes_per_data_element = sizeof(u32),
+	.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
+
+	.enable = false,
+	.interrupt_enable = false,
+	.shutdown = true,
+
+	.modulation = true,
+	.carrier_freq = 36000, /* 36 kHz - RC-5 carrier */
+	.duty_cycle = 25,      /* 25 %   - RC-5 carrier */
+	.invert = false,
+};
+
+int cx23888_ir_probe(struct cx23885_dev *dev)
+{
+	struct cx23888_ir_state *state;
+	struct v4l2_subdev *sd;
+	struct v4l2_subdev_ir_parameters default_params;
+	int ret;
+
+	state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&state->rx_kfifo_lock);
+	state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL,
+				      &state->rx_kfifo_lock);
+	if (state->rx_kfifo == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&state->tx_kfifo_lock);
+	state->tx_kfifo = kfifo_alloc(CX23888_IR_TX_KFIFO_SIZE, GFP_KERNEL,
+				      &state->tx_kfifo_lock);
+	if (state->tx_kfifo == NULL) {
+		kfifo_free(state->rx_kfifo);
+		return -ENOMEM;
+	}
+
+	state->dev = dev;
+	state->id = V4L2_IDENT_CX23888_IR;
+	state->rev = 0;
+	sd = &state->sd;
+
+	v4l2_subdev_init(sd, &cx23888_ir_controller_ops);
+	v4l2_set_subdevdata(sd, state);
+	/* FIXME - fix the formatting of dev->v4l2_dev.name and use it */
+	snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name);
+	sd->grp_id = CX23885_HW_888_IR;
+
+	ret = v4l2_device_register_subdev(&dev->v4l2_dev, sd);
+	if (ret == 0) {
+		/*
+		 * Ensure no interrupts arrive from '888 specific conditions,
+		 * since we ignore them in this driver to have commonality with
+		 * similar IR controller cores.
+		 */
+		cx23888_ir_write4(dev, CX23888_IR_IRQEN_REG, 0);
+
+		mutex_init(&state->rx_params_lock);
+		memcpy(&default_params, &default_rx_params,
+		       sizeof(struct v4l2_subdev_ir_parameters));
+		v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params);
+
+		mutex_init(&state->tx_params_lock);
+		memcpy(&default_params, &default_tx_params,
+		       sizeof(struct v4l2_subdev_ir_parameters));
+		v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
+	} else {
+		kfifo_free(state->rx_kfifo);
+		kfifo_free(state->tx_kfifo);
+	}
+	return ret;
+}
+
+int cx23888_ir_remove(struct cx23885_dev *dev)
+{
+	struct v4l2_subdev *sd;
+	struct cx23888_ir_state *state;
+
+	sd = cx23885_find_hw(dev, CX23885_HW_888_IR);
+	if (sd == NULL)
+		return -ENODEV;
+
+	cx23888_ir_rx_shutdown(sd);
+	cx23888_ir_tx_shutdown(sd);
+
+	state = to_state(sd);
+	v4l2_device_unregister_subdev(sd);
+	kfifo_free(state->rx_kfifo);
+	kfifo_free(state->tx_kfifo);
+	kfree(state);
+	/* Nothing more to free() as state held the actual v4l2_subdev object */
+	return 0;
+}
diff --git a/drivers/media/video/cx23885/cx23888-ir.h b/drivers/media/video/cx23885/cx23888-ir.h
new file mode 100644
index 000000000000..3d446f9eb94b
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23888-ir.h
@@ -0,0 +1,28 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  CX23888 Integrated Consumer Infrared Controller
+ *
+ *  Copyright (C) 2009  Andy Walls <awalls@radix.net>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _CX23888_IR_H_
+#define _CX23888_IR_H_
+int cx23888_ir_probe(struct cx23885_dev *dev);
+int cx23888_ir_remove(struct cx23885_dev *dev);
+#endif
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 2f846f5e0f9f..45608d50529c 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -23,87 +23,137 @@
 
 #include "cx25840-core.h"
 
-static int set_audclk_freq(struct i2c_client *client, u32 freq)
+/*
+ * Note: The PLL and SRC parameters are based on a reference frequency that
+ * would ideally be:
+ *
+ * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+ *
+ * However, it's not the exact reference frequency that matters, only that the
+ * firmware and modules that comprise the driver for a particular board all
+ * use the same value (close to the ideal value).
+ *
+ * Comments below will note which reference frequency is assumed for various
+ * parameters.  They will usually be one of
+ *
+ *	ref_freq = 28.636360 MHz
+ *		or
+ *	ref_freq = 28.636363 MHz
+ */
+
+static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq)
 {
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 
-	if (freq != 32000 && freq != 44100 && freq != 48000)
-		return -EINVAL;
-
-	/* common for all inputs and rates */
-	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
-	if (!state->is_cx23885 && !state->is_cx231xx)
-		cx25840_write(client, 0x127, 0x50);
-
 	if (state->aud_input != CX25840_AUDIO_SERIAL) {
 		switch (freq) {
 		case 32000:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
-				break;
-			}
-
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x1006040f);
-
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x01bb39ee);
-			}
-
-			if (state->is_cx25836)
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10
+			 */
+			cx25840_write4(client, 0x108, 0x1006040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x1bb39ee
+			 * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384
+			 * 196.6 MHz pre-postdivide
+			 * FIXME < 200 MHz is out of specified valid range
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x01bb39ee);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
 				break;
 
-			/* src3/4/6_ctl = 0x0801f77f */
+			/* src3/4/6_ctl */
+			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
 			cx25840_write4(client, 0x900, 0x0801f77f);
 			cx25840_write4(client, 0x904, 0x0801f77f);
 			cx25840_write4(client, 0x90c, 0x0801f77f);
 			break;
 
 		case 44100:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10
+			 */
+			cx25840_write4(client, 0x108, 0x1009040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x0ec6bd6
+			 * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384
+			 * 271 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x00ec6bd6);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
 				break;
-			}
-
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x1009040f);
-
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x00ec6bd6);
-			}
 
-			if (state->is_cx25836)
-				break;
-
-			/* src3/4/6_ctl = 0x08016d59 */
+			/* src3/4/6_ctl */
+			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
 			cx25840_write4(client, 0x900, 0x08016d59);
 			cx25840_write4(client, 0x904, 0x08016d59);
 			cx25840_write4(client, 0x90c, 0x08016d59);
 			break;
 
 		case 48000:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
-				break;
-			}
-
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x100a040f);
-
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x0098d6e5);
-			}
-
-			if (state->is_cx25836)
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10
+			 */
+			cx25840_write4(client, 0x108, 0x100a040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x098d6e5
+			 * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384
+			 * 295 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x0098d6e5);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
 				break;
 
-			/* src3/4/6_ctl = 0x08014faa */
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
 			cx25840_write4(client, 0x900, 0x08014faa);
 			cx25840_write4(client, 0x904, 0x08014faa);
 			cx25840_write4(client, 0x90c, 0x08014faa);
@@ -112,91 +162,249 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
 	} else {
 		switch (freq) {
 		case 32000:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
-				break;
-			}
-
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x1e08040f);
-
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x012a0869);
-			}
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e
+			 */
+			cx25840_write4(client, 0x108, 0x1e08040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x12a0869
+			 * 28636363 * 0x8.9504348/0x1e = 32000 * 256
+			 * 246 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x012a0869);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x54);
 
-			if (state->is_cx25836)
+			if (is_cx2583x(state))
 				break;
 
-			/* src1_ctl = 0x08010000 */
+			/* src1_ctl */
+			/* 0x1.0000 = 32000/32000 */
 			cx25840_write4(client, 0x8f8, 0x08010000);
 
-			/* src3/4/6_ctl = 0x08020000 */
+			/* src3/4/6_ctl */
+			/* 0x2.0000 = 2 * (32000/32000) */
 			cx25840_write4(client, 0x900, 0x08020000);
 			cx25840_write4(client, 0x904, 0x08020000);
 			cx25840_write4(client, 0x90c, 0x08020000);
-
-			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
-			cx25840_write(client, 0x127, 0x54);
 			break;
 
 		case 44100:
-			if (state->is_cx23885) {
-				/* We don't have register values
-				 * so avoid destroying registers. */
-				break;
-			}
-
-
-			if (!state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x1809040f);
-
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x00ec6bd6);
-			}
-
-			if (state->is_cx25836)
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18
+			 */
+			cx25840_write4(client, 0x108, 0x1809040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x0ec6bd6
+			 * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256
+			 * 271 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x00ec6bd6);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
 				break;
 
-			/* src1_ctl = 0x08010000 */
+			/* src1_ctl */
+			/* 0x1.60cd = 44100/32000 */
 			cx25840_write4(client, 0x8f8, 0x080160cd);
 
-			/* src3/4/6_ctl = 0x08020000 */
+			/* src3/4/6_ctl */
+			/* 0x1.7385 = 2 * (32000/44100) */
 			cx25840_write4(client, 0x900, 0x08017385);
 			cx25840_write4(client, 0x904, 0x08017385);
 			cx25840_write4(client, 0x90c, 0x08017385);
 			break;
 
 		case 48000:
-			if (!state->is_cx23885 && !state->is_cx231xx) {
-				/* VID_PLL and AUX_PLL */
-				cx25840_write4(client, 0x108, 0x180a040f);
+			/*
+			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18
+			 */
+			cx25840_write4(client, 0x108, 0x180a040f);
+
+			/*
+			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
+			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
+			 * 432 MHz pre-postdivide
+			 */
+
+			/*
+			 * AUX_PLL Fraction = 0x098d6e5
+			 * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256
+			 * 295 MHz pre-postdivide
+			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
+			 */
+			cx25840_write4(client, 0x110, 0x0098d6e5);
+
+			/*
+			 * SA_MCLK_SEL = 1
+			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
+			 */
+			cx25840_write(client, 0x127, 0x50);
+
+			if (is_cx2583x(state))
+				break;
 
-				/* AUX_PLL_FRAC */
-				cx25840_write4(client, 0x110, 0x0098d6e5);
-			}
+			/* src1_ctl */
+			/* 0x1.8000 = 48000/32000 */
+			cx25840_write4(client, 0x8f8, 0x08018000);
 
-			if (state->is_cx25836)
-				break;
+			/* src3/4/6_ctl */
+			/* 0x1.5555 = 2 * (32000/48000) */
+			cx25840_write4(client, 0x900, 0x08015555);
+			cx25840_write4(client, 0x904, 0x08015555);
+			cx25840_write4(client, 0x90c, 0x08015555);
+			break;
+		}
+	}
+
+	state->audclk_freq = freq;
+
+	return 0;
+}
+
+static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	return cx25840_set_audclk_freq(client, freq);
+}
+
+static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
+		switch (freq) {
+		case 32000:
+		case 44100:
+		case 48000:
+			/* We don't have register values
+			 * so avoid destroying registers. */
+			/* FIXME return -EINVAL; */
+			break;
+		}
+	} else {
+		switch (freq) {
+		case 32000:
+		case 44100:
+			/* We don't have register values
+			 * so avoid destroying registers. */
+			/* FIXME return -EINVAL; */
+			break;
+
+		case 48000:
+			/* src1_ctl */
+			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
+			cx25840_write4(client, 0x8f8, 0x0801867c);
+
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
+			break;
+		}
+	}
+
+	state->audclk_freq = freq;
+
+	return 0;
+}
+
+static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
+		switch (freq) {
+		case 32000:
+			/* src3/4/6_ctl */
+			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
+			cx25840_write4(client, 0x900, 0x0801f77f);
+			cx25840_write4(client, 0x904, 0x0801f77f);
+			cx25840_write4(client, 0x90c, 0x0801f77f);
+			break;
+
+		case 44100:
+			/* src3/4/6_ctl */
+			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
+			cx25840_write4(client, 0x900, 0x08016d59);
+			cx25840_write4(client, 0x904, 0x08016d59);
+			cx25840_write4(client, 0x90c, 0x08016d59);
+			break;
+
+		case 48000:
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
+			break;
+		}
+	} else {
+		switch (freq) {
+		/* FIXME These cases make different assumptions about audclk */
+		case 32000:
+			/* src1_ctl */
+			/* 0x1.0000 = 32000/32000 */
+			cx25840_write4(client, 0x8f8, 0x08010000);
 
-			if (!state->is_cx23885 && !state->is_cx231xx) {
-				/* src1_ctl */
-				cx25840_write4(client, 0x8f8, 0x08018000);
+			/* src3/4/6_ctl */
+			/* 0x2.0000 = 2 * (32000/32000) */
+			cx25840_write4(client, 0x900, 0x08020000);
+			cx25840_write4(client, 0x904, 0x08020000);
+			cx25840_write4(client, 0x90c, 0x08020000);
+			break;
 
-				/* src3/4/6_ctl */
-				cx25840_write4(client, 0x900, 0x08015555);
-				cx25840_write4(client, 0x904, 0x08015555);
-				cx25840_write4(client, 0x90c, 0x08015555);
-			} else {
+		case 44100:
+			/* src1_ctl */
+			/* 0x1.60cd = 44100/32000 */
+			cx25840_write4(client, 0x8f8, 0x080160cd);
 
-				cx25840_write4(client, 0x8f8, 0x0801867c);
+			/* src3/4/6_ctl */
+			/* 0x1.7385 = 2 * (32000/44100) */
+			cx25840_write4(client, 0x900, 0x08017385);
+			cx25840_write4(client, 0x904, 0x08017385);
+			cx25840_write4(client, 0x90c, 0x08017385);
+			break;
 
-				cx25840_write4(client, 0x900, 0x08014faa);
-				cx25840_write4(client, 0x904, 0x08014faa);
-				cx25840_write4(client, 0x90c, 0x08014faa);
-			}
+		case 48000:
+			/* src1_ctl */
+			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
+			cx25840_write4(client, 0x8f8, 0x0801867c);
+
+			/* src3/4/6_ctl */
+			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
 			break;
 		}
 	}
@@ -206,6 +414,25 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
 	return 0;
 }
 
+static int set_audclk_freq(struct i2c_client *client, u32 freq)
+{
+	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+	if (freq != 32000 && freq != 44100 && freq != 48000)
+		return -EINVAL;
+
+	if (is_cx231xx(state))
+		return cx231xx_set_audclk_freq(client, freq);
+
+	if (is_cx2388x(state))
+		return cx23885_set_audclk_freq(client, freq);
+
+	if (is_cx2583x(state))
+		return cx25836_set_audclk_freq(client, freq);
+
+	return cx25840_set_audclk_freq(client, freq);
+}
+
 void cx25840_audio_set_path(struct i2c_client *client)
 {
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
@@ -243,7 +470,7 @@ void cx25840_audio_set_path(struct i2c_client *client)
 	cx25840_and_or(client, 0x810, ~0x1, 0x00);
 
 	/* Ensure the controller is running when we exit */
-	if (state->is_cx23885 || state->is_cx231xx)
+	if (is_cx2388x(state) || is_cx231xx(state))
 		cx25840_and_or(client, 0x803, ~0x10, 0x10);
 }
 
@@ -383,7 +610,7 @@ int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 	struct cx25840_state *state = to_state(sd);
 	int retval;
 
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		cx25840_and_or(client, 0x810, ~0x1, 1);
 	if (state->aud_input != CX25840_AUDIO_SERIAL) {
 		cx25840_and_or(client, 0x803, ~0x10, 0);
@@ -392,7 +619,7 @@ int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 	retval = set_audclk_freq(client, freq);
 	if (state->aud_input != CX25840_AUDIO_SERIAL)
 		cx25840_and_or(client, 0x803, ~0x10, 0x10);
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		cx25840_and_or(client, 0x810, ~0x1, 0);
 	return retval;
 }
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 1aeaf18a9bea..385ecd58f1c0 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -259,6 +259,13 @@ static void cx23885_initialize(struct i2c_client *client)
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 	struct workqueue_struct *q;
 
+	/*
+	 * Come out of digital power down
+	 * The CX23888, at least, needs this, otherwise registers aside from
+	 * 0x0-0x2 can't be read or written.
+	 */
+	cx25840_write(client, 0x000, 0);
+
 	/* Internal Reset */
 	cx25840_and_or(client, 0x102, ~0x01, 0x01);
 	cx25840_and_or(client, 0x102, ~0x01, 0x00);
@@ -269,18 +276,45 @@ static void cx23885_initialize(struct i2c_client *client)
 	/* DIF in reset? */
 	cx25840_write(client, 0x398, 0);
 
-	/* Trust the default xtal, no division */
-	/* This changes for the cx23888 products */
+	/*
+	 * Trust the default xtal, no division
+	 * '885: 28.636363... MHz
+	 * '887: 25.000000 MHz
+	 * '888: 50.000000 MHz
+	 */
 	cx25840_write(client, 0x2, 0x76);
 
-	/* Bring down the regulator for AUX clk */
+	/* Power up all the PLL's and DLL */
 	cx25840_write(client, 0x1, 0x40);
 
-	/* Sys PLL frac */
-	cx25840_write4(client, 0x11c, 0x01d1744c);
-
-	/* Sys PLL int */
-	cx25840_write4(client, 0x118, 0x00000416);
+	/* Sys PLL */
+	switch (state->id) {
+	case V4L2_IDENT_CX23888_AV:
+		/*
+		 * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
+		 * 572.73 MHz before post divide
+		 */
+		cx25840_write4(client, 0x11c, 0x00e8ba26);
+		cx25840_write4(client, 0x118, 0x0000040b);
+		break;
+	case V4L2_IDENT_CX23887_AV:
+		/*
+		 * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz
+		 * 572.73 MHz before post divide
+		 */
+		cx25840_write4(client, 0x11c, 0x01d1744c);
+		cx25840_write4(client, 0x118, 0x00000416);
+		break;
+	case V4L2_IDENT_CX23885_AV:
+	default:
+		/*
+		 * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz
+		 * 572.73 MHz before post divide
+		 */
+		cx25840_write4(client, 0x11c, 0x00000000);
+		cx25840_write4(client, 0x118, 0x00000414);
+		break;
+	}
 
 	/* Disable DIF bypass */
 	cx25840_write4(client, 0x33c, 0x00000001);
@@ -288,11 +322,15 @@ static void cx23885_initialize(struct i2c_client *client)
 	/* DIF Src phase inc */
 	cx25840_write4(client, 0x340, 0x0df7df83);
 
-	/* Vid PLL frac */
-	cx25840_write4(client, 0x10c, 0x01b6db7b);
-
-	/* Vid PLL int */
-	cx25840_write4(client, 0x108, 0x00000512);
+	/*
+	 * Vid PLL
+	 * Setup for a BT.656 pixel clock of 13.5 Mpixels/second
+	 *
+	 * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz
+	 * 432.0 MHz before post divide
+	 */
+	cx25840_write4(client, 0x10c, 0x002be2c9);
+	cx25840_write4(client, 0x108, 0x0000040f);
 
 	/* Luma */
 	cx25840_write4(client, 0x414, 0x00107d12);
@@ -300,11 +338,43 @@ static void cx23885_initialize(struct i2c_client *client)
 	/* Chroma */
 	cx25840_write4(client, 0x420, 0x3d008282);
 
-	/* Aux PLL frac */
-	cx25840_write4(client, 0x114, 0x017dbf48);
-
-	/* Aux PLL int */
-	cx25840_write4(client, 0x110, 0x000a030e);
+	/*
+	 * Aux PLL
+	 * Initial setup for audio sample clock:
+	 * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz
+	 * Intial I2S output/master clock(?):
+	 * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz
+	 */
+	switch (state->id) {
+	case V4L2_IDENT_CX23888_AV:
+		/*
+		 * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz
+		 * 368.64 MHz before post divide
+		 * 122.88 MHz / 0xa = 12.288 MHz
+		 */
+		cx25840_write4(client, 0x114, 0x00bedfa4);
+		cx25840_write4(client, 0x110, 0x000a0307);
+		break;
+	case V4L2_IDENT_CX23887_AV:
+		/*
+		 * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz
+		 * 368.64 MHz before post divide
+		 * 122.88 MHz / 0xa = 12.288 MHz
+		 */
+		cx25840_write4(client, 0x114, 0x017dbf48);
+		cx25840_write4(client, 0x110, 0x000a030e);
+		break;
+	case V4L2_IDENT_CX23885_AV:
+	default:
+		/*
+		 * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz
+		 * 368.64 MHz before post divide
+		 * 122.88 MHz / 0xa = 12.288 MHz
+		 */
+		cx25840_write4(client, 0x114, 0x01bf0c9e);
+		cx25840_write4(client, 0x110, 0x000a030c);
+		break;
+	};
 
 	/* ADC2 input select */
 	cx25840_write(client, 0x102, 0x10);
@@ -494,7 +564,7 @@ void cx25840_std_setup(struct i2c_client *client)
 	}
 
 	/* DEBUG: Displays configured PLL frequency */
-	if (!state->is_cx231xx) {
+	if (!is_cx231xx(state)) {
 		pll_int = cx25840_read(client, 0x108);
 		pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
 		pll_post = cx25840_read(client, 0x109);
@@ -615,13 +685,30 @@ static void input_change(struct i2c_client *client)
 		}
 		cx25840_write(client, 0x80b, 0x00);
 	} else if (std & V4L2_STD_PAL) {
-		/* Follow tuner change procedure for PAL */
+		/* Autodetect audio standard and audio system */
 		cx25840_write(client, 0x808, 0xff);
-		cx25840_write(client, 0x80b, 0x10);
+		/* Since system PAL-L is pretty much non-existant and
+		   not used by any public broadcast network, force
+		   6.5 MHz carrier to be interpreted as System DK,
+		   this avoids DK audio detection instability */
+	       cx25840_write(client, 0x80b, 0x00);
 	} else if (std & V4L2_STD_SECAM) {
-		/* Select autodetect for SECAM */
+		/* Autodetect audio standard and audio system */
 		cx25840_write(client, 0x808, 0xff);
-		cx25840_write(client, 0x80b, 0x10);
+		/* If only one of SECAM-DK / SECAM-L is required, then force
+		  6.5MHz carrier, else autodetect it */
+		if ((std & V4L2_STD_SECAM_DK) &&
+		    !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
+			/* 6.5 MHz carrier to be interpreted as System DK */
+			cx25840_write(client, 0x80b, 0x00);
+	       } else if (!(std & V4L2_STD_SECAM_DK) &&
+			  (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
+			/* 6.5 MHz carrier to be interpreted as System L */
+			cx25840_write(client, 0x80b, 0x08);
+	       } else {
+			/* 6.5 MHz carrier to be autodetected */
+			cx25840_write(client, 0x80b, 0x10);
+	       }
 	}
 
 	cx25840_and_or(client, 0x810, ~0x01, 0);
@@ -633,6 +720,10 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 	u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
 			   vid_input <= CX25840_COMPOSITE8);
+	u8 is_component = (vid_input & CX25840_COMPONENT_ON) ==
+			CX25840_COMPONENT_ON;
+	int luma = vid_input & 0xf0;
+	int chroma = vid_input & 0xf00;
 	u8 reg;
 
 	v4l_dbg(1, cx25840_debug, client,
@@ -645,18 +736,14 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 		reg = vid_input & 0xff;
 		if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON)
 			is_composite = 0;
-		else
+		else if ((vid_input & CX25840_COMPONENT_ON) == 0)
 			is_composite = 1;
 
 		v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
 			reg, is_composite);
-	} else
-	if (is_composite) {
+	} else if (is_composite) {
 		reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
 	} else {
-		int luma = vid_input & 0xf0;
-		int chroma = vid_input & 0xf00;
-
 		if ((vid_input & ~0xff0) ||
 		    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 ||
 		    chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
@@ -678,7 +765,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 	 * configuration in reg (for the cx23885) so we have no
 	 * need to attempt to flip bits for earlier av decoders.
 	 */
-	if (!state->is_cx23885 && !state->is_cx231xx) {
+	if (!is_cx2388x(state) && !is_cx231xx(state)) {
 		switch (aud_input) {
 		case CX25840_AUDIO_SERIAL:
 			/* do nothing, use serial audio input */
@@ -698,10 +785,13 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 
 	cx25840_write(client, 0x103, reg);
 
-	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
-	cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
+	/* Set INPUT_MODE to Composite, S-Video or Component */
+	if (is_component)
+		cx25840_and_or(client, 0x401, ~0x6, 0x6);
+	else
+		cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
 
-	if (!state->is_cx23885 && !state->is_cx231xx) {
+	if (!is_cx2388x(state) && !is_cx231xx(state)) {
 		/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
 		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
 		/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
@@ -710,22 +800,31 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 		else
 			cx25840_and_or(client, 0x102, ~0x4, 0);
 	} else {
-		if (is_composite)
+		/* Set DUAL_MODE_ADC2 to 1 if component*/
+		cx25840_and_or(client, 0x102, ~0x4, is_component ? 0x4 : 0x0);
+		if (is_composite) {
 			/* ADC2 input select channel 2 */
 			cx25840_and_or(client, 0x102, ~0x2, 0);
-		else
-			/* ADC2 input select channel 3 */
-			cx25840_and_or(client, 0x102, ~0x2, 2);
+		} else if (!is_component) {
+			/* S-Video */
+			if (chroma >= CX25840_SVIDEO_CHROMA7) {
+				/* ADC2 input select channel 3 */
+				cx25840_and_or(client, 0x102, ~0x2, 2);
+			} else {
+				/* ADC2 input select channel 2 */
+				cx25840_and_or(client, 0x102, ~0x2, 0);
+			}
+		}
 	}
 
 	state->vid_input = vid_input;
 	state->aud_input = aud_input;
-	if (!state->is_cx25836) {
+	if (!is_cx2583x(state)) {
 		cx25840_audio_set_path(client);
 		input_change(client);
 	}
 
-	if (state->is_cx23885) {
+	if (is_cx2388x(state)) {
 		/* Audio channel 1 src : Parallel 1 */
 		cx25840_write(client, 0x124, 0x03);
 
@@ -741,7 +840,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 		 */
 		cx25840_write(client, 0x918, 0xa0);
 		cx25840_write(client, 0x919, 0x01);
-	} else if (state->is_cx231xx) {
+	} else if (is_cx231xx(state)) {
 		/* Audio channel 1 src : Parallel 1 */
 		cx25840_write(client, 0x124, 0x03);
 
@@ -805,7 +904,7 @@ static int set_v4lstd(struct i2c_client *client)
 	cx25840_and_or(client, 0x400, ~0xf, fmt);
 	cx25840_and_or(client, 0x403, ~0x3, pal_m);
 	cx25840_std_setup(client);
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		input_change(client);
 	return 0;
 }
@@ -868,7 +967,7 @@ static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 	case V4L2_CID_AUDIO_TREBLE:
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_MUTE:
-		if (state->is_cx25836)
+		if (is_cx2583x(state))
 			return -EINVAL;
 		return cx25840_audio_s_ctrl(sd, ctrl);
 
@@ -905,7 +1004,7 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 	case V4L2_CID_AUDIO_TREBLE:
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_MUTE:
-		if (state->is_cx25836)
+		if (is_cx2583x(state))
 			return -EINVAL;
 		return cx25840_audio_g_ctrl(sd, ctrl);
 	default:
@@ -1209,11 +1308,11 @@ static int cx25840_load_fw(struct v4l2_subdev *sd)
 	if (!state->is_initialized) {
 		/* initialize and load firmware */
 		state->is_initialized = 1;
-		if (state->is_cx25836)
+		if (is_cx2583x(state))
 			cx25836_initialize(client);
-		else if (state->is_cx23885)
+		else if (is_cx2388x(state))
 			cx23885_initialize(client);
-		else if (state->is_cx231xx)
+		else if (is_cx231xx(state))
 			cx231xx_initialize(client);
 		else
 			cx25840_initialize(client);
@@ -1256,17 +1355,17 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
 	v4l_dbg(1, cx25840_debug, client, "%s output\n",
 			enable ? "enable" : "disable");
 	if (enable) {
-		if (state->is_cx23885 || state->is_cx231xx) {
+		if (is_cx2388x(state) || is_cx231xx(state)) {
 			u8 v = (cx25840_read(client, 0x421) | 0x0b);
 			cx25840_write(client, 0x421, v);
 		} else {
 			cx25840_write(client, 0x115,
-					state->is_cx25836 ? 0x0c : 0x8c);
+					is_cx2583x(state) ? 0x0c : 0x8c);
 			cx25840_write(client, 0x116,
-					state->is_cx25836 ? 0x04 : 0x07);
+					is_cx2583x(state) ? 0x04 : 0x07);
 		}
 	} else {
-		if (state->is_cx23885 || state->is_cx231xx) {
+		if (is_cx2388x(state) || is_cx231xx(state)) {
 			u8 v = cx25840_read(client, 0x421) & ~(0x0b);
 			cx25840_write(client, 0x421, v);
 		} else {
@@ -1292,7 +1391,7 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 	default:
 		break;
 	}
-	if (state->is_cx25836)
+	if (is_cx2583x(state))
 		return -EINVAL;
 
 	switch (qc->id) {
@@ -1346,7 +1445,7 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
 	struct cx25840_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-	if (state->is_cx25836)
+	if (is_cx2583x(state))
 		return -EINVAL;
 	return set_input(client, state->vid_input, input);
 }
@@ -1356,7 +1455,7 @@ static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fr
 	struct cx25840_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		input_change(client);
 	return 0;
 }
@@ -1373,7 +1472,7 @@ static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 		return 0;
 
 	vt->signal = vpres ? 0xffff : 0x0;
-	if (state->is_cx25836)
+	if (is_cx2583x(state))
 		return 0;
 
 	vt->capability |=
@@ -1404,7 +1503,7 @@ static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 	struct cx25840_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-	if (state->radio || state->is_cx25836)
+	if (state->radio || is_cx2583x(state))
 		return 0;
 
 	switch (vt->audmode) {
@@ -1445,11 +1544,11 @@ static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
 	struct cx25840_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-	if (state->is_cx25836)
+	if (is_cx2583x(state))
 		cx25836_initialize(client);
-	else if (state->is_cx23885)
+	else if (is_cx2388x(state))
 		cx23885_initialize(client);
-	else if (state->is_cx231xx)
+	else if (is_cx231xx(state))
 		cx231xx_initialize(client);
 	else
 		cx25840_initialize(client);
@@ -1470,7 +1569,7 @@ static int cx25840_log_status(struct v4l2_subdev *sd)
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
 	log_video_status(client);
-	if (!state->is_cx25836)
+	if (!is_cx2583x(state))
 		log_audio_status(client);
 	return 0;
 }
@@ -1521,12 +1620,50 @@ static const struct v4l2_subdev_ops cx25840_ops = {
 
 /* ----------------------------------------------------------------------- */
 
+static u32 get_cx2388x_ident(struct i2c_client *client)
+{
+	u32 ret;
+
+	/* Come out of digital power down */
+	cx25840_write(client, 0x000, 0);
+
+	/* Detecting whether the part is cx23885/7/8 is more
+	 * difficult than it needs to be. No ID register. Instead we
+	 * probe certain registers indicated in the datasheets to look
+	 * for specific defaults that differ between the silicon designs. */
+
+	/* It's either 885/7 if the IR Tx Clk Divider register exists */
+	if (cx25840_read4(client, 0x204) & 0xffff) {
+		/* CX23885 returns bogus repetitive byte values for the DIF,
+		 * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */
+		ret = cx25840_read4(client, 0x300);
+		if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) {
+			/* No DIF */
+			ret = V4L2_IDENT_CX23885_AV;
+		} else {
+			/* CX23887 has a broken DIF, but the registers
+			 * appear valid (but unsed), good enough to detect. */
+			ret = V4L2_IDENT_CX23887_AV;
+		}
+	} else if (cx25840_read4(client, 0x300) & 0x0fffffff) {
+		/* DIF PLL Freq Word reg exists; chip must be a CX23888 */
+		ret = V4L2_IDENT_CX23888_AV;
+	} else {
+		v4l_err(client, "Unable to detect h/w, assuming cx23887\n");
+		ret = V4L2_IDENT_CX23887_AV;
+	}
+
+	/* Back into digital power down */
+	cx25840_write(client, 0x000, 2);
+	return ret;
+}
+
 static int cx25840_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
 	struct cx25840_state *state;
 	struct v4l2_subdev *sd;
-	u32 id;
+	u32 id = V4L2_IDENT_NONE;
 	u16 device_id;
 
 	/* Check if the adapter supports the needed features */
@@ -1543,17 +1680,22 @@ static int cx25840_probe(struct i2c_client *client,
 	 * 0x83 for the cx2583x and 0x84 for the cx2584x */
 	if ((device_id & 0xff00) == 0x8300) {
 		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
-	}
-	else if ((device_id & 0xff00) == 0x8400) {
+	} else if ((device_id & 0xff00) == 0x8400) {
 		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
 	} else if (device_id == 0x0000) {
-		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
-	} else if (device_id == 0x1313) {
-		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+		id = get_cx2388x_ident(client);
 	} else if ((device_id & 0xfff0) == 0x5A30) {
-		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
-	}
-	else {
+		/* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */
+		id = V4L2_IDENT_CX2310X_AV;
+	} else if ((device_id & 0xff) == (device_id >> 8)) {
+		v4l_err(client,
+			"likely a confused/unresponsive cx2388[578] A/V decoder"
+			" found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+		v4l_err(client, "A method to reset it from the cx25840 driver"
+			" software is not known at this time\n");
+		return -ENODEV;
+	} else {
 		v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
 		return -ENODEV;
 	}
@@ -1564,17 +1706,45 @@ static int cx25840_probe(struct i2c_client *client,
 
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
-	/* Note: revision '(device_id & 0x0f) == 2' was never built. The
-	   marking skips from 0x1 == 22 to 0x3 == 23. */
-	v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
-		    (device_id & 0xfff0) >> 4,
-		    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
-		    client->addr << 1, client->adapter->name);
+	switch (id) {
+	case V4L2_IDENT_CX23885_AV:
+		v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n",
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX23887_AV:
+		v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n",
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX23888_AV:
+		v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n",
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX2310X_AV:
+		v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n",
+			 device_id, client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX25840:
+	case V4L2_IDENT_CX25841:
+	case V4L2_IDENT_CX25842:
+	case V4L2_IDENT_CX25843:
+		/* Note: revision '(device_id & 0x0f) == 2' was never built. The
+		   marking skips from 0x1 == 22 to 0x3 == 23. */
+		v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
+			 (device_id & 0xfff0) >> 4,
+			 (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1
+						: (device_id & 0x0f),
+			 client->addr << 1, client->adapter->name);
+		break;
+	case V4L2_IDENT_CX25836:
+	case V4L2_IDENT_CX25837:
+	default:
+		v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n",
+			 (device_id & 0xfff0) >> 4, device_id & 0x0f,
+			 client->addr << 1, client->adapter->name);
+		break;
+	}
 
 	state->c = client;
-	state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
-	state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
-	state->is_cx231xx = (device_id == 0x5a3e);
 	state->vid_input = CX25840_COMPOSITE7;
 	state->aud_input = CX25840_AUDIO8;
 	state->audclk_freq = 48000;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 814b56536994..55345444417f 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -23,6 +23,7 @@
 
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
 #include <linux/i2c.h>
 
 /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
@@ -48,9 +49,6 @@ struct cx25840_state {
 	int vbi_line_offset;
 	u32 id;
 	u32 rev;
-	int is_cx25836;
-	int is_cx23885;
-	int is_cx231xx;
 	int is_initialized;
 	wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
 	struct work_struct fw_work;   /* work entry for fw load */
@@ -61,6 +59,24 @@ static inline struct cx25840_state *to_state(struct v4l2_subdev *sd)
 	return container_of(sd, struct cx25840_state, sd);
 }
 
+static inline bool is_cx2583x(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX25836 ||
+	       state->id == V4L2_IDENT_CX25837;
+}
+
+static inline bool is_cx231xx(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX2310X_AV;
+}
+
+static inline bool is_cx2388x(struct cx25840_state *state)
+{
+	return state->id == V4L2_IDENT_CX23885_AV ||
+	       state->id == V4L2_IDENT_CX23887_AV ||
+	       state->id == V4L2_IDENT_CX23888_AV;
+}
+
 /* ----------------------------------------------------------------------- */
 /* cx25850-core.c 							   */
 int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index 1f483c1d0dbe..8150200511da 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -67,9 +67,9 @@ static const char *get_fw_name(struct i2c_client *client)
 
 	if (firmware[0])
 		return firmware;
-	if (state->is_cx23885)
+	if (is_cx2388x(state))
 		return "v4l-cx23885-avcore-01.fw";
-	if (state->is_cx231xx)
+	if (is_cx231xx(state))
 		return "v4l-cx231xx-avcore-01.fw";
 	return "v4l-cx25840.fw";
 }
@@ -112,13 +112,13 @@ int cx25840_loadfw(struct i2c_client *client)
 	int MAX_BUF_SIZE = FWSEND;
 	u32 gpio_oe = 0, gpio_da = 0;
 
-	if (state->is_cx23885) {
+	if (is_cx2388x(state)) {
 		/* Preserve the GPIO OE and output bits */
 		gpio_oe = cx25840_read(client, 0x160);
 		gpio_da = cx25840_read(client, 0x164);
 	}
 
-	if ((state->is_cx231xx) && MAX_BUF_SIZE > 16) {
+	if (is_cx231xx(state) && MAX_BUF_SIZE > 16) {
 		v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
 		MAX_BUF_SIZE = 16;  /* cx231xx cannot accept more than 16 bytes at a time */
 	}
@@ -156,7 +156,7 @@ int cx25840_loadfw(struct i2c_client *client)
 	size = fw->size;
 	release_firmware(fw);
 
-	if (state->is_cx23885) {
+	if (is_cx2388x(state)) {
 		/* Restore GPIO configuration after f/w load */
 		cx25840_write(client, 0x160, gpio_oe);
 		cx25840_write(client, 0x164, gpio_da);
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 49952980dab3..c7e5851d3486 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -61,6 +61,8 @@ 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 DVB_STV0900 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
 	---help---
 	  This adds support for DVB/ATSC cards based on the
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 33be6369871a..d844f2aaa01d 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -2075,6 +2075,18 @@ static const struct cx88_board cx88_boards[] = {
 		},
 		.mpeg           = CX88_MPEG_DVB,
 	},
+	[CX88_BOARD_PROF_7301] = {
+		.name           = "Prof 7301 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
 };
 
 /* ------------------------------------------------------------------ */
@@ -2535,6 +2547,10 @@ static const struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x107d,
 		.subdevice = 0x6618,
 		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+	}, {
+		.subvendor = 0xb034,
+		.subdevice = 0x3034,
+		.card      = CX88_BOARD_PROF_7301,
 	},
 };
 
@@ -3211,6 +3227,7 @@ static void cx88_card_setup(struct cx88_core *core)
 	case  CX88_BOARD_TBS_8920:
 	case  CX88_BOARD_PROF_6200:
 	case  CX88_BOARD_PROF_7300:
+	case  CX88_BOARD_PROF_7301:
 	case  CX88_BOARD_SATTRADE_ST4200:
 		cx_write(MO_GP0_IO, 0x8000);
 		msleep(100);
@@ -3267,7 +3284,7 @@ static void cx88_card_setup(struct cx88_core *core)
 			    ctl.fname);
 		call_all(core, tuner, s_config, &xc2028_cfg);
 	}
-	call_all(core, tuner, s_standby);
+	call_all(core, core, s_power, 0);
 }
 
 /* ------------------------------------------------------------------ */
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 518bcfe18bcb..b14296923250 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -53,6 +53,9 @@
 #include "stv0288.h"
 #include "stb6000.h"
 #include "cx24116.h"
+#include "stv0900.h"
+#include "stb6100.h"
+#include "stb6100_proc.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -573,6 +576,15 @@ static int cx24116_set_ts_param(struct dvb_frontend *fe,
 	return 0;
 }
 
+static int stv0900_set_ts_param(struct dvb_frontend *fe,
+	int is_punctured)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	dev->ts_gen_cntrl = 0;
+
+	return 0;
+}
+
 static int cx24116_reset_device(struct dvb_frontend *fe)
 {
 	struct cx8802_dev *dev = fe->dvb->priv;
@@ -601,6 +613,23 @@ static struct cx24116_config tevii_s460_config = {
 	.reset_device  = cx24116_reset_device,
 };
 
+static struct stv0900_config prof_7301_stv0900_config = {
+	.demod_address = 0x6a,
+/*	demod_mode = 0,*/
+	.xtal = 27000000,
+	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+	.diseqc_mode = 2,/* 2/3 PWM */
+	.tun1_maddress = 0,/* 0x60 */
+	.tun1_adc = 0,/* 2 Vpp */
+	.path1_mode = 3,
+	.set_ts_params = stv0900_set_ts_param,
+};
+
+static struct stb6100_config prof_7301_stb6100_config = {
+	.tuner_address = 0x60,
+	.refclock = 27000000,
+};
+
 static struct stv0299_config tevii_tuner_sharp_config = {
 	.demod_address = 0x68,
 	.inittab = sharp_z0194a_inittab,
@@ -1149,6 +1178,31 @@ static int dvb_register(struct cx8802_dev *dev)
 				goto frontend_detach;
 		}
 		break;
+	case CX88_BOARD_PROF_7301:{
+		struct dvb_tuner_ops *tuner_ops = NULL;
+
+		fe0->dvb.frontend = dvb_attach(stv0900_attach,
+						&prof_7301_stv0900_config,
+						&core->i2c_adap, 0);
+		if (fe0->dvb.frontend != NULL) {
+			if (!dvb_attach(stb6100_attach, fe0->dvb.frontend,
+					&prof_7301_stb6100_config,
+					&core->i2c_adap))
+				goto frontend_detach;
+
+			tuner_ops = &fe0->dvb.frontend->ops.tuner_ops;
+			tuner_ops->set_frequency = stb6100_set_freq;
+			tuner_ops->get_frequency = stb6100_get_freq;
+			tuner_ops->set_bandwidth = stb6100_set_bandw;
+			tuner_ops->get_bandwidth = stb6100_get_bandw;
+
+			core->prev_set_voltage =
+					fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage =
+					tevii_dvbs_set_voltage;
+		}
+		break;
+		}
 	default:
 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       core->name);
@@ -1170,11 +1224,11 @@ 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 */
-	call_all(core, tuner, s_standby);
+	call_all(core, core, s_power, 0);
 
 	/* register everything */
 	return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
-		&dev->pci->dev, adapter_nr, mfe_shared);
+					 &dev->pci->dev, adapter_nr, mfe_shared, NULL);
 
 frontend_detach:
 	core->gate_ctrl = NULL;
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 78b3635178af..92b8cdf9fb81 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -118,13 +118,13 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
 
 		data = (data << 4) | ((gpio_key & 0xf0) >> 4);
 
-		ir_input_keydown(ir->input, &ir->ir, data, data);
+		ir_input_keydown(ir->input, &ir->ir, data);
 		ir_input_nokey(ir->input, &ir->ir);
 
 	} else if (ir->mask_keydown) {
 		/* bit set on keydown */
 		if (gpio & ir->mask_keydown) {
-			ir_input_keydown(ir->input, &ir->ir, data, data);
+			ir_input_keydown(ir->input, &ir->ir, data);
 		} else {
 			ir_input_nokey(ir->input, &ir->ir);
 		}
@@ -132,14 +132,14 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
 	} else if (ir->mask_keyup) {
 		/* bit cleared on keydown */
 		if (0 == (gpio & ir->mask_keyup)) {
-			ir_input_keydown(ir->input, &ir->ir, data, data);
+			ir_input_keydown(ir->input, &ir->ir, data);
 		} else {
 			ir_input_nokey(ir->input, &ir->ir);
 		}
 
 	} else {
 		/* can't distinguish keydown/up :-/ */
-		ir_input_keydown(ir->input, &ir->ir, data, data);
+		ir_input_keydown(ir->input, &ir->ir, data);
 		ir_input_nokey(ir->input, &ir->ir);
 	}
 }
@@ -303,6 +303,23 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		ir->mask_keydown = 0x02;
 		ir->polling      = 50; /* ms */
 		break;
+	case CX88_BOARD_OMICOM_SS4_PCI:
+	case CX88_BOARD_SATTRADE_ST4200:
+	case CX88_BOARD_TBS_8920:
+	case CX88_BOARD_TBS_8910:
+	case CX88_BOARD_PROF_7300:
+	case CX88_BOARD_PROF_7301:
+	case CX88_BOARD_PROF_6200:
+		ir_codes = &ir_codes_tbs_nec_table;
+		ir_type = IR_TYPE_PD;
+		ir->sampling = 0xff00; /* address */
+		break;
+	case CX88_BOARD_TEVII_S460:
+	case CX88_BOARD_TEVII_S420:
+		ir_codes = &ir_codes_tevii_nec_table;
+		ir_type = IR_TYPE_PD;
+		ir->sampling = 0xff00; /* address */
+		break;
 	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
 		ir_codes         = &ir_codes_dntv_live_dvbt_pro_table;
 		ir_type          = IR_TYPE_PD;
@@ -343,7 +360,10 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
 
-	ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
+	err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
+	if (err < 0)
+		goto err_out_free;
+
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
 	input_dev->id.bustype = BUS_PCI;
@@ -373,6 +393,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 	cx88_ir_stop(core, ir);
 	core->ir = NULL;
  err_out_free:
+	ir_input_free(input_dev);
 	input_free_device(input_dev);
 	kfree(ir);
 	return err;
@@ -387,6 +408,7 @@ int cx88_ir_fini(struct cx88_core *core)
 		return 0;
 
 	cx88_ir_stop(core, ir);
+	ir_input_free(ir->input);
 	input_unregister_device(ir->input);
 	kfree(ir);
 
@@ -432,8 +454,17 @@ void cx88_ir_irq(struct cx88_core *core)
 
 	/* decode it */
 	switch (core->boardnr) {
+	case CX88_BOARD_TEVII_S460:
+	case CX88_BOARD_TEVII_S420:
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
 	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+	case CX88_BOARD_OMICOM_SS4_PCI:
+	case CX88_BOARD_SATTRADE_ST4200:
+	case CX88_BOARD_TBS_8920:
+	case CX88_BOARD_TBS_8910:
+	case CX88_BOARD_PROF_7300:
+	case CX88_BOARD_PROF_7301:
+	case CX88_BOARD_PROF_6200:
 		ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
 
 		if (ircode == 0xffffffff) { /* decoding error */
@@ -461,7 +492,7 @@ void cx88_ir_irq(struct cx88_core *core)
 
 		ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f);
 
-		ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f, (ircode >> 16) & 0xff);
+		ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f);
 		ir->release = jiffies + msecs_to_jiffies(120);
 		break;
 	case CX88_BOARD_HAUPPAUGE:
@@ -498,7 +529,7 @@ void cx88_ir_irq(struct cx88_core *core)
 		if ( dev != 0x1e && dev != 0x1f )
 			/* not a hauppauge remote */
 			break;
-		ir_input_keydown(ir->input, &ir->ir, code, ircode);
+		ir_input_keydown(ir->input, &ir->ir, code);
 		ir->release = jiffies + msecs_to_jiffies(120);
 		break;
 	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
@@ -506,7 +537,7 @@ void cx88_ir_irq(struct cx88_core *core)
 		ir_dprintk("biphase decoded: %x\n", ircode);
 		if ((ircode & 0xfffff000) != 0x3000)
 			break;
-		ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f, ircode);
+		ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f);
 		ir->release = jiffies + msecs_to_jiffies(120);
 		break;
 	}
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 57e6b1241090..d7e8fcee559c 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -935,7 +935,7 @@ static int video_release(struct file *file)
 
 	mutex_lock(&dev->core->lock);
 	if(atomic_dec_and_test(&dev->core->users))
-		call_all(dev->core, tuner, s_standby);
+		call_all(dev->core, core, s_power, 0);
 	mutex_unlock(&dev->core->lock);
 
 	return 0;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index d5cea41f4207..e1c521710103 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -238,6 +238,7 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_HAUPPAUGE_IRONLY        80
 #define CX88_BOARD_WINFAST_DTV1800H        81
 #define CX88_BOARD_WINFAST_DTV2000H_J      82
+#define CX88_BOARD_PROF_7301               83
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index 402ce43ef38e..12a1b3d7132d 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -660,7 +660,7 @@ static void vpfe_detach_irq(struct vpfe_device *vpfe_dev)
 
 	frame_format = ccdc_dev->hw_ops.get_frame_format();
 	if (frame_format == CCDC_FRMFMT_PROGRESSIVE)
-		free_irq(IRQ_VDINT1, vpfe_dev);
+		free_irq(vpfe_dev->ccdc_irq1, vpfe_dev);
 }
 
 static int vpfe_attach_irq(struct vpfe_device *vpfe_dev)
@@ -1338,7 +1338,7 @@ static int vpfe_reqbufs(struct file *file, void *priv,
 	vpfe_dev->memory = req_buf->memory;
 	videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue,
 				&vpfe_videobuf_qops,
-				NULL,
+				vpfe_dev->pdev,
 				&vpfe_dev->irqlock,
 				req_buf->type,
 				vpfe_dev->fmt.fmt.pix.field,
@@ -1413,6 +1413,41 @@ static int vpfe_dqbuf(struct file *file, void *priv,
 				      buf, file->f_flags & O_NONBLOCK);
 }
 
+static int vpfe_queryctrl(struct file *file, void *priv,
+		struct v4l2_queryctrl *qctrl)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+
+	sdinfo = vpfe_dev->current_subdev;
+
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 core, queryctrl, qctrl);
+
+}
+
+static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+
+	sdinfo = vpfe_dev->current_subdev;
+
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 core, g_ctrl, ctrl);
+}
+
+static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
+{
+	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
+
+	sdinfo = vpfe_dev->current_subdev;
+
+	return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+					 core, s_ctrl, ctrl);
+}
+
 /*
  * vpfe_calculate_offsets : This function calculates buffers offset
  * for top and bottom field
@@ -1577,7 +1612,7 @@ static int vpfe_cropcap(struct file *file, void *priv,
 
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
 
-	if (vpfe_dev->std_index > ARRAY_SIZE(vpfe_standards))
+	if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards))
 		return -EINVAL;
 
 	memset(crop, 0, sizeof(struct v4l2_cropcap));
@@ -1710,6 +1745,9 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
 	.vidioc_querystd	 = vpfe_querystd,
 	.vidioc_s_std		 = vpfe_s_std,
 	.vidioc_g_std		 = vpfe_g_std,
+	.vidioc_queryctrl	 = vpfe_queryctrl,
+	.vidioc_g_ctrl		 = vpfe_g_ctrl,
+	.vidioc_s_ctrl		 = vpfe_s_ctrl,
 	.vidioc_reqbufs		 = vpfe_reqbufs,
 	.vidioc_querybuf	 = vpfe_querybuf,
 	.vidioc_qbuf		 = vpfe_qbuf,
@@ -1978,8 +2016,7 @@ static __init int vpfe_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, vpfe_dev);
 	/* set driver private data */
 	video_set_drvdata(vpfe_dev->video_dev, vpfe_dev);
-	i2c_adap = i2c_get_adapter(1);
-	vpfe_cfg = pdev->dev.platform_data;
+	i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id);
 	num_subdevs = vpfe_cfg->num_subdevs;
 	vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs,
 				GFP_KERNEL);
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index ac947aecb9c3..bd783387b37d 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -293,7 +293,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
 	dprintk("opening device and trying to acquire exclusive lock\n");
 
 	if (!dev) {
-		printk(KERN_ERR "BUG: em28xx can't find device struct."
+		em28xx_err("BUG: em28xx can't find device struct."
 				" Can't proceed with open\n");
 		return -ENODEV;
 	}
@@ -325,7 +325,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
 
 	return 0;
 err:
-	printk(KERN_ERR "Error while configuring em28xx mixer\n");
+	em28xx_err("Error while configuring em28xx mixer\n");
 	return ret;
 }
 
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index c0fd5c6feeac..82da205047be 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -225,6 +225,14 @@ static struct em28xx_reg_seq silvercrest_reg_seq[] = {
 	{	-1,		-1,	-1,		-1},
 };
 
+static struct em28xx_reg_seq vc211a_enable[] = {
+	{EM28XX_R08_GPIO,	0xff,	0x07,		10},
+	{EM28XX_R08_GPIO,	0xff,	0x0f,		10},
+	{EM28XX_R08_GPIO,	0xff,	0x0b,		10},
+	{	-1,		-1,	-1,		-1},
+};
+
+
 /*
  *  Board definitions
  */
@@ -829,7 +837,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_table,
+		.ir_codes       = &ir_codes_rc5_hauppauge_new_table,
 		.decoder        = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -1009,6 +1017,23 @@ struct em28xx_board em28xx_boards[] = {
 			.amux     = EM28XX_AMUX_LINE_IN,
 		} },
 	},
+	[EM2800_BOARD_VC211A] = {
+		.name         = "Actionmaster/LinXcel/Digitus VC211A",
+		.is_em2800    = 1,
+		.tuner_type   = TUNER_ABSENT,	/* Capture-only board */
+		.decoder      = EM28XX_SAA711X,
+		.input        = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = vc211a_enable,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = EM28XX_AMUX_LINE_IN,
+			.gpio     = vc211a_enable,
+		} },
+	},
 	[EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
 		.name         = "Leadtek Winfast USB II",
 		.is_em2800    = 1,
@@ -1381,10 +1406,14 @@ struct em28xx_board em28xx_boards[] = {
 	},
 	[EM2882_BOARD_TERRATEC_HYBRID_XS] = {
 		.name         = "Terratec Hybrid XS (em2882)",
-		.valid        = EM28XX_BOARD_NOT_VALIDATED,
 		.tuner_type   = TUNER_XC2028,
 		.tuner_gpio   = default_tuner_gpio,
+		.mts_firmware = 1,
 		.decoder      = EM28XX_TVP5150,
+		.has_dvb      = 1,
+		.dvb_gpio     = hauppauge_wintv_hvr_900_digital,
+		.ir_codes     = &ir_codes_terratec_cinergy_xs_table,
+		.xclk         = EM28XX_XCLK_FREQUENCY_12MHZ,
 		.input        = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = TVP5150_COMPOSITE0,
@@ -1608,6 +1637,8 @@ struct usb_device_id em28xx_id_table[] = {
 			.driver_info = EM2820_BOARD_UNKNOWN },
 	{ USB_DEVICE(0xeb1a, 0x2861),
 			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2862),
+			.driver_info = EM2820_BOARD_UNKNOWN },
 	{ USB_DEVICE(0xeb1a, 0x2870),
 			.driver_info = EM2820_BOARD_UNKNOWN },
 	{ USB_DEVICE(0xeb1a, 0x2881),
@@ -2050,6 +2081,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
 	switch (dev->model) {
 	case EM2880_BOARD_EMPIRE_DUAL_TV:
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2882_BOARD_TERRATEC_HYBRID_XS:
 		ctl->demod = XC3028_FE_ZARLINK456;
 		break;
 	case EM2880_BOARD_TERRATEC_HYBRID_XS:
@@ -2227,6 +2259,7 @@ static int em28xx_hint_board(struct em28xx *dev)
 /* ----------------------------------------------------------------------- */
 void em28xx_register_i2c_ir(struct em28xx *dev)
 {
+	struct i2c_board_info info;
 	const unsigned short addr_list[] = {
 		 0x30, 0x47, I2C_CLIENT_END
 	};
@@ -2234,9 +2267,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
 	if (disable_ir)
 		return;
 
-	memset(&dev->info, 0, sizeof(&dev->info));
+	memset(&info, 0, sizeof(struct i2c_board_info));
 	memset(&dev->init_data, 0, sizeof(dev->init_data));
-	strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
 
 	/* detect & configure */
 	switch (dev->model) {
@@ -2259,8 +2292,8 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
 	}
 
 	if (dev->init_data.name)
-		dev->info.platform_data = &dev->init_data;
-	i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
+		info.platform_data = &dev->init_data;
+	i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
 }
 
 void em28xx_card_setup(struct em28xx *dev)
@@ -2524,6 +2557,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 		dev->chip_id = retval;
 
 		switch (dev->chip_id) {
+		case CHIP_ID_EM2800:
+			em28xx_info("chip ID is em2800\n");
+			break;
 		case CHIP_ID_EM2710:
 			em28xx_info("chip ID is em2710\n");
 			break;
@@ -2650,7 +2686,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 	em28xx_init_extension(dev);
 
 	/* Save some power by putting tuner to sleep */
-	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
 
 	return 0;
 
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index a88257a7d94f..3f86d36dff2b 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -50,7 +50,7 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
 		printk(KERN_INFO "%s %s :"fmt, \
 			 dev->name, __func__ , ##arg); } while (0)
 
-static int alt = EM28XX_PINOUT;
+static int alt;
 module_param(alt, int, 0644);
 MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
 
@@ -533,8 +533,15 @@ int em28xx_audio_setup(struct em28xx *dev)
 
 	vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1);
 	if (vid1 < 0) {
-		/* Device likely doesn't support AC97 */
+		/*
+		 * Device likely doesn't support AC97
+		 * Note: (some) em2800 devices without eeprom reports 0x91 on
+		 *	 CHIPCFG register, even not having an AC97 chip
+		 */
 		em28xx_warn("AC97 chip type couldn't be determined\n");
+		dev->audio_mode.ac97 = EM28XX_NO_AC97;
+		dev->has_alsa_audio = 0;
+		dev->audio_mode.has_audio = 0;
 		goto init_audio;
 	}
 
@@ -778,6 +785,16 @@ int em28xx_set_alternate(struct em28xx *dev)
 	int i;
 	unsigned int min_pkt_size = dev->width * 2 + 4;
 
+	/*
+	 * alt = 0 is used only for control messages, so, only values
+	 * greater than 0 can be used for streaming.
+	 */
+	if (alt && alt < dev->num_alt) {
+		em28xx_coredbg("alternate forced to %d\n", dev->alt);
+		dev->alt = alt;
+		goto set_alt;
+	}
+
 	/* When image size is bigger than a certain value,
 	   the frame size should be increased, otherwise, only
 	   green screen will be received.
@@ -798,6 +815,7 @@ int em28xx_set_alternate(struct em28xx *dev)
 			dev->alt = i;
 	}
 
+set_alt:
 	if (dev->alt != prev_alt) {
 		em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
 				min_pkt_size, dev->alt);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index db749461e5c6..cc0505eb900f 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -313,22 +313,20 @@ static int attach_xc3028(u8 addr, struct em28xx *dev)
 	cfg.i2c_addr  = addr;
 
 	if (!dev->dvb->frontend) {
-		printk(KERN_ERR "%s/2: dvb frontend not attached. "
-				"Can't attach xc3028\n",
-		       dev->name);
+		em28xx_errdev("/2: dvb frontend not attached. "
+				"Can't attach xc3028\n");
 		return -EINVAL;
 	}
 
 	fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
 	if (!fe) {
-		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
-		       dev->name);
+		em28xx_errdev("/2: xc3028 attach failed\n");
 		dvb_frontend_detach(dev->dvb->frontend);
 		dev->dvb->frontend = NULL;
 		return -EINVAL;
 	}
 
-	printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
+	em28xx_info("%s/2: xc3028 attached\n", dev->name);
 
 	return 0;
 }
@@ -463,7 +461,7 @@ static int dvb_init(struct em28xx *dev)
 	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
 
 	if (dvb == NULL) {
-		printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
+		em28xx_info("em28xx_dvb: memory allocation failed\n");
 		return -ENOMEM;
 	}
 	dev->dvb = dvb;
@@ -493,6 +491,7 @@ static int dvb_init(struct em28xx *dev)
 		}
 		break;
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2882_BOARD_TERRATEC_HYBRID_XS:
 	case EM2880_BOARD_EMPIRE_DUAL_TV:
 		dvb->frontend = dvb_attach(zl10353_attach,
 					   &em28xx_zl10353_xc3028_no_i2c_gate,
@@ -569,15 +568,12 @@ static int dvb_init(struct em28xx *dev)
 		}
 		break;
 	default:
-		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
-				" isn't supported yet\n",
-		       dev->name);
+		em28xx_errdev("/2: The frontend of your DVB/ATSC card"
+				" isn't supported yet\n");
 		break;
 	}
 	if (NULL == dvb->frontend) {
-		printk(KERN_ERR
-		       "%s/2: frontend initialization failed\n",
-		       dev->name);
+		em28xx_errdev("/2: frontend initialization failed\n");
 		result = -EINVAL;
 		goto out_free;
 	}
@@ -591,7 +587,7 @@ static int dvb_init(struct em28xx *dev)
 		goto out_free;
 
 	em28xx_set_mode(dev, EM28XX_SUSPEND);
-	printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
+	em28xx_info("Successfully loaded em28xx-dvb\n");
 	return 0;
 
 out_free:
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 7a0fe3816e3d..d96ec7c09dca 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -70,6 +70,7 @@ struct em28xx_IR {
 	int polling;
 	struct delayed_work work;
 	unsigned int last_toggle:1;
+	unsigned int full_code:1;
 	unsigned int last_readcount;
 	unsigned int repeat_interval;
 
@@ -246,9 +247,10 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
 		return;
 	}
 
-	dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n",
+	dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x%02x\n",
 		poll_result.toggle_bit, poll_result.read_count,
-		ir->last_readcount, poll_result.rc_data[0]);
+		ir->last_readcount, poll_result.rc_address,
+		poll_result.rc_data[0]);
 
 	if (ir->dev->chip_id == CHIP_ID_EM2874) {
 		/* The em2874 clears the readcount field every time the
@@ -282,8 +284,15 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
 
 	if (do_sendkey) {
 		dprintk("sending keypress\n");
-		ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0],
-				 poll_result.rc_data[0]);
+
+		if (ir->full_code)
+			ir_input_keydown(ir->input, &ir->ir,
+					 poll_result.rc_address << 8 |
+					 poll_result.rc_data[0]);
+		else
+			ir_input_keydown(ir->input, &ir->ir,
+					 poll_result.rc_data[0]);
+
 		ir_input_nokey(ir->input, &ir->ir);
 	}
 
@@ -333,6 +342,8 @@ int em28xx_ir_init(struct em28xx *dev)
 	switch (dev->chip_id) {
 	case CHIP_ID_EM2860:
 	case CHIP_ID_EM2883:
+		if (dev->model == EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950)
+			ir->full_code = 1;
 		ir->get_key = default_polling_getkey;
 		break;
 	case CHIP_ID_EM2874:
@@ -356,7 +367,11 @@ int em28xx_ir_init(struct em28xx *dev)
 	usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
 	strlcat(ir->phys, "/input0", sizeof(ir->phys));
 
-	ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->board.ir_codes);
+	err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER,
+			     dev->board.ir_codes);
+	if (err < 0)
+		goto err_out_free;
+
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
 	input_dev->id.bustype = BUS_USB;
@@ -381,6 +396,7 @@ int em28xx_ir_init(struct em28xx *dev)
 	em28xx_ir_stop(ir);
 	dev->ir = NULL;
  err_out_free:
+	ir_input_free(input_dev);
 	input_free_device(input_dev);
 	kfree(ir);
 	return err;
@@ -395,6 +411,7 @@ int em28xx_ir_fini(struct em28xx *dev)
 		return 0;
 
 	em28xx_ir_stop(ir);
+	ir_input_free(ir->input);
 	input_unregister_device(ir->input);
 	kfree(ir);
 
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
index ed12e7ffcbd0..058ac87639ce 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -192,6 +192,7 @@
 
 /* FIXME: Need to be populated with the other chip ID's */
 enum em28xx_chip_id {
+	CHIP_ID_EM2800 = 7,
 	CHIP_ID_EM2710 = 17,
 	CHIP_ID_EM2820 = 18,	/* Also used by some em2710 */
 	CHIP_ID_EM2840 = 20,
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 3a1dfb7726f8..7ad65370f274 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1060,12 +1060,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 		/* the em2800 can only scale down to 50% */
 		height = height > (3 * maxh / 4) ? maxh : maxh / 2;
 		width = width > (3 * maxw / 4) ? maxw : maxw / 2;
-		/* According to empiatech support the MaxPacketSize is too small
-		 * to support framesizes larger than 640x480 @ 30 fps or 640x576
-		 * @ 25 fps.  As this would cut of a part of the image we prefer
-		 * 360x576 or 360x480 for now */
-		if (width == maxw && height == maxh)
-			width /= 2;
 	} else {
 		/* width must even because of the YUYV format
 		   height must be even because of interlacing */
@@ -2225,7 +2219,7 @@ static int em28xx_v4l2_close(struct file *filp)
 		}
 
 		/* Save some power by putting tuner to sleep */
-		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
+		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
 
 		/* do this before setting alternate! */
 		em28xx_uninit_isoc(dev);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 0a73e8bf0d6e..441df644ddbe 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -110,6 +110,7 @@
 #define EM2820_BOARD_SILVERCREST_WEBCAM           71
 #define EM2861_BOARD_GADMEI_UTV330PLUS           72
 #define EM2870_BOARD_REDDO_DVB_C_USB_BOX          73
+#define EM2800_BOARD_VC211A			  74
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -143,9 +144,6 @@
  */
 #define EM28XX_NUM_PACKETS 40
 
-/* default alternate; 0 means choose the best */
-#define EM28XX_PINOUT 0
-
 #define EM28XX_INTERLACED_DEFAULT 1
 
 /*
@@ -615,7 +613,6 @@ struct em28xx {
 	struct em28xx_dvb *dvb;
 
 	/* I2C keyboard data */
-	struct i2c_board_info info;
 	struct IR_i2c_init_data init_data;
 };
 
@@ -800,7 +797,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev)
 	if (dev->board.is_webcam)
 		return dev->sensor_xres;
 
-	if (dev->board.max_range_640_480)
+	if (dev->board.max_range_640_480 || dev->board.is_em2800)
 		return 640;
 
 	return 720;
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index fe2e490ebc52..609d65b0b10d 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -76,10 +76,11 @@ config USB_GSPCA_MR97310A
 	  module will be called gspca_mr97310a.
 
 config USB_GSPCA_OV519
-	tristate "OV519 USB Camera Driver"
+	tristate "OV51x / OVFX2 / W996xCF USB Camera Driver"
 	depends on VIDEO_V4L2 && USB_GSPCA
 	help
-	  Say Y here if you want support for cameras based on the OV519 chip.
+	  Say Y here if you want support for cameras based on one of these:
+	  OV511(+), OV518(+), OV519, OVFX2, W9967CF, W9968CF
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called gspca_ov519.
@@ -103,6 +104,15 @@ config USB_GSPCA_PAC207
 	  To compile this driver as a module, choose M here: the
 	  module will be called gspca_pac207.
 
+config USB_GSPCA_PAC7302
+	tristate "Pixart PAC7302 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the PAC7302 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_pac7302.
+
 config USB_GSPCA_PAC7311
 	tristate "Pixart PAC7311 USB Camera Driver"
 	depends on VIDEO_V4L2 && USB_GSPCA
@@ -229,6 +239,15 @@ config USB_GSPCA_STK014
 	  To compile this driver as a module, choose M here: the
 	  module will be called gspca_stk014.
 
+config USB_GSPCA_STV0680
+	tristate "STV0680 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the STV0680 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_stv0680.
+
 config USB_GSPCA_SUNPLUS
 	tristate "SUNPLUS USB Camera Driver"
 	depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index b7420818037e..ff2c7279d82e 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -8,6 +8,7 @@ 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_PAC7302)  += gspca_pac7302.o
 obj-$(CONFIG_USB_GSPCA_PAC7311)  += gspca_pac7311.o
 obj-$(CONFIG_USB_GSPCA_SN9C20X)  += gspca_sn9c20x.o
 obj-$(CONFIG_USB_GSPCA_SONIXB)   += gspca_sonixb.o
@@ -22,6 +23,7 @@ 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_STV0680)  += gspca_stv0680.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
@@ -37,6 +39,7 @@ gspca_mr97310a-objs := mr97310a.o
 gspca_ov519-objs    := ov519.o
 gspca_ov534-objs    := ov534.o
 gspca_pac207-objs   := pac207.o
+gspca_pac7302-objs  := pac7302.o
 gspca_pac7311-objs  := pac7311.o
 gspca_sn9c20x-objs  := sn9c20x.o
 gspca_sonixb-objs   := sonixb.o
@@ -50,6 +53,7 @@ gspca_spca561-objs  := spca561.o
 gspca_sq905-objs    := sq905.o
 gspca_sq905c-objs   := sq905c.o
 gspca_stk014-objs   := stk014.o
+gspca_stv0680-objs  := stv0680.o
 gspca_sunplus-objs  := sunplus.o
 gspca_t613-objs     := t613.o
 gspca_tv8532-objs   := tv8532.o
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index eca003566ae3..2f0b8d621e00 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -888,8 +888,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 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;
@@ -897,16 +896,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	if (data[0] == 0xff && data[1] == 0xd8) {
 
 		/* start of frame */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 
 		/* put the JPEG header in the new frame */
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-			sd->jpeg_hdr, JPEG_HDR_SZ);
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
+				sd->jpeg_hdr, JPEG_HDR_SZ);
 		data += 2;
 		len -= 2;
 	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static void setbrightness(struct gspca_dev*gspca_dev)
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
index c1461e63647f..9de86419ae1e 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/video/gspca/etoms.c
@@ -752,8 +752,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 #undef LIMIT
 
 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 */
 {
 	int seqframe;
@@ -767,14 +766,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		       data[2], data[3], data[4], data[5]);
 		data += 30;
 		/* don't change datalength as the chips provided it */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					data, 0);
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 		return;
 	}
 	if (len) {
 		data += 8;
-		gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 	} else {			/* Drop Packet */
 		gspca_dev->last_packet_type = DISCARD_PACKET;
 	}
diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c
index 480ec5c87d0e..5d90e7448579 100644
--- a/drivers/media/video/gspca/finepix.c
+++ b/drivers/media/video/gspca/finepix.c
@@ -82,7 +82,6 @@ static void dostream(struct work_struct *work)
 	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;
 
@@ -118,10 +117,6 @@ 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)) {
@@ -132,21 +127,17 @@ again:
 				 * 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);
+				gspca_frame_add(gspca_dev, LAST_PACKET,
+						data, len);
 				break;
 			}
 
 			/* got a partial image */
-			if (frame)
-				gspca_frame_add(gspca_dev,
-						gspca_dev->last_packet_type
-							== LAST_PACKET
-						? FIRST_PACKET : INTER_PACKET,
-						frame, data, len);
+			gspca_frame_add(gspca_dev,
+					gspca_dev->last_packet_type
+						== LAST_PACKET
+					? FIRST_PACKET : INTER_PACKET,
+					data, len);
 		}
 
 		/* We must wait before trying reading the next
diff --git a/drivers/media/video/gspca/gl860/gl860-mi1320.c b/drivers/media/video/gspca/gl860/gl860-mi1320.c
index 39f6261c1a0c..1355e526ee84 100644
--- a/drivers/media/video/gspca/gl860/gl860-mi1320.c
+++ b/drivers/media/video/gspca/gl860/gl860-mi1320.c
@@ -1,6 +1,5 @@
-/* @file gl860-mi1320.c
- * @author Olivier LORIN from my logs
- * @date 2009-08-27
+/* Subdriver for the GL860 chip with the MI1320 sensor
+ * Author Olivier LORIN from own logs
  *
  * 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
@@ -127,49 +126,49 @@ static u8 dat_wbalBL[] =
 
 static u8 dat_hvflip1[] = {0xf0, 0x00, 0xf1, 0x00};
 
-static u8 s000[] =
+static u8 dat_common00[] =
 	"\x00\x01\x07\x6a\x06\x63\x0d\x6a" "\xc0\x00\x10\x10\xc1\x03\xc2\x42"
 	"\xd8\x04\x58\x00\x04\x02";
-static u8 s001[] =
+static u8 dat_common01[] =
 	"\x0d\x00\xf1\x0b\x0d\x00\xf1\x08" "\x35\x00\xf1\x22\x68\x00\xf1\x5d"
 	"\xf0\x00\xf1\x01\x06\x70\xf1\x0e" "\xf0\x00\xf1\x02\xdd\x18\xf1\xe0";
-static u8 s002[] =
+static u8 dat_common02[] =
 	"\x05\x01\xf1\x84\x06\x00\xf1\x44" "\x07\x00\xf1\xbe\x08\x00\xf1\x1e"
 	"\x20\x01\xf1\x03\x21\x84\xf1\x00" "\x22\x0d\xf1\x0f\x24\x80\xf1\x00"
 	"\x34\x18\xf1\x2d\x35\x00\xf1\x22" "\x43\x83\xf1\x83\x59\x00\xf1\xff";
-static u8 s003[] =
+static u8 dat_common03[] =
 	"\xf0\x00\xf1\x02\x39\x06\xf1\x8c" "\x3a\x06\xf1\x8c\x3b\x03\xf1\xda"
 	"\x3c\x05\xf1\x30\x57\x01\xf1\x0c" "\x58\x01\xf1\x42\x59\x01\xf1\x0c"
 	"\x5a\x01\xf1\x42\x5c\x13\xf1\x0e" "\x5d\x17\xf1\x12\x64\x1e\xf1\x1c";
-static u8 s004[] =
+static u8 dat_common04[] =
 	"\xf0\x00\xf1\x02\x24\x5f\xf1\x20" "\x28\xea\xf1\x02\x5f\x41\xf1\x43";
-static u8 s005[] =
+static u8 dat_common05[] =
 	"\x02\x00\xf1\xee\x03\x29\xf1\x1a" "\x04\x02\xf1\xa4\x09\x00\xf1\x68"
 	"\x0a\x00\xf1\x2a\x0b\x00\xf1\x04" "\x0c\x00\xf1\x93\x0d\x00\xf1\x82"
 	"\x0e\x00\xf1\x40\x0f\x00\xf1\x5f" "\x10\x00\xf1\x4e\x11\x00\xf1\x5b";
-static u8 s006[] =
+static u8 dat_common06[] =
 	"\x15\x00\xf1\xc9\x16\x00\xf1\x5e" "\x17\x00\xf1\x9d\x18\x00\xf1\x06"
 	"\x19\x00\xf1\x89\x1a\x00\xf1\x12" "\x1b\x00\xf1\xa1\x1c\x00\xf1\xe4"
 	"\x1d\x00\xf1\x7a\x1e\x00\xf1\x64" "\xf6\x00\xf1\x5f";
-static u8 s007[] =
+static u8 dat_common07[] =
 	"\xf0\x00\xf1\x01\x53\x09\xf1\x03" "\x54\x3d\xf1\x1c\x55\x99\xf1\x72"
 	"\x56\xc1\xf1\xb1\x57\xd8\xf1\xce" "\x58\xe0\xf1\x00\xdc\x0a\xf1\x03"
 	"\xdd\x45\xf1\x20\xde\xae\xf1\x82" "\xdf\xdc\xf1\xc9\xe0\xf6\xf1\xea"
 	"\xe1\xff\xf1\x00";
-static u8 s008[] =
+static u8 dat_common08[] =
 	"\xf0\x00\xf1\x01\x80\x00\xf1\x06" "\x81\xf6\xf1\x08\x82\xfb\xf1\xf7"
 	"\x83\x00\xf1\xfe\xb6\x07\xf1\x03" "\xb7\x18\xf1\x0c\x84\xfb\xf1\x06"
 	"\x85\xfb\xf1\xf9\x86\x00\xf1\xff" "\xb8\x07\xf1\x04\xb9\x16\xf1\x0a";
-static u8 s009[] =
+static u8 dat_common09[] =
 	"\x87\xfa\xf1\x05\x88\xfc\xf1\xf9" "\x89\x00\xf1\xff\xba\x06\xf1\x03"
 	"\xbb\x17\xf1\x09\x8a\xe8\xf1\x14" "\x8b\xf7\xf1\xf0\x8c\xfd\xf1\xfa"
 	"\x8d\x00\xf1\x00\xbc\x05\xf1\x01" "\xbd\x0c\xf1\x08\xbe\x00\xf1\x14";
-static u8 s010[] =
+static u8 dat_common10[] =
 	"\x8e\xea\xf1\x13\x8f\xf7\xf1\xf2" "\x90\xfd\xf1\xfa\x91\x00\xf1\x00"
 	"\xbf\x05\xf1\x01\xc0\x0a\xf1\x08" "\xc1\x00\xf1\x0c\x92\xed\xf1\x0f"
 	"\x93\xf9\xf1\xf4\x94\xfe\xf1\xfb" "\x95\x00\xf1\x00\xc2\x04\xf1\x01"
 	"\xc3\x0a\xf1\x07\xc4\x00\xf1\x10";
-static u8 s011[] =
+static u8 dat_common11[] =
 	"\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x25\x00\xf1\x55\x34\x10\xf1\x10"
 	"\x35\xf0\xf1\x10\x3a\x02\xf1\x03" "\x3b\x04\xf1\x2a\x9b\x43\xf1\x00"
 	"\xa4\x03\xf1\xc0\xa7\x02\xf1\x81";
@@ -222,26 +221,26 @@ void mi1320_init_settings(struct gspca_dev *gspca_dev)
 
 static void common(struct gspca_dev *gspca_dev)
 {
-	s32 n; /* reserved for FETCH macros */
+	s32 n; /* reserved for FETCH functions */
 
-	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 22, s000);
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 22, dat_common00);
 	ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 32, s001);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 32, dat_common01);
 	n = fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common));
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s002);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s003);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 16, s004);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s005);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 44, s006);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common02);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common03);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 16, dat_common04);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common05);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 44, dat_common06);
 	keep_on_fetching_validx(gspca_dev, tbl_common,
 					ARRAY_SIZE(tbl_common), n);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 52, s007);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s008);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, s009);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 56, s010);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 52, dat_common07);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common08);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common09);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 56, dat_common10);
 	keep_on_fetching_validx(gspca_dev, tbl_common,
 					ARRAY_SIZE(tbl_common), n);
-	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, s011);
+	ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, dat_common11);
 	keep_on_fetching_validx(gspca_dev, tbl_common,
 					ARRAY_SIZE(tbl_common), n);
 }
diff --git a/drivers/media/video/gspca/gl860/gl860-mi2020.c b/drivers/media/video/gspca/gl860/gl860-mi2020.c
index ffb09fed3e8c..80cb3f1b36f7 100644
--- a/drivers/media/video/gspca/gl860/gl860-mi2020.c
+++ b/drivers/media/video/gspca/gl860/gl860-mi2020.c
@@ -1,7 +1,6 @@
-/* @file gl860-mi2020.c
- * @author Olivier LORIN, from Ice/Soro2005's logs(A), Fret_saw/Hulkie's
+/* Subdriver for the GL860 chip with the MI2020 sensor
+ * Author Olivier LORIN, from Ice/Soro2005's logs(A), Fret_saw/Hulkie's
  * logs(B) and Tricid"s logs(C). With the help of Kytrix/BUGabundo/Blazercist.
- * @date 2009-08-27
  *
  * 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
@@ -41,7 +40,7 @@ static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 };
 static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 };
 static u8 dat_multi6[] = { 0x90, 0x00, 0x05 };
 
-static struct validx tbl_common_a[] = {
+static struct validx tbl_common1[] = {
 	{0x0000, 0x0000},
 	{1, 0xffff}, /* msleep(35); */
 	{0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, {0x0000, 0x00c0},
@@ -49,7 +48,7 @@ static struct validx tbl_common_a[] = {
 	{0x0000, 0x0058}, {0x0002, 0x0004}, {0x0041, 0x0000},
 };
 
-static struct validx tbl_common_b[] = {
+static struct validx tbl_common2[] = {
 	{0x006a, 0x0007},
 	{35, 0xffff},
 	{0x00ef, 0x0006},
@@ -60,7 +59,7 @@ static struct validx tbl_common_b[] = {
 	{0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000},
 };
 
-static struct idxdata tbl_common_c[] = {
+static struct idxdata tbl_common3[] = {
 	{0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
 	{6, "\xff\xff\xff"}, /* 12 */
 	{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
@@ -109,7 +108,7 @@ static struct idxdata tbl_common_c[] = {
 	{0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"},
 };
 
-static struct idxdata tbl_common_d[] = {
+static struct idxdata tbl_common4[] = {
 	{0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\xa4\x08"},
 	{0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"},
 	{0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"},
@@ -118,7 +117,7 @@ static struct idxdata tbl_common_d[] = {
 	{0x33, "\x90\x00\xa0"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\xc0"},
 };
 
-static struct idxdata tbl_common_e[] = {
+static struct idxdata tbl_common5[] = {
 	{0x33, "\x8c\xa4\x04"}, {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"},
 	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"},
 	{0x33, "\x8c\xa2\x0c"}, {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"},
@@ -180,7 +179,7 @@ static struct validx tbl_init_at_startup[] = {
 	{53, 0xffff},
 };
 
-static struct idxdata tbl_init_post_alt_low_a[] = {
+static struct idxdata tbl_init_post_alt_low1[] = {
 	{0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\x22\x2e"},
 	{0x33, "\x90\x00\x81"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x17"},
 	{0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x1a"}, {0x33, "\x8c\xa4\x0a"},
@@ -189,7 +188,7 @@ static struct idxdata tbl_init_post_alt_low_a[] = {
 	{0x33, "\x90\x00\x9b"},
 };
 
-static struct idxdata tbl_init_post_alt_low_b[] = {
+static struct idxdata tbl_init_post_alt_low2[] = {
 	{0x33, "\x8c\x27\x03"}, {0x33, "\x90\x03\x24"}, {0x33, "\x8c\x27\x05"},
 	{0x33, "\x90\x02\x58"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
 	{2, "\xff\xff\xff"},
@@ -197,7 +196,7 @@ static struct idxdata tbl_init_post_alt_low_b[] = {
 	{2, "\xff\xff\xff"},
 };
 
-static struct idxdata tbl_init_post_alt_low_c[] = {
+static struct idxdata tbl_init_post_alt_low3[] = {
 	{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
 	{2, "\xff\xff\xff"},
 	{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x20"},
@@ -221,7 +220,7 @@ static struct idxdata tbl_init_post_alt_low_c[] = {
 	{1, "\xff\xff\xff"},
 };
 
-static struct idxdata tbl_init_post_alt_low_d[] = {
+static struct idxdata tbl_init_post_alt_low4[] = {
 	{0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
 	{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
 	{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
@@ -267,7 +266,7 @@ static struct idxdata tbl_init_post_alt_low_d[] = {
 	{0x32, "\x6c\x14\x08"},
 };
 
-static struct idxdata tbl_init_post_alt_big_a[] = {
+static struct idxdata tbl_init_post_alt_big1[] = {
 	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
 	{2, "\xff\xff\xff"},
 	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
@@ -288,7 +287,7 @@ static struct idxdata tbl_init_post_alt_big_a[] = {
 	{0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
 };
 
-static struct idxdata tbl_init_post_alt_big_b[] = {
+static struct idxdata tbl_init_post_alt_big2[] = {
 	{0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
 	{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
 	{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
@@ -317,7 +316,7 @@ static struct idxdata tbl_init_post_alt_big_b[] = {
 	{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
 };
 
-static struct idxdata tbl_init_post_alt_big_c[] = {
+static struct idxdata tbl_init_post_alt_big3[] = {
 	{0x33, "\x8c\xa1\x02"},
 	{0x33, "\x90\x00\x1f"},
 	{0x33, "\x8c\xa1\x02"},
@@ -388,14 +387,14 @@ static void common(struct gspca_dev *gspca_dev)
 	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
 
 	if (_MI2020b_) {
-		fetch_validx(gspca_dev, tbl_common_a, ARRAY_SIZE(tbl_common_a));
+		fetch_validx(gspca_dev, tbl_common1, ARRAY_SIZE(tbl_common1));
 	} else {
 		if (_MI2020_)
 			ctrl_out(gspca_dev, 0x40,  1, 0x0008, 0x0004,  0, NULL);
 		else
 			ctrl_out(gspca_dev, 0x40,  1, 0x0002, 0x0004,  0, NULL);
 		msleep(35);
-		fetch_validx(gspca_dev, tbl_common_b, ARRAY_SIZE(tbl_common_b));
+		fetch_validx(gspca_dev, tbl_common2, ARRAY_SIZE(tbl_common2));
 	}
 	ctrl_out(gspca_dev, 0x40,  3, 0x7a00, 0x0033,  3, "\x86\x25\x01");
 	ctrl_out(gspca_dev, 0x40,  3, 0x7a00, 0x0033,  3, "\x86\x25\x00");
@@ -403,13 +402,13 @@ static void common(struct gspca_dev *gspca_dev)
 	ctrl_out(gspca_dev, 0x40,  3, 0x7a00, 0x0030,  3, "\x1a\x0a\xcc");
 	if (reso == IMAGE_1600)
 		msleep(2); /* 1600 */
-	fetch_idxdata(gspca_dev, tbl_common_c, ARRAY_SIZE(tbl_common_c));
+	fetch_idxdata(gspca_dev, tbl_common3, ARRAY_SIZE(tbl_common3));
 
 	if (_MI2020b_ || _MI2020_)
-		fetch_idxdata(gspca_dev, tbl_common_d,
-				ARRAY_SIZE(tbl_common_d));
+		fetch_idxdata(gspca_dev, tbl_common4,
+				ARRAY_SIZE(tbl_common4));
 
-	fetch_idxdata(gspca_dev, tbl_common_e, ARRAY_SIZE(tbl_common_e));
+	fetch_idxdata(gspca_dev, tbl_common5, ARRAY_SIZE(tbl_common5));
 	if (_MI2020b_ || _MI2020_) {
 		/* Different from fret */
 		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x78");
@@ -525,15 +524,15 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
 				12, dat_800);
 
 		if (_MI2020c_)
-			fetch_idxdata(gspca_dev, tbl_init_post_alt_low_a,
-					ARRAY_SIZE(tbl_init_post_alt_low_a));
+			fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
+					ARRAY_SIZE(tbl_init_post_alt_low1));
 
 		if (reso == IMAGE_800)
-			fetch_idxdata(gspca_dev, tbl_init_post_alt_low_b,
-					ARRAY_SIZE(tbl_init_post_alt_low_b));
+			fetch_idxdata(gspca_dev, tbl_init_post_alt_low2,
+					ARRAY_SIZE(tbl_init_post_alt_low2));
 
-		fetch_idxdata(gspca_dev, tbl_init_post_alt_low_c,
-				ARRAY_SIZE(tbl_init_post_alt_low_c));
+		fetch_idxdata(gspca_dev, tbl_init_post_alt_low3,
+				ARRAY_SIZE(tbl_init_post_alt_low3));
 
 		if (_MI2020b_) {
 			ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
@@ -574,8 +573,8 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
 		msleep(5);/* " */
 
 		if (_MI2020c_) {
-			fetch_idxdata(gspca_dev, tbl_init_post_alt_low_d,
-					ARRAY_SIZE(tbl_init_post_alt_low_d));
+			fetch_idxdata(gspca_dev, tbl_init_post_alt_low4,
+					ARRAY_SIZE(tbl_init_post_alt_low4));
 		} else {
 			ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
 			msleep(14); /* 0xd8 */
@@ -644,8 +643,8 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
 					3, "\x90\x04\xb0");
 		}
 
-		fetch_idxdata(gspca_dev, tbl_init_post_alt_big_a,
-				ARRAY_SIZE(tbl_init_post_alt_big_a));
+		fetch_idxdata(gspca_dev, tbl_init_post_alt_big1,
+				ARRAY_SIZE(tbl_init_post_alt_big1));
 
 		if (reso == IMAGE_1600)
 			msleep(13); /* 1600 */
@@ -708,8 +707,8 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
 		msleep(14);
 
 		if (_MI2020c_)
-			fetch_idxdata(gspca_dev, tbl_init_post_alt_big_b,
-					ARRAY_SIZE(tbl_init_post_alt_big_b));
+			fetch_idxdata(gspca_dev, tbl_init_post_alt_big2,
+					ARRAY_SIZE(tbl_init_post_alt_big2));
 
 		/* flip/mirror */
 		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
@@ -738,8 +737,8 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
 		sd->nbIm = 0;
 
 		if (_MI2020c_)
-			fetch_idxdata(gspca_dev, tbl_init_post_alt_big_c,
-					ARRAY_SIZE(tbl_init_post_alt_big_c));
+			fetch_idxdata(gspca_dev, tbl_init_post_alt_big3,
+					ARRAY_SIZE(tbl_init_post_alt_big3));
 	}
 
 	sd->vold.mirror    = mirror;
diff --git a/drivers/media/video/gspca/gl860/gl860-ov2640.c b/drivers/media/video/gspca/gl860/gl860-ov2640.c
index 14b9c373f9f7..768cac5cd72b 100644
--- a/drivers/media/video/gspca/gl860/gl860-ov2640.c
+++ b/drivers/media/video/gspca/gl860/gl860-ov2640.c
@@ -1,6 +1,5 @@
-/* @file gl860-ov2640.c
- * @author Olivier LORIN, from Malmostoso's logs
- * @date 2009-08-27
+/* Subdriver for the GL860 chip with the OV2640 sensor
+ * Author Olivier LORIN, from Malmostoso's logs
  *
  * 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
@@ -21,8 +20,12 @@
 #include "gl860.h"
 
 static u8 dat_init1[] = "\x00\x41\x07\x6a\x06\x61\x0d\x6a" "\x10\x10\xc1\x01";
-static u8 dat_init2[] = {0x61}; /* expected */
-static u8 dat_init3[] = {0x51}; /* expected */
+
+static u8 c61[] = {0x61}; /* expected */
+static u8 c51[] = {0x51}; /* expected */
+static u8 c50[] = {0x50}; /* expected */
+static u8 c28[] = {0x28}; /* expected */
+static u8 ca8[] = {0xa8}; /* expected */
 
 static u8 dat_post[] =
 	"\x00\x41\x07\x6a\x06\xef\x0d\x6a" "\x10\x10\xc1\x01";
@@ -32,10 +35,6 @@ static u8 dat_800[]  = "\xd0\x01\xd1\x10\xd2\x58\xd3\x02\xd4\x18\xd5\x21";
 static u8 dat_1280[] = "\xd0\x01\xd1\x18\xd2\xc0\xd3\x02\xd4\x28\xd5\x01";
 static u8 dat_1600[] = "\xd0\x01\xd1\x20\xd2\xb0\xd3\x02\xd4\x30\xd5\x41";
 
-static u8 c50[] = {0x50}; /* expected */
-static u8 c28[] = {0x28}; /* expected */
-static u8 ca8[] = {0xa8}; /* expected */
-
 static struct validx tbl_init_at_startup[] = {
 	{0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
 	{0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
@@ -92,7 +91,7 @@ static struct validx tbl_common[] = {
 	{0x6000, 0x0010},
 };
 
-static struct validx tbl_sensor_settings_common_a[] = {
+static struct validx tbl_sensor_settings_common1[] = {
 	{0x0041, 0x0000}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d},
 	{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2},
 	{0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0041, 0x0000},
@@ -104,40 +103,10 @@ static struct validx tbl_sensor_settings_common_a[] = {
 	{0x0040, 0x0000},
 };
 
-static struct validx tbl_sensor_settings_common_b[] = {
+static struct validx tbl_sensor_settings_common2[] = {
 	{0x6001, 0x00ff}, {0x6038, 0x000c},
 	{10, 0xffff},
 	{0x6000, 0x0011},
-	/* backlight=31/64 */
-	{0x6001, 0x00ff}, {0x603e, 0x0024}, {0x6034, 0x0025},
-	/* bright=0/256 */
-	{0x6000, 0x00ff}, {0x6009, 0x007c}, {0x6000, 0x007d},
-	/* wbal=64/128 */
-	{0x6000, 0x00ff}, {0x6003, 0x007c}, {0x6040, 0x007d},
-	/* cntr=0/256 */
-	{0x6000, 0x00ff}, {0x6007, 0x007c}, {0x6000, 0x007d},
-	/* sat=128/256 */
-	{0x6000, 0x00ff}, {0x6001, 0x007c}, {0x6080, 0x007d},
-	/* sharpness=0/32 */
-	{0x6000, 0x00ff}, {0x6001, 0x0092}, {0x60c0, 0x0093},
-	/* hue=0/256 */
-	{0x6000, 0x00ff}, {0x6002, 0x007c}, {0x6000, 0x007d},
-	/* gam=32/64 */
-	{0x6000, 0x00ff}, {0x6008, 0x007c}, {0x6020, 0x007d},
-	/* image right up */
-	{0xffff, 0xffff},
-	{15, 0xffff},
-	{0x6001, 0x00ff}, {0x6000, 0x8004},
-	{0xffff, 0xffff},
-	{0x60a8, 0x0004},
-	{15, 0xffff},
-	{0x6001, 0x00ff}, {0x6000, 0x8004},
-	{0xffff, 0xffff},
-	{0x60f8, 0x0004},
-	/* image right up */
-	{0xffff, 0xffff},
-	/* backlight=31/64 */
-	{0x6001, 0x00ff}, {0x603e, 0x0024}, {0x6034, 0x0025},
 };
 
 static struct validx tbl_640[] = {
@@ -166,7 +135,7 @@ static struct validx tbl_800[] = {
 	{0x60ff, 0x00dd}, {0x6020, 0x008c}, {0x6001, 0x00ff}, {0x6044, 0x0018},
 };
 
-static struct validx tbl_big_a[] = {
+static struct validx tbl_big1[] = {
 	{0x0002, 0x00c1}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
 	{0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045},
 	{0x6000, 0x0010}, {0x6000, 0x0011}, {0x6011, 0x0017}, {0x6075, 0x0018},
@@ -176,14 +145,14 @@ static struct validx tbl_big_a[] = {
 	{0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c},
 };
 
-static struct validx tbl_big_b[] = {
+static struct validx tbl_big2[] = {
 	{0x603d, 0x0086}, {0x6000, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052},
 	{0x6000, 0x0053}, {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057},
 	{0x6040, 0x005a}, {0x60f0, 0x005b}, {0x6001, 0x005c}, {0x6082, 0x00d3},
 	{0x6000, 0x008e},
 };
 
-static struct validx tbl_big_c[] = {
+static struct validx tbl_big3[] = {
 	{0x6004, 0x00da}, {0x6000, 0x00e0}, {0x6067, 0x00e1}, {0x60ff, 0x00dd},
 	{0x6001, 0x00ff}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
 	{0x6001, 0x00ff}, {0x6000, 0x0011}, {0x6000, 0x00ff}, {0x6010, 0x00c7},
@@ -223,17 +192,19 @@ void ov2640_init_settings(struct gspca_dev *gspca_dev)
 	sd->vcur.hue        =   0;
 	sd->vcur.saturation = 128;
 	sd->vcur.whitebal   =  64;
+	sd->vcur.mirror     =   0;
+	sd->vcur.flip       =   0;
 
 	sd->vmax.backlight  =  64;
 	sd->vmax.brightness = 255;
 	sd->vmax.sharpness  =  31;
 	sd->vmax.contrast   = 255;
 	sd->vmax.gamma      =  64;
-	sd->vmax.hue        = 255 + 1;
+	sd->vmax.hue        = 254 + 2;
 	sd->vmax.saturation = 255;
 	sd->vmax.whitebal   = 128;
-	sd->vmax.mirror     = 0;
-	sd->vmax.flip       = 0;
+	sd->vmax.mirror     = 1;
+	sd->vmax.flip       = 1;
 	sd->vmax.AC50Hz     = 0;
 
 	sd->dev_camera_settings = ov2640_camera_settings;
@@ -259,11 +230,11 @@ static int ov2640_init_at_startup(struct gspca_dev *gspca_dev)
 
 	common(gspca_dev);
 
-	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0006, 1, dat_init2);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0006, 1, c61);
 
 	ctrl_out(gspca_dev, 0x40, 1, 0x00ef, 0x0006, 0, NULL);
 
-	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, dat_init3);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c51);
 
 	ctrl_out(gspca_dev, 0x40, 1, 0x0051, 0x0000, 0, NULL);
 /*	ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */
@@ -275,6 +246,8 @@ static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
+	sd->mirrorMask = 0;
+
 	sd->vold.backlight  = -1;
 	sd->vold.brightness = -1;
 	sd->vold.sharpness  = -1;
@@ -283,6 +256,8 @@ static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev)
 	sd->vold.gamma    = -1;
 	sd->vold.hue      = -1;
 	sd->vold.whitebal = -1;
+	sd->vold.mirror = -1;
+	sd->vold.flip   = -1;
 
 	ov2640_init_post_alt(gspca_dev);
 
@@ -292,16 +267,16 @@ static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev)
 static int ov2640_init_post_alt(struct gspca_dev *gspca_dev)
 {
 	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
-	s32 n; /* reserved for FETCH macros */
+	s32 n; /* reserved for FETCH functions */
 
 	ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
 
-	n = fetch_validx(gspca_dev, tbl_sensor_settings_common_a,
-			ARRAY_SIZE(tbl_sensor_settings_common_a));
+	n = fetch_validx(gspca_dev, tbl_sensor_settings_common1,
+			ARRAY_SIZE(tbl_sensor_settings_common1));
 	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_post);
 	common(gspca_dev);
-	keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_a,
-				ARRAY_SIZE(tbl_sensor_settings_common_a), n);
+	keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common1,
+				ARRAY_SIZE(tbl_sensor_settings_common1), n);
 
 	switch (reso) {
 	case IMAGE_640:
@@ -316,18 +291,18 @@ static int ov2640_init_post_alt(struct gspca_dev *gspca_dev)
 
 	case IMAGE_1600:
 	case IMAGE_1280:
-		n = fetch_validx(gspca_dev, tbl_big_a, ARRAY_SIZE(tbl_big_a));
+		n = fetch_validx(gspca_dev, tbl_big1, ARRAY_SIZE(tbl_big1));
 
 		if (reso == IMAGE_1280) {
-			n = fetch_validx(gspca_dev, tbl_big_b,
-					ARRAY_SIZE(tbl_big_b));
+			n = fetch_validx(gspca_dev, tbl_big2,
+					ARRAY_SIZE(tbl_big2));
 		} else {
 			ctrl_out(gspca_dev, 0x40, 1, 0x601d, 0x0086, 0, NULL);
 			ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00d7, 0, NULL);
 			ctrl_out(gspca_dev, 0x40, 1, 0x6082, 0x00d3, 0, NULL);
 		}
 
-		n = fetch_validx(gspca_dev, tbl_big_c, ARRAY_SIZE(tbl_big_c));
+		n = fetch_validx(gspca_dev, tbl_big3, ARRAY_SIZE(tbl_big3));
 
 		if (reso == IMAGE_1280) {
 			ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
@@ -343,20 +318,8 @@ static int ov2640_init_post_alt(struct gspca_dev *gspca_dev)
 		break;
 	}
 
-	n = fetch_validx(gspca_dev, tbl_sensor_settings_common_b,
-			ARRAY_SIZE(tbl_sensor_settings_common_b));
-	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50);
-	keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b,
-				ARRAY_SIZE(tbl_sensor_settings_common_b), n);
-	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, c28);
-	keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b,
-				ARRAY_SIZE(tbl_sensor_settings_common_b), n);
-	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, ca8);
-	keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b,
-				ARRAY_SIZE(tbl_sensor_settings_common_b), n);
-	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50);
-	keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common_b,
-				ARRAY_SIZE(tbl_sensor_settings_common_b), n);
+	n = fetch_validx(gspca_dev, tbl_sensor_settings_common2,
+			ARRAY_SIZE(tbl_sensor_settings_common2));
 
 	ov2640_camera_settings(gspca_dev);
 
@@ -393,18 +356,20 @@ static int ov2640_camera_settings(struct gspca_dev *gspca_dev)
 	s32 sat    = sd->vcur.saturation;
 	s32 hue    = sd->vcur.hue;
 	s32 wbal   = sd->vcur.whitebal;
+	s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) == 0);
+	s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) == 0);
 
 	if (backlight != sd->vold.backlight) {
+		/* No sd->vold.backlight=backlight; (to be done again later) */
 		if (backlight < 0 || backlight > sd->vmax.backlight)
 			backlight = 0;
 
 		ctrl_out(gspca_dev, 0x40, 1, 0x6001                 , 0x00ff,
 				0, NULL);
-		ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight     , 0x0024,
+		ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight     , 0x0024,
 				0, NULL);
-		ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight - 10, 0x0025,
+		ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025,
 				0, NULL);
-		/* No sd->vold.backlight=backlight; (to be done again later) */
 	}
 
 	if (bright != sd->vold.brightness) {
@@ -466,7 +431,7 @@ static int ov2640_camera_settings(struct gspca_dev *gspca_dev)
 		ctrl_out(gspca_dev, 0x40, 1, 0x6002     , 0x007c, 0, NULL);
 		ctrl_out(gspca_dev, 0x40, 1, 0x6000 + hue * (hue < 255), 0x007d,
 				0, NULL);
-		if (hue >= sd->vmax.hue)
+		if (hue >= 255)
 			sd->swapRB = 1;
 		else
 			sd->swapRB = 0;
@@ -482,14 +447,33 @@ static int ov2640_camera_settings(struct gspca_dev *gspca_dev)
 		ctrl_out(gspca_dev, 0x40, 1, 0x6000 + gam, 0x007d, 0, NULL);
 	}
 
+	if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
+		sd->vold.mirror = mirror;
+		sd->vold.flip   = flip;
+
+		mirror = 0x80 * mirror;
+		ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL);
+		ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, c28);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6028 + mirror, 0x0004, 0, NULL);
+
+		flip = 0x50 * flip + mirror;
+		ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL);
+		ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, ca8);
+		ctrl_out(gspca_dev, 0x40, 1, 0x6028 + flip, 0x0004, 0, NULL);
+
+		ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50);
+	}
+
 	if (backlight != sd->vold.backlight) {
 		sd->vold.backlight = backlight;
 
 		ctrl_out(gspca_dev, 0x40, 1, 0x6001                 , 0x00ff,
 				0, NULL);
-		ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight     , 0x0024,
+		ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight     , 0x0024,
 				0, NULL);
-		ctrl_out(gspca_dev, 0x40, 1, 0x601f + backlight - 10, 0x0025,
+		ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025,
 				0, NULL);
 	}
 
diff --git a/drivers/media/video/gspca/gl860/gl860-ov9655.c b/drivers/media/video/gspca/gl860/gl860-ov9655.c
index eda3346f939c..d412694c50af 100644
--- a/drivers/media/video/gspca/gl860/gl860-ov9655.c
+++ b/drivers/media/video/gspca/gl860/gl860-ov9655.c
@@ -1,7 +1,6 @@
-/* @file gl860-ov9655.c
- * @author Olivier LORIN, from logs done by Simon (Sur3) and Almighurt
+/* Subdriver for the GL860 chip with the OV9655 sensor
+ * Author Olivier LORIN, from logs done by Simon (Sur3) and Almighurt
  * on dsd's weblog
- * @date 2009-08-27
  *
  * 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
@@ -104,14 +103,14 @@ static u8 *tbl_800[] = {
 };
 
 static u8 c04[] = {0x04};
-static u8 dat_post_1[] = "\x04\x00\x10\x20\xa1\x00\x00\x02";
-static u8 dat_post_2[] = "\x10\x10\xc1\x02";
-static u8 dat_post_3[] = "\x04\x00\x10\x7c\xa1\x00\x00\x04";
-static u8 dat_post_4[] = "\x10\x02\xc1\x06";
-static u8 dat_post_5[] = "\x04\x00\x10\x7b\xa1\x00\x00\x08";
-static u8 dat_post_6[] = "\x10\x10\xc1\x05";
-static u8 dat_post_7[] = "\x04\x00\x10\x7c\xa1\x00\x00\x08";
-static u8 dat_post_8[] = "\x04\x00\x10\x7c\xa1\x00\x00\x09";
+static u8 dat_post1[] = "\x04\x00\x10\x20\xa1\x00\x00\x02";
+static u8 dat_post2[] = "\x10\x10\xc1\x02";
+static u8 dat_post3[] = "\x04\x00\x10\x7c\xa1\x00\x00\x04";
+static u8 dat_post4[] = "\x10\x02\xc1\x06";
+static u8 dat_post5[] = "\x04\x00\x10\x7b\xa1\x00\x00\x08";
+static u8 dat_post6[] = "\x10\x10\xc1\x05";
+static u8 dat_post7[] = "\x04\x00\x10\x7c\xa1\x00\x00\x08";
+static u8 dat_post8[] = "\x04\x00\x10\x7c\xa1\x00\x00\x09";
 
 static struct validx tbl_init_post_alt[] = {
 	{0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x603c, 0x00ff},
@@ -212,7 +211,7 @@ static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev)
 static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
 {
 	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
-	s32 n; /* reserved for FETCH macros */
+	s32 n; /* reserved for FETCH functions */
 	s32 i;
 	u8 **tbl;
 
@@ -243,7 +242,7 @@ static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
 	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
 	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
 					ARRAY_SIZE(tbl_init_post_alt), n);
-	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1);
 	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
 					ARRAY_SIZE(tbl_init_post_alt), n);
 
@@ -259,7 +258,7 @@ static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
 	ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04);
 	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
 					ARRAY_SIZE(tbl_init_post_alt), n);
-	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1);
 	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
 					ARRAY_SIZE(tbl_init_post_alt), n);
 
@@ -270,18 +269,18 @@ static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
 	keep_on_fetching_validx(gspca_dev, tbl_init_post_alt,
 					ARRAY_SIZE(tbl_init_post_alt), n);
 
-	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1);
 
-	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post_2);
-	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_3);
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post2);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post3);
 
-	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post_4);
-	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_5);
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post4);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post5);
 
-	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post_6);
-	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_7);
+	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post6);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post7);
 
-	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post_8);
+	ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post8);
 
 	ov9655_camera_settings(gspca_dev);
 
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index 6ef59ac7f502..a695e0ae13c2 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -1,9 +1,7 @@
-/* @file gl860.c
- * @date 2009-08-27
+/* GSPCA subdrivers for Genesys Logic webcams with the GL860 chip
+ * Subdriver core
  *
- * Genesys Logic webcam with gl860 subdrivers
- *
- * Driver by Olivier Lorin <o.lorin@laposte.net>
+ * 2009/09/24 Olivier Lorin <o.lorin@laposte.net>
  * GSPCA by Jean-Francois Moine <http://moinejf.free.fr>
  * Thanks BUGabundo and Malmostoso for your amazing help!
  *
@@ -23,8 +21,8 @@
 #include "gspca.h"
 #include "gl860.h"
 
-MODULE_AUTHOR("Olivier Lorin <lorin@laposte.net>");
-MODULE_DESCRIPTION("GSPCA/Genesys Logic GL860 USB Camera Driver");
+MODULE_AUTHOR("Olivier Lorin <o.lorin@laposte.net>");
+MODULE_DESCRIPTION("Genesys Logic USB PC Camera Driver");
 MODULE_LICENSE("GPL");
 
 /*======================== static function declarations ====================*/
@@ -38,7 +36,7 @@ static int  sd_isoc_init(struct gspca_dev *gspca_dev);
 static int  sd_start(struct gspca_dev *gspca_dev);
 static void sd_stop0(struct gspca_dev *gspca_dev);
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame, u8 *data, s32 len);
+			u8 *data, int len);
 static void sd_callback(struct gspca_dev *gspca_dev);
 
 static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
@@ -53,7 +51,7 @@ MODULE_PARM_DESC(AC50Hz, " Does AC power frequency is 50Hz? (0/1)");
 static char sensor[7];
 module_param_string(sensor, sensor, sizeof(sensor), 0644);
 MODULE_PARM_DESC(sensor,
-		" Driver sensor ('MI1320'/'MI2020'/'OV9655'/'OV2640'/'')");
+		" Driver sensor ('MI1320'/'MI2020'/'OV9655'/'OV2640')");
 
 /*============================ webcam controls =============================*/
 
@@ -156,7 +154,7 @@ static int gl860_build_control_table(struct gspca_dev *gspca_dev)
 	SET_MY_CTRL(V4L2_CID_VFLIP,
 		V4L2_CTRL_TYPE_BOOLEAN, "Flip", flip)
 	SET_MY_CTRL(V4L2_CID_POWER_LINE_FREQUENCY,
-		V4L2_CTRL_TYPE_BOOLEAN, "50Hz", AC50Hz)
+		V4L2_CTRL_TYPE_BOOLEAN, "AC power 50Hz", AC50Hz)
 
 	return nCtrls;
 }
@@ -435,7 +433,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 
 /* This function is called when an image is being received */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame, u8 *data, s32 len)
+			u8 *data, int len)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	static s32 nSkipped;
@@ -447,11 +445,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	/* Test only against 0202h, so endianess does not matter */
 	switch (*(s16 *) data) {
 	case 0x0202:		/* End of frame, start a new one */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 		nSkipped = 0;
 		if (sd->nbIm >= 0 && sd->nbIm < 10)
 			sd->nbIm++;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
 		break;
 
 	default:
@@ -466,7 +464,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 				nSkipped = nToSkip + 1;
 			}
 			gspca_frame_add(gspca_dev,
-				INTER_PACKET, frame, data, len);
+				INTER_PACKET, data, len);
 		}
 		break;
 	}
@@ -702,6 +700,7 @@ static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
 		ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL);
 		msleep(56);
 
+		PDEBUG(D_PROBE, "probing for sensor MI2020 or OVXXXX");
 		nOV = 0;
 		for (ntry = 0; ntry < 4; ntry++) {
 			ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
@@ -711,14 +710,14 @@ static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
 			ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL);
 			msleep(10);
 			ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &probe);
-			PDEBUG(D_PROBE, "1st probe=%02x", probe);
+			PDEBUG(D_PROBE, "probe=0x%02x", probe);
 			if (probe == 0xff)
 				nOV++;
 		}
 
 		if (nOV) {
-			PDEBUG(D_PROBE, "0xff -> sensor OVXXXX");
-			PDEBUG(D_PROBE, "Probing for sensor OV2640 or OV9655");
+			PDEBUG(D_PROBE, "0xff -> OVXXXX");
+			PDEBUG(D_PROBE, "probing for sensor OV2640 or OV9655");
 
 			nb26 = nb96 = 0;
 			for (ntry = 0; ntry < 4; ntry++) {
@@ -728,40 +727,38 @@ static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
 				ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x800a,
 						0, NULL);
 				msleep(10);
+
 				/* Wait for 26(OV2640) or 96(OV9655) */
 				ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x800a,
 						1, &probe);
 
-				PDEBUG(D_PROBE, "2nd probe=%02x", probe);
-				if (probe == 0x00)
-					nb26++;
 				if (probe == 0x26 || probe == 0x40) {
+					PDEBUG(D_PROBE,
+						"probe=0x%02x -> OV2640",
+						probe);
 					sd->sensor = ID_OV2640;
 					nb26 += 4;
 					break;
 				}
 				if (probe == 0x96 || probe == 0x55) {
+					PDEBUG(D_PROBE,
+						"probe=0x%02x -> OV9655",
+						probe);
 					sd->sensor = ID_OV9655;
 					nb96 += 4;
 					break;
 				}
+				PDEBUG(D_PROBE, "probe=0x%02x", probe);
+				if (probe == 0x00)
+					nb26++;
 				if (probe == 0xff)
 					nb96++;
 				msleep(3);
 			}
-			if (nb26 < 4 && nb96 < 4) {
-				PDEBUG(D_PROBE, "No relevant answer ");
-				PDEBUG(D_PROBE, "* 1.3Mpixels -> use OV9655");
-				PDEBUG(D_PROBE, "* 2.0Mpixels -> use OV2640");
-				PDEBUG(D_PROBE,
-					"To force a sensor, add that line to "
-					"/etc/modprobe.d/options.conf:");
-				PDEBUG(D_PROBE, "options gspca_gl860 "
-					"sensor=\"OV2640\" or \"OV9655\"");
+			if (nb26 < 4 && nb96 < 4)
 				return -1;
-			}
-		} else { /* probe = 0 */
-			PDEBUG(D_PROBE, "No 0xff -> sensor MI2020");
+		} else {
+			PDEBUG(D_PROBE, "Not any 0xff -> MI2020");
 			sd->sensor = ID_MI2020;
 		}
 	}
diff --git a/drivers/media/video/gspca/gl860/gl860.h b/drivers/media/video/gspca/gl860/gl860.h
index cef4e24c1e61..305061ff8387 100644
--- a/drivers/media/video/gspca/gl860/gl860.h
+++ b/drivers/media/video/gspca/gl860/gl860.h
@@ -1,6 +1,7 @@
-/* @file gl860.h
- * @author Olivier LORIN, tiré du pilote Syntek par Nicolas VIVIEN
- * @date 2009-08-27
+/* GSPCA subdrivers for Genesys Logic webcams with the GL860 chip
+ * Subdriver declarations
+ *
+ * 2009/10/14 Olivier LORIN <o.lorin@laposte.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
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 23d3fb776918..4076f8e5a6fc 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -47,7 +47,7 @@ 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, 7, 0)
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 8, 0)
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -74,7 +74,7 @@ static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
 #define PDEBUG_MODE(txt, pixfmt, w, h)
 #endif
 
-/* specific memory types - !! should different from V4L2_MEMORY_xxx */
+/* specific memory types - !! should be different from V4L2_MEMORY_xxx */
 #define GSPCA_MEMORY_NO 0	/* V4L2_MEMORY_xxx starts from 1 */
 #define GSPCA_MEMORY_READ 7
 
@@ -126,7 +126,6 @@ EXPORT_SYMBOL(gspca_get_i_frame);
 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 */
 	int i, len, st;
 	cam_pkt_op pkt_scan;
@@ -135,21 +134,16 @@ static void fill_frame(struct gspca_dev *gspca_dev,
 		if (urb->status == -ESHUTDOWN)
 			return;		/* disconnection */
 #ifdef CONFIG_PM
-		if (!gspca_dev->frozen)
+		if (gspca_dev->frozen)
+			return;
 #endif
-			PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
-		return;
+		PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+		urb->status = 0;
+		goto resubmit;
 	}
 	pkt_scan = gspca_dev->sd_desc->pkt_scan;
 	for (i = 0; i < urb->number_of_packets; i++) {
 
-		/* check the availability of the frame buffer */
-		frame = gspca_get_i_frame(gspca_dev);
-		if (!frame) {
-			gspca_dev->last_packet_type = DISCARD_PACKET;
-			break;
-		}
-
 		/* check the packet status and length */
 		len = urb->iso_frame_desc[i].actual_length;
 		if (len == 0) {
@@ -171,9 +165,10 @@ static void fill_frame(struct gspca_dev *gspca_dev,
 			i, urb->iso_frame_desc[i].offset, len);
 		data = (u8 *) urb->transfer_buffer
 					+ urb->iso_frame_desc[i].offset;
-		pkt_scan(gspca_dev, frame, data, len);
+		pkt_scan(gspca_dev, data, len);
 	}
 
+resubmit:
 	/* resubmit the URB */
 	st = usb_submit_urb(urb, GFP_ATOMIC);
 	if (st < 0)
@@ -201,7 +196,6 @@ static void isoc_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;
 	int st;
 
 	PDEBUG(D_PACK, "bulk irq");
@@ -212,29 +206,22 @@ static void bulk_irq(struct urb *urb)
 		break;
 	case -ESHUTDOWN:
 		return;		/* disconnection */
-	case -ECONNRESET:
-		urb->status = 0;
-		break;
 	default:
 #ifdef CONFIG_PM
-		if (!gspca_dev->frozen)
+		if (gspca_dev->frozen)
+			return;
 #endif
-			PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
-		return;
+		PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+		urb->status = 0;
+		goto resubmit;
 	}
 
-	/* check the availability of the frame buffer */
-	frame = gspca_get_i_frame(gspca_dev);
-	if (!frame) {
-		gspca_dev->last_packet_type = DISCARD_PACKET;
-	} else {
-		PDEBUG(D_PACK, "packet l:%d", urb->actual_length);
-		gspca_dev->sd_desc->pkt_scan(gspca_dev,
-					frame,
-					urb->transfer_buffer,
-					urb->actual_length);
-	}
+	PDEBUG(D_PACK, "packet l:%d", urb->actual_length);
+	gspca_dev->sd_desc->pkt_scan(gspca_dev,
+				urb->transfer_buffer,
+				urb->actual_length);
 
+resubmit:
 	/* resubmit the URB */
 	if (gspca_dev->cam.bulk_nurbs != 0) {
 		st = usb_submit_urb(urb, GFP_ATOMIC);
@@ -255,24 +242,27 @@ static void bulk_irq(struct urb *urb)
  * DISCARD_PACKET invalidates the whole frame.
  * On LAST_PACKET, a new frame is returned.
  */
-struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
-				    enum gspca_packet_type packet_type,
-				    struct gspca_frame *frame,
-				    const __u8 *data,
-				    int len)
+void gspca_frame_add(struct gspca_dev *gspca_dev,
+			enum gspca_packet_type packet_type,
+			const u8 *data,
+			int len)
 {
+	struct gspca_frame *frame;
 	int i, j;
 
 	PDEBUG(D_PACK, "add t:%d l:%d",	packet_type, len);
 
+	/* check the availability of the frame buffer */
+	frame = gspca_dev->cur_frame;
+	if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
+					!= V4L2_BUF_FLAG_QUEUED) {
+		gspca_dev->last_packet_type = DISCARD_PACKET;
+		return;
+	}
+
 	/* when start of a new frame, if the current frame buffer
 	 * is not queued, discard the whole frame */
 	if (packet_type == FIRST_PACKET) {
-		if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
-						!= V4L2_BUF_FLAG_QUEUED) {
-			gspca_dev->last_packet_type = DISCARD_PACKET;
-			return frame;
-		}
 		frame->data_end = frame->data;
 		jiffies_to_timeval(get_jiffies_64(),
 				   &frame->v4l2_buf.timestamp);
@@ -280,7 +270,7 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
 	} else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
 		if (packet_type == LAST_PACKET)
 			gspca_dev->last_packet_type = packet_type;
-		return frame;
+		return;
 	}
 
 	/* append the packet to the frame buffer */
@@ -312,9 +302,9 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
 			i,
 			gspca_dev->fr_o);
 		j = gspca_dev->fr_queue[i];
-		frame = &gspca_dev->frame[j];
+		gspca_dev->cur_frame = &gspca_dev->frame[j];
 	}
-	return frame;
+	return;
 }
 EXPORT_SYMBOL(gspca_frame_add);
 
@@ -395,6 +385,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
 		frame->v4l2_buf.m.offset = i * frsz;
 	}
 	gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
+	gspca_dev->cur_frame = &gspca_dev->frame[0];
 	gspca_dev->last_packet_type = DISCARD_PACKET;
 	gspca_dev->sequence = 0;
 	return 0;
@@ -475,10 +466,18 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
 	xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
 				   : USB_ENDPOINT_XFER_ISOC;
 	i = gspca_dev->alt;			/* previous alt setting */
-	while (--i >= 0) {
-		ep = alt_xfer(&intf->altsetting[i], xfer);
-		if (ep)
-			break;
+	if (gspca_dev->cam.reverse_alts) {
+		while (++i < gspca_dev->nbalt) {
+			ep = alt_xfer(&intf->altsetting[i], xfer);
+			if (ep)
+				break;
+		}
+	} else {
+		while (--i >= 0) {
+			ep = alt_xfer(&intf->altsetting[i], xfer);
+			if (ep)
+				break;
+		}
 	}
 	if (ep == NULL) {
 		err("no transfer endpoint found");
@@ -599,7 +598,11 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
 
 	/* set the higher alternate setting and
 	 * loop until urb submit succeeds */
-	gspca_dev->alt = gspca_dev->nbalt;
+	if (gspca_dev->cam.reverse_alts)
+		gspca_dev->alt = 0;
+	else
+		gspca_dev->alt = gspca_dev->nbalt;
+
 	if (gspca_dev->sd_desc->isoc_init) {
 		ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
 		if (ret < 0)
@@ -641,15 +644,19 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
 		}
 		if (ret >= 0)
 			break;
-		PDEBUG(D_ERR|D_STREAM,
-			"usb_submit_urb alt %d err %d", gspca_dev->alt, ret);
 		gspca_dev->streaming = 0;
 		destroy_urbs(gspca_dev);
-		if (ret != -ENOSPC)
+		if (ret != -ENOSPC) {
+			PDEBUG(D_ERR|D_STREAM,
+				"usb_submit_urb alt %d err %d",
+				gspca_dev->alt, ret);
 			goto out;
+		}
 
 		/* the bandwidth is not wide enough
 		 * negociate or try a lower alternate setting */
+		PDEBUG(D_ERR|D_STREAM,
+			"bandwidth not wide enough - trying again");
 		msleep(20);	/* wait for kill complete */
 		if (gspca_dev->sd_desc->isoc_nego) {
 			ret = gspca_dev->sd_desc->isoc_nego(gspca_dev);
@@ -980,7 +987,7 @@ static void gspca_release(struct video_device *vfd)
 {
 	struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev);
 
-	PDEBUG(D_STREAM, "device released");
+	PDEBUG(D_PROBE, "/dev/video%d released", gspca_dev->vdev.num);
 
 	kfree(gspca_dev->usb_buf);
 	kfree(gspca_dev);
@@ -991,7 +998,7 @@ static int dev_open(struct file *file)
 	struct gspca_dev *gspca_dev;
 	int ret;
 
-	PDEBUG(D_STREAM, "%s open", current->comm);
+	PDEBUG(D_STREAM, "[%s] open", current->comm);
 	gspca_dev = (struct gspca_dev *) video_devdata(file);
 	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
 		return -ERESTARTSYS;
@@ -1037,7 +1044,7 @@ static int dev_close(struct file *file)
 {
 	struct gspca_dev *gspca_dev = file->private_data;
 
-	PDEBUG(D_STREAM, "%s close", current->comm);
+	PDEBUG(D_STREAM, "[%s] close", current->comm);
 	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
 		return -ERESTARTSYS;
 	gspca_dev->users--;
@@ -1138,10 +1145,13 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 		}
 	} else {
 		ctrls = get_ctrl(gspca_dev, id);
+		i = ctrls - gspca_dev->sd_desc->ctrls;
 	}
 	if (ctrls == NULL)
 		return -EINVAL;
 	memcpy(q_ctrl, ctrls, sizeof *q_ctrl);
+	if (gspca_dev->ctrl_inac & (1 << i))
+		q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 	return 0;
 }
 
@@ -1603,7 +1613,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
 		size -= PAGE_SIZE;
 	}
 
-	vma->vm_ops = &gspca_vm_ops;
+	vma->vm_ops = (struct vm_operations_struct *) &gspca_vm_ops;
 	vma->vm_private_data = frame;
 	gspca_vm_open(vma);
 	ret = 0;
@@ -2001,11 +2011,15 @@ int gspca_dev_probe(struct usb_interface *intf,
 	PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
 
 	/* we don't handle multi-config cameras */
-	if (dev->descriptor.bNumConfigurations != 1)
+	if (dev->descriptor.bNumConfigurations != 1) {
+		PDEBUG(D_ERR, "Too many config");
 		return -ENODEV;
+	}
 	interface = &intf->cur_altsetting->desc;
-	if (interface->bInterfaceNumber > 0)
+	if (interface->bInterfaceNumber > 0) {
+		PDEBUG(D_ERR, "intf != 0");
 		return -ENODEV;
+	}
 
 	/* create the device */
 	if (dev_size < sizeof *gspca_dev)
@@ -2059,7 +2073,7 @@ int gspca_dev_probe(struct usb_interface *intf,
 	}
 
 	usb_set_intfdata(intf, gspca_dev);
-	PDEBUG(D_PROBE, "probe ok");
+	PDEBUG(D_PROBE, "/dev/video%d created", gspca_dev->vdev.num);
 	return 0;
 out:
 	kfree(gspca_dev->usb_buf);
@@ -2078,6 +2092,7 @@ void gspca_disconnect(struct usb_interface *intf)
 {
 	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
 
+	PDEBUG(D_PROBE, "/dev/video%d disconnect", gspca_dev->vdev.num);
 	mutex_lock(&gspca_dev->usb_lock);
 	gspca_dev->present = 0;
 
@@ -2096,7 +2111,7 @@ void gspca_disconnect(struct usb_interface *intf)
 	/* (this will call gspca_release() immediatly or on last close) */
 	video_unregister_device(&gspca_dev->vdev);
 
-	PDEBUG(D_PROBE, "disconnect complete");
+/*	PDEBUG(D_PROBE, "disconnect complete"); */
 }
 EXPORT_SYMBOL(gspca_disconnect);
 
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 70b1fd830876..181617355ec3 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -58,6 +58,7 @@ struct cam {
 	u8 npkt;		/* number of packets in an ISOC message
 				 * 0 is the default value: 32 packets */
 	u32 input_flags;	/* value for ENUM_INPUT status flags */
+	char reverse_alts;	/* Alt settings are in high to low order */
 };
 
 struct gspca_dev;
@@ -78,8 +79,7 @@ typedef int (*cam_streamparm_op) (struct gspca_dev *,
 typedef int (*cam_qmnu_op) (struct gspca_dev *,
 			struct v4l2_querymenu *);
 typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
-				struct gspca_frame *frame,
-				__u8 *data,
+				u8 *data,
 				int len);
 
 struct ctrl {
@@ -142,6 +142,7 @@ struct gspca_dev {
 	struct cam cam;				/* device information */
 	const struct sd_desc *sd_desc;		/* subdriver description */
 	unsigned ctrl_dis;		/* disabled controls (bit map) */
+	unsigned ctrl_inac;		/* inactive controls (bit map) */
 
 #define USB_BUF_SZ 64
 	__u8 *usb_buf;				/* buffer for USB exchanges */
@@ -149,6 +150,7 @@ struct gspca_dev {
 
 	__u8 *frbuf;				/* buffer for nframes */
 	struct gspca_frame frame[GSPCA_MAX_FRAMES];
+	struct gspca_frame *cur_frame;		/* frame beeing filled */
 	__u32 frsz;				/* frame size */
 	char nframes;				/* number of frames */
 	char fr_i;				/* frame being filled */
@@ -189,11 +191,10 @@ int gspca_dev_probe(struct usb_interface *intf,
 		int dev_size,
 		struct module *module);
 void gspca_disconnect(struct usb_interface *intf);
-struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
-				    enum gspca_packet_type packet_type,
-				    struct gspca_frame *frame,
-				    const __u8 *data,
-				    int len);
+void gspca_frame_add(struct gspca_dev *gspca_dev,
+			enum gspca_packet_type packet_type,
+			const u8 *data,
+			int len);
 struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev);
 #ifdef CONFIG_PM
 int gspca_suspend(struct usb_interface *intf, pm_message_t message);
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
index a11c97ebeb0f..2019b04f9235 100644
--- a/drivers/media/video/gspca/jeilinj.c
+++ b/drivers/media/video/gspca/jeilinj.c
@@ -181,11 +181,9 @@ static void jlj_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 blocks_left; /* 0x200-sized blocks remaining in current frame. */
 	int size_in_blocks;
 	int act_len;
-	int discarding = 0; /* true if we failed to get space for frame. */
 	int packet_type;
 	int ret;
 	u8 *buffer;
@@ -196,15 +194,6 @@ static void jlj_dostream(struct work_struct *work)
 		goto quit_stream;
 	}
 	while (gspca_dev->present && gspca_dev->streaming) {
-		if (!gspca_dev->present)
-			goto quit_stream;
-		/* Start a new frame, and add the JPEG header, first thing */
-		frame = gspca_get_i_frame(gspca_dev);
-		if (frame && !discarding)
-			gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-					dev->jpeg_hdr, JPEG_HDR_SZ);
-		 else
-			discarding = 1;
 		/*
 		 * Now request data block 0. Line 0 reports the size
 		 * to download, in blocks of size 0x200, and also tells the
@@ -222,14 +211,15 @@ static void jlj_dostream(struct work_struct *work)
 		size_in_blocks = buffer[0x0a];
 		blocks_left = buffer[0x0a] - 1;
 		PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left);
-		packet_type = INTER_PACKET;
-		if (frame && !discarding)
-			/* Toss line 0 of data block 0, keep the rest. */
-			gspca_frame_add(gspca_dev, packet_type,
-				frame, buffer + FRAME_HEADER_LEN,
+
+		/* Start a new frame, and add the JPEG header, first thing */
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
+				dev->jpeg_hdr, JPEG_HDR_SZ);
+		/* Toss line 0 of data block 0, keep the rest. */
+		gspca_frame_add(gspca_dev, INTER_PACKET,
+				buffer + FRAME_HEADER_LEN,
 				JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN);
-			else
-				discarding = 1;
+
 		while (blocks_left > 0) {
 			if (!gspca_dev->present)
 				goto quit_stream;
@@ -246,12 +236,8 @@ static void jlj_dostream(struct work_struct *work)
 				packet_type = LAST_PACKET;
 			else
 				packet_type = INTER_PACKET;
-			if (frame && !discarding)
-				gspca_frame_add(gspca_dev, packet_type,
-						frame, buffer,
-						JEILINJ_MAX_TRANSFER);
-			else
-				discarding = 1;
+			gspca_frame_add(gspca_dev, packet_type,
+					buffer, JEILINJ_MAX_TRANSFER);
 		}
 	}
 quit_stream:
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index 7f1e5415850b..844fc1d886d1 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -274,8 +274,7 @@ static int m5602_start_transfer(struct gspca_dev *gspca_dev)
 }
 
 static void m5602_urb_complete(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,
-			__u8 *data, int len)
+				u8 *data, int len)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -295,19 +294,27 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
 		len -= 6;
 
 		/* Complete the last frame (if any) */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET,
-					frame, data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET,
+				NULL, 0);
 		sd->frame_count++;
 
 		/* Create a new frame */
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 
 		PDEBUG(D_FRAM, "Starting new frame %d",
 		       sd->frame_count);
 
 	} else {
-		int cur_frame_len = frame->data_end - frame->data;
+		struct gspca_frame *frame;
+		int cur_frame_len;
 
+		frame = gspca_get_i_frame(gspca_dev);
+		if (frame == NULL) {
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			return;
+		}
+
+		cur_frame_len = frame->data_end - frame->data;
 		/* Remove urb header */
 		data += 4;
 		len -= 4;
@@ -316,12 +323,12 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
 			PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
 			       sd->frame_count, len);
 
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			gspca_frame_add(gspca_dev, INTER_PACKET,
 					data, len);
 		} else if (frame->v4l2_buf.length - cur_frame_len > 0) {
 			/* Add the remaining data up to frame size */
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame, data,
-					frame->v4l2_buf.length - cur_frame_len);
+			gspca_frame_add(gspca_dev, INTER_PACKET, data,
+				    frame->v4l2_buf.length - cur_frame_len);
 		}
 	}
 }
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index de769caf013d..9cf8d68c71bf 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -325,8 +325,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 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;
@@ -348,11 +347,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			    || data[5 + p] == 0x67) {
 				PDEBUG(D_PACK, "sof offset: %d len: %d",
 					p, len);
-				frame = gspca_frame_add(gspca_dev, LAST_PACKET,
-							frame, data, p);
+				gspca_frame_add(gspca_dev, LAST_PACKET,
+						data, p);
 
 				/* put the JPEG header */
-				gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				gspca_frame_add(gspca_dev, FIRST_PACKET,
 					sd->jpeg_hdr, JPEG_HDR_SZ);
 				data += p + 16;
 				len -= p + 16;
@@ -360,7 +359,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			}
 		}
 	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c
index f8328b9efae5..126d968dd9e0 100644
--- a/drivers/media/video/gspca/mr97310a.c
+++ b/drivers/media/video/gspca/mr97310a.c
@@ -1,23 +1,30 @@
 /*
  * Mars MR97310A library
  *
+ * The original mr97310a driver, which supported the Aiptek Pencam VGA+, is
  * Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
  *
  * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+
  * and for the routines for detecting and classifying these various cameras,
+ * is Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
  *
+ * Support for the control settings for the CIF cameras is
+ * Copyright (C) 2009 Hans de Goede <hdgoede@redhat.com> and
+ * Thomas Kaiser <thomas@kaiser-linux.li>
+ *
+ * Support for the control settings for the VGA cameras is
  * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
  *
- * Acknowledgements:
+ * Several previously unsupported cameras are owned and have been tested by
+ * Hans de Goede <hdgoede@redhat.com> and
+ * Thomas Kaiser <thomas@kaiser-linux.li> and
+ * Theodore Kilgore <kilgota@auburn.edu> and
+ * Edmond Rodriguez <erodrig_97@yahoo.com> and
+ * Aurelien Jacobs <aurel@gnuage.org>
  *
  * The MR97311A support in gspca/mars.c has been helpful in understanding some
  * of the registers in these cameras.
  *
- * Hans de Goede <hdgoede@redhat.com> and
- * Thomas Kaiser <thomas@kaiser-linux.li>
- * have assisted with their experience. Each of them has also helped by
- * testing a previously unsupported camera.
- *
  * 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
@@ -40,11 +47,9 @@
 #define CAM_TYPE_CIF			0
 #define CAM_TYPE_VGA			1
 
-#define MR97310A_BRIGHTNESS_MIN		-254
-#define MR97310A_BRIGHTNESS_MAX		255
 #define MR97310A_BRIGHTNESS_DEFAULT	0
 
-#define MR97310A_EXPOSURE_MIN		300
+#define MR97310A_EXPOSURE_MIN		0
 #define MR97310A_EXPOSURE_MAX		4095
 #define MR97310A_EXPOSURE_DEFAULT	1000
 
@@ -52,6 +57,10 @@
 #define MR97310A_GAIN_MAX		31
 #define MR97310A_GAIN_DEFAULT		25
 
+#define MR97310A_MIN_CLOCKDIV_MIN	3
+#define MR97310A_MIN_CLOCKDIV_MAX	8
+#define MR97310A_MIN_CLOCKDIV_DEFAULT	3
+
 MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>,"
 	      "Theodore Kilgore <kilgota@auburn.edu>");
 MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
@@ -69,10 +78,12 @@ struct sd {
 	u8 cam_type;	/* 0 is CIF and 1 is VGA */
 	u8 sensor_type;	/* We use 0 and 1 here, too. */
 	u8 do_lcd_stop;
+	u8 adj_colors;
 
 	int brightness;
 	u16 exposure;
 	u8 gain;
+	u8 min_clockdiv;
 };
 
 struct sensor_w_data {
@@ -82,26 +93,31 @@ struct sensor_w_data {
 	int len;
 };
 
+static void sd_stopN(struct gspca_dev *gspca_dev);
 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_setexposure(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val);
 static void setbrightness(struct gspca_dev *gspca_dev);
 static void setexposure(struct gspca_dev *gspca_dev);
 static void setgain(struct gspca_dev *gspca_dev);
 
 /* V4L2 controls supported by the driver */
 static struct ctrl sd_ctrls[] = {
+/* Separate brightness control description for Argus QuickClix as it has
+   different limits from the other mr97310a cameras */
 	{
-#define BRIGHTNESS_IDX 0
+#define NORM_BRIGHTNESS_IDX 0
 		{
 			.id = V4L2_CID_BRIGHTNESS,
 			.type = V4L2_CTRL_TYPE_INTEGER,
 			.name = "Brightness",
-			.minimum = MR97310A_BRIGHTNESS_MIN,
-			.maximum = MR97310A_BRIGHTNESS_MAX,
+			.minimum = -254,
+			.maximum = 255,
 			.step = 1,
 			.default_value = MR97310A_BRIGHTNESS_DEFAULT,
 			.flags = 0,
@@ -110,7 +126,22 @@ static struct ctrl sd_ctrls[] = {
 		.get = sd_getbrightness,
 	},
 	{
-#define EXPOSURE_IDX 1
+#define ARGUS_QC_BRIGHTNESS_IDX 1
+		{
+			.id = V4L2_CID_BRIGHTNESS,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Brightness",
+			.minimum = 0,
+			.maximum = 15,
+			.step = 1,
+			.default_value = MR97310A_BRIGHTNESS_DEFAULT,
+			.flags = 0,
+		},
+		.set = sd_setbrightness,
+		.get = sd_getbrightness,
+	},
+	{
+#define EXPOSURE_IDX 2
 		{
 			.id = V4L2_CID_EXPOSURE,
 			.type = V4L2_CTRL_TYPE_INTEGER,
@@ -125,7 +156,7 @@ static struct ctrl sd_ctrls[] = {
 		.get = sd_getexposure,
 	},
 	{
-#define GAIN_IDX 2
+#define GAIN_IDX 3
 		{
 			.id = V4L2_CID_GAIN,
 			.type = V4L2_CTRL_TYPE_INTEGER,
@@ -139,6 +170,21 @@ static struct ctrl sd_ctrls[] = {
 		.set = sd_setgain,
 		.get = sd_getgain,
 	},
+	{
+#define MIN_CLOCKDIV_IDX 4
+		{
+			.id = V4L2_CID_PRIVATE_BASE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Minimum Clock Divider",
+			.minimum = MR97310A_MIN_CLOCKDIV_MIN,
+			.maximum = MR97310A_MIN_CLOCKDIV_MAX,
+			.step = 1,
+			.default_value = MR97310A_MIN_CLOCKDIV_DEFAULT,
+			.flags = 0,
+		},
+		.set = sd_setmin_clockdiv,
+		.get = sd_getmin_clockdiv,
+	},
 };
 
 static const struct v4l2_pix_format vga_mode[] = {
@@ -230,12 +276,17 @@ static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data)
 	int rc;
 
 	buf = data;
-	rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1);
+	if (sd->cam_type == CAM_TYPE_CIF) {
+		rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1);
+		confirm_reg = sd->sensor_type ? 0x13 : 0x11;
+	} else {
+		rc = sensor_write_reg(gspca_dev, reg, 0x00, &buf, 1);
+		confirm_reg = 0x11;
+	}
 	if (rc < 0)
 		return rc;
 
 	buf = 0x01;
-	confirm_reg = sd->sensor_type ? 0x13 : 0x11;
 	rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1);
 	if (rc < 0)
 		return rc;
@@ -243,18 +294,26 @@ static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data)
 	return 0;
 }
 
-static int cam_get_response16(struct gspca_dev *gspca_dev)
+static int cam_get_response16(struct gspca_dev *gspca_dev, u8 reg, int verbose)
 {
-	__u8 *data = gspca_dev->usb_buf;
 	int err_code;
 
-	data[0] = 0x21;
+	gspca_dev->usb_buf[0] = reg;
 	err_code = mr_write(gspca_dev, 1);
 	if (err_code < 0)
 		return err_code;
 
 	err_code = mr_read(gspca_dev, 16);
-	return err_code;
+	if (err_code < 0)
+		return err_code;
+
+	if (verbose)
+		PDEBUG(D_PROBE, "Register: %02x reads %02x%02x%02x", reg,
+		       gspca_dev->usb_buf[0],
+		       gspca_dev->usb_buf[1],
+		       gspca_dev->usb_buf[2]);
+
+	return 0;
 }
 
 static int zero_the_pointer(struct gspca_dev *gspca_dev)
@@ -264,7 +323,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
 	u8 status = 0;
 	int tries = 0;
 
-	err_code = cam_get_response16(gspca_dev);
+	err_code = cam_get_response16(gspca_dev, 0x21, 0);
 	if (err_code < 0)
 		return err_code;
 
@@ -275,7 +334,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
 	if (err_code < 0)
 		return err_code;
 
-	err_code = cam_get_response16(gspca_dev);
+	err_code = cam_get_response16(gspca_dev, 0x21, 0);
 	if (err_code < 0)
 		return err_code;
 
@@ -285,7 +344,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
 	if (err_code < 0)
 		return err_code;
 
-	err_code = cam_get_response16(gspca_dev);
+	err_code = cam_get_response16(gspca_dev, 0x21, 0);
 	if (err_code < 0)
 		return err_code;
 
@@ -295,7 +354,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
 	if (err_code < 0)
 		return err_code;
 
-	err_code = cam_get_response16(gspca_dev);
+	err_code = cam_get_response16(gspca_dev, 0x21, 0);
 	if (err_code < 0)
 		return err_code;
 
@@ -306,7 +365,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
 		return err_code;
 
 	while (status != 0x0a && tries < 256) {
-		err_code = cam_get_response16(gspca_dev);
+		err_code = cam_get_response16(gspca_dev, 0x21, 0);
 		status = data[0];
 		tries++;
 		if (err_code < 0)
@@ -323,7 +382,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
 		if (err_code < 0)
 			return err_code;
 
-		err_code = cam_get_response16(gspca_dev);
+		err_code = cam_get_response16(gspca_dev, 0x21, 0);
 		status = data[0];
 		tries++;
 		if (err_code < 0)
@@ -342,89 +401,202 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
 	return 0;
 }
 
-static u8 get_sensor_id(struct gspca_dev *gspca_dev)
+static int stream_start(struct gspca_dev *gspca_dev)
 {
-	int err_code;
-
-	gspca_dev->usb_buf[0] = 0x1e;
-	err_code = mr_write(gspca_dev, 1);
-	if (err_code < 0)
-		return err_code;
+	gspca_dev->usb_buf[0] = 0x01;
+	gspca_dev->usb_buf[1] = 0x01;
+	return mr_write(gspca_dev, 2);
+}
 
-	err_code = mr_read(gspca_dev, 16);
-	if (err_code < 0)
-		return err_code;
+static void stream_stop(struct gspca_dev *gspca_dev)
+{
+	gspca_dev->usb_buf[0] = 0x01;
+	gspca_dev->usb_buf[1] = 0x00;
+	if (mr_write(gspca_dev, 2) < 0)
+		PDEBUG(D_ERR, "Stream Stop failed");
+}
 
-	PDEBUG(D_PROBE, "Byte zero reported is %01x", gspca_dev->usb_buf[0]);
+static void lcd_stop(struct gspca_dev *gspca_dev)
+{
+	gspca_dev->usb_buf[0] = 0x19;
+	gspca_dev->usb_buf[1] = 0x54;
+	if (mr_write(gspca_dev, 2) < 0)
+		PDEBUG(D_ERR, "LCD Stop failed");
+}
 
-	return gspca_dev->usb_buf[0];
+static int isoc_enable(struct gspca_dev *gspca_dev)
+{
+	gspca_dev->usb_buf[0] = 0x00;
+	gspca_dev->usb_buf[1] = 0x4d;  /* ISOC transfering enable... */
+	return mr_write(gspca_dev, 2);
 }
 
-/* this function is called at probe time */
+/* 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;
-	__u8 *data = gspca_dev->usb_buf;
 	int err_code;
 
 	cam = &gspca_dev->cam;
 	cam->cam_mode = vga_mode;
 	cam->nmodes = ARRAY_SIZE(vga_mode);
+	sd->do_lcd_stop = 0;
+
+	/* Several of the supported CIF cameras share the same USB ID but
+	 * require different initializations and different control settings.
+	 * The same is true of the VGA cameras. Therefore, we are forced
+	 * to start the initialization process in order to determine which
+	 * camera is present. Some of the supported cameras require the
+	 * memory pointer to be set to 0 as the very first item of business
+	 * or else they will not stream. So we do that immediately.
+	 */
+	err_code = zero_the_pointer(gspca_dev);
+	if (err_code < 0)
+		return err_code;
+
+	err_code = stream_start(gspca_dev);
+	if (err_code < 0)
+		return err_code;
 
-	if (id->idProduct == 0x010e) {
+	if (id->idProduct == 0x0110 || id->idProduct == 0x010e) {
 		sd->cam_type = CAM_TYPE_CIF;
 		cam->nmodes--;
-
-		data[0] = 0x01;
-		data[1] = 0x01;
-		err_code = mr_write(gspca_dev, 2);
+		err_code = cam_get_response16(gspca_dev, 0x06, 1);
 		if (err_code < 0)
 			return err_code;
-
-		msleep(200);
-		data[0] = get_sensor_id(gspca_dev);
 		/*
-		 * Known CIF cameras. If you have another to report, please do
+		 * All but one of the known CIF cameras share the same USB ID,
+		 * but two different init routines are in use, and the control
+		 * settings are different, too. We need to detect which camera
+		 * of the two known varieties is connected!
 		 *
-		 * Name			byte just read		sd->sensor_type
-		 *					reported by
-		 * Sakar Spy-shot	0x28		T. Kilgore	0
-		 * Innovage		0xf5 (unstable)	T. Kilgore	0
-		 * Vivitar Mini		0x53		H. De Goede	0
-		 * Vivitar Mini		0x04 / 0x24	E. Rodriguez	0
-		 * Vivitar Mini		0x08		T. Kilgore	1
-		 * Elta-Media 8212dc	0x23		T. Kaiser	1
-		 * Philips dig. keych.	0x37		T. Kilgore	1
+		 * A list of known CIF cameras follows. They all report either
+		 * 0002 for type 0 or 0003 for type 1.
+		 * If you have another to report, please do
+		 *
+		 * Name		sd->sensor_type		reported by
+		 *
+		 * Sakar Spy-shot	0		T. Kilgore
+		 * Innovage		0		T. Kilgore
+		 * Vivitar Mini		0		H. De Goede
+		 * Vivitar Mini		0		E. Rodriguez
+		 * Vivitar Mini		1		T. Kilgore
+		 * Elta-Media 8212dc	1		T. Kaiser
+		 * Philips dig. keych.	1		T. Kilgore
+		 * Trust Spyc@m 100	1		A. Jacobs
 		 */
-		if ((data[0] & 0x78) == 8 ||
-		    ((data[0] & 0x2) == 0x2 && data[0] != 0x53))
-			sd->sensor_type = 1;
-		else
+		switch (gspca_dev->usb_buf[1]) {
+		case 2:
 			sd->sensor_type = 0;
-
+			break;
+		case 3:
+			sd->sensor_type = 1;
+			break;
+		default:
+			PDEBUG(D_ERR, "Unknown CIF Sensor id : %02x",
+			       gspca_dev->usb_buf[1]);
+			return -ENODEV;
+		}
 		PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d",
 		       sd->sensor_type);
+	} else {
+		sd->cam_type = CAM_TYPE_VGA;
 
-		if (force_sensor_type != -1) {
-			sd->sensor_type = !! force_sensor_type;
-			PDEBUG(D_PROBE, "Forcing sensor type to: %d",
-			       sd->sensor_type);
+		err_code = cam_get_response16(gspca_dev, 0x07, 1);
+		if (err_code < 0)
+			return err_code;
+
+		/*
+		 * Here is a table of the responses to the previous command
+		 * from the known MR97310A VGA cameras.
+		 *
+		 * Name			gspca_dev->usb_buf[]	sd->sensor_type
+		 *				sd->do_lcd_stop
+		 * Aiptek Pencam VGA+	0300		0		1
+		 * ION digital		0350		0		1
+		 * Argus DC-1620	0450		1		0
+		 * Argus QuickClix	0420		1		1
+		 *
+		 * Based upon these results, we assume default settings
+		 * and then correct as necessary, as follows.
+		 *
+		 */
+
+		sd->sensor_type = 1;
+		sd->do_lcd_stop = 0;
+		sd->adj_colors = 0;
+		if ((gspca_dev->usb_buf[0] != 0x03) &&
+					(gspca_dev->usb_buf[0] != 0x04)) {
+			PDEBUG(D_ERR, "Unknown VGA Sensor id Byte 0: %02x",
+					gspca_dev->usb_buf[1]);
+			PDEBUG(D_ERR, "Defaults assumed, may not work");
+			PDEBUG(D_ERR, "Please report this");
+		}
+		/* Sakar Digital color needs to be adjusted. */
+		if ((gspca_dev->usb_buf[0] == 0x03) &&
+					(gspca_dev->usb_buf[1] == 0x50))
+			sd->adj_colors = 1;
+		if (gspca_dev->usb_buf[0] == 0x04) {
+			sd->do_lcd_stop = 1;
+			switch (gspca_dev->usb_buf[1]) {
+			case 0x50:
+				sd->sensor_type = 0;
+				PDEBUG(D_PROBE, "sensor_type corrected to 0");
+				break;
+			case 0x20:
+				/* Nothing to do here. */
+				break;
+			default:
+				PDEBUG(D_ERR,
+					"Unknown VGA Sensor id Byte 1: %02x",
+					gspca_dev->usb_buf[1]);
+				PDEBUG(D_ERR,
+					"Defaults assumed, may not work");
+				PDEBUG(D_ERR, "Please report this");
+			}
 		}
+		PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d",
+		       sd->sensor_type);
+	}
+	/* Stop streaming as we've started it to probe the sensor type. */
+	sd_stopN(gspca_dev);
+
+	if (force_sensor_type != -1) {
+		sd->sensor_type = !!force_sensor_type;
+		PDEBUG(D_PROBE, "Forcing sensor type to: %d",
+		       sd->sensor_type);
+	}
 
+	/* Setup controls depending on camera type */
+	if (sd->cam_type == CAM_TYPE_CIF) {
+		/* No brightness for sensor_type 0 */
 		if (sd->sensor_type == 0)
-			gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
+			gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
+					      (1 << ARGUS_QC_BRIGHTNESS_IDX);
+		else
+			gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) |
+					      (1 << MIN_CLOCKDIV_IDX);
 	} else {
-		sd->cam_type = CAM_TYPE_VGA;
-		PDEBUG(D_PROBE, "MR97310A VGA camera detected");
-		gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) |
-				      (1 << EXPOSURE_IDX) | (1 << GAIN_IDX);
+		/* All controls need to be disabled if VGA sensor_type is 0 */
+		if (sd->sensor_type == 0)
+			gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
+					      (1 << ARGUS_QC_BRIGHTNESS_IDX) |
+					      (1 << EXPOSURE_IDX) |
+					      (1 << GAIN_IDX) |
+					      (1 << MIN_CLOCKDIV_IDX);
+		else if (sd->do_lcd_stop)
+			/* Argus QuickClix has different brightness limits */
+			gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX);
+		else
+			gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX);
 	}
 
 	sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
 	sd->exposure = MR97310A_EXPOSURE_DEFAULT;
 	sd->gain = MR97310A_GAIN_DEFAULT;
+	sd->min_clockdiv = MR97310A_MIN_CLOCKDIV_DEFAULT;
 
 	return 0;
 }
@@ -455,11 +627,6 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
 	};
 
 	/* Note: Some of the above descriptions guessed from MR97113A driver */
-	data[0] = 0x01;
-	data[1] = 0x01;
-	err_code = mr_write(gspca_dev, 2);
-	if (err_code < 0)
-		return err_code;
 
 	memcpy(data, startup_string, 11);
 	if (sd->sensor_type)
@@ -533,22 +700,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
 		err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
 					 ARRAY_SIZE(cif_sensor1_init_data));
 	}
-	if (err_code < 0)
-		return err_code;
-
-	setbrightness(gspca_dev);
-	setexposure(gspca_dev);
-	setgain(gspca_dev);
-
-	msleep(200);
-
-	data[0] = 0x00;
-	data[1] = 0x4d;  /* ISOC transfering enable... */
-	err_code = mr_write(gspca_dev, 2);
-	if (err_code < 0)
-		return err_code;
-
-	return 0;
+	return err_code;
 }
 
 static int start_vga_cam(struct gspca_dev *gspca_dev)
@@ -558,84 +710,8 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
 	int err_code;
 	const __u8 startup_string[] = {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b,
 				       0x00, 0x00, 0x00, 0x50, 0xc0};
-
 	/* What some of these mean is explained in start_cif_cam(), above */
-	sd->sof_read = 0;
-
-	/*
-	 * We have to know which camera we have, because the register writes
-	 * depend upon the camera. This test, run before we actually enter
-	 * the initialization routine, distinguishes most of the cameras, If
-	 * needed, another routine is done later, too.
-	 */
-	memset(data, 0, 16);
-	data[0] = 0x20;
-	err_code = mr_write(gspca_dev, 1);
-	if (err_code < 0)
-		return err_code;
-
-	err_code = mr_read(gspca_dev, 16);
-	if (err_code < 0)
-		return err_code;
-
-	PDEBUG(D_PROBE, "Byte reported is %02x", data[0]);
-
-	msleep(200);
-	/*
-	 * Known VGA cameras. If you have another to report, please do
-	 *
-	 * Name			byte just read		sd->sensor_type
-	 *				sd->do_lcd_stop
-	 * Aiptek Pencam VGA+	0x31		0	1
-	 * ION digital		0x31		0	1
-	 * Argus DC-1620	0x30		1	0
-	 * Argus QuickClix	0x30		1	1 (not caught here)
-	 */
-	sd->sensor_type = data[0] & 1;
-	sd->do_lcd_stop = (~data[0]) & 1;
-
-
-
-	/* Streaming setup begins here. */
-
-
-	data[0] = 0x01;
-	data[1] = 0x01;
-	err_code = mr_write(gspca_dev, 2);
-	if (err_code < 0)
-		return err_code;
 
-	/*
-	 * A second test can now resolve any remaining ambiguity in the
-	 * identification of the camera type,
-	 */
-	if (!sd->sensor_type) {
-		data[0] = get_sensor_id(gspca_dev);
-		if (data[0] == 0x7f) {
-			sd->sensor_type = 1;
-			PDEBUG(D_PROBE, "sensor_type corrected to 1");
-		}
-		msleep(200);
-	}
-
-	if (force_sensor_type != -1) {
-		sd->sensor_type = !! force_sensor_type;
-		PDEBUG(D_PROBE, "Forcing sensor type to: %d",
-		       sd->sensor_type);
-	}
-
-	/*
-	 * Known VGA cameras.
-	 * This test is only run if the previous test returned 0x30, but
-	 * here is the information for all others, too, just for reference.
-	 *
-	 * Name			byte just read		sd->sensor_type
-	 *
-	 * Aiptek Pencam VGA+	0xfb	(this test not run)	1
-	 * ION digital		0xbd	(this test not run)	1
-	 * Argus DC-1620	0xe5	(no change)		0
-	 * Argus QuickClix	0x7f	(reclassified)		1
-	 */
 	memcpy(data, startup_string, 11);
 	if (!sd->sensor_type) {
 		data[5]  = 0x00;
@@ -689,29 +765,44 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
 		err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data,
 					 ARRAY_SIZE(vga_sensor0_init_data));
 	} else {	/* sd->sensor_type = 1 */
-		const struct sensor_w_data vga_sensor1_init_data[] = {
+		const struct sensor_w_data color_adj[] = {
 			{0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
-				0x07, 0x00, 0x01}, 8},
+				/* adjusted blue, green, red gain correct
+				   too much blue from the Sakar Digital */
+				0x05, 0x01, 0x04}, 8}
+		};
+
+		const struct sensor_w_data color_no_adj[] = {
+			{0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
+				/* default blue, green, red gain settings */
+				0x07, 0x00, 0x01}, 8}
+		};
+
+		const struct sensor_w_data vga_sensor1_init_data[] = {
 			{0x11, 0x04, {0x01}, 1},
-			/*{0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01, */
-			{0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01,
+			{0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01,
+			/* These settings may be better for some cameras */
+			/* {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, */
 				0x00, 0x0a}, 7},
 			{0x11, 0x04, {0x01}, 1},
 			{0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6},
 			{0x11, 0x04, {0x01}, 1},
 			{0, 0, {0}, 0}
 		};
+
+		if (sd->adj_colors)
+			err_code = sensor_write_regs(gspca_dev, color_adj,
+					 ARRAY_SIZE(color_adj));
+		else
+			err_code = sensor_write_regs(gspca_dev, color_no_adj,
+					 ARRAY_SIZE(color_no_adj));
+
+		if (err_code < 0)
+			return err_code;
+
 		err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
 					 ARRAY_SIZE(vga_sensor1_init_data));
 	}
-	if (err_code < 0)
-		return err_code;
-
-	msleep(200);
-	data[0] = 0x00;
-	data[1] = 0x4d;  /* ISOC transfering enable... */
-	err_code = mr_write(gspca_dev, 2);
-
 	return err_code;
 }
 
@@ -719,97 +810,120 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int err_code;
-	struct cam *cam;
 
-	cam = &gspca_dev->cam;
 	sd->sof_read = 0;
-	/*
-	 * Some of the supported cameras require the memory pointer to be
-	 * set to 0, or else they will not stream.
-	 */
-	zero_the_pointer(gspca_dev);
-	msleep(200);
+
+	/* Some of the VGA cameras require the memory pointer
+	 * to be set to 0 again. We have been forced to start the
+	 * stream in sd_config() to detect the hardware, and closed it.
+	 * Thus, we need here to do a completely fresh and clean start. */
+	err_code = zero_the_pointer(gspca_dev);
+	if (err_code < 0)
+		return err_code;
+
+	err_code = stream_start(gspca_dev);
+	if (err_code < 0)
+		return err_code;
+
 	if (sd->cam_type == CAM_TYPE_CIF) {
 		err_code = start_cif_cam(gspca_dev);
 	} else {
 		err_code = start_vga_cam(gspca_dev);
 	}
-	return err_code;
+	if (err_code < 0)
+		return err_code;
+
+	setbrightness(gspca_dev);
+	setexposure(gspca_dev);
+	setgain(gspca_dev);
+
+	return isoc_enable(gspca_dev);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int result;
-
-	gspca_dev->usb_buf[0] = 1;
-	gspca_dev->usb_buf[1] = 0;
-	result = mr_write(gspca_dev, 2);
-	if (result < 0)
-		PDEBUG(D_ERR, "Camera Stop failed");
 
+	stream_stop(gspca_dev);
 	/* Not all the cams need this, but even if not, probably a good idea */
 	zero_the_pointer(gspca_dev);
-	if (sd->do_lcd_stop) {
-		gspca_dev->usb_buf[0] = 0x19;
-		gspca_dev->usb_buf[1] = 0x54;
-		result = mr_write(gspca_dev, 2);
-		if (result < 0)
-			PDEBUG(D_ERR, "Camera Stop failed");
-	}
+	if (sd->do_lcd_stop)
+		lcd_stop(gspca_dev);
 }
 
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 val;
-
-	if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX))
+	u8 sign_reg = 7;  /* This reg and the next one used on CIF cams. */
+	u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */
+	const u8 quick_clix_table[] =
+	/*	  0  1  2   3  4  5  6  7  8  9  10  11  12  13  14  15 */
+		{ 0, 4, 8, 12, 1, 2, 3, 5, 6, 9,  7, 10, 13, 11, 14, 15};
+	/*
+	 * This control is disabled for CIF type 1 and VGA type 0 cameras.
+	 * It does not quite act linearly for the Argus QuickClix camera,
+	 * but it does control brightness. The values are 0 - 15 only, and
+	 * the table above makes them act consecutively.
+	 */
+	if ((gspca_dev->ctrl_dis & (1 << NORM_BRIGHTNESS_IDX)) &&
+	    (gspca_dev->ctrl_dis & (1 << ARGUS_QC_BRIGHTNESS_IDX)))
 		return;
 
-	/* Note register 7 is also seen as 0x8x or 0xCx in dumps */
+	if (sd->cam_type == CAM_TYPE_VGA) {
+		sign_reg += 4;
+		value_reg += 4;
+	}
+
+	/* Note register 7 is also seen as 0x8x or 0xCx in some dumps */
 	if (sd->brightness > 0) {
-		sensor_write1(gspca_dev, 7, 0x00);
+		sensor_write1(gspca_dev, sign_reg, 0x00);
 		val = sd->brightness;
 	} else {
-		sensor_write1(gspca_dev, 7, 0x01);
-		val = 257 - sd->brightness;
+		sensor_write1(gspca_dev, sign_reg, 0x01);
+		val = (257 - sd->brightness);
 	}
-	sensor_write1(gspca_dev, 8, val);
+	/* Use lookup table for funky Argus QuickClix brightness */
+	if (sd->do_lcd_stop)
+		val = quick_clix_table[val];
+
+	sensor_write1(gspca_dev, value_reg, val);
 }
 
 static void setexposure(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	u8 val;
+	int exposure;
+	u8 buf[2];
 
 	if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
 		return;
 
-	if (sd->sensor_type) {
-		val = sd->exposure >> 4;
-		sensor_write1(gspca_dev, 3, val);
-		val = sd->exposure & 0xf;
-		sensor_write1(gspca_dev, 4, val);
+	if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
+		/* This cam does not like exposure settings < 300,
+		   so scale 0 - 4095 to 300 - 4095 */
+		exposure = (sd->exposure * 9267) / 10000 + 300;
+		sensor_write1(gspca_dev, 3, exposure >> 4);
+		sensor_write1(gspca_dev, 4, exposure & 0x0f);
 	} else {
-		u8 clockdiv;
-		int exposure;
-
 		/* We have both a clock divider and an exposure register.
 		   We first calculate the clock divider, as that determines
-		   the maximum exposure and then we calculayte the exposure
+		   the maximum exposure and then we calculate the exposure
 		   register setting (which goes from 0 - 511).
 
 		   Note our 0 - 4095 exposure is mapped to 0 - 511
 		   milliseconds exposure time */
-		clockdiv = (60 * sd->exposure + 7999) / 8000;
+		u8 clockdiv = (60 * sd->exposure + 7999) / 8000;
 
 		/* Limit framerate to not exceed usb bandwidth */
-		if (clockdiv < 3 && gspca_dev->width >= 320)
-			clockdiv = 3;
+		if (clockdiv < sd->min_clockdiv && gspca_dev->width >= 320)
+			clockdiv = sd->min_clockdiv;
 		else if (clockdiv < 2)
 			clockdiv = 2;
 
+		if (sd->cam_type == CAM_TYPE_VGA && clockdiv < 4)
+			clockdiv = 4;
+
 		/* Frame exposure time in ms = 1000 * clockdiv / 60 ->
 		exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
 		exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv);
@@ -819,9 +933,10 @@ static void setexposure(struct gspca_dev *gspca_dev)
 		/* exposure register value is reversed! */
 		exposure = 511 - exposure;
 
+		buf[0] = exposure & 0xff;
+		buf[1] = exposure >> 8;
+		sensor_write_reg(gspca_dev, 0x0e, 0, buf, 2);
 		sensor_write1(gspca_dev, 0x02, clockdiv);
-		sensor_write1(gspca_dev, 0x0e, exposure & 0xff);
-		sensor_write1(gspca_dev, 0x0f, exposure >> 8);
 	}
 }
 
@@ -832,7 +947,7 @@ static void setgain(struct gspca_dev *gspca_dev)
 	if (gspca_dev->ctrl_dis & (1 << GAIN_IDX))
 		return;
 
-	if (sd->sensor_type) {
+	if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
 		sensor_write1(gspca_dev, 0x0e, sd->gain);
 	} else {
 		sensor_write1(gspca_dev, 0x10, sd->gain);
@@ -893,17 +1008,35 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
 	return 0;
 }
 
+static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->min_clockdiv = val;
+	if (gspca_dev->streaming)
+		setexposure(gspca_dev);
+	return 0;
+}
+
+static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->min_clockdiv;
+	return 0;
+}
+
 /* 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 */
+			u8 *data,		/* isoc packet */
+			int len)		/* iso packet length */
 {
+	struct sd *sd = (struct sd *) gspca_dev;
 	unsigned char *sof;
 
-	sof = pac_find_sof(gspca_dev, data, len);
+	sof = pac_find_sof(&sd->sof_read, data, len);
 	if (sof) {
 		int n;
 
@@ -913,15 +1046,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			n -= sizeof pac_sof_marker;
 		else
 			n = 0;
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+		gspca_frame_add(gspca_dev, LAST_PACKET,
 					data, n);
 		/* Start next frame. */
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
 			pac_sof_marker, sizeof pac_sof_marker);
 		len -= sof - data;
 		data = sof;
 	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 /* sub-driver description */
@@ -938,6 +1071,7 @@ static const struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x08ca, 0x0110)},	/* Trust Spyc@m 100 */
 	{USB_DEVICE(0x08ca, 0x0111)},	/* Aiptek Pencam VGA+ */
 	{USB_DEVICE(0x093a, 0x010f)},	/* All other known MR97310A VGA cams */
 	{USB_DEVICE(0x093a, 0x010e)},	/* All known MR97310A CIF cams */
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index a5c190e93799..ad9ec339981d 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -2,14 +2,19 @@
  * OV519 driver
  *
  * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com>
  *
  * This module is adapted from the ov51x-jpeg package, which itself
  * was adapted from the ov511 driver.
  *
  * Original copyright for the ov511 driver is:
  *
- * Copyright (c) 1999-2004 Mark W. McClelland
+ * Copyright (c) 1999-2006 Mark W. McClelland
  * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach
+ * Many improvements by Bret Wallach <bwallac1@san.rr.com>
+ * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
+ * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
+ * Changes by Claudio Matsuoka <claudio@conectiva.com>
  *
  * ov51x-jpeg original copyright is:
  *
@@ -58,6 +63,8 @@ struct sd {
 #define BRIDGE_OV518		2
 #define BRIDGE_OV518PLUS	3
 #define BRIDGE_OV519		4
+#define BRIDGE_OVFX2		5
+#define BRIDGE_W9968CF		6
 #define BRIDGE_MASK		7
 
 	char invert_led;
@@ -73,6 +80,10 @@ struct sd {
 	__u8 vflip;
 	__u8 autobrightness;
 	__u8 freq;
+	__u8 quality;
+#define QUALITY_MIN 50
+#define QUALITY_MAX 70
+#define QUALITY_DEF 50
 
 	__u8 stopped;		/* Streaming is temporarily paused */
 
@@ -81,17 +92,31 @@ struct sd {
 
 	char sensor;		/* Type of image sensor chip (SEN_*) */
 #define SEN_UNKNOWN 0
-#define SEN_OV6620 1
-#define SEN_OV6630 2
-#define SEN_OV66308AF 3
-#define SEN_OV7610 4
-#define SEN_OV7620 5
-#define SEN_OV7640 6
-#define SEN_OV7670 7
-#define SEN_OV76BE 8
-#define SEN_OV8610 9
+#define SEN_OV2610 1
+#define SEN_OV3610 2
+#define SEN_OV6620 3
+#define SEN_OV6630 4
+#define SEN_OV66308AF 5
+#define SEN_OV7610 6
+#define SEN_OV7620 7
+#define SEN_OV7640 8
+#define SEN_OV7670 9
+#define SEN_OV76BE 10
+#define SEN_OV8610 11
+
+	u8 sensor_addr;
+	int sensor_width;
+	int sensor_height;
+	int sensor_reg_cache[256];
+
+	u8 *jpeg_hdr;
 };
 
+/* Note this is a bit of a hack, but the w9968cf driver needs the code for all
+   the ov sensors which is already present here. When we have the time we
+   really should move the sensor drivers to v4l2 sub drivers. */
+#include "w996Xcf.c"
+
 /* 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);
@@ -345,6 +370,75 @@ static const struct v4l2_pix_format ov511_sif_mode[] = {
 		.priv = 0},
 };
 
+static const struct v4l2_pix_format ovfx2_vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+static const struct v4l2_pix_format ovfx2_cif_mode[] = {
+	{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 3},
+	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2},
+	{352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+static const struct v4l2_pix_format ovfx2_ov2610_mode[] = {
+	{1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 1600,
+		.sizeimage = 1600 * 1200,
+		.colorspace = V4L2_COLORSPACE_SRGB},
+};
+static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
+	{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 800,
+		.sizeimage = 800 * 600,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 1024,
+		.sizeimage = 1024 * 768,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 1600,
+		.sizeimage = 1600 * 1200,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+	{2048, 1536, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 2048,
+		.sizeimage = 2048 * 1536,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+
 /* Registers common to OV511 / OV518 */
 #define R51x_FIFO_PSIZE			0x30	/* 2 bytes wide w/ OV518(+) */
 #define R51x_SYS_RESET          	0x50
@@ -406,6 +500,30 @@ static const struct v4l2_pix_format ov511_sif_mode[] = {
 
 #define OV511_ENDPOINT_ADDRESS  1	/* Isoc endpoint number */
 
+/*
+ * The FX2 chip does not give us a zero length read at end of frame.
+ * It does, however, give a short read at the end of a frame, if
+ * neccessary, rather than run two frames together.
+ *
+ * By choosing the right bulk transfer size, we are guaranteed to always
+ * get a short read for the last read of each frame.  Frame sizes are
+ * always a composite number (width * height, or a multiple) so if we
+ * choose a prime number, we are guaranteed that the last read of a
+ * frame will be short.
+ *
+ * But it isn't that easy: the 2.6 kernel requires a multiple of 4KB,
+ * otherwise EOVERFLOW "babbling" errors occur.  I have not been able
+ * to figure out why.  [PMiller]
+ *
+ * The constant (13 * 4096) is the largest "prime enough" number less than 64KB.
+ *
+ * It isn't enough to know the number of bytes per frame, in case we
+ * have data dropouts or buffer overruns (even though the FX2 double
+ * buffers, there are some pretty strict real time constraints for
+ * isochronous transfer for larger frame sizes).
+ */
+#define OVFX2_BULK_SIZE (13 * 4096)
+
 /* I2C registers */
 #define R51x_I2C_W_SID		0x41
 #define R51x_I2C_SADDR_3	0x42
@@ -413,9 +531,11 @@ static const struct v4l2_pix_format ov511_sif_mode[] = {
 #define R51x_I2C_R_SID		0x44
 #define R51x_I2C_DATA		0x45
 #define R518_I2C_CTL		0x47	/* OV518(+) only */
+#define OVFX2_I2C_ADDR		0x00
 
 /* I2C ADDRESSES */
 #define OV7xx0_SID   0x42
+#define OV_HIRES_SID 0x60		/* OV9xxx / OV2xxx / OV3xxx */
 #define OV8xx0_SID   0xa0
 #define OV6xx0_SID   0xc0
 
@@ -508,6 +628,696 @@ struct ov_i2c_regvals {
 	__u8 val;
 };
 
+/* Settings for OV2610 camera chip */
+static const struct ov_i2c_regvals norm_2610[] =
+{
+	{ 0x12, 0x80 },	/* reset */
+};
+
+static const struct ov_i2c_regvals norm_3620b[] =
+{
+	/*
+	 * From the datasheet: "Note that after writing to register COMH
+	 * (0x12) to change the sensor mode, registers related to the
+	 * sensor’s cropping window will be reset back to their default
+	 * values."
+	 *
+	 * "wait 4096 external clock ... to make sure the sensor is
+	 * stable and ready to access registers" i.e. 160us at 24MHz
+	 */
+
+	{ 0x12, 0x80 }, /* COMH reset */
+	{ 0x12, 0x00 }, /* QXGA, master */
+
+	/*
+	 * 11 CLKRC "Clock Rate Control"
+	 * [7] internal frequency doublers: on
+	 * [6] video port mode: master
+	 * [5:0] clock divider: 1
+	 */
+	{ 0x11, 0x80 },
+
+	/*
+	 * 13 COMI "Common Control I"
+	 *                  = 192 (0xC0) 11000000
+	 *    COMI[7] "AEC speed selection"
+	 *                  =   1 (0x01) 1....... "Faster AEC correction"
+	 *    COMI[6] "AEC speed step selection"
+	 *                  =   1 (0x01) .1...... "Big steps, fast"
+	 *    COMI[5] "Banding filter on off"
+	 *                  =   0 (0x00) ..0..... "Off"
+	 *    COMI[4] "Banding filter option"
+	 *                  =   0 (0x00) ...0.... "Main clock is 48 MHz and
+	 *                                         the PLL is ON"
+	 *    COMI[3] "Reserved"
+	 *                  =   0 (0x00) ....0...
+	 *    COMI[2] "AGC auto manual control selection"
+	 *                  =   0 (0x00) .....0.. "Manual"
+	 *    COMI[1] "AWB auto manual control selection"
+	 *                  =   0 (0x00) ......0. "Manual"
+	 *    COMI[0] "Exposure control"
+	 *                  =   0 (0x00) .......0 "Manual"
+	 */
+	{ 0x13, 0xC0 },
+
+	/*
+	 * 09 COMC "Common Control C"
+	 *                  =   8 (0x08) 00001000
+	 *    COMC[7:5] "Reserved"
+	 *                  =   0 (0x00) 000.....
+	 *    COMC[4] "Sleep Mode Enable"
+	 *                  =   0 (0x00) ...0.... "Normal mode"
+	 *    COMC[3:2] "Sensor sampling reset timing selection"
+	 *                  =   2 (0x02) ....10.. "Longer reset time"
+	 *    COMC[1:0] "Output drive current select"
+	 *                  =   0 (0x00) ......00 "Weakest"
+	 */
+	{ 0x09, 0x08 },
+
+	/*
+	 * 0C COMD "Common Control D"
+	 *                  =   8 (0x08) 00001000
+	 *    COMD[7] "Reserved"
+	 *                  =   0 (0x00) 0.......
+	 *    COMD[6] "Swap MSB and LSB at the output port"
+	 *                  =   0 (0x00) .0...... "False"
+	 *    COMD[5:3] "Reserved"
+	 *                  =   1 (0x01) ..001...
+	 *    COMD[2] "Output Average On Off"
+	 *                  =   0 (0x00) .....0.. "Output Normal"
+	 *    COMD[1] "Sensor precharge voltage selection"
+	 *                  =   0 (0x00) ......0. "Selects internal
+	 *                                         reference precharge
+	 *                                         voltage"
+	 *    COMD[0] "Snapshot option"
+	 *                  =   0 (0x00) .......0 "Enable live video output
+	 *                                         after snapshot sequence"
+	 */
+	{ 0x0c, 0x08 },
+
+	/*
+	 * 0D COME "Common Control E"
+	 *                  = 161 (0xA1) 10100001
+	 *    COME[7] "Output average option"
+	 *                  =   1 (0x01) 1....... "Output average of 4 pixels"
+	 *    COME[6] "Anti-blooming control"
+	 *                  =   0 (0x00) .0...... "Off"
+	 *    COME[5:3] "Reserved"
+	 *                  =   4 (0x04) ..100...
+	 *    COME[2] "Clock output power down pin status"
+	 *                  =   0 (0x00) .....0.. "Tri-state data output pin
+	 *                                         on power down"
+	 *    COME[1] "Data output pin status selection at power down"
+	 *                  =   0 (0x00) ......0. "Tri-state VSYNC, PCLK,
+	 *                                         HREF, and CHSYNC pins on
+	 *                                         power down"
+	 *    COME[0] "Auto zero circuit select"
+	 *                  =   1 (0x01) .......1 "On"
+	 */
+	{ 0x0d, 0xA1 },
+
+	/*
+	 * 0E COMF "Common Control F"
+	 *                  = 112 (0x70) 01110000
+	 *    COMF[7] "System clock selection"
+	 *                  =   0 (0x00) 0....... "Use 24 MHz system clock"
+	 *    COMF[6:4] "Reserved"
+	 *                  =   7 (0x07) .111....
+	 *    COMF[3] "Manual auto negative offset canceling selection"
+	 *                  =   0 (0x00) ....0... "Auto detect negative
+	 *                                         offset and cancel it"
+	 *    COMF[2:0] "Reserved"
+	 *                  =   0 (0x00) .....000
+	 */
+	{ 0x0e, 0x70 },
+
+	/*
+	 * 0F COMG "Common Control G"
+	 *                  =  66 (0x42) 01000010
+	 *    COMG[7] "Optical black output selection"
+	 *                  =   0 (0x00) 0....... "Disable"
+	 *    COMG[6] "Black level calibrate selection"
+	 *                  =   1 (0x01) .1...... "Use optical black pixels
+	 *                                         to calibrate"
+	 *    COMG[5:4] "Reserved"
+	 *                  =   0 (0x00) ..00....
+	 *    COMG[3] "Channel offset adjustment"
+	 *                  =   0 (0x00) ....0... "Disable offset adjustment"
+	 *    COMG[2] "ADC black level calibration option"
+	 *                  =   0 (0x00) .....0.. "Use B/G line and G/R
+	 *                                         line to calibrate each
+	 *                                         channel's black level"
+	 *    COMG[1] "Reserved"
+	 *                  =   1 (0x01) ......1.
+	 *    COMG[0] "ADC black level calibration enable"
+	 *                  =   0 (0x00) .......0 "Disable"
+	 */
+	{ 0x0f, 0x42 },
+
+	/*
+	 * 14 COMJ "Common Control J"
+	 *                  = 198 (0xC6) 11000110
+	 *    COMJ[7:6] "AGC gain ceiling"
+	 *                  =   3 (0x03) 11...... "8x"
+	 *    COMJ[5:4] "Reserved"
+	 *                  =   0 (0x00) ..00....
+	 *    COMJ[3] "Auto banding filter"
+	 *                  =   0 (0x00) ....0... "Banding filter is always
+	 *                                         on off depending on
+	 *                                         COMI[5] setting"
+	 *    COMJ[2] "VSYNC drop option"
+	 *                  =   1 (0x01) .....1.. "SYNC is dropped if frame
+	 *                                         data is dropped"
+	 *    COMJ[1] "Frame data drop"
+	 *                  =   1 (0x01) ......1. "Drop frame data if
+	 *                                         exposure is not within
+	 *                                         tolerance.  In AEC mode,
+	 *                                         data is normally dropped
+	 *                                         when data is out of
+	 *                                         range."
+	 *    COMJ[0] "Reserved"
+	 *                  =   0 (0x00) .......0
+	 */
+	{ 0x14, 0xC6 },
+
+	/*
+	 * 15 COMK "Common Control K"
+	 *                  =   2 (0x02) 00000010
+	 *    COMK[7] "CHSYNC pin output swap"
+	 *                  =   0 (0x00) 0....... "CHSYNC"
+	 *    COMK[6] "HREF pin output swap"
+	 *                  =   0 (0x00) .0...... "HREF"
+	 *    COMK[5] "PCLK output selection"
+	 *                  =   0 (0x00) ..0..... "PCLK always output"
+	 *    COMK[4] "PCLK edge selection"
+	 *                  =   0 (0x00) ...0.... "Data valid on falling edge"
+	 *    COMK[3] "HREF output polarity"
+	 *                  =   0 (0x00) ....0... "positive"
+	 *    COMK[2] "Reserved"
+	 *                  =   0 (0x00) .....0..
+	 *    COMK[1] "VSYNC polarity"
+	 *                  =   1 (0x01) ......1. "negative"
+	 *    COMK[0] "HSYNC polarity"
+	 *                  =   0 (0x00) .......0 "positive"
+	 */
+	{ 0x15, 0x02 },
+
+	/*
+	 * 33 CHLF "Current Control"
+	 *                  =   9 (0x09) 00001001
+	 *    CHLF[7:6] "Sensor current control"
+	 *                  =   0 (0x00) 00......
+	 *    CHLF[5] "Sensor current range control"
+	 *                  =   0 (0x00) ..0..... "normal range"
+	 *    CHLF[4] "Sensor current"
+	 *                  =   0 (0x00) ...0.... "normal current"
+	 *    CHLF[3] "Sensor buffer current control"
+	 *                  =   1 (0x01) ....1... "half current"
+	 *    CHLF[2] "Column buffer current control"
+	 *                  =   0 (0x00) .....0.. "normal current"
+	 *    CHLF[1] "Analog DSP current control"
+	 *                  =   0 (0x00) ......0. "normal current"
+	 *    CHLF[1] "ADC current control"
+	 *                  =   0 (0x00) ......0. "normal current"
+	 */
+	{ 0x33, 0x09 },
+
+	/*
+	 * 34 VBLM "Blooming Control"
+	 *                  =  80 (0x50) 01010000
+	 *    VBLM[7] "Hard soft reset switch"
+	 *                  =   0 (0x00) 0....... "Hard reset"
+	 *    VBLM[6:4] "Blooming voltage selection"
+	 *                  =   5 (0x05) .101....
+	 *    VBLM[3:0] "Sensor current control"
+	 *                  =   0 (0x00) ....0000
+	 */
+	{ 0x34, 0x50 },
+
+	/*
+	 * 36 VCHG "Sensor Precharge Voltage Control"
+	 *                  =   0 (0x00) 00000000
+	 *    VCHG[7] "Reserved"
+	 *                  =   0 (0x00) 0.......
+	 *    VCHG[6:4] "Sensor precharge voltage control"
+	 *                  =   0 (0x00) .000....
+	 *    VCHG[3:0] "Sensor array common reference"
+	 *                  =   0 (0x00) ....0000
+	 */
+	{ 0x36, 0x00 },
+
+	/*
+	 * 37 ADC "ADC Reference Control"
+	 *                  =   4 (0x04) 00000100
+	 *    ADC[7:4] "Reserved"
+	 *                  =   0 (0x00) 0000....
+	 *    ADC[3] "ADC input signal range"
+	 *                  =   0 (0x00) ....0... "Input signal 1.0x"
+	 *    ADC[2:0] "ADC range control"
+	 *                  =   4 (0x04) .....100
+	 */
+	{ 0x37, 0x04 },
+
+	/*
+	 * 38 ACOM "Analog Common Ground"
+	 *                  =  82 (0x52) 01010010
+	 *    ACOM[7] "Analog gain control"
+	 *                  =   0 (0x00) 0....... "Gain 1x"
+	 *    ACOM[6] "Analog black level calibration"
+	 *                  =   1 (0x01) .1...... "On"
+	 *    ACOM[5:0] "Reserved"
+	 *                  =  18 (0x12) ..010010
+	 */
+	{ 0x38, 0x52 },
+
+	/*
+	 * 3A FREFA "Internal Reference Adjustment"
+	 *                  =   0 (0x00) 00000000
+	 *    FREFA[7:0] "Range"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x3a, 0x00 },
+
+	/*
+	 * 3C FVOPT "Internal Reference Adjustment"
+	 *                  =  31 (0x1F) 00011111
+	 *    FVOPT[7:0] "Range"
+	 *                  =  31 (0x1F) 00011111
+	 */
+	{ 0x3c, 0x1F },
+
+	/*
+	 * 44 Undocumented  =   0 (0x00) 00000000
+	 *    44[7:0] "It's a secret"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x44, 0x00 },
+
+	/*
+	 * 40 Undocumented  =   0 (0x00) 00000000
+	 *    40[7:0] "It's a secret"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x40, 0x00 },
+
+	/*
+	 * 41 Undocumented  =   0 (0x00) 00000000
+	 *    41[7:0] "It's a secret"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x41, 0x00 },
+
+	/*
+	 * 42 Undocumented  =   0 (0x00) 00000000
+	 *    42[7:0] "It's a secret"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x42, 0x00 },
+
+	/*
+	 * 43 Undocumented  =   0 (0x00) 00000000
+	 *    43[7:0] "It's a secret"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x43, 0x00 },
+
+	/*
+	 * 45 Undocumented  = 128 (0x80) 10000000
+	 *    45[7:0] "It's a secret"
+	 *                  = 128 (0x80) 10000000
+	 */
+	{ 0x45, 0x80 },
+
+	/*
+	 * 48 Undocumented  = 192 (0xC0) 11000000
+	 *    48[7:0] "It's a secret"
+	 *                  = 192 (0xC0) 11000000
+	 */
+	{ 0x48, 0xC0 },
+
+	/*
+	 * 49 Undocumented  =  25 (0x19) 00011001
+	 *    49[7:0] "It's a secret"
+	 *                  =  25 (0x19) 00011001
+	 */
+	{ 0x49, 0x19 },
+
+	/*
+	 * 4B Undocumented  = 128 (0x80) 10000000
+	 *    4B[7:0] "It's a secret"
+	 *                  = 128 (0x80) 10000000
+	 */
+	{ 0x4B, 0x80 },
+
+	/*
+	 * 4D Undocumented  = 196 (0xC4) 11000100
+	 *    4D[7:0] "It's a secret"
+	 *                  = 196 (0xC4) 11000100
+	 */
+	{ 0x4D, 0xC4 },
+
+	/*
+	 * 35 VREF "Reference Voltage Control"
+	 *                  =  76 (0x4C) 01001100
+	 *    VREF[7:5] "Column high reference control"
+	 *                  =   2 (0x02) 010..... "higher voltage"
+	 *    VREF[4:2] "Column low reference control"
+	 *                  =   3 (0x03) ...011.. "Highest voltage"
+	 *    VREF[1:0] "Reserved"
+	 *                  =   0 (0x00) ......00
+	 */
+	{ 0x35, 0x4C },
+
+	/*
+	 * 3D Undocumented  =   0 (0x00) 00000000
+	 *    3D[7:0] "It's a secret"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x3D, 0x00 },
+
+	/*
+	 * 3E Undocumented  =   0 (0x00) 00000000
+	 *    3E[7:0] "It's a secret"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x3E, 0x00 },
+
+	/*
+	 * 3B FREFB "Internal Reference Adjustment"
+	 *                  =  24 (0x18) 00011000
+	 *    FREFB[7:0] "Range"
+	 *                  =  24 (0x18) 00011000
+	 */
+	{ 0x3b, 0x18 },
+
+	/*
+	 * 33 CHLF "Current Control"
+	 *                  =  25 (0x19) 00011001
+	 *    CHLF[7:6] "Sensor current control"
+	 *                  =   0 (0x00) 00......
+	 *    CHLF[5] "Sensor current range control"
+	 *                  =   0 (0x00) ..0..... "normal range"
+	 *    CHLF[4] "Sensor current"
+	 *                  =   1 (0x01) ...1.... "double current"
+	 *    CHLF[3] "Sensor buffer current control"
+	 *                  =   1 (0x01) ....1... "half current"
+	 *    CHLF[2] "Column buffer current control"
+	 *                  =   0 (0x00) .....0.. "normal current"
+	 *    CHLF[1] "Analog DSP current control"
+	 *                  =   0 (0x00) ......0. "normal current"
+	 *    CHLF[1] "ADC current control"
+	 *                  =   0 (0x00) ......0. "normal current"
+	 */
+	{ 0x33, 0x19 },
+
+	/*
+	 * 34 VBLM "Blooming Control"
+	 *                  =  90 (0x5A) 01011010
+	 *    VBLM[7] "Hard soft reset switch"
+	 *                  =   0 (0x00) 0....... "Hard reset"
+	 *    VBLM[6:4] "Blooming voltage selection"
+	 *                  =   5 (0x05) .101....
+	 *    VBLM[3:0] "Sensor current control"
+	 *                  =  10 (0x0A) ....1010
+	 */
+	{ 0x34, 0x5A },
+
+	/*
+	 * 3B FREFB "Internal Reference Adjustment"
+	 *                  =   0 (0x00) 00000000
+	 *    FREFB[7:0] "Range"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x3b, 0x00 },
+
+	/*
+	 * 33 CHLF "Current Control"
+	 *                  =   9 (0x09) 00001001
+	 *    CHLF[7:6] "Sensor current control"
+	 *                  =   0 (0x00) 00......
+	 *    CHLF[5] "Sensor current range control"
+	 *                  =   0 (0x00) ..0..... "normal range"
+	 *    CHLF[4] "Sensor current"
+	 *                  =   0 (0x00) ...0.... "normal current"
+	 *    CHLF[3] "Sensor buffer current control"
+	 *                  =   1 (0x01) ....1... "half current"
+	 *    CHLF[2] "Column buffer current control"
+	 *                  =   0 (0x00) .....0.. "normal current"
+	 *    CHLF[1] "Analog DSP current control"
+	 *                  =   0 (0x00) ......0. "normal current"
+	 *    CHLF[1] "ADC current control"
+	 *                  =   0 (0x00) ......0. "normal current"
+	 */
+	{ 0x33, 0x09 },
+
+	/*
+	 * 34 VBLM "Blooming Control"
+	 *                  =  80 (0x50) 01010000
+	 *    VBLM[7] "Hard soft reset switch"
+	 *                  =   0 (0x00) 0....... "Hard reset"
+	 *    VBLM[6:4] "Blooming voltage selection"
+	 *                  =   5 (0x05) .101....
+	 *    VBLM[3:0] "Sensor current control"
+	 *                  =   0 (0x00) ....0000
+	 */
+	{ 0x34, 0x50 },
+
+	/*
+	 * 12 COMH "Common Control H"
+	 *                  =  64 (0x40) 01000000
+	 *    COMH[7] "SRST"
+	 *                  =   0 (0x00) 0....... "No-op"
+	 *    COMH[6:4] "Resolution selection"
+	 *                  =   4 (0x04) .100.... "XGA"
+	 *    COMH[3] "Master slave selection"
+	 *                  =   0 (0x00) ....0... "Master mode"
+	 *    COMH[2] "Internal B/R channel option"
+	 *                  =   0 (0x00) .....0.. "B/R use same channel"
+	 *    COMH[1] "Color bar test pattern"
+	 *                  =   0 (0x00) ......0. "Off"
+	 *    COMH[0] "Reserved"
+	 *                  =   0 (0x00) .......0
+	 */
+	{ 0x12, 0x40 },
+
+	/*
+	 * 17 HREFST "Horizontal window start"
+	 *                  =  31 (0x1F) 00011111
+	 *    HREFST[7:0] "Horizontal window start, 8 MSBs"
+	 *                  =  31 (0x1F) 00011111
+	 */
+	{ 0x17, 0x1F },
+
+	/*
+	 * 18 HREFEND "Horizontal window end"
+	 *                  =  95 (0x5F) 01011111
+	 *    HREFEND[7:0] "Horizontal Window End, 8 MSBs"
+	 *                  =  95 (0x5F) 01011111
+	 */
+	{ 0x18, 0x5F },
+
+	/*
+	 * 19 VSTRT "Vertical window start"
+	 *                  =   0 (0x00) 00000000
+	 *    VSTRT[7:0] "Vertical Window Start, 8 MSBs"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x19, 0x00 },
+
+	/*
+	 * 1A VEND "Vertical window end"
+	 *                  =  96 (0x60) 01100000
+	 *    VEND[7:0] "Vertical Window End, 8 MSBs"
+	 *                  =  96 (0x60) 01100000
+	 */
+	{ 0x1a, 0x60 },
+
+	/*
+	 * 32 COMM "Common Control M"
+	 *                  =  18 (0x12) 00010010
+	 *    COMM[7:6] "Pixel clock divide option"
+	 *                  =   0 (0x00) 00...... "/1"
+	 *    COMM[5:3] "Horizontal window end position, 3 LSBs"
+	 *                  =   2 (0x02) ..010...
+	 *    COMM[2:0] "Horizontal window start position, 3 LSBs"
+	 *                  =   2 (0x02) .....010
+	 */
+	{ 0x32, 0x12 },
+
+	/*
+	 * 03 COMA "Common Control A"
+	 *                  =  74 (0x4A) 01001010
+	 *    COMA[7:4] "AWB Update Threshold"
+	 *                  =   4 (0x04) 0100....
+	 *    COMA[3:2] "Vertical window end line control 2 LSBs"
+	 *                  =   2 (0x02) ....10..
+	 *    COMA[1:0] "Vertical window start line control 2 LSBs"
+	 *                  =   2 (0x02) ......10
+	 */
+	{ 0x03, 0x4A },
+
+	/*
+	 * 11 CLKRC "Clock Rate Control"
+	 *                  = 128 (0x80) 10000000
+	 *    CLKRC[7] "Internal frequency doublers on off seclection"
+	 *                  =   1 (0x01) 1....... "On"
+	 *    CLKRC[6] "Digital video master slave selection"
+	 *                  =   0 (0x00) .0...... "Master mode, sensor
+	 *                                         provides PCLK"
+	 *    CLKRC[5:0] "Clock divider { CLK = PCLK/(1+CLKRC[5:0]) }"
+	 *                  =   0 (0x00) ..000000
+	 */
+	{ 0x11, 0x80 },
+
+	/*
+	 * 12 COMH "Common Control H"
+	 *                  =   0 (0x00) 00000000
+	 *    COMH[7] "SRST"
+	 *                  =   0 (0x00) 0....... "No-op"
+	 *    COMH[6:4] "Resolution selection"
+	 *                  =   0 (0x00) .000.... "QXGA"
+	 *    COMH[3] "Master slave selection"
+	 *                  =   0 (0x00) ....0... "Master mode"
+	 *    COMH[2] "Internal B/R channel option"
+	 *                  =   0 (0x00) .....0.. "B/R use same channel"
+	 *    COMH[1] "Color bar test pattern"
+	 *                  =   0 (0x00) ......0. "Off"
+	 *    COMH[0] "Reserved"
+	 *                  =   0 (0x00) .......0
+	 */
+	{ 0x12, 0x00 },
+
+	/*
+	 * 12 COMH "Common Control H"
+	 *                  =  64 (0x40) 01000000
+	 *    COMH[7] "SRST"
+	 *                  =   0 (0x00) 0....... "No-op"
+	 *    COMH[6:4] "Resolution selection"
+	 *                  =   4 (0x04) .100.... "XGA"
+	 *    COMH[3] "Master slave selection"
+	 *                  =   0 (0x00) ....0... "Master mode"
+	 *    COMH[2] "Internal B/R channel option"
+	 *                  =   0 (0x00) .....0.. "B/R use same channel"
+	 *    COMH[1] "Color bar test pattern"
+	 *                  =   0 (0x00) ......0. "Off"
+	 *    COMH[0] "Reserved"
+	 *                  =   0 (0x00) .......0
+	 */
+	{ 0x12, 0x40 },
+
+	/*
+	 * 17 HREFST "Horizontal window start"
+	 *                  =  31 (0x1F) 00011111
+	 *    HREFST[7:0] "Horizontal window start, 8 MSBs"
+	 *                  =  31 (0x1F) 00011111
+	 */
+	{ 0x17, 0x1F },
+
+	/*
+	 * 18 HREFEND "Horizontal window end"
+	 *                  =  95 (0x5F) 01011111
+	 *    HREFEND[7:0] "Horizontal Window End, 8 MSBs"
+	 *                  =  95 (0x5F) 01011111
+	 */
+	{ 0x18, 0x5F },
+
+	/*
+	 * 19 VSTRT "Vertical window start"
+	 *                  =   0 (0x00) 00000000
+	 *    VSTRT[7:0] "Vertical Window Start, 8 MSBs"
+	 *                  =   0 (0x00) 00000000
+	 */
+	{ 0x19, 0x00 },
+
+	/*
+	 * 1A VEND "Vertical window end"
+	 *                  =  96 (0x60) 01100000
+	 *    VEND[7:0] "Vertical Window End, 8 MSBs"
+	 *                  =  96 (0x60) 01100000
+	 */
+	{ 0x1a, 0x60 },
+
+	/*
+	 * 32 COMM "Common Control M"
+	 *                  =  18 (0x12) 00010010
+	 *    COMM[7:6] "Pixel clock divide option"
+	 *                  =   0 (0x00) 00...... "/1"
+	 *    COMM[5:3] "Horizontal window end position, 3 LSBs"
+	 *                  =   2 (0x02) ..010...
+	 *    COMM[2:0] "Horizontal window start position, 3 LSBs"
+	 *                  =   2 (0x02) .....010
+	 */
+	{ 0x32, 0x12 },
+
+	/*
+	 * 03 COMA "Common Control A"
+	 *                  =  74 (0x4A) 01001010
+	 *    COMA[7:4] "AWB Update Threshold"
+	 *                  =   4 (0x04) 0100....
+	 *    COMA[3:2] "Vertical window end line control 2 LSBs"
+	 *                  =   2 (0x02) ....10..
+	 *    COMA[1:0] "Vertical window start line control 2 LSBs"
+	 *                  =   2 (0x02) ......10
+	 */
+	{ 0x03, 0x4A },
+
+	/*
+	 * 02 RED "Red Gain Control"
+	 *                  = 175 (0xAF) 10101111
+	 *    RED[7] "Action"
+	 *                  =   1 (0x01) 1....... "gain = 1/(1+bitrev([6:0]))"
+	 *    RED[6:0] "Value"
+	 *                  =  47 (0x2F) .0101111
+	 */
+	{ 0x02, 0xAF },
+
+	/*
+	 * 2D ADDVSL "VSYNC Pulse Width"
+	 *                  = 210 (0xD2) 11010010
+	 *    ADDVSL[7:0] "VSYNC pulse width, LSB"
+	 *                  = 210 (0xD2) 11010010
+	 */
+	{ 0x2d, 0xD2 },
+
+	/*
+	 * 00 GAIN          =  24 (0x18) 00011000
+	 *    GAIN[7:6] "Reserved"
+	 *                  =   0 (0x00) 00......
+	 *    GAIN[5] "Double"
+	 *                  =   0 (0x00) ..0..... "False"
+	 *    GAIN[4] "Double"
+	 *                  =   1 (0x01) ...1.... "True"
+	 *    GAIN[3:0] "Range"
+	 *                  =   8 (0x08) ....1000
+	 */
+	{ 0x00, 0x18 },
+
+	/*
+	 * 01 BLUE "Blue Gain Control"
+	 *                  = 240 (0xF0) 11110000
+	 *    BLUE[7] "Action"
+	 *                  =   1 (0x01) 1....... "gain = 1/(1+bitrev([6:0]))"
+	 *    BLUE[6:0] "Value"
+	 *                  = 112 (0x70) .1110000
+	 */
+	{ 0x01, 0xF0 },
+
+	/*
+	 * 10 AEC "Automatic Exposure Control"
+	 *                  =  10 (0x0A) 00001010
+	 *    AEC[7:0] "Automatic Exposure Control, 8 MSBs"
+	 *                  =  10 (0x0A) 00001010
+	 */
+	{ 0x10, 0x0A },
+
+	{ 0xE1, 0x67 },
+	{ 0xE3, 0x03 },
+	{ 0xE4, 0x26 },
+	{ 0xE5, 0x3E },
+	{ 0xF8, 0x01 },
+	{ 0xFF, 0x01 },
+};
+
 static const struct ov_i2c_regvals norm_6x20[] = {
 	{ 0x12, 0x80 }, /* reset */
 	{ 0x11, 0x01 },
@@ -678,6 +1488,7 @@ static const struct ov_i2c_regvals norm_7610[] = {
 };
 
 static const struct ov_i2c_regvals norm_7620[] = {
+	{ 0x12, 0x80 },		/* reset */
 	{ 0x00, 0x00 },		/* gain */
 	{ 0x01, 0x80 },		/* blue gain */
 	{ 0x02, 0x80 },		/* red gain */
@@ -1042,10 +1853,28 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
 }
 
 /* Write a OV519 register */
-static int reg_w(struct sd *sd, __u16 index, __u8 value)
+static int reg_w(struct sd *sd, __u16 index, __u16 value)
 {
-	int ret;
-	int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 2 : 1;
+	int ret, req = 0;
+
+	switch (sd->bridge) {
+	case BRIDGE_OV511:
+	case BRIDGE_OV511PLUS:
+		req = 2;
+		break;
+	case BRIDGE_OVFX2:
+		req = 0x0a;
+		/* fall through */
+	case BRIDGE_W9968CF:
+		ret = usb_control_msg(sd->gspca_dev.dev,
+			usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+		goto leave;
+	default:
+		req = 1;
+	}
 
 	sd->gspca_dev.usb_buf[0] = value;
 	ret = usb_control_msg(sd->gspca_dev.dev,
@@ -1054,17 +1883,35 @@ static int reg_w(struct sd *sd, __u16 index, __u8 value)
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			0, index,
 			sd->gspca_dev.usb_buf, 1, 500);
-	if (ret < 0)
-		PDEBUG(D_ERR, "Write reg [%02x] %02x failed", index, value);
-	return ret;
+leave:
+	if (ret < 0) {
+		PDEBUG(D_ERR, "Write reg 0x%04x -> [0x%02x] failed",
+		       value, index);
+		return ret;
+	}
+
+	PDEBUG(D_USBO, "Write reg 0x%04x -> [0x%02x]", value, index);
+	return 0;
 }
 
-/* Read from a OV519 register */
+/* Read from a OV519 register, note not valid for the w9968cf!! */
 /* returns: negative is error, pos or zero is data */
 static int reg_r(struct sd *sd, __u16 index)
 {
 	int ret;
-	int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 3 : 1;
+	int req;
+
+	switch (sd->bridge) {
+	case BRIDGE_OV511:
+	case BRIDGE_OV511PLUS:
+		req = 3;
+		break;
+	case BRIDGE_OVFX2:
+		req = 0x0b;
+		break;
+	default:
+		req = 1;
+	}
 
 	ret = usb_control_msg(sd->gspca_dev.dev,
 			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
@@ -1072,10 +1919,12 @@ static int reg_r(struct sd *sd, __u16 index)
 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			0, index, sd->gspca_dev.usb_buf, 1, 500);
 
-	if (ret >= 0)
+	if (ret >= 0) {
 		ret = sd->gspca_dev.usb_buf[0];
-	else
+		PDEBUG(D_USBI, "Read reg [0x%02X] -> 0x%04X", index, ret);
+	} else
 		PDEBUG(D_ERR, "Read reg [0x%02x] failed", index);
+
 	return ret;
 }
 
@@ -1095,6 +1944,7 @@ static int reg_r8(struct sd *sd,
 		ret = sd->gspca_dev.usb_buf[0];
 	else
 		PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index);
+
 	return ret;
 }
 
@@ -1140,9 +1990,12 @@ static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			0, index,
 			sd->gspca_dev.usb_buf, n, 500);
-	if (ret < 0)
+	if (ret < 0) {
 		PDEBUG(D_ERR, "Write reg32 [%02x] %08x failed", index, value);
-	return ret;
+		return ret;
+	}
+
+	return 0;
 }
 
 static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value)
@@ -1324,32 +2177,110 @@ static int ov518_i2c_r(struct sd *sd, __u8 reg)
 	return value;
 }
 
+static int ovfx2_i2c_w(struct sd *sd, __u8 reg, __u8 value)
+{
+	int ret;
+
+	ret = usb_control_msg(sd->gspca_dev.dev,
+			usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+			0x02,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			(__u16)value, (__u16)reg, NULL, 0, 500);
+
+	if (ret < 0) {
+		PDEBUG(D_ERR, "i2c 0x%02x -> [0x%02x] failed", value, reg);
+		return ret;
+	}
+
+	PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+	return 0;
+}
+
+static int ovfx2_i2c_r(struct sd *sd, __u8 reg)
+{
+	int ret;
+
+	ret = usb_control_msg(sd->gspca_dev.dev,
+			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+			0x03,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0, (__u16)reg, sd->gspca_dev.usb_buf, 1, 500);
+
+	if (ret >= 0) {
+		ret = sd->gspca_dev.usb_buf[0];
+		PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, ret);
+	} else
+		PDEBUG(D_ERR, "i2c read [0x%02x] failed", reg);
+
+	return ret;
+}
+
 static int i2c_w(struct sd *sd, __u8 reg, __u8 value)
 {
+	int ret = -1;
+
+	if (sd->sensor_reg_cache[reg] == value)
+		return 0;
+
 	switch (sd->bridge) {
 	case BRIDGE_OV511:
 	case BRIDGE_OV511PLUS:
-		return ov511_i2c_w(sd, reg, value);
+		ret = ov511_i2c_w(sd, reg, value);
+		break;
 	case BRIDGE_OV518:
 	case BRIDGE_OV518PLUS:
 	case BRIDGE_OV519:
-		return ov518_i2c_w(sd, reg, value);
+		ret = ov518_i2c_w(sd, reg, value);
+		break;
+	case BRIDGE_OVFX2:
+		ret = ovfx2_i2c_w(sd, reg, value);
+		break;
+	case BRIDGE_W9968CF:
+		ret = w9968cf_i2c_w(sd, reg, value);
+		break;
 	}
-	return -1; /* Should never happen */
+
+	if (ret >= 0) {
+		/* Up on sensor reset empty the register cache */
+		if (reg == 0x12 && (value & 0x80))
+			memset(sd->sensor_reg_cache, -1,
+			       sizeof(sd->sensor_reg_cache));
+		else
+			sd->sensor_reg_cache[reg] = value;
+	}
+
+	return ret;
 }
 
 static int i2c_r(struct sd *sd, __u8 reg)
 {
+	int ret = -1;
+
+	if (sd->sensor_reg_cache[reg] != -1)
+		return sd->sensor_reg_cache[reg];
+
 	switch (sd->bridge) {
 	case BRIDGE_OV511:
 	case BRIDGE_OV511PLUS:
-		return ov511_i2c_r(sd, reg);
+		ret = ov511_i2c_r(sd, reg);
+		break;
 	case BRIDGE_OV518:
 	case BRIDGE_OV518PLUS:
 	case BRIDGE_OV519:
-		return ov518_i2c_r(sd, reg);
+		ret = ov518_i2c_r(sd, reg);
+		break;
+	case BRIDGE_OVFX2:
+		ret = ovfx2_i2c_r(sd, reg);
+		break;
+	case BRIDGE_W9968CF:
+		ret = w9968cf_i2c_r(sd, reg);
+		break;
 	}
-	return -1; /* Should never happen */
+
+	if (ret >= 0)
+		sd->sensor_reg_cache[reg] = ret;
+
+	return ret;
 }
 
 /* Writes bits at positions specified by mask to an I2C reg. Bits that are in
@@ -1389,6 +2320,10 @@ static inline int ov51x_stop(struct sd *sd)
 		return reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
 	case BRIDGE_OV519:
 		return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+	case BRIDGE_OVFX2:
+		return reg_w_mask(sd, 0x0f, 0x00, 0x02);
+	case BRIDGE_W9968CF:
+		return reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */
 	}
 
 	return 0;
@@ -1418,18 +2353,27 @@ static inline int ov51x_restart(struct sd *sd)
 		return reg_w(sd, R51x_SYS_RESET, 0x00);
 	case BRIDGE_OV519:
 		return reg_w(sd, OV519_SYS_RESET1, 0x00);
+	case BRIDGE_OVFX2:
+		return reg_w_mask(sd, 0x0f, 0x02, 0x02);
+	case BRIDGE_W9968CF:
+		return reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */
 	}
 
 	return 0;
 }
 
+static int ov51x_set_slave_ids(struct sd *sd, __u8 slave);
+
 /* This does an initial reset of an OmniVision sensor and ensures that I2C
  * is synchronized. Returns <0 on failure.
  */
-static int init_ov_sensor(struct sd *sd)
+static int init_ov_sensor(struct sd *sd, __u8 slave)
 {
 	int i;
 
+	if (ov51x_set_slave_ids(sd, slave) < 0)
+		return -EIO;
+
 	/* Reset the sensor */
 	if (i2c_w(sd, 0x12, 0x80) < 0)
 		return -EIO;
@@ -1466,6 +2410,14 @@ static int ov51x_set_slave_ids(struct sd *sd,
 {
 	int rc;
 
+	switch (sd->bridge) {
+	case BRIDGE_OVFX2:
+		return reg_w(sd, OVFX2_I2C_ADDR, slave);
+	case BRIDGE_W9968CF:
+		sd->sensor_addr = slave;
+		return 0;
+	}
+
 	rc = reg_w(sd, R51x_I2C_W_SID, slave);
 	if (rc < 0)
 		return rc;
@@ -1508,6 +2460,39 @@ static int write_i2c_regvals(struct sd *sd,
  *
  ***************************************************************************/
 
+/* This initializes the OV2x10 / OV3610 / OV3620 */
+static int ov_hires_configure(struct sd *sd)
+{
+	int high, low;
+
+	if (sd->bridge != BRIDGE_OVFX2) {
+		PDEBUG(D_ERR, "error hires sensors only supported with ovfx2");
+		return -1;
+	}
+
+	PDEBUG(D_PROBE, "starting ov hires configuration");
+
+	/* Detect sensor (sub)type */
+	high = i2c_r(sd, 0x0a);
+	low = i2c_r(sd, 0x0b);
+	/* info("%x, %x", high, low); */
+	if (high == 0x96 && low == 0x40) {
+		PDEBUG(D_PROBE, "Sensor is an OV2610");
+		sd->sensor = SEN_OV2610;
+	} else if (high == 0x36 && (low & 0x0f) == 0x00) {
+		PDEBUG(D_PROBE, "Sensor is an OV3610");
+		sd->sensor = SEN_OV3610;
+	} else {
+		PDEBUG(D_ERR, "Error unknown sensor type: 0x%02x%02x",
+		       high, low);
+		return -1;
+	}
+
+	/* Set sensor-specific vars */
+	return 0;
+}
+
+
 /* This initializes the OV8110, OV8610 sensor. The OV8110 uses
  * the same register settings as the OV8610, since they are very similar.
  */
@@ -1966,12 +2951,29 @@ static int ov519_configure(struct sd *sd)
 	return write_regvals(sd, init_519, ARRAY_SIZE(init_519));
 }
 
+static int ovfx2_configure(struct sd *sd)
+{
+	static const struct ov_regvals init_fx2[] = {
+		{ 0x00, 0x60 },
+		{ 0x02, 0x01 },
+		{ 0x0f, 0x1d },
+		{ 0xe9, 0x82 },
+		{ 0xea, 0xc7 },
+		{ 0xeb, 0x10 },
+		{ 0xec, 0xf6 },
+	};
+
+	sd->stopped = 1;
+
+	return write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2));
+}
+
 /* 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;
+	struct cam *cam = &gspca_dev->cam;
 	int ret = 0;
 
 	sd->bridge = id->driver_info & BRIDGE_MASK;
@@ -1989,6 +2991,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	case BRIDGE_OV519:
 		ret = ov519_configure(sd);
 		break;
+	case BRIDGE_OVFX2:
+		ret = ovfx2_configure(sd);
+		cam->bulk_size = OVFX2_BULK_SIZE;
+		cam->bulk_nurbs = MAX_NURBS;
+		cam->bulk = 1;
+		break;
+	case BRIDGE_W9968CF:
+		ret = w9968cf_configure(sd);
+		cam->reverse_alts = 1;
+		break;
 	}
 
 	if (ret)
@@ -1996,49 +3008,39 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
 	ov51x_led_control(sd, 0);	/* turn LED off */
 
-	/* Test for 76xx */
-	if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)
-		goto error;
-
 	/* The OV519 must be more aggressive about sensor detection since
 	 * I2C write will never fail if the sensor is not present. We have
 	 * to try to initialize the sensor to detect its presence */
-	if (init_ov_sensor(sd) >= 0) {
+
+	/* Test for 76xx */
+	if (init_ov_sensor(sd, OV7xx0_SID) >= 0) {
 		if (ov7xx0_configure(sd) < 0) {
 			PDEBUG(D_ERR, "Failed to configure OV7xx0");
 			goto error;
 		}
-	} else {
-
-		/* Test for 6xx0 */
-		if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)
+	/* Test for 6xx0 */
+	} else if (init_ov_sensor(sd, OV6xx0_SID) >= 0) {
+		if (ov6xx0_configure(sd) < 0) {
+			PDEBUG(D_ERR, "Failed to configure OV6xx0");
+			goto error;
+		}
+	/* Test for 8xx0 */
+	} else if (init_ov_sensor(sd, OV8xx0_SID) >= 0) {
+		if (ov8xx0_configure(sd) < 0) {
+			PDEBUG(D_ERR, "Failed to configure OV8xx0");
 			goto error;
-
-		if (init_ov_sensor(sd) >= 0) {
-			if (ov6xx0_configure(sd) < 0) {
-				PDEBUG(D_ERR, "Failed to configure OV6xx0");
-				goto error;
-			}
-		} else {
-
-			/* Test for 8xx0 */
-			if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)
-				goto error;
-
-			if (init_ov_sensor(sd) < 0) {
-				PDEBUG(D_ERR,
-					"Can't determine sensor slave IDs");
-				goto error;
-			}
-			if (ov8xx0_configure(sd) < 0) {
-				PDEBUG(D_ERR,
-					"Failed to configure OV8xx0 sensor");
-				goto error;
-			}
 		}
+	/* Test for 3xxx / 2xxx */
+	} else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) {
+		if (ov_hires_configure(sd) < 0) {
+			PDEBUG(D_ERR, "Failed to configure high res OV");
+			goto error;
+		}
+	} else {
+		PDEBUG(D_ERR, "Can't determine sensor slave IDs");
+		goto error;
 	}
 
-	cam = &gspca_dev->cam;
 	switch (sd->bridge) {
 	case BRIDGE_OV511:
 	case BRIDGE_OV511PLUS:
@@ -2069,6 +3071,31 @@ static int sd_config(struct gspca_dev *gspca_dev,
 			cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
 		}
 		break;
+	case BRIDGE_OVFX2:
+		if (sd->sensor == SEN_OV2610) {
+			cam->cam_mode = ovfx2_ov2610_mode;
+			cam->nmodes = ARRAY_SIZE(ovfx2_ov2610_mode);
+		} else if (sd->sensor == SEN_OV3610) {
+			cam->cam_mode = ovfx2_ov3610_mode;
+			cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode);
+		} else if (!sd->sif) {
+			cam->cam_mode = ov519_vga_mode;
+			cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
+		} else {
+			cam->cam_mode = ov519_sif_mode;
+			cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
+		}
+		break;
+	case BRIDGE_W9968CF:
+		cam->cam_mode = w9968cf_vga_mode;
+		cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
+		if (sd->sif)
+			cam->nmodes--;
+
+		/* w9968cf needs initialisation once the sensor is known */
+		if (w9968cf_init(sd) < 0)
+			goto error;
+		break;
 	}
 	sd->brightness = BRIGHTNESS_DEF;
 	if (sd->sensor == SEN_OV6630 || sd->sensor == SEN_OV66308AF)
@@ -2087,11 +3114,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
 		gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) |
 				      (1 << OV7670_FREQ_IDX);
 	}
+	sd->quality = QUALITY_DEF;
 	if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
 		gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX;
 	/* OV8610 Frequency filter control should work but needs testing */
 	if (sd->sensor == SEN_OV8610)
 		gspca_dev->ctrl_dis |= 1 << FREQ_IDX;
+	/* No controls for the OV2610/OV3610 */
+	if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
+		gspca_dev->ctrl_dis |= 0xFF;
 
 	return 0;
 error:
@@ -2106,6 +3137,20 @@ static int sd_init(struct gspca_dev *gspca_dev)
 
 	/* initialize the sensor */
 	switch (sd->sensor) {
+	case SEN_OV2610:
+		if (write_i2c_regvals(sd, norm_2610, ARRAY_SIZE(norm_2610)))
+			return -EIO;
+		/* Enable autogain, autoexpo, awb, bandfilter */
+		if (i2c_w_mask(sd, 0x13, 0x27, 0x27) < 0)
+			return -EIO;
+		break;
+	case SEN_OV3610:
+		if (write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b)))
+			return -EIO;
+		/* Enable autogain, autoexpo, awb, bandfilter */
+		if (i2c_w_mask(sd, 0x13, 0x27, 0x27) < 0)
+			return -EIO;
+		break;
 	case SEN_OV6620:
 		if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
 			return -EIO;
@@ -2548,19 +3593,60 @@ static int ov519_mode_init_regs(struct sd *sd)
 static int mode_init_ov_sensor_regs(struct sd *sd)
 {
 	struct gspca_dev *gspca_dev;
-	int qvga;
+	int qvga, xstart, xend, ystart, yend;
+	__u8 v;
 
 	gspca_dev = &sd->gspca_dev;
 	qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
 
 	/******** Mode (VGA/QVGA) and sensor specific regs ********/
 	switch (sd->sensor) {
+	case SEN_OV2610:
+		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
+		i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);
+		i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);
+		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
+		i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
+		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
+		return 0;
+	case SEN_OV3610:
+		if (qvga) {
+			xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4);
+			ystart = (776 - gspca_dev->height) / 2;
+		} else {
+			xstart = (2076 - gspca_dev->width) / 2 + (0x10 << 4);
+			ystart = (1544 - gspca_dev->height) / 2;
+		}
+		xend = xstart + gspca_dev->width;
+		yend = ystart + gspca_dev->height;
+		/* Writing to the COMH register resets the other windowing regs
+		   to their default values, so we must do this first. */
+		i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0xf0);
+		i2c_w_mask(sd, 0x32,
+			   (((xend >> 1) & 7) << 3) | ((xstart >> 1) & 7),
+			   0x3f);
+		i2c_w_mask(sd, 0x03,
+			   (((yend >> 1) & 3) << 2) | ((ystart >> 1) & 3),
+			   0x0f);
+		i2c_w(sd, 0x17, xstart >> 4);
+		i2c_w(sd, 0x18, xend >> 4);
+		i2c_w(sd, 0x19, ystart >> 3);
+		i2c_w(sd, 0x1a, yend >> 3);
+		return 0;
 	case SEN_OV8610:
 		/* For OV8610 qvga means qsvga */
 		i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
+		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
+		i2c_w_mask(sd, 0x2d, 0x00, 0x40); /* from windrv 090403 */
+		i2c_w_mask(sd, 0x28, 0x20, 0x20); /* progressive mode on */
 		break;
 	case SEN_OV7610:
 		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		i2c_w(sd, 0x35, qvga?0x1e:0x9e);
+		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
 		break;
 	case SEN_OV7620:
 	case SEN_OV76BE:
@@ -2571,6 +3657,10 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
 		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
 		i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0);
 		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
+		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
+		if (sd->sensor == SEN_OV76BE)
+			i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e);
 		break;
 	case SEN_OV7640:
 		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
@@ -2580,6 +3670,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
 /*		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); */
 /*		i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); */
 /*		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */
+		i2c_w_mask(sd, 0x12, 0x04, 0x04); /* AWB: 1 */
 		break;
 	case SEN_OV7670:
 		/* set COM7_FMT_VGA or COM7_FMT_QVGA
@@ -2588,55 +3679,56 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
 		i2c_w_mask(sd, OV7670_REG_COM7,
 			 qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
 			 OV7670_COM7_FMT_MASK);
+		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+		i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB,
+				OV7670_COM8_AWB);
+		if (qvga) {		/* QVGA from ov7670.c by
+					 * Jonathan Corbet */
+			xstart = 164;
+			xend = 28;
+			ystart = 14;
+			yend = 494;
+		} else {		/* VGA */
+			xstart = 158;
+			xend = 14;
+			ystart = 10;
+			yend = 490;
+		}
+		/* OV7670 hardware window registers are split across
+		 * multiple locations */
+		i2c_w(sd, OV7670_REG_HSTART, xstart >> 3);
+		i2c_w(sd, OV7670_REG_HSTOP, xend >> 3);
+		v = i2c_r(sd, OV7670_REG_HREF);
+		v = (v & 0xc0) | ((xend & 0x7) << 3) | (xstart & 0x07);
+		msleep(10);	/* need to sleep between read and write to
+				 * same reg! */
+		i2c_w(sd, OV7670_REG_HREF, v);
+
+		i2c_w(sd, OV7670_REG_VSTART, ystart >> 2);
+		i2c_w(sd, OV7670_REG_VSTOP, yend >> 2);
+		v = i2c_r(sd, OV7670_REG_VREF);
+		v = (v & 0xc0) | ((yend & 0x3) << 2) | (ystart & 0x03);
+		msleep(10);	/* need to sleep between read and write to
+				 * same reg! */
+		i2c_w(sd, OV7670_REG_VREF, v);
 		break;
 	case SEN_OV6620:
+		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
+		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
+		break;
 	case SEN_OV6630:
 	case SEN_OV66308AF:
 		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	/******** Palette-specific regs ********/
-
-	/* The OV518 needs special treatment. Although both the OV518
-	 * and the OV6630 support a 16-bit video bus, only the 8 bit Y
-	 * bus is actually used. The UV bus is tied to ground.
-	 * Therefore, the OV6630 needs to be in 8-bit multiplexed
-	 * output mode */
-
-	/* OV7640 is 8-bit only */
-
-	if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV66308AF &&
-					sd->sensor != SEN_OV7640)
-		i2c_w_mask(sd, 0x13, 0x00, 0x20);
-
 	/******** Clock programming ********/
 	i2c_w(sd, 0x11, sd->clockdiv);
 
-	/******** Special Features ********/
-/* no evidence this is possible with OV7670, either */
-	/* Test Pattern */
-	if (sd->sensor != SEN_OV7640 && sd->sensor != SEN_OV7670)
-		i2c_w_mask(sd, 0x12, 0x00, 0x02);
-
-	/* Enable auto white balance */
-	if (sd->sensor == SEN_OV7670)
-		i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB,
-				OV7670_COM8_AWB);
-	else
-		i2c_w_mask(sd, 0x12, 0x04, 0x04);
-
-	/* This will go away as soon as ov51x_mode_init_sensor_regs() */
-	/* is fully tested. */
-	/* 7620/6620/6630? don't have register 0x35, so play it safe */
-	if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
-		if (!qvga)
-			i2c_w(sd, 0x35, 0x9e);
-		else
-			i2c_w(sd, 0x35, 0x1e);
-	}
 	return 0;
 }
 
@@ -2659,8 +3751,12 @@ static int set_ov_sensor_window(struct sd *sd)
 	struct gspca_dev *gspca_dev;
 	int qvga, crop;
 	int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
-	int ret, hstart, hstop, vstop, vstart;
-	__u8 v;
+	int ret;
+
+	/* mode setup is fully handled in mode_init_ov_sensor_regs for these */
+	if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610 ||
+	    sd->sensor == SEN_OV7670)
+		return mode_init_ov_sensor_regs(sd);
 
 	gspca_dev = &sd->gspca_dev;
 	qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
@@ -2708,11 +3804,6 @@ static int set_ov_sensor_window(struct sd *sd)
 		hwebase = 0x1a;
 		vwsbase = vwebase = 0x03;
 		break;
-	case SEN_OV7670:
-		/*handling of OV7670 hardware sensor start and stop values
-		 * is very odd, compared to the other OV sensors */
-		vwsbase = vwebase = hwebase = hwsbase = 0x00;
-		break;
 	default:
 		return -EINVAL;
 	}
@@ -2753,58 +3844,11 @@ static int set_ov_sensor_window(struct sd *sd)
 	if (ret < 0)
 		return ret;
 
-	if (sd->sensor == SEN_OV8610) {
-		i2c_w_mask(sd, 0x2d, 0x05, 0x40);
-				/* old 0x95, new 0x05 from windrv 090403 */
-						/* bits 5-7: reserved */
-		i2c_w_mask(sd, 0x28, 0x20, 0x20);
-					/* bit 5: progressive mode on */
-	}
-
-	/* The below is wrong for OV7670s because their window registers
-	 * only store the high bits in 0x17 to 0x1a */
-
-	/* SRH Use sd->max values instead of requested win values */
-	/* SCS Since we're sticking with only the max hardware widths
-	 * for a given mode */
-	/* I can hard code this for OV7670s */
-	/* Yes, these numbers do look odd, but they're tested and work! */
-	if (sd->sensor == SEN_OV7670) {
-		if (qvga) {		/* QVGA from ov7670.c by
-					 * Jonathan Corbet */
-			hstart = 164;
-			hstop = 28;
-			vstart = 14;
-			vstop = 494;
-		} else {		/* VGA */
-			hstart = 158;
-			hstop = 14;
-			vstart = 10;
-			vstop = 490;
-		}
-		/* OV7670 hardware window registers are split across
-		 * multiple locations */
-		i2c_w(sd, OV7670_REG_HSTART, hstart >> 3);
-		i2c_w(sd, OV7670_REG_HSTOP, hstop >> 3);
-		v = i2c_r(sd, OV7670_REG_HREF);
-		v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07);
-		msleep(10);	/* need to sleep between read and write to
-				 * same reg! */
-		i2c_w(sd, OV7670_REG_HREF, v);
+	i2c_w(sd, 0x17, hwsbase);
+	i2c_w(sd, 0x18, hwebase + (sd->sensor_width >> hwscale));
+	i2c_w(sd, 0x19, vwsbase);
+	i2c_w(sd, 0x1a, vwebase + (sd->sensor_height >> vwscale));
 
-		i2c_w(sd, OV7670_REG_VSTART, vstart >> 2);
-		i2c_w(sd, OV7670_REG_VSTOP, vstop >> 2);
-		v = i2c_r(sd, OV7670_REG_VREF);
-		v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03);
-		msleep(10);	/* need to sleep between read and write to
-				 * same reg! */
-		i2c_w(sd, OV7670_REG_VREF, v);
-	} else {
-		i2c_w(sd, 0x17, hwsbase);
-		i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale));
-		i2c_w(sd, 0x19, vwsbase);
-		i2c_w(sd, 0x1a, vwebase + (sd->gspca_dev.height >> vwscale));
-	}
 	return 0;
 }
 
@@ -2814,6 +3858,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
 	struct sd *sd = (struct sd *) gspca_dev;
 	int ret = 0;
 
+	/* Default for most bridges, allow bridge_mode_init_regs to override */
+	sd->sensor_width = sd->gspca_dev.width;
+	sd->sensor_height = sd->gspca_dev.height;
+
 	switch (sd->bridge) {
 	case BRIDGE_OV511:
 	case BRIDGE_OV511PLUS:
@@ -2826,6 +3874,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
 	case BRIDGE_OV519:
 		ret = ov519_mode_init_regs(sd);
 		break;
+	/* case BRIDGE_OVFX2: nothing to do */
+	case BRIDGE_W9968CF:
+		ret = w9968cf_mode_init_regs(sd);
+		break;
 	}
 	if (ret < 0)
 		goto out;
@@ -2859,10 +3911,17 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 	ov51x_led_control(sd, 0);
 }
 
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->bridge == BRIDGE_W9968CF)
+		w9968cf_stop0(sd);
+}
+
 static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
-			__u8 *in,			/* isoc packet */
-			int len)			/* iso packet length */
+			u8 *in,			/* isoc packet */
+			int len)		/* iso packet length */
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -2893,11 +3952,11 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
 				return;
 			}
 			/* Add 11 byte footer to frame, might be usefull */
-			gspca_frame_add(gspca_dev, LAST_PACKET, frame, in, 11);
+			gspca_frame_add(gspca_dev, LAST_PACKET, in, 11);
 			return;
 		} else {
 			/* Frame start */
-			gspca_frame_add(gspca_dev, FIRST_PACKET, frame, in, 0);
+			gspca_frame_add(gspca_dev, FIRST_PACKET, in, 0);
 			sd->packet_nr = 0;
 		}
 	}
@@ -2906,12 +3965,11 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
 	len--;
 
 	/* intermediate packet */
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, in, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, in, len);
 }
 
 static void ov518_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;
@@ -2919,8 +3977,8 @@ static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
 	/* A false positive here is likely, until OVT gives me
 	 * the definitive SOF/EOF format */
 	if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) {
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
 		sd->packet_nr = 0;
 	}
 
@@ -2944,12 +4002,11 @@ static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
 	}
 
 	/* intermediate packet */
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static void ov519_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 */
 {
 	/* Header of ov519 is 16 bytes:
@@ -2972,7 +4029,7 @@ static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
 			len -= HDRSZ;
 #undef HDRSZ
 			if (data[0] == 0xff || data[1] == 0xd8)
-				gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				gspca_frame_add(gspca_dev, FIRST_PACKET,
 						data, len);
 			else
 				gspca_dev->last_packet_type = DISCARD_PACKET;
@@ -2980,20 +4037,31 @@ static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
 		case 0x51:		/* end of frame */
 			if (data[9] != 0)
 				gspca_dev->last_packet_type = DISCARD_PACKET;
-			gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					data, 0);
+			gspca_frame_add(gspca_dev, LAST_PACKET,
+					NULL, 0);
 			return;
 		}
 	}
 
 	/* intermediate packet */
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-			data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	/* A short read signals EOF */
+	if (len < OVFX2_BULK_SIZE) {
+		gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+		return;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 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;
@@ -3001,14 +4069,20 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	switch (sd->bridge) {
 	case BRIDGE_OV511:
 	case BRIDGE_OV511PLUS:
-		ov511_pkt_scan(gspca_dev, frame, data, len);
+		ov511_pkt_scan(gspca_dev, data, len);
 		break;
 	case BRIDGE_OV518:
 	case BRIDGE_OV518PLUS:
-		ov518_pkt_scan(gspca_dev, frame, data, len);
+		ov518_pkt_scan(gspca_dev, data, len);
 		break;
 	case BRIDGE_OV519:
-		ov519_pkt_scan(gspca_dev, frame, data, len);
+		ov519_pkt_scan(gspca_dev, data, len);
+		break;
+	case BRIDGE_OVFX2:
+		ovfx2_pkt_scan(gspca_dev, data, len);
+		break;
+	case BRIDGE_W9968CF:
+		w9968cf_pkt_scan(gspca_dev, data, len);
 		break;
 	}
 }
@@ -3124,7 +4198,8 @@ static void setcolors(struct gspca_dev *gspca_dev)
 
 static void setautobrightness(struct sd *sd)
 {
-	if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
+	if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670 ||
+	    sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
 		return;
 
 	i2c_w_mask(sd, 0x2d, sd->autobrightness ? 0x10 : 0x00, 0x10);
@@ -3132,6 +4207,9 @@ static void setautobrightness(struct sd *sd)
 
 static void setfreq(struct sd *sd)
 {
+	if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
+		return;
+
 	if (sd->sensor == SEN_OV7670) {
 		switch (sd->freq) {
 		case 0: /* Banding filter disabled */
@@ -3301,8 +4379,12 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->freq = val;
-	if (gspca_dev->streaming)
+	if (gspca_dev->streaming) {
 		setfreq(sd);
+		/* Ugly but necessary */
+		if (sd->bridge == BRIDGE_W9968CF)
+			w9968cf_set_crop_window(sd);
+	}
 	return 0;
 }
 
@@ -3343,6 +4425,45 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
 	return -EINVAL;
 }
 
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+			struct v4l2_jpegcompression *jcomp)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->bridge != BRIDGE_W9968CF)
+		return -EINVAL;
+
+	memset(jcomp, 0, sizeof *jcomp);
+	jcomp->quality = sd->quality;
+	jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT |
+			      V4L2_JPEG_MARKER_DRI;
+	return 0;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+			struct v4l2_jpegcompression *jcomp)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->bridge != BRIDGE_W9968CF)
+		return -EINVAL;
+
+	if (gspca_dev->streaming)
+		return -EBUSY;
+
+	if (jcomp->quality < QUALITY_MIN)
+		sd->quality = QUALITY_MIN;
+	else if (jcomp->quality > QUALITY_MAX)
+		sd->quality = QUALITY_MAX;
+	else
+		sd->quality = jcomp->quality;
+
+	/* Return resulting jcomp params to app */
+	sd_get_jcomp(gspca_dev, jcomp);
+
+	return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
@@ -3352,18 +4473,23 @@ 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 -- */
 static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
 	{USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
 	{USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
 	{USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
 	{USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
 	{USB_DEVICE(0x041e, 0x4064),
 	 .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+	{USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 },
 	{USB_DEVICE(0x041e, 0x4068),
 	 .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
 	{USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
@@ -3373,11 +4499,16 @@ static const __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
 	{USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
 	{USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 },
+	{USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 },
 	{USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 },
 	{USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
 	{USB_DEVICE(0x05a9, 0xa511), .driver_info = BRIDGE_OV511PLUS },
 	{USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS },
 	{USB_DEVICE(0x0813, 0x0002), .driver_info = BRIDGE_OV511PLUS },
+	{USB_DEVICE(0x0b62, 0x0059), .driver_info = BRIDGE_OVFX2 },
+	{USB_DEVICE(0x0e96, 0xc001), .driver_info = BRIDGE_OVFX2 },
+	{USB_DEVICE(0x1046, 0x9967), .driver_info = BRIDGE_W9968CF },
+	{USB_DEVICE(0x8020, 0xEF04), .driver_info = BRIDGE_OVFX2 },
 	{}
 };
 
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 4b528b372911..4dbb882c83dc 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -1,5 +1,6 @@
 /*
  * 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
@@ -8,6 +9,10 @@
  * USB protocol reverse engineered by Jim Paris <jim@jtan.com>
  * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/
  *
+ * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr
+ * PS3 Eye camera, brightness, contrast, hue, AWB control added
+ *	by Max Thrun <bear24rw@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
@@ -51,16 +56,335 @@ struct sd {
 	u16 last_fid;
 	u8 frame_rate;
 
+	u8 brightness;
+	u8 contrast;
+	u8 gain;
+	u8 exposure;
+	u8 redblc;
+	u8 blueblc;
+	u8 hue;
+	u8 autogain;
+	u8 awb;
+	s8 sharpness;
+	u8 hflip;
+	u8 vflip;
+	u8 satur;
+	u8 lightfreq;
+
 	u8 sensor;
 #define SENSOR_OV772X 0
 #define SENSOR_OV965X 1
 };
 
 /* V4L2 controls supported by the driver */
-static struct ctrl sd_ctrls[] = {
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setredblc(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getredblc(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setblueblc(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getblueblc(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_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
+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 int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls_ov772x[] = {
+    {							/* 0 */
+	{
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define BRIGHTNESS_77_DEF 20
+		.default_value = BRIGHTNESS_77_DEF,
+	},
+	.set = sd_setbrightness,
+	.get = sd_getbrightness,
+    },
+    {							/* 1 */
+	{
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define CONTRAST_77_DEF 37
+		.default_value = CONTRAST_77_DEF,
+	},
+	.set = sd_setcontrast,
+	.get = sd_getcontrast,
+    },
+    {							/* 2 */
+	{
+	    .id      = V4L2_CID_GAIN,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Main Gain",
+	    .minimum = 0,
+	    .maximum = 63,
+	    .step    = 1,
+#define GAIN_DEF 20
+	    .default_value = GAIN_DEF,
+	},
+	.set = sd_setgain,
+	.get = sd_getgain,
+    },
+    {							/* 3 */
+	{
+	    .id      = V4L2_CID_EXPOSURE,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Exposure",
+	    .minimum = 0,
+	    .maximum = 255,
+	    .step    = 1,
+#define EXPO_77_DEF 120
+	    .default_value = EXPO_77_DEF,
+	},
+	.set = sd_setexposure,
+	.get = sd_getexposure,
+    },
+    {							/* 4 */
+	{
+	    .id      = V4L2_CID_RED_BALANCE,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Red Balance",
+	    .minimum = 0,
+	    .maximum = 255,
+	    .step    = 1,
+#define RED_BALANCE_DEF 128
+	    .default_value = RED_BALANCE_DEF,
+	},
+	.set = sd_setredblc,
+	.get = sd_getredblc,
+    },
+    {							/* 5 */
+	{
+	    .id      = V4L2_CID_BLUE_BALANCE,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Blue Balance",
+	    .minimum = 0,
+	    .maximum = 255,
+	    .step    = 1,
+#define BLUE_BALANCE_DEF 128
+	    .default_value = BLUE_BALANCE_DEF,
+	},
+	.set = sd_setblueblc,
+	.get = sd_getblueblc,
+    },
+    {							/* 6 */
+	{
+		.id      = V4L2_CID_HUE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Hue",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define HUE_DEF 143
+		.default_value = HUE_DEF,
+	},
+	.set = sd_sethue,
+	.get = sd_gethue,
+    },
+    {							/* 7 */
+	{
+	    .id      = V4L2_CID_AUTOGAIN,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "Autogain",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+#define AUTOGAIN_77_DEF 0
+	    .default_value = AUTOGAIN_77_DEF,
+	},
+	.set = sd_setautogain,
+	.get = sd_getautogain,
+    },
+#define AWB_77_IDX 8
+    {							/* 8 */
+	{
+		.id      = V4L2_CID_AUTO_WHITE_BALANCE,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto White Balance",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define AWB_DEF 0
+		.default_value = AWB_DEF,
+	},
+	.set = sd_setawb,
+	.get = sd_getawb,
+    },
+    {							/* 9 */
+	{
+	    .id      = V4L2_CID_SHARPNESS,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Sharpness",
+	    .minimum = 0,
+	    .maximum = 63,
+	    .step    = 1,
+#define SHARPNESS_77_DEF 0
+	    .default_value = SHARPNESS_77_DEF,
+	},
+	.set = sd_setsharpness,
+	.get = sd_getsharpness,
+    },
+    {							/* 10 */
+	{
+	    .id      = V4L2_CID_HFLIP,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "HFlip",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+#define HFLIP_DEF 0
+	    .default_value = HFLIP_DEF,
+	},
+	.set = sd_sethflip,
+	.get = sd_gethflip,
+    },
+    {							/* 11 */
+	{
+	    .id      = V4L2_CID_VFLIP,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "VFlip",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+#define VFLIP_DEF 0
+	    .default_value = VFLIP_DEF,
+	},
+	.set = sd_setvflip,
+	.get = sd_getvflip,
+    },
+};
+static struct ctrl sd_ctrls_ov965x[] = {
+    {							/* 0 */
+	{
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 15,
+		.step    = 1,
+#define BRIGHTNESS_96_DEF 7
+		.default_value = BRIGHTNESS_96_DEF,
+	},
+	.set = sd_setbrightness,
+	.get = sd_getbrightness,
+    },
+    {							/* 1 */
+	{
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 15,
+		.step    = 1,
+#define CONTRAST_96_DEF 3
+		.default_value = CONTRAST_96_DEF,
+	},
+	.set = sd_setcontrast,
+	.get = sd_getcontrast,
+    },
+    {							/* 2 */
+	{
+	    .id      = V4L2_CID_AUTOGAIN,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "Autogain",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+#define AUTOGAIN_96_DEF 1
+	    .default_value = AUTOGAIN_96_DEF,
+	},
+	.set = sd_setautogain,
+	.get = sd_getautogain,
+    },
+#define EXPO_96_IDX 3
+    {							/* 3 */
+	{
+	    .id      = V4L2_CID_EXPOSURE,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Exposure",
+	    .minimum = 0,
+	    .maximum = 3,
+	    .step    = 1,
+#define EXPO_96_DEF 0
+	    .default_value = EXPO_96_DEF,
+	},
+	.set = sd_setexposure,
+	.get = sd_getexposure,
+    },
+    {							/* 4 */
+	{
+	    .id      = V4L2_CID_SHARPNESS,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Sharpness",
+	    .minimum = -1,		/* -1 = auto */
+	    .maximum = 4,
+	    .step    = 1,
+#define SHARPNESS_96_DEF -1
+	    .default_value = SHARPNESS_96_DEF,
+	},
+	.set = sd_setsharpness,
+	.get = sd_getsharpness,
+    },
+    {							/* 5 */
+	{
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Saturation",
+		.minimum = 0,
+		.maximum = 4,
+		.step    = 1,
+#define SATUR_DEF 2
+		.default_value = SATUR_DEF,
+	},
+	.set = sd_setsatur,
+	.get = sd_getsatur,
+    },
+    {
+	{
+		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
+		.type    = V4L2_CTRL_TYPE_MENU,
+		.name    = "Light frequency filter",
+		.minimum = 0,
+		.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
+		.step    = 1,
+#define FREQ_DEF 0
+		.default_value = FREQ_DEF,
+	},
+	.set = sd_setfreq,
+	.get = sd_getfreq,
+    },
 };
 
-static const struct v4l2_pix_format vga_yuyv_mode[] = {
+static const struct v4l2_pix_format ov772x_mode[] = {
+	{320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+	 .bytesperline = 320 * 2,
+	 .sizeimage = 320 * 240 * 2,
+	 .colorspace = V4L2_COLORSPACE_SRGB,
+	 .priv = 1},
 	{640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
 	 .bytesperline = 640 * 2,
 	 .sizeimage = 640 * 480 * 2,
@@ -68,20 +392,35 @@ static const struct v4l2_pix_format vga_yuyv_mode[] = {
 	 .priv = 0},
 };
 
-static const struct v4l2_pix_format vga_jpeg_mode[] = {
+static const struct v4l2_pix_format ov965x_mode[] = {
 	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 	 .bytesperline = 320,
 	 .sizeimage = 320 * 240 * 3 / 8 + 590,
 	 .colorspace = V4L2_COLORSPACE_JPEG,
-	 .priv = 1},
+	 .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},
+	{800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+	 .bytesperline = 800,
+	 .sizeimage = 800 * 600 * 3 / 8 + 590,
+	 .colorspace = V4L2_COLORSPACE_JPEG,
+	 .priv = 2},
+	{1024, 768, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+	 .bytesperline = 1024,
+	 .sizeimage = 1024 * 768 * 3 / 8 + 590,
+	 .colorspace = V4L2_COLORSPACE_JPEG,
+	 .priv = 1},
+	{1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+	 .bytesperline = 1280,
+	 .sizeimage = 1280 * 1024 * 3 / 8 + 590,
+	 .colorspace = V4L2_COLORSPACE_JPEG,
 	 .priv = 0},
 };
 
-static const u8 bridge_init_ov722x[][2] = {
+static const u8 bridge_init_ov772x[][2] = {
 	{ 0xc2, 0x0c },
 	{ 0x88, 0xf8 },
 	{ 0xc3, 0x69 },
@@ -122,6 +461,7 @@ static const u8 bridge_init_ov722x[][2] = {
 	{ 0x1d, 0x40 },
 	{ 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */
 	{ 0x1d, 0x00 }, /* payload size */
+
 	{ 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */
 	{ 0x1d, 0x58 }, /* frame size */
 	{ 0x1d, 0x00 }, /* frame size */
@@ -138,10 +478,20 @@ static const u8 bridge_init_ov722x[][2] = {
 	{ 0xc1, 0x3c },
 	{ 0xc2, 0x0c },
 };
-
-static const u8 sensor_init_ov722x[][2] = {
+static const u8 sensor_init_ov772x[][2] = {
 	{ 0x12, 0x80 },
 	{ 0x11, 0x01 },
+/*fixme: better have a delay?*/
+	{ 0x11, 0x01 },
+	{ 0x11, 0x01 },
+	{ 0x11, 0x01 },
+	{ 0x11, 0x01 },
+	{ 0x11, 0x01 },
+	{ 0x11, 0x01 },
+	{ 0x11, 0x01 },
+	{ 0x11, 0x01 },
+	{ 0x11, 0x01 },
+	{ 0x11, 0x01 },
 
 	{ 0x3d, 0x03 },
 	{ 0x17, 0x26 },
@@ -154,10 +504,10 @@ static const u8 sensor_init_ov722x[][2] = {
 	{ 0x65, 0x20 },
 	{ 0x11, 0x01 },
 	{ 0x42, 0x7f },
-	{ 0x63, 0xe0 },
+	{ 0x63, 0xaa },		/* AWB - was e0 */
 	{ 0x64, 0xff },
 	{ 0x66, 0x00 },
-	{ 0x13, 0xf0 },
+	{ 0x13, 0xf0 },		/* com8 */
 	{ 0x0d, 0x41 },
 	{ 0x0f, 0xc5 },
 	{ 0x14, 0x11 },
@@ -170,7 +520,7 @@ static const u8 sensor_init_ov722x[][2] = {
 	{ 0x2a, 0x00 },
 	{ 0x2b, 0x00 },
 	{ 0x6b, 0xaa },
-	{ 0x13, 0xff },
+	{ 0x13, 0xff },		/* AWB */
 
 	{ 0x90, 0x05 },
 	{ 0x91, 0x01 },
@@ -218,9 +568,51 @@ static const u8 sensor_init_ov722x[][2] = {
 	{ 0x14, 0x41 },
 	{ 0x0e, 0xcd },
 	{ 0xac, 0xbf },
-	{ 0x8e, 0x00 },
+	{ 0x8e, 0x00 },		/* De-noise threshold */
 	{ 0x0c, 0xd0 }
 };
+static const u8 bridge_start_ov772x_vga[][2] = {
+	{0x1c, 0x00},
+	{0x1d, 0x40},
+	{0x1d, 0x02},
+	{0x1d, 0x00},
+	{0x1d, 0x02},
+	{0x1d, 0x58},
+	{0x1d, 0x00},
+	{0xc0, 0x50},
+	{0xc1, 0x3c},
+};
+static const u8 sensor_start_ov772x_vga[][2] = {
+	{0x12, 0x00},
+	{0x17, 0x26},
+	{0x18, 0xa0},
+	{0x19, 0x07},
+	{0x1a, 0xf0},
+	{0x29, 0xa0},
+	{0x2c, 0xf0},
+	{0x65, 0x20},
+};
+static const u8 bridge_start_ov772x_qvga[][2] = {
+	{0x1c, 0x00},
+	{0x1d, 0x40},
+	{0x1d, 0x02},
+	{0x1d, 0x00},
+	{0x1d, 0x01},
+	{0x1d, 0x4b},
+	{0x1d, 0x00},
+	{0xc0, 0x28},
+	{0xc1, 0x1e},
+};
+static const u8 sensor_start_ov772x_qvga[][2] = {
+	{0x12, 0x40},
+	{0x17, 0x3f},
+	{0x18, 0x50},
+	{0x19, 0x03},
+	{0x1a, 0x78},
+	{0x29, 0x50},
+	{0x2c, 0x78},
+	{0x65, 0x2f},
+};
 
 static const u8 bridge_init_ov965x[][2] = {
 	{0x88, 0xf8},
@@ -403,7 +795,7 @@ static const u8 sensor_init_ov965x[][2] = {
 	{0xcb, 0xf0},
 	{0xcc, 0xd8},
 	{0xcd, 0xf1},
-	{0x4f, 0x98},
+	{0x4f, 0x98},	/* matrix */
 	{0x50, 0x98},
 	{0x51, 0x00},
 	{0x52, 0x28},
@@ -412,6 +804,7 @@ static const u8 sensor_init_ov965x[][2] = {
 	{0x58, 0x1a},
 	{0xff, 0x41},	/* read 41, write ff 00 */
 	{0x41, 0x40},	/* com16 */
+
 	{0xc5, 0x03},	/* 60 Hz banding filter */
 	{0x6a, 0x02},	/* 50 Hz banding filter */
 
@@ -455,8 +848,8 @@ static const u8 bridge_init_ov965x_2[][2] = {
 	{0x52, 0x3c},
 	{0x53, 0x00},
 	{0x54, 0x00},
-	{0x55, 0x00},	/* brightness */
-	{0x57, 0x00},	/* contrast 2 */
+	{0x55, 0x00},
+	{0x57, 0x00},
 	{0x5c, 0x00},
 	{0x5a, 0xa0},
 	{0x5b, 0x78},
@@ -479,14 +872,16 @@ static const u8 sensor_init_ov965x_2[][2] = {
 	{0xa3, 0x3e},
 	{0x2d, 0x00},
 	{0xff, 0x42},	/* read 42, write ff 00 */
-	{0x42, 0xc0},
+	{0x42, 0xc0},	/* com17 */
 	{0x2d, 0x00},
 	{0xff, 0x42},	/* read 42, write ff 00 */
-	{0x42, 0xc1},
+	{0x42, 0xc1},	/* com17 */
+/* sharpness */
 	{0x3f, 0x01},
 	{0xff, 0x42},	/* read 42, write ff 00 */
-	{0x42, 0xc1},
-	{0x4f, 0x98},
+	{0x42, 0xc1},	/* com17 */
+/* saturation */
+	{0x4f, 0x98},	/* matrix */
 	{0x50, 0x98},
 	{0x51, 0x00},
 	{0x52, 0x28},
@@ -495,14 +890,17 @@ static const u8 sensor_init_ov965x_2[][2] = {
 	{0x58, 0x1a},
 	{0xff, 0x41},	/* read 41, write ff 00 */
 	{0x41, 0x40},	/* com16 */
+/* contrast */
 	{0x56, 0x40},
+/* brightness */
 	{0x55, 0x8f},
+/* expo */
 	{0x10, 0x25},	/* aech - exposure high bits */
 	{0xff, 0x13},	/* read 13, write ff 00 */
 	{0x13, 0xe7},	/* com8 - everything (AGC, AWB and AEC) */
 };
 
-static const u8 sensor_start_ov965x[][2] = {
+static const u8 sensor_start_ov965x_1_vga[][2] = {	/* same for qvga */
 	{0x12, 0x62},	/* com7 - 30fps VGA YUV */
 	{0x36, 0xfa},	/* aref3 */
 	{0x69, 0x0a},	/* hv */
@@ -523,10 +921,77 @@ static const u8 sensor_start_ov965x[][2] = {
 	{0x1a, 0x3d},	/* vstop */
 	{0x32, 0xff},	/* href */
 	{0xc0, 0xaa},
-	{}
 };
 
-static const u8 bridge_start_ov965x[][2] = {
+static const u8 sensor_start_ov965x_1_svga[][2] = {
+	{0x12, 0x02},	/* com7 - YUYV - VGA 15 full resolution */
+	{0x36, 0xf8},	/* aref3 */
+	{0x69, 0x02},	/* hv */
+	{0x8c, 0x0d},	/* com22 */
+	{0x3e, 0x0c},	/* com14 */
+	{0x41, 0x40},	/* com16 */
+	{0x72, 0x00},
+	{0x73, 0x01},
+	{0x74, 0x3a},
+	{0x75, 0x35},
+	{0x76, 0x01},
+	{0xc7, 0x80},	/* com24 */
+	{0x03, 0x1b},	/* vref */
+	{0x17, 0x1d},	/* hstart */
+	{0x18, 0xbd},	/* hstop */
+	{0x19, 0x01},	/* vstrt */
+	{0x1a, 0x81},	/* vstop */
+	{0x32, 0xff},	/* href */
+	{0xc0, 0xe2},
+};
+
+static const u8 sensor_start_ov965x_1_xga[][2] = {
+	{0x12, 0x02},	/* com7 */
+	{0x36, 0xf8},	/* aref3 */
+	{0x69, 0x02},	/* hv */
+	{0x8c, 0x89},	/* com22 */
+	{0x14, 0x28},	/* com9 */
+	{0x3e, 0x0c},	/* com14 */
+	{0x41, 0x40},	/* com16 */
+	{0x72, 0x00},
+	{0x73, 0x01},
+	{0x74, 0x3a},
+	{0x75, 0x35},
+	{0x76, 0x01},
+	{0xc7, 0x80},	/* com24 */
+	{0x03, 0x1b},	/* vref */
+	{0x17, 0x1d},	/* hstart */
+	{0x18, 0xbd},	/* hstop */
+	{0x19, 0x01},	/* vstrt */
+	{0x1a, 0x81},	/* vstop */
+	{0x32, 0xff},	/* href */
+	{0xc0, 0xe2},
+};
+
+static const u8 sensor_start_ov965x_1_sxga[][2] = {
+	{0x12, 0x02},	/* com7 */
+	{0x36, 0xf8},	/* aref3 */
+	{0x69, 0x02},	/* hv */
+	{0x8c, 0x89},	/* com22 */
+	{0x14, 0x28},	/* com9 */
+	{0x3e, 0x0c},	/* com14 */
+	{0x41, 0x40},	/* com16 */
+	{0x72, 0x00},
+	{0x73, 0x01},
+	{0x74, 0x3a},
+	{0x75, 0x35},
+	{0x76, 0x01},
+	{0xc7, 0x80},	/* com24 */
+	{0x03, 0x1b},	/* vref */
+	{0x17, 0x1d},	/* hstart */
+	{0x18, 0x02},	/* hstop */
+	{0x19, 0x01},	/* vstrt */
+	{0x1a, 0x81},	/* vstop */
+	{0x32, 0xff},	/* href */
+	{0xc0, 0xe2},
+};
+
+static const u8 bridge_start_ov965x_qvga[][2] = {
 	{0x94, 0xaa},
 	{0xf1, 0x60},
 	{0xe5, 0x04},
@@ -535,10 +1000,34 @@ static const u8 bridge_start_ov965x[][2] = {
 	{0x8c, 0x00},
 	{0x8d, 0x1c},
 	{0x34, 0x05},
-	{}
+
+	{0xc2, 0x4c},
+	{0xc3, 0xf9},
+	{0xda, 0x00},
+	{0x50, 0x00},
+	{0x51, 0xa0},
+	{0x52, 0x78},
+	{0x53, 0x00},
+	{0x54, 0x00},
+	{0x55, 0x00},
+	{0x57, 0x00},
+	{0x5c, 0x00},
+	{0x5a, 0x50},
+	{0x5b, 0x3c},
+	{0x35, 0x02},
+	{0xd9, 0x10},
+	{0x94, 0x11},
 };
 
 static const u8 bridge_start_ov965x_vga[][2] = {
+	{0x94, 0xaa},
+	{0xf1, 0x60},
+	{0xe5, 0x04},
+	{0xc0, 0x50},
+	{0xc1, 0x3c},
+	{0x8c, 0x00},
+	{0x8d, 0x1c},
+	{0x34, 0x05},
 	{0xc2, 0x0c},
 	{0xc3, 0xf9},
 	{0xda, 0x01},
@@ -555,30 +1044,98 @@ static const u8 bridge_start_ov965x_vga[][2] = {
 	{0x35, 0x02},
 	{0xd9, 0x10},
 	{0x94, 0x11},
-	{}
 };
 
-static const u8 bridge_start_ov965x_cif[][2] = {
+static const u8 bridge_start_ov965x_svga[][2] = {
+	{0x94, 0xaa},
+	{0xf1, 0x60},
+	{0xe5, 0x04},
+	{0xc0, 0xa0},
+	{0xc1, 0x80},
+	{0x8c, 0x00},
+	{0x8d, 0x1c},
+	{0x34, 0x05},
 	{0xc2, 0x4c},
 	{0xc3, 0xf9},
-	{0xda, 0x00},
 	{0x50, 0x00},
-	{0x51, 0xa0},
-	{0x52, 0x78},
+	{0x51, 0x40},
+	{0x52, 0x00},
 	{0x53, 0x00},
 	{0x54, 0x00},
-	{0x55, 0x00},
+	{0x55, 0x88},
 	{0x57, 0x00},
 	{0x5c, 0x00},
-	{0x5a, 0x50},
-	{0x5b, 0x3c},
+	{0x5a, 0xc8},
+	{0x5b, 0x96},
 	{0x35, 0x02},
 	{0xd9, 0x10},
+	{0xda, 0x00},
 	{0x94, 0x11},
-	{}
 };
 
-static const u8 sensor_start_ov965x_vga[][2] = {
+static const u8 bridge_start_ov965x_xga[][2] = {
+	{0x94, 0xaa},
+	{0xf1, 0x60},
+	{0xe5, 0x04},
+	{0xc0, 0xa0},
+	{0xc1, 0x80},
+	{0x8c, 0x00},
+	{0x8d, 0x1c},
+	{0x34, 0x05},
+	{0xc2, 0x4c},
+	{0xc3, 0xf9},
+	{0x50, 0x00},
+	{0x51, 0x40},
+	{0x52, 0x00},
+	{0x53, 0x00},
+	{0x54, 0x00},
+	{0x55, 0x88},
+	{0x57, 0x00},
+	{0x5c, 0x01},
+	{0x5a, 0x00},
+	{0x5b, 0xc0},
+	{0x35, 0x02},
+	{0xd9, 0x10},
+	{0xda, 0x01},
+	{0x94, 0x11},
+};
+
+static const u8 bridge_start_ov965x_sxga[][2] = {
+	{0x94, 0xaa},
+	{0xf1, 0x60},
+	{0xe5, 0x04},
+	{0xc0, 0xa0},
+	{0xc1, 0x80},
+	{0x8c, 0x00},
+	{0x8d, 0x1c},
+	{0x34, 0x05},
+	{0xc2, 0x0c},
+	{0xc3, 0xf9},
+	{0xda, 0x00},
+	{0x35, 0x02},
+	{0xd9, 0x10},
+	{0x94, 0x11},
+};
+
+static const u8 sensor_start_ov965x_2_qvga[][2] = {
+	{0x3b, 0xe4},	/* com11 - night mode 1/4 frame rate */
+	{0x1e, 0x04},	/* mvfp */
+	{0x13, 0xe0},	/* com8 */
+	{0x00, 0x00},
+	{0x13, 0xe7},	/* com8 - everything (AGC, AWB and AEC) */
+	{0x11, 0x01},	/* clkrc */
+	{0x6b, 0x5a},	/* dblv */
+	{0x6a, 0x02},	/* 50 Hz banding filter */
+	{0xc5, 0x03},	/* 60 Hz banding filter */
+	{0xa2, 0x96},	/* bd50 */
+	{0xa3, 0x7d},	/* bd60 */
+
+	{0xff, 0x13},	/* read 13, write ff 00 */
+	{0x13, 0xe7},
+	{0x3a, 0x80},	/* tslb - yuyv */
+};
+
+static const u8 sensor_start_ov965x_2_vga[][2] = {
 	{0x3b, 0xc4},	/* com11 - night mode 1/4 frame rate */
 	{0x1e, 0x04},	/* mvfp */
 	{0x13, 0xe0},	/* com8 */
@@ -592,35 +1149,36 @@ static const u8 sensor_start_ov965x_vga[][2] = {
 	{0xa3, 0x3e},	/* bd60 */
 
 	{0x2d, 0x00},	/* advfl */
-	{}
 };
 
-static const u8 sensor_start_ov965x_cif[][2] = {
-	{0x3b, 0xe4},	/* com11 - night mode 1/4 frame rate */
+static const u8 sensor_start_ov965x_2_svga[][2] = {	/* same for xga */
+	{0x3b, 0xc4},	/* com11 - night mode 1/4 frame rate */
 	{0x1e, 0x04},	/* mvfp */
 	{0x13, 0xe0},	/* com8 */
 	{0x00, 0x00},
 	{0x13, 0xe7},	/* com8 - everything (AGC, AWB and AEC) */
 	{0x11, 0x01},	/* clkrc */
 	{0x6b, 0x5a},	/* dblv */
-	{0x6a, 0x02},	/* 50 Hz banding filter */
-	{0xc5, 0x03},	/* 60 Hz banding filter */
-	{0xa2, 0x96},	/* bd50 */
-	{0xa3, 0x7d},	/* bd60 */
-
-	{0xff, 0x13},	/* read 13, write ff 00 */
-	{0x13, 0xe7},
-	{0x3a, 0x80},	/* tslb - yuyv */
-	{}
+	{0x6a, 0x0c},	/* 50 Hz banding filter */
+	{0xc5, 0x0f},	/* 60 Hz banding filter */
+	{0xa2, 0x4e},	/* bd50 */
+	{0xa3, 0x41},	/* bd60 */
 };
 
-static const u8 sensor_start_ov965x_2[][2] = {
-	{0xff, 0x42},	/* read 42, write ff 00 */
-	{0x42, 0xc1},	/* com17 - 50 Hz filter */
-	{}
+static const u8 sensor_start_ov965x_2_sxga[][2] = {
+	{0x13, 0xe0},	/* com8 */
+	{0x00, 0x00},
+	{0x13, 0xe7},	/* com8 - everything (AGC, AWB and AEC) */
+	{0x3b, 0xc4},	/* com11 - night mode 1/4 frame rate */
+	{0x1e, 0x04},	/* mvfp */
+	{0x11, 0x01},	/* clkrc */
+	{0x6b, 0x5a},	/* dblv */
+	{0x6a, 0x0c},	/* 50 Hz banding filter */
+	{0xc5, 0x0f},	/* 60 Hz banding filter */
+	{0xa2, 0x4e},	/* bd50 */
+	{0xa3, 0x41},	/* bd60 */
 };
 
-
 static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
 {
 	struct usb_device *udev = gspca_dev->dev;
@@ -753,39 +1311,310 @@ static void sccb_w_array(struct gspca_dev *gspca_dev,
 	}
 }
 
-/* set framerate */
-static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
+/* ov772x specific controls */
+static void set_frame_rate(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	struct rate_s {
+		u8 fps;
+		u8 r11;
+		u8 r0d;
+		u8 re5;
+	};
+	const struct rate_s *r;
+	static const struct rate_s rate_0[] = {	/* 640x480 */
+		{60, 0x01, 0xc1, 0x04},
+		{50, 0x01, 0x41, 0x02},
+		{40, 0x02, 0xc1, 0x04},
+		{30, 0x04, 0x81, 0x02},
+		{15, 0x03, 0x41, 0x04},
+	};
+	static const struct rate_s rate_1[] = {	/* 320x240 */
+		{125, 0x02, 0x81, 0x02},
+		{100, 0x02, 0xc1, 0x04},
+		{75, 0x03, 0xc1, 0x04},
+		{60, 0x04, 0xc1, 0x04},
+		{50, 0x02, 0x41, 0x04},
+		{40, 0x03, 0x41, 0x04},
+		{30, 0x04, 0x41, 0x04},
+	};
+
+	if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) {
+		r = rate_0;
+		i = ARRAY_SIZE(rate_0);
+	} else {
+		r = rate_1;
+		i = ARRAY_SIZE(rate_1);
+	}
+	while (--i > 0) {
+		if (sd->frame_rate >= r->fps)
+			break;
+		r++;
+	}
+
+	sccb_reg_write(gspca_dev, 0x11, r->r11);
+	sccb_reg_write(gspca_dev, 0x0d, r->r0d);
+	ov534_reg_write(gspca_dev, 0xe5, r->re5);
+
+	PDEBUG(D_PROBE, "frame_rate: %d", r->fps);
+}
+
+static void setbrightness_77(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sccb_reg_write(gspca_dev, 0x9B, sd->brightness);
+}
+
+static void setcontrast_77(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int fr = sd->frame_rate;
 
-	switch (fr) {
-	case 50:
-		sccb_reg_write(gspca_dev, 0x11, 0x01);
-		sccb_reg_write(gspca_dev, 0x0d, 0x41);
-		ov534_reg_write(gspca_dev, 0xe5, 0x02);
+	sccb_reg_write(gspca_dev, 0x9C, sd->contrast);
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 val;
+
+	val = sd->gain;
+	switch (val & 0x30) {
+	case 0x00:
+		val &= 0x0f;
 		break;
-	case 40:
-		sccb_reg_write(gspca_dev, 0x11, 0x02);
-		sccb_reg_write(gspca_dev, 0x0d, 0xc1);
-		ov534_reg_write(gspca_dev, 0xe5, 0x04);
+	case 0x10:
+		val &= 0x0f;
+		val |= 0x30;
 		break;
-/*	case 30: */
-	default:
-		fr = 30;
-		sccb_reg_write(gspca_dev, 0x11, 0x04);
-		sccb_reg_write(gspca_dev, 0x0d, 0x81);
-		ov534_reg_write(gspca_dev, 0xe5, 0x02);
+	case 0x20:
+		val &= 0x0f;
+		val |= 0x70;
 		break;
-	case 15:
-		sccb_reg_write(gspca_dev, 0x11, 0x03);
-		sccb_reg_write(gspca_dev, 0x0d, 0x41);
-		ov534_reg_write(gspca_dev, 0xe5, 0x04);
+	default:
+/*	case 0x30: */
+		val &= 0x0f;
+		val |= 0xf0;
 		break;
 	}
+	sccb_reg_write(gspca_dev, 0x00, val);
+}
+
+static void setexposure_77(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 val;
+
+	val = sd->exposure;
+	sccb_reg_write(gspca_dev, 0x08, val >> 7);
+	sccb_reg_write(gspca_dev, 0x10, val << 1);
+}
+
+static void setredblc(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sccb_reg_write(gspca_dev, 0x43, sd->redblc);
+}
+
+static void setblueblc(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sccb_reg_write(gspca_dev, 0x42, sd->blueblc);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sccb_reg_write(gspca_dev, 0x01, sd->hue);
+}
+
+static void setautogain_77(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->autogain) {
+		sccb_reg_write(gspca_dev, 0x13, 0xf7); /* AGC,AEC,AWB ON */
+		sccb_reg_write(gspca_dev, 0x64,
+				sccb_reg_read(gspca_dev, 0x64) | 0x03);
+	} else {
+		sccb_reg_write(gspca_dev, 0x13, 0xf0); /* AGC,AEC,AWB OFF */
+		sccb_reg_write(gspca_dev, 0x64,
+				sccb_reg_read(gspca_dev, 0x64) & 0xfc);
+	}
+}
+
+static void setawb(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->awb)
+		sccb_reg_write(gspca_dev, 0x63, 0xe0);	/* AWB on */
+	else
+		sccb_reg_write(gspca_dev, 0x63, 0xaa);	/* AWB off */
+}
+
+static void setsharpness_77(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 val;
+
+	val = sd->sharpness;
+	sccb_reg_write(gspca_dev, 0x91, val);	/* vga noise */
+	sccb_reg_write(gspca_dev, 0x8e, val);	/* qvga noise */
+}
+
+static void sethflip(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->hflip == 0)
+		sccb_reg_write(gspca_dev, 0x0c,
+				sccb_reg_read(gspca_dev, 0x0c) | 0x40);
+	else
+		sccb_reg_write(gspca_dev, 0x0c,
+				sccb_reg_read(gspca_dev, 0x0c) & 0xbf);
+}
+
+static void setvflip(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->vflip == 0)
+		sccb_reg_write(gspca_dev, 0x0c,
+				sccb_reg_read(gspca_dev, 0x0c) | 0x80);
+	else
+		sccb_reg_write(gspca_dev, 0x0c,
+				sccb_reg_read(gspca_dev, 0x0c) & 0x7f);
+}
+
+/* ov965x specific controls */
+static void setbrightness_96(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 val;
+
+	val = sd->brightness;
+	if (val < 8)
+		val = 15 - val;		/* f .. 8 */
+	else
+		val = val - 8;		/* 0 .. 7 */
+	sccb_reg_write(gspca_dev, 0x55,	/* brtn - brightness adjustment */
+			0x0f | (val << 4));
+}
+
+static void setcontrast_96(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sccb_reg_write(gspca_dev, 0x56,	/* cnst1 - contrast 1 ctrl coeff */
+			sd->contrast << 4);
+}
+
+static void setexposure_96(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 val;
+	static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e};
+
+	sccb_reg_write(gspca_dev, 0x10,			/* aec[9:2] */
+			expo[sd->exposure]);
+	val = sccb_reg_read(gspca_dev, 0x13);		/* com8 */
+	sccb_reg_write(gspca_dev, 0xff, 0x00);
+	sccb_reg_write(gspca_dev, 0x13, val);
+	val = sccb_reg_read(gspca_dev, 0xa1);		/* aech */
+	sccb_reg_write(gspca_dev, 0xff, 0x00);
+	sccb_reg_write(gspca_dev, 0xa1, val & 0xe0);	/* aec[15:10] = 0 */
+}
+
+static void setsharpness_96(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 val;
+
+	val = sd->sharpness;
+	if (val < 0) {				/* auto */
+		val = sccb_reg_read(gspca_dev, 0x42);	/* com17 */
+		sccb_reg_write(gspca_dev, 0xff, 0x00);
+		sccb_reg_write(gspca_dev, 0x42, val | 0x40);
+				/* Edge enhancement strength auto adjust */
+		return;
+	}
+	if (val != 0)
+		val = 1 << (val - 1);
+	sccb_reg_write(gspca_dev, 0x3f,	/* edge - edge enhance. factor */
+			val);
+	val = sccb_reg_read(gspca_dev, 0x42);		/* com17 */
+	sccb_reg_write(gspca_dev, 0xff, 0x00);
+	sccb_reg_write(gspca_dev, 0x42, val & 0xbf);
+}
+
+static void setautogain_96(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 val;
+
+/*fixme: should adjust agc/awb/aec by different controls */
+	val = sd->autogain;
+	val = sccb_reg_read(gspca_dev, 0x13);		/* com8 */
+	sccb_reg_write(gspca_dev, 0xff, 0x00);
+	if (sd->autogain)
+		val |= 0x05;		/* agc & aec */
+	else
+		val &= 0xfa;
+	sccb_reg_write(gspca_dev, 0x13, val);
+}
+
+static void setsatur(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 val1, val2, val3;
+	static const u8 matrix[5][2] = {
+		{0x14, 0x38},
+		{0x1e, 0x54},
+		{0x28, 0x70},
+		{0x32, 0x8c},
+		{0x48, 0x90}
+	};
+
+	val1 = matrix[sd->satur][0];
+	val2 = matrix[sd->satur][1];
+	val3 = val1 + val2;
+	sccb_reg_write(gspca_dev, 0x4f, val3);	/* matrix coeff */
+	sccb_reg_write(gspca_dev, 0x50, val3);
+	sccb_reg_write(gspca_dev, 0x51, 0x00);
+	sccb_reg_write(gspca_dev, 0x52, val1);
+	sccb_reg_write(gspca_dev, 0x53, val2);
+	sccb_reg_write(gspca_dev, 0x54, val3);
+	sccb_reg_write(gspca_dev, 0x58, 0x1a);	/* mtxs - coeff signs */
+	val1 = sccb_reg_read(gspca_dev, 0x41);	/* com16 */
+	sccb_reg_write(gspca_dev, 0xff, 0x00);
+	sccb_reg_write(gspca_dev, 0x41, val1);
+}
+
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 val;
+
+	val = sccb_reg_read(gspca_dev, 0x13);		/* com8 */
+	sccb_reg_write(gspca_dev, 0xff, 0x00);
+	if (sd->lightfreq == 0) {
+		sccb_reg_write(gspca_dev, 0x13, val & 0xdf);
+		return;
+	}
+	sccb_reg_write(gspca_dev, 0x13, val | 0x20);
 
-	sd->frame_rate = fr;
-	PDEBUG(D_PROBE, "frame_rate: %d", fr);
+	val = sccb_reg_read(gspca_dev, 0x42);		/* com17 */
+	sccb_reg_write(gspca_dev, 0xff, 0x00);
+	if (sd->lightfreq == 1)
+		val |= 0x01;
+	else
+		val &= 0xfe;
+	sccb_reg_write(gspca_dev, 0x42, val);
 }
 
 /* this function is called at probe time */
@@ -800,17 +1629,60 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	cam = &gspca_dev->cam;
 
 	if (sd->sensor == SENSOR_OV772X) {
-		cam->cam_mode = vga_yuyv_mode;
-		cam->nmodes = ARRAY_SIZE(vga_yuyv_mode);
+		cam->cam_mode = ov772x_mode;
+		cam->nmodes = ARRAY_SIZE(ov772x_mode);
 
 		cam->bulk = 1;
 		cam->bulk_size = 16384;
 		cam->bulk_nurbs = 2;
 	} else {		/* ov965x */
-		cam->cam_mode = vga_jpeg_mode;
-		cam->nmodes = ARRAY_SIZE(vga_jpeg_mode);
+		cam->cam_mode = ov965x_mode;
+		cam->nmodes = ARRAY_SIZE(ov965x_mode);
 	}
 
+	sd->frame_rate = 30;
+
+	if (sd->sensor == SENSOR_OV772X) {
+		sd->brightness = BRIGHTNESS_77_DEF;
+		sd->contrast = CONTRAST_77_DEF;
+		sd->gain = GAIN_DEF;
+		sd->exposure = EXPO_77_DEF;
+		sd->redblc = RED_BALANCE_DEF;
+		sd->blueblc = BLUE_BALANCE_DEF;
+		sd->hue = HUE_DEF;
+#if AUTOGAIN_77_DEF != 0
+		sd->autogain = AUTOGAIN_77_DEF;
+#else
+		gspca_dev->ctrl_inac |= (1 << AWB_77_IDX);
+#endif
+#if AWB_DEF != 0
+		sd->awb = AWB_DEF
+#endif
+#if SHARPNESS_77_DEF != 0
+		sd->sharpness = SHARPNESS_77_DEF;
+#endif
+#if HFLIP_DEF != 0
+		sd->hflip = HFLIP_DEF;
+#endif
+#if VFLIP_DEF != 0
+		sd->vflip = VFLIP_DEF;
+#endif
+	} else {
+		sd->brightness = BRIGHTNESS_96_DEF;
+		sd->contrast = CONTRAST_96_DEF;
+#if AUTOGAIN_96_DEF != 0
+		sd->autogain = AUTOGAIN_96_DEF;
+		gspca_dev->ctrl_inac |= (1 << EXPO_96_IDX);
+#endif
+#if EXPO_96_DEF != 0
+		sd->exposure = EXPO_96_DEF;
+#endif
+#if SHARPNESS_96_DEF != 0
+		sd->sharpness = SHARPNESS_96_DEF;
+#endif
+		sd->satur = SATUR_DEF;
+		sd->lightfreq = FREQ_DEF;
+	}
 	return 0;
 }
 
@@ -847,14 +1719,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
 	/* initialize */
 	switch (sd->sensor) {
 	case SENSOR_OV772X:
-		reg_w_array(gspca_dev, bridge_init_ov722x,
-				ARRAY_SIZE(bridge_init_ov722x));
+		reg_w_array(gspca_dev, bridge_init_ov772x,
+				ARRAY_SIZE(bridge_init_ov772x));
 		ov534_set_led(gspca_dev, 1);
-		sccb_w_array(gspca_dev, sensor_init_ov722x,
-				ARRAY_SIZE(sensor_init_ov722x));
+		sccb_w_array(gspca_dev, sensor_init_ov772x,
+				ARRAY_SIZE(sensor_init_ov772x));
 		ov534_reg_write(gspca_dev, 0xe0, 0x09);
 		ov534_set_led(gspca_dev, 0);
-		ov534_set_frame_rate(gspca_dev);
+		set_frame_rate(gspca_dev);
 		break;
 	default:
 /*	case SENSOR_OV965X: */
@@ -875,60 +1747,115 @@ static int sd_init(struct gspca_dev *gspca_dev)
 	return 0;
 }
 
-static int sd_start(struct gspca_dev *gspca_dev)
+static int sd_start_ov772x(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
 	int mode;
 
-	switch (sd->sensor) {
-	case SENSOR_OV772X:
-		ov534_set_led(gspca_dev, 1);
-		ov534_reg_write(gspca_dev, 0xe0, 0x00);
-		break;
-	default:
-/*	case SENSOR_OV965X: */
-
-		sccb_w_array(gspca_dev, sensor_start_ov965x,
-				ARRAY_SIZE(sensor_start_ov965x));
-		reg_w_array(gspca_dev, bridge_start_ov965x,
-				ARRAY_SIZE(bridge_start_ov965x));
-		mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
-		if (mode != 0) {	/* 320x240 */
-			reg_w_array(gspca_dev, bridge_start_ov965x_cif,
-					ARRAY_SIZE(bridge_start_ov965x_cif));
-			sccb_w_array(gspca_dev, sensor_start_ov965x_cif,
-					ARRAY_SIZE(sensor_start_ov965x_cif));
-		} else {		/* 640x480 */
-			reg_w_array(gspca_dev, bridge_start_ov965x_vga,
-					ARRAY_SIZE(bridge_start_ov965x_vga));
-			sccb_w_array(gspca_dev, sensor_start_ov965x_vga,
-					ARRAY_SIZE(sensor_start_ov965x_vga));
-		}
-		sccb_w_array(gspca_dev, sensor_start_ov965x_2,
-				ARRAY_SIZE(sensor_start_ov965x_2));
-		ov534_reg_write(gspca_dev, 0xe0, 0x00);
-		ov534_reg_write(gspca_dev, 0xe0, 0x00);
-		ov534_set_led(gspca_dev, 1);
+	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+	if (mode != 0) {	/* 320x240 */
+		reg_w_array(gspca_dev, bridge_start_ov772x_qvga,
+				ARRAY_SIZE(bridge_start_ov772x_qvga));
+		sccb_w_array(gspca_dev, sensor_start_ov772x_qvga,
+				ARRAY_SIZE(sensor_start_ov772x_qvga));
+	} else {		/* 640x480 */
+		reg_w_array(gspca_dev, bridge_start_ov772x_vga,
+				ARRAY_SIZE(bridge_start_ov772x_vga));
+		sccb_w_array(gspca_dev, sensor_start_ov772x_vga,
+				ARRAY_SIZE(sensor_start_ov772x_vga));
 	}
+	set_frame_rate(gspca_dev);
+
+	setautogain_77(gspca_dev);
+	setawb(gspca_dev);
+	setgain(gspca_dev);
+	setredblc(gspca_dev);
+	setblueblc(gspca_dev);
+	sethue(gspca_dev);
+	setexposure_77(gspca_dev);
+	setbrightness_77(gspca_dev);
+	setcontrast_77(gspca_dev);
+	setsharpness_77(gspca_dev);
+	setvflip(gspca_dev);
+	sethflip(gspca_dev);
+
+	ov534_set_led(gspca_dev, 1);
+	ov534_reg_write(gspca_dev, 0xe0, 0x00);
 	return 0;
 }
 
-static void sd_stopN(struct gspca_dev *gspca_dev)
+static int sd_start_ov965x(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
+	int mode;
 
-	switch (sd->sensor) {
-	case SENSOR_OV772X:
-		ov534_reg_write(gspca_dev, 0xe0, 0x09);
-		ov534_set_led(gspca_dev, 0);
-		break;
+	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+	switch (mode) {
 	default:
-/*	case SENSOR_OV965X: */
-		ov534_reg_write(gspca_dev, 0xe0, 0x01);
-		ov534_set_led(gspca_dev, 0);
-		ov534_reg_write(gspca_dev, 0xe0, 0x00);
+/*	case 4:			 * 320x240 */
+		sccb_w_array(gspca_dev, sensor_start_ov965x_1_vga,
+				ARRAY_SIZE(sensor_start_ov965x_1_vga));
+		reg_w_array(gspca_dev, bridge_start_ov965x_qvga,
+				ARRAY_SIZE(bridge_start_ov965x_qvga));
+		sccb_w_array(gspca_dev, sensor_start_ov965x_2_qvga,
+				ARRAY_SIZE(sensor_start_ov965x_2_qvga));
+		break;
+	case 3:			/* 640x480 */
+		sccb_w_array(gspca_dev, sensor_start_ov965x_1_vga,
+				ARRAY_SIZE(sensor_start_ov965x_1_vga));
+		reg_w_array(gspca_dev, bridge_start_ov965x_vga,
+				ARRAY_SIZE(bridge_start_ov965x_vga));
+		sccb_w_array(gspca_dev, sensor_start_ov965x_2_vga,
+				ARRAY_SIZE(sensor_start_ov965x_2_vga));
+		break;
+	case 2:			/* 800x600 */
+		sccb_w_array(gspca_dev, sensor_start_ov965x_1_svga,
+				ARRAY_SIZE(sensor_start_ov965x_1_svga));
+		reg_w_array(gspca_dev, bridge_start_ov965x_svga,
+				ARRAY_SIZE(bridge_start_ov965x_svga));
+		sccb_w_array(gspca_dev, sensor_start_ov965x_2_svga,
+				ARRAY_SIZE(sensor_start_ov965x_2_svga));
+		break;
+	case 1:			/* 1024x768 */
+		sccb_w_array(gspca_dev, sensor_start_ov965x_1_xga,
+				ARRAY_SIZE(sensor_start_ov965x_1_xga));
+		reg_w_array(gspca_dev, bridge_start_ov965x_xga,
+				ARRAY_SIZE(bridge_start_ov965x_xga));
+		sccb_w_array(gspca_dev, sensor_start_ov965x_2_svga,
+				ARRAY_SIZE(sensor_start_ov965x_2_svga));
+		break;
+	case 0:			/* 1280x1024 */
+		sccb_w_array(gspca_dev, sensor_start_ov965x_1_sxga,
+				ARRAY_SIZE(sensor_start_ov965x_1_sxga));
+		reg_w_array(gspca_dev, bridge_start_ov965x_sxga,
+				ARRAY_SIZE(bridge_start_ov965x_sxga));
+		sccb_w_array(gspca_dev, sensor_start_ov965x_2_sxga,
+				ARRAY_SIZE(sensor_start_ov965x_2_sxga));
 		break;
 	}
+	setfreq(gspca_dev);
+	setautogain_96(gspca_dev);
+	setbrightness_96(gspca_dev);
+	setcontrast_96(gspca_dev);
+	setexposure_96(gspca_dev);
+	setsharpness_96(gspca_dev);
+	setsatur(gspca_dev);
+
+	ov534_reg_write(gspca_dev, 0xe0, 0x00);
+	ov534_reg_write(gspca_dev, 0xe0, 0x00);
+	ov534_set_led(gspca_dev, 1);
+	return 0;
+}
+
+static void sd_stopN_ov772x(struct gspca_dev *gspca_dev)
+{
+	ov534_reg_write(gspca_dev, 0xe0, 0x09);
+	ov534_set_led(gspca_dev, 0);
+}
+
+static void sd_stopN_ov965x(struct gspca_dev *gspca_dev)
+{
+	ov534_reg_write(gspca_dev, 0xe0, 0x01);
+	ov534_set_led(gspca_dev, 0);
+	ov534_reg_write(gspca_dev, 0xe0, 0x00);
 }
 
 /* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
@@ -941,8 +1868,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 #define UVC_STREAM_EOF	(1 << 1)
 #define UVC_STREAM_FID	(1 << 0)
 
-static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
-			__u8 *data, int len)
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data, int len)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	__u32 this_pts;
@@ -983,32 +1910,30 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
 		/* If PTS or FID has changed, start a new frame. */
 		if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
 			if (gspca_dev->last_packet_type == INTER_PACKET)
-				frame = gspca_frame_add(gspca_dev,
-							LAST_PACKET, frame,
-							NULL, 0);
+				gspca_frame_add(gspca_dev, LAST_PACKET,
+						NULL, 0);
 			sd->last_pts = this_pts;
 			sd->last_fid = this_fid;
-			gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
 					data + 12, len - 12);
 		/* If this packet is marked as EOF, end the frame */
 		} else if (data[1] & UVC_STREAM_EOF) {
 			sd->last_pts = 0;
-			frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-						data + 12, len - 12);
+			gspca_frame_add(gspca_dev, LAST_PACKET,
+					data + 12, len - 12);
 		} else {
 
 			/* Add the data from this payload */
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-						data + 12, len - 12);
+			gspca_frame_add(gspca_dev, INTER_PACKET,
+					data + 12, len - 12);
 		}
 
-
 		/* Done this payload */
 		goto scan_next;
 
 discard:
 		/* Discard data until a new frame starts. */
-		gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
+		gspca_dev->last_packet_type = DISCARD_PACKET;
 
 scan_next:
 		remaining_len -= len;
@@ -1016,6 +1941,291 @@ scan_next:
 	} while (remaining_len > 0);
 }
 
+/* controls */
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gain = val;
+	if (gspca_dev->streaming)
+		setgain(gspca_dev);
+	return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gain;
+	return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->exposure = val;
+	if (gspca_dev->streaming) {
+		if (sd->sensor == SENSOR_OV772X)
+			setexposure_77(gspca_dev);
+		else
+			setexposure_96(gspca_dev);
+	}
+	return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->exposure;
+	return 0;
+}
+
+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) {
+		if (sd->sensor == SENSOR_OV772X)
+			setbrightness_77(gspca_dev);
+		else
+			setbrightness_96(gspca_dev);
+	}
+	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_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming) {
+		if (sd->sensor == SENSOR_OV772X)
+			setcontrast_77(gspca_dev);
+		else
+			setcontrast_96(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;
+}
+
+static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->satur = val;
+	if (gspca_dev->streaming)
+		setsatur(gspca_dev);
+	return 0;
+}
+
+static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->satur;
+	return 0;
+}
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->lightfreq = val;
+	if (gspca_dev->streaming)
+		setfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->lightfreq;
+	return 0;
+}
+
+static int sd_setredblc(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->redblc = val;
+	if (gspca_dev->streaming)
+		setredblc(gspca_dev);
+	return 0;
+}
+
+static int sd_getredblc(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->redblc;
+	return 0;
+}
+
+static int sd_setblueblc(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->blueblc = val;
+	if (gspca_dev->streaming)
+		setblueblc(gspca_dev);
+	return 0;
+}
+
+static int sd_getblueblc(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->blueblc;
+	return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hue = val;
+	if (gspca_dev->streaming)
+		sethue(gspca_dev);
+	return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->hue;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+
+	if (gspca_dev->streaming) {
+		if (sd->sensor == SENSOR_OV772X) {
+
+			/* the auto white balance control works only
+			 * when auto gain is set */
+			if (val)
+				gspca_dev->ctrl_inac &= ~(1 << AWB_77_IDX);
+			else
+				gspca_dev->ctrl_inac |= (1 << AWB_77_IDX);
+			setautogain_77(gspca_dev);
+		} else {
+			if (val)
+				gspca_dev->ctrl_inac |= (1 << EXPO_96_IDX);
+			else
+				gspca_dev->ctrl_inac &= ~(1 << EXPO_96_IDX);
+			setautogain_96(gspca_dev);
+		}
+	}
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->awb = val;
+	if (gspca_dev->streaming)
+		setawb(gspca_dev);
+	return 0;
+}
+
+static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->awb;
+	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) {
+		if (sd->sensor == SENSOR_OV772X)
+			setsharpness_77(gspca_dev);
+		else
+			setsharpness_96(gspca_dev);
+	}
+	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_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hflip = val;
+	if (gspca_dev->streaming)
+		sethflip(gspca_dev);
+	return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->hflip;
+	return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->vflip = val;
+	if (gspca_dev->streaming)
+		setvflip(gspca_dev);
+	return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->vflip;
+	return 0;
+}
+
 /* get stream parameters (framerate) */
 static int sd_get_streamparm(struct gspca_dev *gspca_dev,
 			     struct v4l2_streamparm *parm)
@@ -1047,7 +2257,8 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev,
 
 	/* Set requested framerate */
 	sd->frame_rate = tpf->denominator / tpf->numerator;
-	ov534_set_frame_rate(gspca_dev);
+	if (gspca_dev->streaming && sd->sensor == SENSOR_OV772X)
+		set_frame_rate(gspca_dev);
 
 	/* Return the actual framerate */
 	tpf->numerator = 1;
@@ -1056,20 +2267,53 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev,
 	return 0;
 }
 
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 0:		/* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+			strcpy((char *) menu->name, "NoFliker");
+			return 0;
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy((char *) menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy((char *) menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
 /* sub-driver description */
-static const struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc_ov772x = {
 	.name     = MODULE_NAME,
-	.ctrls    = sd_ctrls,
-	.nctrls   = ARRAY_SIZE(sd_ctrls),
+	.ctrls    = sd_ctrls_ov772x,
+	.nctrls   = ARRAY_SIZE(sd_ctrls_ov772x),
 	.config   = sd_config,
 	.init     = sd_init,
-	.start    = sd_start,
-	.stopN    = sd_stopN,
+	.start    = sd_start_ov772x,
+	.stopN    = sd_stopN_ov772x,
 	.pkt_scan = sd_pkt_scan,
 	.get_streamparm = sd_get_streamparm,
 	.set_streamparm = sd_set_streamparm,
 };
 
+static const struct sd_desc sd_desc_ov965x = {
+	.name     = MODULE_NAME,
+	.ctrls    = sd_ctrls_ov965x,
+	.nctrls   = ARRAY_SIZE(sd_ctrls_ov965x),
+	.config   = sd_config,
+	.init     = sd_init,
+	.start    = sd_start_ov965x,
+	.stopN    = sd_stopN_ov965x,
+	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
+};
+
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE(0x06f8, 0x3003), .driver_info = SENSOR_OV965X},
@@ -1082,8 +2326,12 @@ 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);
+	return gspca_dev_probe(intf, id,
+				id->driver_info == SENSOR_OV772X
+					? &sd_desc_ov772x
+					: &sd_desc_ov965x,
+				sizeof(struct sd),
+				THIS_MODULE);
 }
 
 static struct usb_driver sd_driver = {
@@ -1101,6 +2349,7 @@ static struct usb_driver sd_driver = {
 static int __init sd_mod_init(void)
 {
 	int ret;
+
 	ret = usb_register(&sd_driver);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 96659433d248..4706a823add0 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -337,14 +337,13 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,
-			__u8 *data,
+			u8 *data,
 			int len)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	unsigned char *sof;
 
-	sof = pac_find_sof(gspca_dev, data, len);
+	sof = pac_find_sof(&sd->sof_read, data, len);
 	if (sof) {
 		int n;
 
@@ -354,10 +353,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			n -= sizeof pac_sof_marker;
 		else
 			n = 0;
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					data, n);
+		gspca_frame_add(gspca_dev, LAST_PACKET,
+				data, n);
 		sd->header_read = 0;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
 		len -= sof - data;
 		data = sof;
 	}
@@ -381,7 +380,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		sd->header_read = 11;
 	}
 
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static void setbrightness(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
new file mode 100644
index 000000000000..74acceea8094
--- /dev/null
+++ b/drivers/media/video/gspca/pac7302.c
@@ -0,0 +1,1272 @@
+/*
+ *		Pixart PAC7302 library
+ *		Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * Separated from Pixart PAC7311 library by Márton Németh <nm127@freemail.hu>
+ *
+ * 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
+ */
+
+/* Some documentation about various registers as determined by trial and error.
+   When the register addresses differ between the 7202 and the 7311 the 2
+   different addresses are written as 7302addr/7311addr, when one of the 2
+   addresses is a - sign that register description is not valid for the
+   matching IC.
+
+   Register page 1:
+
+   Address	Description
+   -/0x08	Unknown compressor related, must always be 8 except when not
+		in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
+   -/0x1b	Auto white balance related, bit 0 is AWB enable (inverted)
+		bits 345 seem to toggle per color gains on/off (inverted)
+   0x78		Global control, bit 6 controls the LED (inverted)
+   -/0x80	JPEG compression ratio ? Best not touched
+
+   Register page 3/4:
+
+   Address	Description
+   0x02		Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
+		the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
+   -/0x0f	Master gain 1-245, low value = high gain
+   0x10/-	Master gain 0-31
+   -/0x10	Another gain 0-15, limited influence (1-2x gain I guess)
+   0x21		Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+   -/0x27	Seems to toggle various gains on / off, Setting bit 7 seems to
+		completely disable the analog amplification block. Set to 0x68
+		for max gain, 0x14 for minimal gain.
+
+   The registers are accessed in the following functions:
+
+   Page | Register   | Function
+   -----+------------+---------------------------------------------------
+    0   | 0x0f..0x20 | setcolors()
+    0   | 0xa2..0xab | setbrightcont()
+    0   | 0xc5       | setredbalance()
+    0   | 0xc6       | setwhitebalance()
+    0   | 0xc7       | setbluebalance()
+    0   | 0xdc       | setbrightcont(), setcolors()
+    3   | 0x02       | setexposure()
+    3   | 0x10       | setgain()
+    3   | 0x11       | setcolors(), setgain(), setexposure(), sethvflip()
+    3   | 0x21       | sethvflip()
+*/
+
+#define MODULE_NAME "pac7302"
+
+#include <media/v4l2-chip-ident.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
+MODULE_DESCRIPTION("Pixart PAC7302");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor for pac7302 */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char white_balance;
+	unsigned char red_balance;
+	unsigned char blue_balance;
+	unsigned char gain;
+	unsigned char exposure;
+	unsigned char autogain;
+	__u8 hflip;
+	__u8 vflip;
+
+	u8 sof_read;
+	u8 autogain_ignore_frames;
+
+	atomic_t avg_lum;
+};
+
+/* 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 int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbluebalance(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_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+/* This control is pac7302 only */
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+#define BRIGHTNESS_MAX 0x20
+		.maximum = BRIGHTNESS_MAX,
+		.step    = 1,
+#define BRIGHTNESS_DEF 0x10
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+/* This control is for both the 7302 and the 7311 */
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+#define CONTRAST_MAX 255
+		.maximum = CONTRAST_MAX,
+		.step    = 1,
+#define CONTRAST_DEF 127
+		.default_value = CONTRAST_DEF,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+/* This control is pac7302 only */
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Saturation",
+		.minimum = 0,
+#define COLOR_MAX 255
+		.maximum = COLOR_MAX,
+		.step    = 1,
+#define COLOR_DEF 127
+		.default_value = COLOR_DEF,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+	{
+	    {
+		.id      = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "White Balance",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define WHITEBALANCE_DEF 4
+		.default_value = WHITEBALANCE_DEF,
+	    },
+	    .set = sd_setwhitebalance,
+	    .get = sd_getwhitebalance,
+	},
+	{
+	    {
+		.id      = V4L2_CID_RED_BALANCE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Red",
+		.minimum = 0,
+		.maximum = 3,
+		.step    = 1,
+#define REDBALANCE_DEF 1
+		.default_value = REDBALANCE_DEF,
+	    },
+	    .set = sd_setredbalance,
+	    .get = sd_getredbalance,
+	},
+	{
+	    {
+		.id      = V4L2_CID_BLUE_BALANCE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Blue",
+		.minimum = 0,
+		.maximum = 3,
+		.step    = 1,
+#define BLUEBALANCE_DEF 1
+		.default_value = BLUEBALANCE_DEF,
+	    },
+	    .set = sd_setbluebalance,
+	    .get = sd_getbluebalance,
+	},
+/* All controls below are for both the 7302 and the 7311 */
+	{
+	    {
+		.id      = V4L2_CID_GAIN,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Gain",
+		.minimum = 0,
+#define GAIN_MAX 255
+		.maximum = GAIN_MAX,
+		.step    = 1,
+#define GAIN_DEF 127
+#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
+		.default_value = GAIN_DEF,
+	    },
+	    .set = sd_setgain,
+	    .get = sd_getgain,
+	},
+	{
+	    {
+		.id      = V4L2_CID_EXPOSURE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Exposure",
+		.minimum = 0,
+#define EXPOSURE_MAX 255
+		.maximum = EXPOSURE_MAX,
+		.step    = 1,
+#define EXPOSURE_DEF  16 /*  32 ms / 30 fps */
+#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+		.default_value = EXPOSURE_DEF,
+	    },
+	    .set = sd_setexposure,
+	    .get = sd_getexposure,
+	},
+	{
+	    {
+		.id      = V4L2_CID_AUTOGAIN,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define AUTOGAIN_DEF 1
+		.default_value = AUTOGAIN_DEF,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+	{
+	    {
+		.id      = V4L2_CID_HFLIP,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Mirror",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define HFLIP_DEF 0
+		.default_value = HFLIP_DEF,
+	    },
+	    .set = sd_sethflip,
+	    .get = sd_gethflip,
+	},
+	{
+	    {
+		.id      = V4L2_CID_VFLIP,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Vflip",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define VFLIP_DEF 0
+		.default_value = VFLIP_DEF,
+	    },
+	    .set = sd_setvflip,
+	    .get = sd_getvflip,
+	},
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+	{640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+#define LOAD_PAGE3		255
+#define LOAD_PAGE4		254
+#define END_OF_SEQUENCE		0
+
+/* pac 7302 */
+static const __u8 init_7302[] = {
+/*	index,value */
+	0xff, 0x01,		/* page 1 */
+	0x78, 0x00,		/* deactivate */
+	0xff, 0x01,
+	0x78, 0x40,		/* led off */
+};
+static const __u8 start_7302[] = {
+/*	index, len, [value]* */
+	0xff, 1,	0x00,		/* page 0 */
+	0x00, 12,	0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
+			0x00, 0x00, 0x00, 0x00,
+	0x0d, 24,	0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
+			0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
+			0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
+	0x26, 2,	0xaa, 0xaa,
+	0x2e, 1,	0x31,
+	0x38, 1,	0x01,
+	0x3a, 3,	0x14, 0xff, 0x5a,
+	0x43, 11,	0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
+			0x00, 0x54, 0x11,
+	0x55, 1,	0x00,
+	0x62, 4, 	0x10, 0x1e, 0x1e, 0x18,
+	0x6b, 1,	0x00,
+	0x6e, 3,	0x08, 0x06, 0x00,
+	0x72, 3,	0x00, 0xff, 0x00,
+	0x7d, 23,	0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
+			0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
+			0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
+	0xa2, 10,	0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
+			0xd2, 0xeb,
+	0xaf, 1,	0x02,
+	0xb5, 2,	0x08, 0x08,
+	0xb8, 2,	0x08, 0x88,
+	0xc4, 4,	0xae, 0x01, 0x04, 0x01,
+	0xcc, 1,	0x00,
+	0xd1, 11,	0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
+			0xc1, 0xd7, 0xec,
+	0xdc, 1,	0x01,
+	0xff, 1,	0x01,		/* page 1 */
+	0x12, 3,	0x02, 0x00, 0x01,
+	0x3e, 2,	0x00, 0x00,
+	0x76, 5,	0x01, 0x20, 0x40, 0x00, 0xf2,
+	0x7c, 1,	0x00,
+	0x7f, 10,	0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
+			0x02, 0x00,
+	0x96, 5,	0x01, 0x10, 0x04, 0x01, 0x04,
+	0xc8, 14,	0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
+			0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
+	0xd8, 1,	0x01,
+	0xdb, 2,	0x00, 0x01,
+	0xde, 7,	0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
+	0xe6, 4,	0x00, 0x00, 0x00, 0x01,
+	0xeb, 1,	0x00,
+	0xff, 1,	0x02,		/* page 2 */
+	0x22, 1,	0x00,
+	0xff, 1,	0x03,		/* page 3 */
+	0, LOAD_PAGE3,			/* load the page 3 */
+	0x11, 1,	0x01,
+	0xff, 1,	0x02,		/* page 2 */
+	0x13, 1,	0x00,
+	0x22, 4,	0x1f, 0xa4, 0xf0, 0x96,
+	0x27, 2,	0x14, 0x0c,
+	0x2a, 5,	0xc8, 0x00, 0x18, 0x12, 0x22,
+	0x64, 8,	0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
+	0x6e, 1,	0x08,
+	0xff, 1,	0x01,		/* page 1 */
+	0x78, 1,	0x00,
+	0, END_OF_SEQUENCE		/* end of sequence */
+};
+
+#define SKIP		0xaa
+/* page 3 - the value SKIP says skip the index - see reg_w_page() */
+static const __u8 page3_7302[] = {
+	0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
+	0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
+	0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
+	0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
+	0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
+	0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
+	0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
+	0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+	0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
+	0x00
+};
+
+static int reg_w_buf(struct gspca_dev *gspca_dev,
+		  __u8 index,
+		  const char *buffer, int len)
+{
+	int ret;
+
+	memcpy(gspca_dev->usb_buf, buffer, len);
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			1,		/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index, gspca_dev->usb_buf, len,
+			500);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg_w_buf(): "
+		"Failed to write registers to index 0x%x, error %i",
+		index, ret);
+	return ret;
+}
+
+
+static int reg_w(struct gspca_dev *gspca_dev,
+		  __u8 index,
+		  __u8 value)
+{
+	int ret;
+
+	gspca_dev->usb_buf[0] = value;
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0, index, gspca_dev->usb_buf, 1,
+			500);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg_w(): "
+		"Failed to write register to index 0x%x, value 0x%x, error %i",
+		index, value, ret);
+	return ret;
+}
+
+static int reg_w_seq(struct gspca_dev *gspca_dev,
+		const __u8 *seq, int len)
+{
+	int ret = 0;
+	while (--len >= 0) {
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, seq[0], seq[1]);
+		seq += 2;
+	}
+	return ret;
+}
+
+/* load the beginning of a page */
+static int reg_w_page(struct gspca_dev *gspca_dev,
+			const __u8 *page, int len)
+{
+	int index;
+	int ret = 0;
+
+	for (index = 0; index < len; index++) {
+		if (page[index] == SKIP)		/* skip this index */
+			continue;
+		gspca_dev->usb_buf[0] = page[index];
+		ret = usb_control_msg(gspca_dev->dev,
+				usb_sndctrlpipe(gspca_dev->dev, 0),
+				0,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				0, index, gspca_dev->usb_buf, 1,
+				500);
+		if (ret < 0) {
+			PDEBUG(D_ERR, "reg_w_page(): "
+			"Failed to write register to index 0x%x, "
+			"value 0x%x, error %i",
+			index, page[index], ret);
+			break;
+		}
+	}
+	return ret;
+}
+
+/* output a variable sequence */
+static int reg_w_var(struct gspca_dev *gspca_dev,
+			const __u8 *seq,
+			const __u8 *page3, unsigned int page3_len,
+			const __u8 *page4, unsigned int page4_len)
+{
+	int index, len;
+	int ret = 0;
+
+	for (;;) {
+		index = *seq++;
+		len = *seq++;
+		switch (len) {
+		case END_OF_SEQUENCE:
+			return ret;
+		case LOAD_PAGE4:
+			ret = reg_w_page(gspca_dev, page4, page4_len);
+			break;
+		case LOAD_PAGE3:
+			ret = reg_w_page(gspca_dev, page3, page3_len);
+			break;
+		default:
+			if (len > USB_BUF_SZ) {
+				PDEBUG(D_ERR|D_STREAM,
+					"Incorrect variable sequence");
+				return -EINVAL;
+			}
+			while (len > 0) {
+				if (len < 8) {
+					ret = reg_w_buf(gspca_dev,
+						index, seq, len);
+					if (ret < 0)
+						return ret;
+					seq += len;
+					break;
+				}
+				ret = reg_w_buf(gspca_dev, index, seq, 8);
+				seq += 8;
+				index += 8;
+				len -= 8;
+			}
+		}
+		if (ret < 0)
+			return ret;
+	}
+	/* not reached */
+}
+
+/* this function is called at probe time for pac7302 */
+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;
+
+	cam = &gspca_dev->cam;
+
+	PDEBUG(D_CONF, "Find Sensor PAC7302");
+	cam->cam_mode = vga_mode;	/* only 640x480 */
+	cam->nmodes = ARRAY_SIZE(vga_mode);
+
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->colors = COLOR_DEF;
+	sd->white_balance = WHITEBALANCE_DEF;
+	sd->red_balance = REDBALANCE_DEF;
+	sd->blue_balance = BLUEBALANCE_DEF;
+	sd->gain = GAIN_DEF;
+	sd->exposure = EXPOSURE_DEF;
+	sd->autogain = AUTOGAIN_DEF;
+	sd->hflip = HFLIP_DEF;
+	sd->vflip = VFLIP_DEF;
+	return 0;
+}
+
+/* This function is used by pac7302 only */
+static int setbrightcont(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, v;
+	int ret;
+	static const __u8 max[10] =
+		{0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
+		 0xd4, 0xec};
+	static const __u8 delta[10] =
+		{0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
+		 0x11, 0x0b};
+
+	ret = reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	for (i = 0; i < 10; i++) {
+		v = max[i];
+		v += (sd->brightness - BRIGHTNESS_MAX)
+			* 150 / BRIGHTNESS_MAX;		/* 200 ? */
+		v -= delta[i] * sd->contrast / CONTRAST_MAX;
+		if (v < 0)
+			v = 0;
+		else if (v > 0xff)
+			v = 0xff;
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0xa2 + i, v);
+	}
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xdc, 0x01);
+	return ret;
+}
+
+/* This function is used by pac7302 only */
+static int setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, v;
+	int ret;
+	static const int a[9] =
+		{217, -212, 0, -101, 170, -67, -38, -315, 355};
+	static const int b[9] =
+		{19, 106, 0, 19, 106, 1, 19, 106, 1};
+
+	ret = reg_w(gspca_dev, 0xff, 0x03);	/* page 3 */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x11, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	for (i = 0; i < 9; i++) {
+		v = a[i] * sd->colors / COLOR_MAX + b[i];
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
+	}
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xdc, 0x01);
+	PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
+	return ret;
+}
+
+static int setwhitebalance(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xc6, sd->white_balance);
+
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xdc, 0x01);
+	PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
+	return ret;
+}
+
+static int setredbalance(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xc5, sd->red_balance);
+
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xdc, 0x01);
+	PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
+	return ret;
+}
+
+static int setbluebalance(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xc7, sd->blue_balance);
+
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xdc, 0x01);
+	PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
+	return ret;
+}
+
+static int setgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x10, sd->gain >> 3);
+
+	/* load registers to sensor (Bit 0, auto clear) */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x11, 0x01);
+	return ret;
+}
+
+static int setexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+	__u8 reg;
+
+	/* register 2 of frame 3/4 contains the clock divider configuring the
+	   no fps according to the formula: 60 / reg. sd->exposure is the
+	   desired exposure time in ms. */
+	reg = 120 * sd->exposure / 1000;
+	if (reg < 2)
+		reg = 2;
+	else if (reg > 63)
+		reg = 63;
+
+	/* On the pac7302 reg2 MUST be a multiple of 3, so round it to
+	   the nearest multiple of 3, except when between 6 and 12? */
+	if (reg < 6 || reg > 12)
+		reg = ((reg + 1) / 3) * 3;
+	ret = reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x02, reg);
+
+	/* load registers to sensor (Bit 0, auto clear) */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x11, 0x01);
+	return ret;
+}
+
+static int sethvflip(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+	__u8 data;
+
+	ret = reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
+	data = (sd->hflip ? 0x08 : 0x00) | (sd->vflip ? 0x04 : 0x00);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x21, data);
+	/* load registers to sensor (Bit 0, auto clear) */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x11, 0x01);
+	return ret;
+}
+
+/* this function is called at probe and resume time for pac7302 */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	return reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret = 0;
+
+	sd->sof_read = 0;
+
+	ret = reg_w_var(gspca_dev, start_7302,
+		page3_7302, sizeof(page3_7302),
+		NULL, 0);
+	if (0 <= ret)
+		ret = setbrightcont(gspca_dev);
+	if (0 <= ret)
+		ret = setcolors(gspca_dev);
+	if (0 <= ret)
+		ret = setwhitebalance(gspca_dev);
+	if (0 <= ret)
+		ret = setredbalance(gspca_dev);
+	if (0 <= ret)
+		ret = setbluebalance(gspca_dev);
+	if (0 <= ret)
+		ret = setgain(gspca_dev);
+	if (0 <= ret)
+		ret = setexposure(gspca_dev);
+	if (0 <= ret)
+		ret = sethvflip(gspca_dev);
+
+	/* only resolution 640x480 is supported for pac7302 */
+
+	sd->sof_read = 0;
+	sd->autogain_ignore_frames = 0;
+	atomic_set(&sd->avg_lum, -1);
+
+	/* start stream */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xff, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x78, 0x01);
+
+	return ret;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	int ret;
+
+	/* stop stream */
+	ret = reg_w(gspca_dev, 0xff, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x78, 0x00);
+}
+
+/* called on streamoff with alt 0 and on disconnect for pac7302 */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	int ret;
+
+	if (!gspca_dev->present)
+		return;
+	ret = reg_w(gspca_dev, 0xff, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x78, 0x40);
+}
+
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
+static void do_autogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int avg_lum = atomic_read(&sd->avg_lum);
+	int desired_lum, deadzone;
+
+	if (avg_lum == -1)
+		return;
+
+	desired_lum = 270 + sd->brightness * 4;
+	/* Hack hack, with the 7202 the first exposure step is
+	   pretty large, so if we're about to make the first
+	   exposure increase make the deadzone large to avoid
+	   oscilating */
+	if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
+			sd->exposure > EXPOSURE_DEF &&
+			sd->exposure < 42)
+		deadzone = 90;
+	else
+		deadzone = 30;
+
+	if (sd->autogain_ignore_frames > 0)
+		sd->autogain_ignore_frames--;
+	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+			deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
+}
+
+/* JPEG header, part 1 */
+static const unsigned char pac_jpeg_header1[] = {
+  0xff, 0xd8,		/* SOI: Start of Image */
+
+  0xff, 0xc0,		/* SOF0: Start of Frame (Baseline DCT) */
+  0x00, 0x11,		/* length = 17 bytes (including this length field) */
+  0x08			/* Precision: 8 */
+  /* 2 bytes is placed here: number of image lines */
+  /* 2 bytes is placed here: samples per line */
+};
+
+/* JPEG header, continued */
+static const unsigned char pac_jpeg_header2[] = {
+  0x03,			/* Number of image components: 3 */
+  0x01, 0x21, 0x00,	/* ID=1, Subsampling 1x1, Quantization table: 0 */
+  0x02, 0x11, 0x01,	/* ID=2, Subsampling 2x1, Quantization table: 1 */
+  0x03, 0x11, 0x01,	/* ID=3, Subsampling 2x1, Quantization table: 1 */
+
+  0xff, 0xda,		/* SOS: Start Of Scan */
+  0x00, 0x0c,		/* length = 12 bytes (including this length field) */
+  0x03,			/* number of components: 3 */
+  0x01, 0x00,		/* selector 1, table 0x00 */
+  0x02, 0x11,		/* selector 2, table 0x11 */
+  0x03, 0x11,		/* selector 3, table 0x11 */
+  0x00, 0x3f,		/* Spectral selection: 0 .. 63 */
+  0x00			/* Successive approximation: 0 */
+};
+
+static void pac_start_frame(struct gspca_dev *gspca_dev,
+		struct gspca_frame *frame,
+		__u16 lines, __u16 samples_per_line)
+{
+	unsigned char tmpbuf[4];
+
+	gspca_frame_add(gspca_dev, FIRST_PACKET,
+		pac_jpeg_header1, sizeof(pac_jpeg_header1));
+
+	tmpbuf[0] = lines >> 8;
+	tmpbuf[1] = lines & 0xff;
+	tmpbuf[2] = samples_per_line >> 8;
+	tmpbuf[3] = samples_per_line & 0xff;
+
+	gspca_frame_add(gspca_dev, INTER_PACKET,
+		tmpbuf, sizeof(tmpbuf));
+	gspca_frame_add(gspca_dev, INTER_PACKET,
+		pac_jpeg_header2, sizeof(pac_jpeg_header2));
+}
+
+/* this function is run at interrupt level */
+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;
+	struct gspca_frame *frame;
+	unsigned char *sof;
+
+	sof = pac_find_sof(&sd->sof_read, data, len);
+	if (sof) {
+		int n, lum_offset, footer_length;
+
+		frame = gspca_get_i_frame(gspca_dev);
+		if (frame == NULL) {
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			return;
+		}
+
+		/* 6 bytes after the FF D9 EOF marker a number of lumination
+		   bytes are send corresponding to different parts of the
+		   image, the 14th and 15th byte after the EOF seem to
+		   correspond to the center of the image */
+		lum_offset = 61 + sizeof pac_sof_marker;
+		footer_length = 74;
+
+		/* Finish decoding current frame */
+		n = (sof - data) - (footer_length + sizeof pac_sof_marker);
+		if (n < 0) {
+			frame->data_end += n;
+			n = 0;
+		}
+		gspca_frame_add(gspca_dev, INTER_PACKET,
+					data, n);
+		if (gspca_dev->last_packet_type != DISCARD_PACKET &&
+				frame->data_end[-2] == 0xff &&
+				frame->data_end[-1] == 0xd9)
+			gspca_frame_add(gspca_dev, LAST_PACKET,
+						NULL, 0);
+
+		n = sof - data;
+		len -= n;
+		data = sof;
+
+		/* Get average lumination */
+		if (gspca_dev->last_packet_type == LAST_PACKET &&
+				n >= lum_offset)
+			atomic_set(&sd->avg_lum, data[-lum_offset] +
+						data[-lum_offset + 1]);
+		else
+			atomic_set(&sd->avg_lum, -1);
+
+		/* Start the new frame with the jpeg header */
+		/* The PAC7302 has the image rotated 90 degrees */
+		pac_start_frame(gspca_dev, frame,
+			gspca_dev->width, gspca_dev->height);
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, 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)
+		setbrightcont(gspca_dev);
+	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_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming) {
+		setbrightcont(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;
+}
+
+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)
+		setcolors(gspca_dev);
+	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_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret = 0;
+
+	sd->white_balance = val;
+	if (gspca_dev->streaming)
+		ret = setwhitebalance(gspca_dev);
+	if (0 <= ret)
+		ret = 0;
+	return ret;
+}
+
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->white_balance;
+	return 0;
+}
+
+static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret = 0;
+
+	sd->red_balance = val;
+	if (gspca_dev->streaming)
+		ret = setredbalance(gspca_dev);
+	if (0 <= ret)
+		ret = 0;
+	return ret;
+}
+
+static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->red_balance;
+	return 0;
+}
+
+static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret = 0;
+
+	sd->blue_balance = val;
+	if (gspca_dev->streaming)
+		ret = setbluebalance(gspca_dev);
+	if (0 <= ret)
+		ret = 0;
+	return ret;
+}
+
+static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->blue_balance;
+	return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gain = val;
+	if (gspca_dev->streaming)
+		setgain(gspca_dev);
+	return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gain;
+	return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->exposure = val;
+	if (gspca_dev->streaming)
+		setexposure(gspca_dev);
+	return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->exposure;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	/* when switching to autogain set defaults to make sure
+	   we are on a valid point of the autogain gain /
+	   exposure knee graph, and give this change time to
+	   take effect before doing autogain. */
+	if (sd->autogain) {
+		sd->exposure = EXPOSURE_DEF;
+		sd->gain = GAIN_DEF;
+		if (gspca_dev->streaming) {
+			sd->autogain_ignore_frames =
+				PAC_AUTOGAIN_IGNORE_FRAMES;
+			setexposure(gspca_dev);
+			setgain(gspca_dev);
+		}
+	}
+
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hflip = val;
+	if (gspca_dev->streaming)
+		sethvflip(gspca_dev);
+	return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->hflip;
+	return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->vflip = val;
+	if (gspca_dev->streaming)
+		sethvflip(gspca_dev);
+	return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->vflip;
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
+			struct v4l2_dbg_register *reg)
+{
+	int ret = -EINVAL;
+	__u8 index;
+	__u8 value;
+
+	/* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
+			       long on the USB bus)
+	*/
+	if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
+	    reg->match.addr == 0 &&
+	    (reg->reg < 0x000000ff) &&
+	    (reg->val <= 0x000000ff)
+	) {
+		/* Currently writing to page 0 is only supported. */
+		/* reg_w() only supports 8bit index */
+		index = reg->reg & 0x000000ff;
+		value = reg->val & 0x000000ff;
+
+		/* Note that there shall be no access to other page
+		   by any other function between the page swith and
+		   the actual register write */
+		ret = reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, index, value);
+
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0xdc, 0x01);
+	}
+	return ret;
+}
+
+static int sd_chip_ident(struct gspca_dev *gspca_dev,
+			struct v4l2_dbg_chip_ident *chip)
+{
+	int ret = -EINVAL;
+
+	if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
+	    chip->match.addr == 0) {
+		chip->revision = 0;
+		chip->ident = V4L2_IDENT_UNKNOWN;
+		ret = 0;
+	}
+	return ret;
+}
+#endif
+
+/* sub-driver description for pac7302 */
+static 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,
+	.stop0 = sd_stop0,
+	.pkt_scan = sd_pkt_scan,
+	.dq_callback = do_autogain,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.set_register = sd_dbg_s_register,
+	.get_chip_ident = sd_chip_ident,
+#endif
+};
+
+/* -- module initialisation -- */
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x06f8, 0x3009)},
+	{USB_DEVICE(0x093a, 0x2620)},
+	{USB_DEVICE(0x093a, 0x2621)},
+	{USB_DEVICE(0x093a, 0x2622)},
+	{USB_DEVICE(0x093a, 0x2624)},
+	{USB_DEVICE(0x093a, 0x2626)},
+	{USB_DEVICE(0x093a, 0x2628)},
+	{USB_DEVICE(0x093a, 0x2629)},
+	{USB_DEVICE(0x093a, 0x262a)},
+	{USB_DEVICE(0x093a, 0x262c)},
+	{}
+};
+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)
+{
+	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/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 052714484e83..e5697a6345e8 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -57,23 +57,17 @@ MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
 MODULE_DESCRIPTION("Pixart PAC7311");
 MODULE_LICENSE("GPL");
 
-/* specific webcam descriptor */
+/* specific webcam descriptor for pac7311 */
 struct sd {
 	struct gspca_dev gspca_dev;		/* !! must be the first item */
 
-	unsigned char brightness;
 	unsigned char contrast;
-	unsigned char colors;
 	unsigned char gain;
 	unsigned char exposure;
 	unsigned char autogain;
 	__u8 hflip;
 	__u8 vflip;
 
-	__u8 sensor;
-#define SENSOR_PAC7302 0
-#define SENSOR_PAC7311 1
-
 	u8 sof_read;
 	u8 autogain_ignore_frames;
 
@@ -81,12 +75,8 @@ 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 int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(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_sethflip(struct gspca_dev *gspca_dev, __s32 val);
@@ -99,23 +89,6 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
-/* This control is pac7302 only */
-#define BRIGHTNESS_IDX 0
-	{
-	    {
-		.id      = V4L2_CID_BRIGHTNESS,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Brightness",
-		.minimum = 0,
-#define BRIGHTNESS_MAX 0x20
-		.maximum = BRIGHTNESS_MAX,
-		.step    = 1,
-#define BRIGHTNESS_DEF 0x10
-		.default_value = BRIGHTNESS_DEF,
-	    },
-	    .set = sd_setbrightness,
-	    .get = sd_getbrightness,
-	},
 /* This control is for both the 7302 and the 7311 */
 	{
 	    {
@@ -132,23 +105,6 @@ static struct ctrl sd_ctrls[] = {
 	    .set = sd_setcontrast,
 	    .get = sd_getcontrast,
 	},
-/* This control is pac7302 only */
-#define SATURATION_IDX 2
-	{
-	    {
-		.id      = V4L2_CID_SATURATION,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Saturation",
-		.minimum = 0,
-#define COLOR_MAX 255
-		.maximum = COLOR_MAX,
-		.step    = 1,
-#define COLOR_DEF 127
-		.default_value = COLOR_DEF,
-	    },
-	    .set = sd_setcolors,
-	    .get = sd_getcolors,
-	},
 /* All controls below are for both the 7302 and the 7311 */
 	{
 	    {
@@ -244,101 +200,9 @@ static const struct v4l2_pix_format vga_mode[] = {
 		.priv = 0},
 };
 
-/* pac 7302 */
-static const __u8 init_7302[] = {
-/*	index,value */
-	0xff, 0x01,		/* page 1 */
-	0x78, 0x00,		/* deactivate */
-	0xff, 0x01,
-	0x78, 0x40,		/* led off */
-};
-static const __u8 start_7302[] = {
-/*	index, len, [value]* */
-	0xff, 1,	0x00,		/* page 0 */
-	0x00, 12,	0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
-			0x00, 0x00, 0x00, 0x00,
-	0x0d, 24,	0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
-			0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
-			0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
-	0x26, 2,	0xaa, 0xaa,
-	0x2e, 1,	0x31,
-	0x38, 1,	0x01,
-	0x3a, 3,	0x14, 0xff, 0x5a,
-	0x43, 11,	0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
-			0x00, 0x54, 0x11,
-	0x55, 1,	0x00,
-	0x62, 4, 	0x10, 0x1e, 0x1e, 0x18,
-	0x6b, 1,	0x00,
-	0x6e, 3,	0x08, 0x06, 0x00,
-	0x72, 3,	0x00, 0xff, 0x00,
-	0x7d, 23,	0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
-			0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
-			0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
-	0xa2, 10,	0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
-			0xd2, 0xeb,
-	0xaf, 1,	0x02,
-	0xb5, 2,	0x08, 0x08,
-	0xb8, 2,	0x08, 0x88,
-	0xc4, 4,	0xae, 0x01, 0x04, 0x01,
-	0xcc, 1,	0x00,
-	0xd1, 11,	0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
-			0xc1, 0xd7, 0xec,
-	0xdc, 1,	0x01,
-	0xff, 1,	0x01,		/* page 1 */
-	0x12, 3,	0x02, 0x00, 0x01,
-	0x3e, 2,	0x00, 0x00,
-	0x76, 5,	0x01, 0x20, 0x40, 0x00, 0xf2,
-	0x7c, 1,	0x00,
-	0x7f, 10,	0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
-			0x02, 0x00,
-	0x96, 5,	0x01, 0x10, 0x04, 0x01, 0x04,
-	0xc8, 14,	0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
-			0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
-	0xd8, 1,	0x01,
-	0xdb, 2,	0x00, 0x01,
-	0xde, 7,	0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
-	0xe6, 4,	0x00, 0x00, 0x00, 0x01,
-	0xeb, 1,	0x00,
-	0xff, 1,	0x02,		/* page 2 */
-	0x22, 1,	0x00,
-	0xff, 1,	0x03,		/* page 3 */
-	0x00, 255,			/* load the page 3 */
-	0x11, 1,	0x01,
-	0xff, 1,	0x02,		/* page 2 */
-	0x13, 1,	0x00,
-	0x22, 4,	0x1f, 0xa4, 0xf0, 0x96,
-	0x27, 2,	0x14, 0x0c,
-	0x2a, 5,	0xc8, 0x00, 0x18, 0x12, 0x22,
-	0x64, 8,	0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
-	0x6e, 1,	0x08,
-	0xff, 1,	0x01,		/* page 1 */
-	0x78, 1,	0x00,
-	0, 0				/* end of sequence */
-};
-
-/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
-static const __u8 page3_7302[] = {
-	0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
-	0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
-	0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
-	0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
-	0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
-	0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
-	0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
-	0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
-	0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
-	0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
-	0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
-	0x00
-};
+#define LOAD_PAGE3		255
+#define LOAD_PAGE4		254
+#define END_OF_SEQUENCE		0
 
 /* pac 7311 */
 static const __u8 init_7311[] = {
@@ -378,119 +242,154 @@ static const __u8 start_7311[] = {
 	0xf0, 13,	0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
 			0x3f, 0x00, 0x0a, 0x01, 0x00,
 	0xff, 1,	0x04,		/* page 4 */
-	0x00, 254,			/* load the page 4 */
+	0, LOAD_PAGE4,			/* load the page 4 */
 	0x11, 1,	0x01,
-	0, 0				/* end of sequence */
+	0, END_OF_SEQUENCE		/* end of sequence */
 };
 
-/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
+#define SKIP		0xaa
+/* page 4 - the value SKIP says skip the index - see reg_w_page() */
 static const __u8 page4_7311[] = {
-	0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
-	0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
-	0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
-	0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68,
+	SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
+	0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
+	0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
+	SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
 	0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
 	0x23, 0x28, 0x04, 0x11, 0x00, 0x00
 };
 
-static void reg_w_buf(struct gspca_dev *gspca_dev,
+static int reg_w_buf(struct gspca_dev *gspca_dev,
 		  __u8 index,
 		  const char *buffer, int len)
 {
+	int ret;
+
 	memcpy(gspca_dev->usb_buf, buffer, len);
-	usb_control_msg(gspca_dev->dev,
+	ret = usb_control_msg(gspca_dev->dev,
 			usb_sndctrlpipe(gspca_dev->dev, 0),
 			1,		/* request */
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			0,		/* value */
 			index, gspca_dev->usb_buf, len,
 			500);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg_w_buf(): "
+		"Failed to write registers to index 0x%x, error %i",
+		index, ret);
+	return ret;
 }
 
 
-static void reg_w(struct gspca_dev *gspca_dev,
+static int reg_w(struct gspca_dev *gspca_dev,
 		  __u8 index,
 		  __u8 value)
 {
+	int ret;
+
 	gspca_dev->usb_buf[0] = value;
-	usb_control_msg(gspca_dev->dev,
+	ret = usb_control_msg(gspca_dev->dev,
 			usb_sndctrlpipe(gspca_dev->dev, 0),
 			0,			/* request */
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			0, index, gspca_dev->usb_buf, 1,
 			500);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg_w(): "
+		"Failed to write register to index 0x%x, value 0x%x, error %i",
+		index, value, ret);
+	return ret;
 }
 
-static void reg_w_seq(struct gspca_dev *gspca_dev,
+static int reg_w_seq(struct gspca_dev *gspca_dev,
 		const __u8 *seq, int len)
 {
+	int ret = 0;
 	while (--len >= 0) {
-		reg_w(gspca_dev, seq[0], seq[1]);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, seq[0], seq[1]);
 		seq += 2;
 	}
+	return ret;
 }
 
 /* load the beginning of a page */
-static void reg_w_page(struct gspca_dev *gspca_dev,
+static int reg_w_page(struct gspca_dev *gspca_dev,
 			const __u8 *page, int len)
 {
 	int index;
+	int ret = 0;
 
 	for (index = 0; index < len; index++) {
-		if (page[index] == 0xaa)		/* skip this index */
+		if (page[index] == SKIP)		/* skip this index */
 			continue;
 		gspca_dev->usb_buf[0] = page[index];
-		usb_control_msg(gspca_dev->dev,
+		ret = usb_control_msg(gspca_dev->dev,
 				usb_sndctrlpipe(gspca_dev->dev, 0),
 				0,			/* request */
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 				0, index, gspca_dev->usb_buf, 1,
 				500);
+		if (ret < 0) {
+			PDEBUG(D_ERR, "reg_w_page(): "
+			"Failed to write register to index 0x%x, "
+			"value 0x%x, error %i",
+			index, page[index], ret);
+			break;
+		}
 	}
+	return ret;
 }
 
 /* output a variable sequence */
-static void reg_w_var(struct gspca_dev *gspca_dev,
-			const __u8 *seq)
+static int reg_w_var(struct gspca_dev *gspca_dev,
+			const __u8 *seq,
+			const __u8 *page3, unsigned int page3_len,
+			const __u8 *page4, unsigned int page4_len)
 {
 	int index, len;
+	int ret = 0;
 
 	for (;;) {
 		index = *seq++;
 		len = *seq++;
 		switch (len) {
-		case 0:
-			return;
-		case 254:
-			reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
+		case END_OF_SEQUENCE:
+			return ret;
+		case LOAD_PAGE4:
+			ret = reg_w_page(gspca_dev, page4, page4_len);
 			break;
-		case 255:
-			reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
+		case LOAD_PAGE3:
+			ret = reg_w_page(gspca_dev, page3, page3_len);
 			break;
 		default:
-			if (len > 64) {
+			if (len > USB_BUF_SZ) {
 				PDEBUG(D_ERR|D_STREAM,
 					"Incorrect variable sequence");
-				return;
+				return -EINVAL;
 			}
 			while (len > 0) {
 				if (len < 8) {
-					reg_w_buf(gspca_dev, index, seq, len);
+					ret = reg_w_buf(gspca_dev,
+						index, seq, len);
+					if (ret < 0)
+						return ret;
 					seq += len;
 					break;
 				}
-				reg_w_buf(gspca_dev, index, seq, 8);
+				ret = reg_w_buf(gspca_dev, index, seq, 8);
 				seq += 8;
 				index += 8;
 				len -= 8;
 			}
 		}
+		if (ret < 0)
+			return ret;
 	}
 	/* not reached */
 }
 
-/* this function is called at probe time */
+/* this function is called at probe time for pac7311 */
 static int sd_config(struct gspca_dev *gspca_dev,
 			const struct usb_device_id *id)
 {
@@ -499,22 +398,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
 	cam = &gspca_dev->cam;
 
-	sd->sensor = id->driver_info;
-	if (sd->sensor == SENSOR_PAC7302) {
-		PDEBUG(D_CONF, "Find Sensor PAC7302");
-		cam->cam_mode = &vga_mode[2];	/* only 640x480 */
-		cam->nmodes = 1;
-	} else {
-		PDEBUG(D_CONF, "Find Sensor PAC7311");
-		cam->cam_mode = vga_mode;
-		cam->nmodes = ARRAY_SIZE(vga_mode);
-		gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
-				| (1 << SATURATION_IDX);
-	}
+	PDEBUG(D_CONF, "Find Sensor PAC7311");
+	cam->cam_mode = vga_mode;
+	cam->nmodes = ARRAY_SIZE(vga_mode);
 
-	sd->brightness = BRIGHTNESS_DEF;
 	sd->contrast = CONTRAST_DEF;
-	sd->colors = COLOR_DEF;
 	sd->gain = GAIN_DEF;
 	sd->exposure = EXPOSURE_DEF;
 	sd->autogain = AUTOGAIN_DEF;
@@ -523,91 +411,47 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	return 0;
 }
 
-/* This function is used by pac7302 only */
-static void setbrightcont(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	int i, v;
-	static const __u8 max[10] =
-		{0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
-		 0xd4, 0xec};
-	static const __u8 delta[10] =
-		{0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
-		 0x11, 0x0b};
-
-	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
-	for (i = 0; i < 10; i++) {
-		v = max[i];
-		v += (sd->brightness - BRIGHTNESS_MAX)
-			* 150 / BRIGHTNESS_MAX;		/* 200 ? */
-		v -= delta[i] * sd->contrast / CONTRAST_MAX;
-		if (v < 0)
-			v = 0;
-		else if (v > 0xff)
-			v = 0xff;
-		reg_w(gspca_dev, 0xa2 + i, v);
-	}
-	reg_w(gspca_dev, 0xdc, 0x01);
-}
-
 /* This function is used by pac7311 only */
-static void setcontrast(struct gspca_dev *gspca_dev)
+static int setcontrast(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
 
-	reg_w(gspca_dev, 0xff, 0x04);
-	reg_w(gspca_dev, 0x10, sd->contrast >> 4);
+	ret = reg_w(gspca_dev, 0xff, 0x04);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x10, sd->contrast >> 4);
 	/* load registers to sensor (Bit 0, auto clear) */
-	reg_w(gspca_dev, 0x11, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x11, 0x01);
+	return ret;
 }
 
-/* This function is used by pac7302 only */
-static void setcolors(struct gspca_dev *gspca_dev)
+static int setgain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int i, v;
-	static const int a[9] =
-		{217, -212, 0, -101, 170, -67, -38, -315, 355};
-	static const int b[9] =
-		{19, 106, 0, 19, 106, 1, 19, 106, 1};
-
-	reg_w(gspca_dev, 0xff, 0x03);	/* page 3 */
-	reg_w(gspca_dev, 0x11, 0x01);
-	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
-	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
-	for (i = 0; i < 9; i++) {
-		v = a[i] * sd->colors / COLOR_MAX + b[i];
-		reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
-		reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
-	}
-	reg_w(gspca_dev, 0xdc, 0x01);
-	PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
-}
+	int gain = GAIN_MAX - sd->gain;
+	int ret;
 
-static void setgain(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
+	if (gain < 1)
+		gain = 1;
+	else if (gain > 245)
+		gain = 245;
+	ret = reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x0e, 0x00);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x0f, gain);
 
-	if (sd->sensor == SENSOR_PAC7302) {
-		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
-		reg_w(gspca_dev, 0x10, sd->gain >> 3);
-	} else {
-		int gain = GAIN_MAX - sd->gain;
-		if (gain < 1)
-			gain = 1;
-		else if (gain > 245)
-			gain = 245;
-		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
-		reg_w(gspca_dev, 0x0e, 0x00);
-		reg_w(gspca_dev, 0x0f, gain);
-	}
 	/* load registers to sensor (Bit 0, auto clear) */
-	reg_w(gspca_dev, 0x11, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x11, 0x01);
+	return ret;
 }
 
-static void setexposure(struct gspca_dev *gspca_dev)
+static int setexposure(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
 	__u8 reg;
 
 	/* register 2 of frame 3/4 contains the clock divider configuring the
@@ -619,97 +463,94 @@ static void setexposure(struct gspca_dev *gspca_dev)
 	else if (reg > 63)
 		reg = 63;
 
-	if (sd->sensor == SENSOR_PAC7302) {
-		/* On the pac7302 reg2 MUST be a multiple of 3, so round it to
-		   the nearest multiple of 3, except when between 6 and 12? */
-		if (reg < 6 || reg > 12)
-			reg = ((reg + 1) / 3) * 3;
-		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
-		reg_w(gspca_dev, 0x02, reg);
+	ret = reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x02, reg);
+	/* Page 1 register 8 must always be 0x08 except when not in
+	   640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xff, 0x01);
+	if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
+			reg <= 3) {
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x08, 0x09);
 	} else {
-		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
-		reg_w(gspca_dev, 0x02, reg);
-		/* Page 1 register 8 must always be 0x08 except when not in
-		   640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
-		reg_w(gspca_dev, 0xff, 0x01);
-		if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
-				reg <= 3)
-			reg_w(gspca_dev, 0x08, 0x09);
-		else
-			reg_w(gspca_dev, 0x08, 0x08);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x08, 0x08);
 	}
+
 	/* load registers to sensor (Bit 0, auto clear) */
-	reg_w(gspca_dev, 0x11, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x11, 0x01);
+	return ret;
 }
 
-static void sethvflip(struct gspca_dev *gspca_dev)
+static int sethvflip(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
 	__u8 data;
 
-	if (sd->sensor == SENSOR_PAC7302) {
-		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
-		data = (sd->hflip ? 0x08 : 0x00)
-			| (sd->vflip ? 0x04 : 0x00);
-	} else {
-		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
-		data = (sd->hflip ? 0x04 : 0x00)
-			| (sd->vflip ? 0x08 : 0x00);
-	}
-	reg_w(gspca_dev, 0x21, data);
+	ret = reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
+	data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x21, data);
 	/* load registers to sensor (Bit 0, auto clear) */
-	reg_w(gspca_dev, 0x11, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x11, 0x01);
+	return ret;
 }
 
-/* this function is called at probe and resume time */
+/* this function is called at probe and resume time for pac7311 */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	if (sd->sensor == SENSOR_PAC7302)
-		reg_w_seq(gspca_dev, init_7302, sizeof init_7302);
-	else
-		reg_w_seq(gspca_dev, init_7311, sizeof init_7311);
-
-	return 0;
+	return reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
 
 	sd->sof_read = 0;
 
-	if (sd->sensor == SENSOR_PAC7302) {
-		reg_w_var(gspca_dev, start_7302);
-		setbrightcont(gspca_dev);
-		setcolors(gspca_dev);
-	} else {
-		reg_w_var(gspca_dev, start_7311);
-		setcontrast(gspca_dev);
-	}
-	setgain(gspca_dev);
-	setexposure(gspca_dev);
-	sethvflip(gspca_dev);
+	ret = reg_w_var(gspca_dev, start_7311,
+		NULL, 0,
+		page4_7311, sizeof(page4_7311));
+	if (0 <= ret)
+		ret = setcontrast(gspca_dev);
+	if (0 <= ret)
+		ret = setgain(gspca_dev);
+	if (0 <= ret)
+		ret = setexposure(gspca_dev);
+	if (0 <= ret)
+		ret = sethvflip(gspca_dev);
 
 	/* set correct resolution */
 	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
 	case 2:					/* 160x120 pac7311 */
-		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x17, 0x20);
-		reg_w(gspca_dev, 0x87, 0x10);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0xff, 0x01);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x17, 0x20);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x87, 0x10);
 		break;
 	case 1:					/* 320x240 pac7311 */
-		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x17, 0x30);
-		reg_w(gspca_dev, 0x87, 0x11);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0xff, 0x01);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x17, 0x30);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x87, 0x11);
 		break;
 	case 0:					/* 640x480 */
-		if (sd->sensor == SENSOR_PAC7302)
-			break;
-		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x17, 0x00);
-		reg_w(gspca_dev, 0x87, 0x12);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0xff, 0x01);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x17, 0x00);
+		if (0 <= ret)
+			ret = reg_w(gspca_dev, 0x87, 0x12);
 		break;
 	}
 
@@ -718,47 +559,42 @@ static int sd_start(struct gspca_dev *gspca_dev)
 	atomic_set(&sd->avg_lum, -1);
 
 	/* start stream */
-	reg_w(gspca_dev, 0xff, 0x01);
-	if (sd->sensor == SENSOR_PAC7302)
-		reg_w(gspca_dev, 0x78, 0x01);
-	else
-		reg_w(gspca_dev, 0x78, 0x05);
-	return 0;
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xff, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x78, 0x05);
+
+	return ret;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	if (sd->sensor == SENSOR_PAC7302) {
-		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x78, 0x00);
-		reg_w(gspca_dev, 0x78, 0x00);
-		return;
-	}
-	reg_w(gspca_dev, 0xff, 0x04);
-	reg_w(gspca_dev, 0x27, 0x80);
-	reg_w(gspca_dev, 0x28, 0xca);
-	reg_w(gspca_dev, 0x29, 0x53);
-	reg_w(gspca_dev, 0x2a, 0x0e);
-	reg_w(gspca_dev, 0xff, 0x01);
-	reg_w(gspca_dev, 0x3e, 0x20);
-	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
-	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
-	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
-}
+	int ret;
 
-/* called on streamoff with alt 0 and on disconnect */
+	ret = reg_w(gspca_dev, 0xff, 0x04);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x27, 0x80);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x28, 0xca);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x29, 0x53);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x2a, 0x0e);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0xff, 0x01);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x3e, 0x20);
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+	if (0 <= ret)
+		ret = reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+}
+
+/* called on streamoff with alt 0 and on disconnect for 7311 */
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	if (!gspca_dev->present)
-		return;
-	if (sd->sensor == SENSOR_PAC7302) {
-		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x78, 0x40);
-	}
 }
 
 /* Include pac common sof detection functions */
@@ -773,22 +609,8 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 	if (avg_lum == -1)
 		return;
 
-	if (sd->sensor == SENSOR_PAC7302) {
-		desired_lum = 270 + sd->brightness * 4;
-		/* Hack hack, with the 7202 the first exposure step is
-		   pretty large, so if we're about to make the first
-		   exposure increase make the deadzone large to avoid
-		   oscilating */
-		if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
-				sd->exposure > EXPOSURE_DEF &&
-				sd->exposure < 42)
-			deadzone = 90;
-		else
-			deadzone = 30;
-	} else {
-		desired_lum = 200;
-		deadzone = 20;
-	}
+	desired_lum = 200;
+	deadzone = 20;
 
 	if (sd->autogain_ignore_frames > 0)
 		sd->autogain_ignore_frames--;
@@ -797,53 +619,92 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
-static const unsigned char pac7311_jpeg_header1[] = {
-  0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
+/* JPEG header, part 1 */
+static const unsigned char pac_jpeg_header1[] = {
+  0xff, 0xd8,		/* SOI: Start of Image */
+
+  0xff, 0xc0,		/* SOF0: Start of Frame (Baseline DCT) */
+  0x00, 0x11,		/* length = 17 bytes (including this length field) */
+  0x08			/* Precision: 8 */
+  /* 2 bytes is placed here: number of image lines */
+  /* 2 bytes is placed here: samples per line */
 };
 
-static const unsigned char pac7311_jpeg_header2[] = {
-  0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
-  0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+/* JPEG header, continued */
+static const unsigned char pac_jpeg_header2[] = {
+  0x03,			/* Number of image components: 3 */
+  0x01, 0x21, 0x00,	/* ID=1, Subsampling 1x1, Quantization table: 0 */
+  0x02, 0x11, 0x01,	/* ID=2, Subsampling 2x1, Quantization table: 1 */
+  0x03, 0x11, 0x01,	/* ID=3, Subsampling 2x1, Quantization table: 1 */
+
+  0xff, 0xda,		/* SOS: Start Of Scan */
+  0x00, 0x0c,		/* length = 12 bytes (including this length field) */
+  0x03,			/* number of components: 3 */
+  0x01, 0x00,		/* selector 1, table 0x00 */
+  0x02, 0x11,		/* selector 2, table 0x11 */
+  0x03, 0x11,		/* selector 3, table 0x11 */
+  0x00, 0x3f,		/* Spectral selection: 0 .. 63 */
+  0x00			/* Successive approximation: 0 */
 };
 
+static void pac_start_frame(struct gspca_dev *gspca_dev,
+		struct gspca_frame *frame,
+		__u16 lines, __u16 samples_per_line)
+{
+	unsigned char tmpbuf[4];
+
+	gspca_frame_add(gspca_dev, FIRST_PACKET,
+		pac_jpeg_header1, sizeof(pac_jpeg_header1));
+
+	tmpbuf[0] = lines >> 8;
+	tmpbuf[1] = lines & 0xff;
+	tmpbuf[2] = samples_per_line >> 8;
+	tmpbuf[3] = samples_per_line & 0xff;
+
+	gspca_frame_add(gspca_dev, INTER_PACKET,
+		tmpbuf, sizeof(tmpbuf));
+	gspca_frame_add(gspca_dev, INTER_PACKET,
+		pac_jpeg_header2, sizeof(pac_jpeg_header2));
+}
+
 /* 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;
 	unsigned char *sof;
+	struct gspca_frame *frame;
 
-	sof = pac_find_sof(gspca_dev, data, len);
+	sof = pac_find_sof(&sd->sof_read, data, len);
 	if (sof) {
-		unsigned char tmpbuf[4];
 		int n, lum_offset, footer_length;
 
-		if (sd->sensor == SENSOR_PAC7302) {
-		  /* 6 bytes after the FF D9 EOF marker a number of lumination
-		     bytes are send corresponding to different parts of the
-		     image, the 14th and 15th byte after the EOF seem to
-		     correspond to the center of the image */
-		  lum_offset = 61 + sizeof pac_sof_marker;
-		  footer_length = 74;
-		} else {
-		  lum_offset = 24 + sizeof pac_sof_marker;
-		  footer_length = 26;
+		frame = gspca_get_i_frame(gspca_dev);
+		if (frame == NULL) {
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			return;
 		}
 
+		/* 6 bytes after the FF D9 EOF marker a number of lumination
+		   bytes are send corresponding to different parts of the
+		   image, the 14th and 15th byte after the EOF seem to
+		   correspond to the center of the image */
+		lum_offset = 24 + sizeof pac_sof_marker;
+		footer_length = 26;
+
 		/* Finish decoding current frame */
 		n = (sof - data) - (footer_length + sizeof pac_sof_marker);
 		if (n < 0) {
 			frame->data_end += n;
 			n = 0;
 		}
-		frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+		gspca_frame_add(gspca_dev, INTER_PACKET,
 					data, n);
 		if (gspca_dev->last_packet_type != DISCARD_PACKET &&
 				frame->data_end[-2] == 0xff &&
 				frame->data_end[-1] == 0xd9)
-			frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+			gspca_frame_add(gspca_dev, LAST_PACKET,
 						NULL, 0);
 
 		n = sof - data;
@@ -859,43 +720,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			atomic_set(&sd->avg_lum, -1);
 
 		/* Start the new frame with the jpeg header */
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-			pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
-		if (sd->sensor == SENSOR_PAC7302) {
-			/* The PAC7302 has the image rotated 90 degrees */
-			tmpbuf[0] = gspca_dev->width >> 8;
-			tmpbuf[1] = gspca_dev->width & 0xff;
-			tmpbuf[2] = gspca_dev->height >> 8;
-			tmpbuf[3] = gspca_dev->height & 0xff;
-		} else {
-			tmpbuf[0] = gspca_dev->height >> 8;
-			tmpbuf[1] = gspca_dev->height & 0xff;
-			tmpbuf[2] = gspca_dev->width >> 8;
-			tmpbuf[3] = gspca_dev->width & 0xff;
-		}
-		gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
-		gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-			pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
+		pac_start_frame(gspca_dev, frame,
+			gspca_dev->height, gspca_dev->width);
 	}
-	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)
-		setbrightcont(gspca_dev);
-	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;
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
@@ -904,10 +732,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
 
 	sd->contrast = val;
 	if (gspca_dev->streaming) {
-		if (sd->sensor == SENSOR_PAC7302)
-			setbrightcont(gspca_dev);
-		else
-			setcontrast(gspca_dev);
+		setcontrast(gspca_dev);
 	}
 	return 0;
 }
@@ -920,24 +745,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
 	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)
-		setcolors(gspca_dev);
-	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_setgain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1041,7 +848,7 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
 	return 0;
 }
 
-/* sub-driver description */
+/* sub-driver description for pac7311 */
 static struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
 	.ctrls = sd_ctrls,
@@ -1057,21 +864,12 @@ static struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 static __devinitdata struct usb_device_id device_table[] = {
-	{USB_DEVICE(0x06f8, 0x3009), .driver_info = SENSOR_PAC7302},
-	{USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
-	{USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
-	{USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
-	{USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
-	{USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
-	{USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
-	{USB_DEVICE(0x093a, 0x2620), .driver_info = SENSOR_PAC7302},
-	{USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
-	{USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302},
-	{USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
-	{USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
-	{USB_DEVICE(0x093a, 0x2629), .driver_info = SENSOR_PAC7302},
-	{USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
-	{USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302},
+	{USB_DEVICE(0x093a, 0x2600)},
+	{USB_DEVICE(0x093a, 0x2601)},
+	{USB_DEVICE(0x093a, 0x2603)},
+	{USB_DEVICE(0x093a, 0x2608)},
+	{USB_DEVICE(0x093a, 0x260e)},
+	{USB_DEVICE(0x093a, 0x260f)},
 	{}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h
index 34d4b1494cd5..20f67d9b8c06 100644
--- a/drivers/media/video/gspca/pac_common.h
+++ b/drivers/media/video/gspca/pac_common.h
@@ -33,26 +33,101 @@
 static const unsigned char pac_sof_marker[5] =
 		{ 0xff, 0xff, 0x00, 0xff, 0x96 };
 
-static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev,
+/*
+   The following state machine finds the SOF marker sequence
+   0xff, 0xff, 0x00, 0xff, 0x96 in a byte stream.
+
+	   +----------+
+	   | 0: START |<---------------\
+	   +----------+<-\             |
+	     |       \---/otherwise    |
+	     v 0xff                    |
+	   +----------+ otherwise      |
+	   |     1    |--------------->*
+	   |          |                ^
+	   +----------+                |
+	     |                         |
+	     v 0xff                    |
+	   +----------+<-\0xff         |
+	/->|          |--/             |
+	|  |     2    |--------------->*
+	|  |          | otherwise      ^
+	|  +----------+                |
+	|    |                         |
+	|    v 0x00                    |
+	|  +----------+                |
+	|  |     3    |                |
+	|  |          |--------------->*
+	|  +----------+ otherwise      ^
+	|    |                         |
+   0xff |    v 0xff                    |
+	|  +----------+                |
+	\--|     4    |                |
+	   |          |----------------/
+	   +----------+ otherwise
+	     |
+	     v 0x96
+	   +----------+
+	   |  FOUND   |
+	   +----------+
+*/
+
+static unsigned char *pac_find_sof(u8 *sof_read,
 					unsigned char *m, int len)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
 	int i;
 
 	/* Search for the SOF marker (fixed part) in the header */
 	for (i = 0; i < len; i++) {
-		if (m[i] == pac_sof_marker[sd->sof_read]) {
-			sd->sof_read++;
-			if (sd->sof_read == sizeof(pac_sof_marker)) {
+		switch (*sof_read) {
+		case 0:
+			if (m[i] == 0xff)
+				*sof_read = 1;
+			break;
+		case 1:
+			if (m[i] == 0xff)
+				*sof_read = 2;
+			else
+				*sof_read = 0;
+			break;
+		case 2:
+			switch (m[i]) {
+			case 0x00:
+				*sof_read = 3;
+				break;
+			case 0xff:
+				/* stay in this state */
+				break;
+			default:
+				*sof_read = 0;
+			}
+			break;
+		case 3:
+			if (m[i] == 0xff)
+				*sof_read = 4;
+			else
+				*sof_read = 0;
+			break;
+		case 4:
+			switch (m[i]) {
+			case 0x96:
+				/* Pattern found */
 				PDEBUG(D_FRAM,
 					"SOF found, bytes to analyze: %u."
 					" Frame starts at byte #%u",
 					len, i + 1);
-				sd->sof_read = 0;
+				*sof_read = 0;
 				return m + i + 1;
+				break;
+			case 0xff:
+				*sof_read = 2;
+				break;
+			default:
+				*sof_read = 0;
 			}
-		} else {
-			sd->sof_read = 0;
+			break;
+		default:
+			*sof_read = 0;
 		}
 	}
 
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index cdad3db33367..b1944a7cbb0f 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -2342,7 +2342,6 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
@@ -2378,22 +2377,22 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		avg_lum >>= 9;
 		atomic_set(&sd->avg_lum, avg_lum);
 		gspca_frame_add(gspca_dev, LAST_PACKET,
-				frame, data, len);
+				data, len);
 		return;
 	}
 	if (gspca_dev->last_packet_type == LAST_PACKET) {
 		if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
 				& MODE_JPEG) {
-			gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
 				sd->jpeg_hdr, JPEG_HDR_SZ);
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			gspca_frame_add(gspca_dev, INTER_PACKET,
 				data, len);
 		} else {
-			gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
 				data, len);
 		}
 	} else {
-		gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 	}
 }
 
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index e39efb45fa1c..5be95bc65138 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -995,8 +995,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
-			unsigned char *data,		/* isoc packet */
+			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
 	int i;
@@ -1054,12 +1053,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 					pkt_type = DISCARD_PACKET;
 				}
 
-				frame = gspca_frame_add(gspca_dev, pkt_type,
-							frame, data, 0);
+				gspca_frame_add(gspca_dev, pkt_type,
+						NULL, 0);
 				data += i + fr_h_sz;
 				len -= i + fr_h_sz;
 				gspca_frame_add(gspca_dev, FIRST_PACKET,
-						frame, data, len);
+						data, len);
 				return;
 			}
 		}
@@ -1068,15 +1067,21 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
 		/* In raw mode we sometimes get some garbage after the frame
 		   ignore this */
-		int used = frame->data_end - frame->data;
+		struct gspca_frame *frame;
+		int used;
 		int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
 
+		frame = gspca_get_i_frame(gspca_dev);
+		if (frame == NULL) {
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			return;
+		}
+		used = frame->data_end - frame->data;
 		if (used + len > size)
 			len = size - used;
 	}
 
-	gspca_frame_add(gspca_dev, INTER_PACKET,
-			frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 33f4d0a1f6fd..0bd36a00dd2a 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -1,8 +1,8 @@
 /*
- *		Sonix sn9c102p sn9c105 sn9c120 (jpeg) library
- *		Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ * Sonix sn9c102p sn9c105 sn9c120 (jpeg) subdriver
  *
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2005 Michel Xhaard mxhaard@magic.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
@@ -72,8 +72,9 @@ struct sd {
 #define SENSOR_OV7630 5
 #define SENSOR_OV7648 6
 #define SENSOR_OV7660 7
-#define SENSOR_SP80708 8
-	u8 i2c_base;
+#define SENSOR_PO1030 8
+#define SENSOR_SP80708 9
+	u8 i2c_addr;
 
 	u8 *jpeg_hdr;
 };
@@ -250,7 +251,7 @@ static struct ctrl sd_ctrls[] = {
 		.minimum = 0,
 		.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
 		.step    = 1,
-#define FREQ_DEF 2
+#define FREQ_DEF 1
 		.default_value = FREQ_DEF,
 	    },
 	    .set = sd_setfreq,
@@ -277,7 +278,9 @@ static __u32 ctrl_dis[] = {
 	(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
 						/* SENSOR_OV7660 7 */
 	(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
-			      (1 << FREQ_IDX),	/* SENSOR_SP80708 8 */
+			      (1 << FREQ_IDX),	/* SENSOR_PO1030 8 */
+	(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
+			      (1 << FREQ_IDX),	/* SENSOR_SP80708 9 */
 };
 
 static const struct v4l2_pix_format vga_mode[] = {
@@ -304,7 +307,7 @@ 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,
+	0x81,	0x11,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
 /*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
 	0x03,	0x00,	0x00,	0x01,	0x03,	0x28,	0x1e,	0x41,
 /*	reg18	reg19	reg1a	reg1b */
@@ -315,7 +318,7 @@ 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,
+	0x81,	0x5d,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
 /*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
 	0x03,	0x00,	0x00,	0x02,	0x0a,	0x28,	0x1e,	0x61,
 /*	reg18	reg19	reg1a	reg1b */
@@ -337,7 +340,7 @@ 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,
+	0x81,	0x5c,	0x00,	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 */
@@ -346,7 +349,7 @@ static const u8 sn_mt9v111[0x1c] = {
 
 static const u8 sn_om6802[0x1c] = {
 /*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
-	0x00,	0x23,	0x72,	0x00,	0x1a,	0x34,	0x27,	0x20,
+	0x00,	0x23,	0x72,	0x00,	0x1a,	0x20,	0x20,	0x19,
 /*	reg8	reg9	rega	regb	regc	regd	rege	regf */
 	0x80,	0x34,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
 /*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
@@ -359,7 +362,7 @@ 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,
+	0x81,	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
 /*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
 	0x03,	0x00,	0x04,	0x01,	0x0a,	0x28,	0x1e,	0xc2,
 /*	reg18	reg19	reg1a	reg1b */
@@ -370,7 +373,7 @@ 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,
+	0x81,	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
 /*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
 	0x03,	0x00,	0x00,	0x01,	0x00,	0x28,	0x1e,	0x00,
 /*	reg18	reg19	reg1a	reg1b */
@@ -388,11 +391,22 @@ static const u8 sn_ov7660[0x1c] = {
 	0x07,	0x00,	0x00,	0x00
 };
 
+static const u8 sn_po1030[0x1c] = {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x21,	0x62,	0x00,	0x1a,	0x20,	0x20,	0x20,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0x81,	0x6e,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x00,	0x06,	0x06,	0x28,	0x1e,	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,
+	0x81,	0x18,	0x00,	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 */
@@ -409,6 +423,7 @@ static const u8 *sn_tb[] = {
 	sn_ov7630,
 	sn_ov7648,
 	sn_ov7660,
+	sn_po1030,
 	sn_sp80708
 };
 
@@ -455,7 +470,7 @@ static const u8 hv7131r_sensor_init[][8] = {
 
 	{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, 0x21, 0xd0, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
 
@@ -464,6 +479,8 @@ static const u8 hv7131r_sensor_init[][8] = {
 	{0xa1, 0x11, 0x21, 0xd0, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10},
+							/* set sensor clock */
 	{}
 };
 static const u8 mi0360_sensor_init[][8] = {
@@ -545,7 +562,7 @@ static const u8 mo4000_sensor_init[][8] = {
 };
 static const u8 mt9v111_sensor_init[][8] = {
 	{0xb1, 0x5c, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, /* reset? */
-	/* delay 20 ms */
+	{0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
 	{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 */
@@ -572,7 +589,9 @@ static const u8 mt9v111_sensor_init[][8] = {
 	{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},
-	/*******/
+	{}
+};
+static const u8 mt9v111_sensor_param1[][8] = {
 	{0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
 	{0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
 	{0xb1, 0x5c, 0x09, 0x01, 0x2c, 0x00, 0x00, 0x10},
@@ -585,14 +604,20 @@ static const u8 mt9v111_sensor_init[][8] = {
 	{0xb1, 0x5c, 0x35, 0x01, 0xc0, 0x00, 0x00, 0x10}, /* global gain */
 	{}
 };
+static const u8 om6802_init0[2][8] = {
+/*fixme: variable*/
+	{0xa0, 0x34, 0x29, 0x0e, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x34, 0x23, 0xb0, 0x00, 0x00, 0x00, 0x10},
+};
 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},
+	{0xa0, 0x34, 0xdf, 0x6d, 0x00, 0x00, 0x00, 0x10},
+						/* factory mode */
 	{0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10},
+						/* output raw RGB */
+	{0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10},
 /*	{0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */
 	{0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10},
-					/* white balance & auto-exposure */
+		/* auto-exposure speed (0) / white balance mode (auto RGB) */
 /*	{0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10},
 							 * set color mode */
 /*	{0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10},
@@ -606,26 +631,29 @@ static const u8 om6802_sensor_init[][8] = {
 /*	{0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10},
 							 * preset gamma */
 	{0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10},
-					/* luminance mode (0x4f = AE) */
+				/* luminance mode (0x4f -> AutoExpo on) */
 	{0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10},
 							/* preset shutter */
 /*	{0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10},
 							 * auto frame rate */
 /*	{0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */
-
-/*	{0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, */
-/*	{0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, */
-/*	{0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, */
-/*	{0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */
+	{0xa0, 0x34, 0x5d, 0x80, 0x00, 0x00, 0x00, 0x10},
+	{}
+};
+static const u8 om6802_sensor_param1[][8] = {
+	{0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10},
 	{}
 };
 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 */
+	{0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
 	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
-/* win: delay 20ms */
+	{0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
 	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
 /* win: i2c_r from 00 to 80 */
 	{0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
@@ -677,6 +705,7 @@ static const u8 ov7630_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 */
+	{0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
 	{0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
 	{0xd1, 0x21, 0x03, 0xa4, 0x30, 0x88, 0x00, 0x10},
 	{0xb1, 0x21, 0x11, 0x80, 0x08, 0x00, 0x00, 0x10},
@@ -701,7 +730,9 @@ static const u8 ov7648_sensor_init[][8] = {
 /*	{0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */
 /*	{0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */
 /*	{0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10}, set by setfreq */
-/*...*/
+	{}
+};
+static const u8 ov7648_sensor_param1[][8] = {
 /*	{0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */
 /*	{0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10},   * COMN
 							 * set by setvflip */
@@ -723,7 +754,7 @@ static const u8 ov7648_sensor_init[][8] = {
 
 static const u8 ov7660_sensor_init[][8] = {
 	{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
-/*		(delay 20ms) */
+	{0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
 	{0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
 						/* Outformat = rawRGB */
 	{0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
@@ -783,8 +814,11 @@ static const u8 ov7660_sensor_init[][8] = {
 	{0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
 	{0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
 	{0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */
+/* not in all ms-win traces*/
 	{0xa1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10},
-/****** (some exchanges in the win trace) ******/
+	{}
+};
+static const u8 ov7660_sensor_param1[][8] = {
 	{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
 						/* bits[3..0]reserved */
 	{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
@@ -797,6 +831,7 @@ static const u8 ov7660_sensor_init[][8] = {
 	{0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, /* GAIN */
 /*	{0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, * BLUE */
 /****** (some exchanges in the win trace) ******/
+/*fixme:param2*/
 	{0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
 	{0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10}, /* dummy line low */
 	{0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCH */
@@ -804,6 +839,7 @@ static const u8 ov7660_sensor_init[][8] = {
 /*	{0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10},  * RED */
 /****** (some exchanges in the win trace) ******/
 /******!! startsensor KO if changed !!****/
+/*fixme: param3*/
 	{0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
@@ -811,6 +847,60 @@ static const u8 ov7660_sensor_init[][8] = {
 	{}
 };
 
+static const u8 po1030_sensor_init[][8] = {
+/* the sensor registers are described in m5602/m5602_po1030.h */
+	{0xa1, 0x6e, 0x3f, 0x20, 0x00, 0x00, 0x00, 0x10}, /* sensor reset */
+	{0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+	{0xa1, 0x6e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x04, 0x02, 0xb1, 0x02, 0x39, 0x10},
+	{0xd1, 0x6e, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x0c, 0x02, 0x7f, 0x01, 0xe0, 0x10},
+	{0xd1, 0x6e, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
+	{0xd1, 0x6e, 0x16, 0x85, 0x40, 0x4a, 0x40, 0x10}, /* r/g1/b/g2 gains */
+	{0xc1, 0x6e, 0x1a, 0x00, 0x80, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x1d, 0x08, 0x03, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x23, 0x00, 0xb0, 0x00, 0x94, 0x10},
+	{0xd1, 0x6e, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
+	{0xb1, 0x6e, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x2d, 0x14, 0x35, 0x61, 0x84, 0x10}, /* gamma corr */
+	{0xd1, 0x6e, 0x31, 0xa2, 0xbd, 0xd8, 0xff, 0x10},
+	{0xd1, 0x6e, 0x35, 0x06, 0x1e, 0x12, 0x02, 0x10}, /* color matrix */
+	{0xd1, 0x6e, 0x39, 0xaa, 0x53, 0x37, 0xd5, 0x10},
+	{0xa1, 0x6e, 0x3d, 0xf2, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x3e, 0x00, 0x00, 0x80, 0x03, 0x10},
+	{0xd1, 0x6e, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xc1, 0x6e, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
+	{0xd1, 0x6e, 0x4b, 0x02, 0xef, 0x08, 0xcd, 0x10},
+	{0xd1, 0x6e, 0x4f, 0x00, 0xd0, 0x00, 0xa0, 0x10},
+	{0xd1, 0x6e, 0x53, 0x01, 0xaa, 0x01, 0x40, 0x10},
+	{0xd1, 0x6e, 0x5a, 0x50, 0x04, 0x30, 0x03, 0x10}, /* raw rgb bayer */
+	{0xa1, 0x6e, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x5f, 0x10, 0x40, 0xff, 0x00, 0x10},
+
+	{0xd1, 0x6e, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x6e, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xc1, 0x6e, 0x73, 0x10, 0x80, 0xeb, 0x00, 0x10},
+	{}
+};
+static const u8 po1030_sensor_param1[][8] = {
+/* from ms-win traces - these values change with auto gain/expo/wb.. */
+	{0xa1, 0x6e, 0x1e, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x6e, 0x1e, 0x03, 0x00, 0x00, 0x00, 0x10},
+/* mean values */
+	{0xc1, 0x6e, 0x1a, 0x02, 0xd4, 0xa4, 0x00, 0x10}, /* integlines */
+	{0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, /* global gain */
+	{0xc1, 0x6e, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10}, /* r/g1/b gains */
+
+	{0xa1, 0x6e, 0x1d, 0x08, 0x00, 0x00, 0x00, 0x10}, /* control1 */
+	{0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, /* frameheight */
+	{0xa1, 0x6e, 0x07, 0xd5, 0x00, 0x00, 0x00, 0x10},
+/*	{0xc1, 0x6e, 0x16, 0x49, 0x40, 0x45, 0x00, 0x10}, */
+	{}
+};
+
 static const u8 sp80708_sensor_init[][8] = {
 	{0xa1, 0x18, 0x06, 0xf9, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x18, 0x09, 0x1f, 0x00, 0x00, 0x00, 0x10},
@@ -883,7 +973,9 @@ static const u8 sp80708_sensor_init[][8] = {
 	{0xa1, 0x18, 0x67, 0x24, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x18, 0x68, 0x08, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x18, 0x2f, 0xc9, 0x00, 0x00, 0x00, 0x10},
-	/********/
+	{}
+};
+static const u8 sp80708_sensor_param1[][8] = {
 	{0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x18, 0x03, 0x01, 0x00, 0x00, 0x00, 0x10},
@@ -894,6 +986,19 @@ static const u8 sp80708_sensor_init[][8] = {
 	{}
 };
 
+static const u8 (*sensor_init[10])[8] = {
+	hv7131r_sensor_init,	/* HV7131R 0 */
+	mi0360_sensor_init,	/* MI0360 1 */
+	mo4000_sensor_init,	/* MO4000 2 */
+	mt9v111_sensor_init,	/* MT9V111 3 */
+	om6802_sensor_init,	/* OM6802 4 */
+	ov7630_sensor_init,	/* OV7630 5 */
+	ov7648_sensor_init,	/* OV7648 6 */
+	ov7660_sensor_init,	/* OV7660 7 */
+	po1030_sensor_init,	/* PO1030 8 */
+	sp80708_sensor_init,	/* SP80708 9 */
+};
+
 /* read <len> bytes to gspca_dev->usb_buf */
 static void reg_r(struct gspca_dev *gspca_dev,
 		  u16 value, int len)
@@ -958,8 +1063,15 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	PDEBUG(D_USBO, "i2c_w2 [%02x] = %02x", reg, val);
-	gspca_dev->usb_buf[0] = 0x81 | (2 << 4);	/* = a1 */
-	gspca_dev->usb_buf[1] = sd->i2c_base;
+	switch (sd->sensor) {
+	case SENSOR_OM6802:		/* i2c command = a0 (100 kHz) */
+		gspca_dev->usb_buf[0] = 0x80 | (2 << 4);
+		break;
+	default:			/* i2c command = a1 (400 kHz) */
+		gspca_dev->usb_buf[0] = 0x81 | (2 << 4);
+		break;
+	}
+	gspca_dev->usb_buf[1] = sd->i2c_addr;
 	gspca_dev->usb_buf[2] = reg;
 	gspca_dev->usb_buf[3] = val;
 	gspca_dev->usb_buf[4] = 0;
@@ -991,14 +1103,21 @@ static void i2c_w8(struct gspca_dev *gspca_dev,
 	msleep(2);
 }
 
-/* read 5 bytes in gspca_dev->usb_buf */
-static void i2c_r5(struct gspca_dev *gspca_dev, u8 reg)
+/* sensor read 'len' (1..5) bytes in gspca_dev->usb_buf */
+static void i2c_r(struct gspca_dev *gspca_dev, u8 reg, int len)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 mode[8];
 
-	mode[0] = 0x81 | 0x10;
-	mode[1] = sd->i2c_base;
+	switch (sd->sensor) {
+	case SENSOR_OM6802:		/* i2c command = 90 (100 kHz) */
+		mode[0] = 0x80 | 0x10;
+		break;
+	default:			/* i2c command = 91 (400 kHz) */
+		mode[0] = 0x81 | 0x10;
+		break;
+	}
+	mode[1] = sd->i2c_addr;
 	mode[2] = reg;
 	mode[3] = 0;
 	mode[4] = 0;
@@ -1007,33 +1126,43 @@ static void i2c_r5(struct gspca_dev *gspca_dev, u8 reg)
 	mode[7] = 0x10;
 	i2c_w8(gspca_dev, mode);
 	msleep(2);
-	mode[0] = 0x81 | (5 << 4) | 0x02;
+	mode[0] = (mode[0] & 0x81) | (len << 4) | 0x02;
 	mode[2] = 0;
 	i2c_w8(gspca_dev, mode);
 	msleep(2);
 	reg_r(gspca_dev, 0x0a, 5);
 }
 
-static int hv7131r_probe(struct gspca_dev *gspca_dev)
+static void i2c_w_seq(struct gspca_dev *gspca_dev,
+			const u8 (*data)[8])
+{
+	while ((*data)[0] != 0) {
+		if ((*data)[0] != 0xdd)
+			i2c_w8(gspca_dev, *data);
+		else
+			msleep((*data)[1]);
+		data++;
+	}
+}
+
+static void hv7131r_probe(struct gspca_dev *gspca_dev)
 {
 	i2c_w1(gspca_dev, 0x02, 0);			/* sensor wakeup */
 	msleep(10);
 	reg_w1(gspca_dev, 0x02, 0x66);			/* Gpio on */
 	msleep(10);
-	i2c_r5(gspca_dev, 0);				/* read sensor id */
+	i2c_r(gspca_dev, 0, 5);				/* read sensor id */
 	if (gspca_dev->usb_buf[0] == 0x02
 	    && gspca_dev->usb_buf[1] == 0x09
 	    && gspca_dev->usb_buf[2] == 0x01
 	    && gspca_dev->usb_buf[3] == 0x00
 	    && gspca_dev->usb_buf[4] == 0x00) {
-		PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
-		return 0;
+		PDEBUG(D_PROBE, "Sensor sn9c102P HV7131R found");
+		return;
 	}
-	PDEBUG(D_PROBE, "Find Sensor 0x%02x 0x%02x 0x%02x",
+	PDEBUG(D_PROBE, "Sensor 0x%02x 0x%02x 0x%02x - sn9c102P not found",
 		gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
 		gspca_dev->usb_buf[2]);
-	PDEBUG(D_PROBE, "Sensor sn9c102P Not found");
-	return -ENODEV;
 }
 
 static void mi0360_probe(struct gspca_dev *gspca_dev)
@@ -1075,7 +1204,6 @@ static void mi0360_probe(struct gspca_dev *gspca_dev)
 	case 0x823a:
 		PDEBUG(D_PROBE, "Sensor mt9v111");
 		sd->sensor = SENSOR_MT9V111;
-		sd->i2c_base = 0x5c;
 		break;
 	case 0x8243:
 		PDEBUG(D_PROBE, "Sensor mi0360");
@@ -1086,7 +1214,42 @@ static void mi0360_probe(struct gspca_dev *gspca_dev)
 	}
 }
 
-static int configure_gpio(struct gspca_dev *gspca_dev,
+static void ov7648_probe(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* check ov76xx */
+	reg_w1(gspca_dev, 0x17, 0x62);
+	reg_w1(gspca_dev, 0x01, 0x08);
+	sd->i2c_addr = 0x21;
+	i2c_r(gspca_dev, 0x0a, 2);
+	if (gspca_dev->usb_buf[3] == 0x76) {	/* ov76xx */
+		PDEBUG(D_PROBE, "Sensor ov%02x%02x",
+			gspca_dev->usb_buf[3], gspca_dev->usb_buf[4]);
+		return;
+	}
+
+	/* reset */
+	reg_w1(gspca_dev, 0x01, 0x29);
+	reg_w1(gspca_dev, 0x17, 0x42);
+
+	/* check po1030 */
+	reg_w1(gspca_dev, 0x17, 0x62);
+	reg_w1(gspca_dev, 0x01, 0x08);
+	sd->i2c_addr = 0x6e;
+	i2c_r(gspca_dev, 0x00, 2);
+	if (gspca_dev->usb_buf[3] == 0x10	/* po1030 */
+	    && gspca_dev->usb_buf[4] == 0x30) {
+		PDEBUG(D_PROBE, "Sensor po1030");
+		sd->sensor = SENSOR_PO1030;
+		return;
+	}
+
+	PDEBUG(D_PROBE, "Unknown sensor %02x%02x",
+		gspca_dev->usb_buf[3], gspca_dev->usb_buf[4]);
+}
+
+static void bridge_init(struct gspca_dev *gspca_dev,
 			  const u8 *sn9c1xx)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1103,9 +1266,10 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
 	/* configure gpio */
 	reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
 	reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
-	reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);	/* jfm len was 3 */
+	reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
 	switch (sd->sensor) {
 	case SENSOR_OV7660:
+	case SENSOR_PO1030:
 	case SENSOR_SP80708:
 		reg9a = reg9a_spec;
 		break;
@@ -1115,7 +1279,7 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
 	}
 	reg_w(gspca_dev, 0x9a, reg9a, 6);
 
-	reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); /*fixme:jfm was 60 only*/
+	reg_w(gspca_dev, 0xd4, regd4, sizeof regd4);
 
 	reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
 
@@ -1127,10 +1291,22 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
 		reg_w1(gspca_dev, 0x01, 0x40);
 		break;
 	case SENSOR_OM6802:
-		reg_w1(gspca_dev, 0x02, 0x71);
-		reg_w1(gspca_dev, 0x01, 0x42);
+		msleep(10);
+		reg_w1(gspca_dev, 0x02, 0x73);
+		reg_w1(gspca_dev, 0x17, 0x60);
+		reg_w1(gspca_dev, 0x01, 0x22);
+		msleep(100);
+		reg_w1(gspca_dev, 0x01, 0x62);
+		reg_w1(gspca_dev, 0x17, 0x64);
 		reg_w1(gspca_dev, 0x17, 0x64);
 		reg_w1(gspca_dev, 0x01, 0x42);
+		msleep(10);
+		reg_w1(gspca_dev, 0x01, 0x42);
+		i2c_w8(gspca_dev, om6802_init0[0]);
+		i2c_w8(gspca_dev, om6802_init0[1]);
+		msleep(15);
+		reg_w1(gspca_dev, 0x02, 0x71);
+		msleep(150);
 		break;
 	case SENSOR_OV7630:
 		reg_w1(gspca_dev, 0x01, 0x61);
@@ -1144,7 +1320,14 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
 		reg_w1(gspca_dev, 0x01, 0x62);
 		reg_w1(gspca_dev, 0x01, 0x42);
 		break;
+	case SENSOR_PO1030:
+		reg_w1(gspca_dev, 0x01, 0x61);
+		reg_w1(gspca_dev, 0x17, 0x20);
+		reg_w1(gspca_dev, 0x01, 0x60);
+		reg_w1(gspca_dev, 0x01, 0x40);
+		break;
 	case SENSOR_OV7660:
+		/* fall thru */
 	case SENSOR_SP80708:
 		reg_w1(gspca_dev, 0x01, 0x63);
 		reg_w1(gspca_dev, 0x17, 0x20);
@@ -1153,143 +1336,18 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
 		msleep(100);
 		reg_w1(gspca_dev, 0x02, 0x62);
 		break;
+	default:
 /*	case SENSOR_HV7131R: */
 /*	case SENSOR_MI0360: */
 /*	case SENSOR_MO4000: */
-	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 (hv7131r_probe(gspca_dev) < 0)
-				return -ENODEV;
-		}
+		if (sd->sensor == SENSOR_HV7131R
+		    && sd->bridge == BRIDGE_SN9C102P)
+			hv7131r_probe(gspca_dev);
 		break;
 	}
-	return 0;
-}
-
-static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
-{
-	int i = 0;
-	static const u8 SetSensorClk[] =	/* 0x08 Mclk */
-		{ 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
-
-	while (hv7131r_sensor_init[i][0]) {
-		i2c_w8(gspca_dev, hv7131r_sensor_init[i]);
-		i++;
-	}
-	i2c_w8(gspca_dev, SetSensorClk);
-}
-
-static void mi0360_InitSensor(struct gspca_dev *gspca_dev)
-{
-	int i = 0;
-
-	while (mi0360_sensor_init[i][0]) {
-		i2c_w8(gspca_dev, mi0360_sensor_init[i]);
-		i++;
-	}
-}
-
-static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
-{
-	int i = 0;
-
-	while (mo4000_sensor_init[i][0]) {
-		i2c_w8(gspca_dev, mo4000_sensor_init[i]);
-		i++;
-	}
-}
-
-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;
-
-	while (om6802_sensor_init[i][0]) {
-		i2c_w8(gspca_dev, om6802_sensor_init[i]);
-		i++;
-	}
-}
-
-static void ov7630_InitSensor(struct gspca_dev *gspca_dev)
-{
-	int i = 0;
-
-	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 76 01 */
-	i++;
-	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 c8 (RGB+SRST) */
-	i++;
-	msleep(20);
-	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 48 */
-	i++;
-	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 c8 */
-	i++;
-	msleep(20);
-	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 48 */
-	i++;
-/*jfm:win i2c_r from 00 to 80*/
-
-	while (ov7630_sensor_init[i][0]) {
-		i2c_w8(gspca_dev, ov7630_sensor_init[i]);
-		i++;
-	}
-}
-
-static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
-{
-	int i = 0;
-
-	i2c_w8(gspca_dev, ov7648_sensor_init[i]);
-	i++;
-/* win: dble reset */
-	i2c_w8(gspca_dev, ov7648_sensor_init[i]);	/* reset */
-	i++;
-	msleep(20);
-/* win: i2c reg read 00..7f */
-	while (ov7648_sensor_init[i][0]) {
-		i2c_w8(gspca_dev, ov7648_sensor_init[i]);
-		i++;
-	}
-}
-
-static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
-{
-	int i = 0;
-
-	i2c_w8(gspca_dev, ov7660_sensor_init[i]);	/* reset SCCB */
-	i++;
-	msleep(20);
-	while (ov7660_sensor_init[i][0]) {
-		i2c_w8(gspca_dev, ov7660_sensor_init[i]);
-		i++;
-	}
-}
-
-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 */
@@ -1305,8 +1363,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	cam->npkt = 24;			/* 24 packets per ISOC message */
 
 	sd->bridge = id->driver_info >> 16;
-	sd->sensor = id->driver_info >> 8;
-	sd->i2c_base = id->driver_info;
+	sd->sensor = id->driver_info;
 
 	sd->brightness = BRIGHTNESS_DEF;
 	sd->contrast = CONTRAST_DEF;
@@ -1322,7 +1379,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->quality = QUALITY_DEF;
 	sd->jpegqual = 80;
 
-	gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
 	return 0;
 }
 
@@ -1330,6 +1386,7 @@ 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;
+	const u8 *sn9c1xx;
 	u8 regGpio[] = { 0x29, 0x74 };
 	u8 regF1;
 
@@ -1356,8 +1413,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
 	case BRIDGE_SN9C120:
 		if (regF1 != 0x12)
 			return -ENODEV;
-		if (sd->sensor == SENSOR_MI0360)
+		switch (sd->sensor) {
+		case SENSOR_MI0360:
 			mi0360_probe(gspca_dev);
+			break;
+		case SENSOR_OV7648:
+			ov7648_probe(gspca_dev);
+			break;
+		}
 		regGpio[1] = 0x70;
 		reg_w(gspca_dev, 0x01, regGpio, 2);
 		break;
@@ -1372,6 +1435,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
 
 	reg_w1(gspca_dev, 0xf1, 0x01);
 
+	/* set the i2c address */
+	sn9c1xx = sn_tb[sd->sensor];
+	sd->i2c_addr = sn9c1xx[9];
+
+	gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
+
 	return 0;
 }
 
@@ -1383,7 +1452,7 @@ static u32 setexposure(struct gspca_dev *gspca_dev,
 	switch (sd->sensor) {
 	case SENSOR_HV7131R: {
 		u8 Expodoit[] =
-			{ 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
+			{ 0xc1, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x16 };
 
 		Expodoit[3] = expo >> 16;
 		Expodoit[4] = expo >> 8;
@@ -1393,7 +1462,7 @@ static u32 setexposure(struct gspca_dev *gspca_dev,
 	    }
 	case SENSOR_MI0360: {
 		u8 expoMi[] =		/* exposure 0x0635 -> 4 fp/s 0x10 */
-			{ 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
+			{ 0xb1, 0x5d, 0x09, 0x00, 0x00, 0x00, 0x00, 0x16 };
 		static const u8 doit[] =		/* update sensor */
 			{ 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
 		static const u8 sensorgo[] =		/* sensor on */
@@ -1412,9 +1481,9 @@ static u32 setexposure(struct gspca_dev *gspca_dev,
 	    }
 	case SENSOR_MO4000: {
 		u8 expoMof[] =
-			{ 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
+			{ 0xa1, 0x21, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x10 };
 		u8 expoMo10[] =
-			{ 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
+			{ 0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10 };
 		static const u8 gainMo[] =
 			{ 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
 
@@ -1450,6 +1519,7 @@ static u32 setexposure(struct gspca_dev *gspca_dev,
 	case SENSOR_OM6802: {
 		u8 gainOm[] =
 			{ 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 };
+				/* preset AGC - works when AutoExpo = off */
 
 		if (expo > 0x03ff)
 			expo = 0x03ff;
@@ -1457,7 +1527,7 @@ static u32 setexposure(struct gspca_dev *gspca_dev,
 			expo = 0x0001;
 		gainOm[3] = expo >> 2;
 		i2c_w8(gspca_dev, gainOm);
-		reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f);
+		reg_w1(gspca_dev, 0x96, expo >> 5);
 		PDEBUG(D_FRAM, "set exposure %d", gainOm[3]);
 		break;
 	    }
@@ -1489,7 +1559,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 	case SENSOR_MT9V111:
 		expo = sd->brightness >> 8;
 		sd->exposure = setexposure(gspca_dev, expo);
-		break;
+		return;			/* don't set the Y offset */
 	case SENSOR_OM6802:
 		expo = sd->brightness >> 6;
 		sd->exposure = setexposure(gspca_dev, expo);
@@ -1497,8 +1567,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 		break;
 	}
 
-	if (sd->sensor != SENSOR_MT9V111)
-		reg_w1(gspca_dev, 0x96, k2);	/* color matrix Y offset */
+	reg_w1(gspca_dev, 0x96, k2);	/* color matrix Y offset */
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
@@ -1526,6 +1595,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
 		-24, -38, 64,		/* UR UG UB */
 		 62, -51, -9		/* VR VG VB */
 	};
+
 	for (i = 0; i < 6; i++) {
 		v = uv[i] * sd->colors / COLOR_DEF;
 		reg8a[i * 2] = v;
@@ -1605,6 +1675,8 @@ static void setvflip(struct sd *sd)
 {
 	u8 comn;
 
+	if (sd->gspca_dev.ctrl_dis & (1 << VFLIP_IDX))
+		return;
 	if (sd->sensor == SENSOR_OV7630) {
 		comn = 0x02;
 		if (!sd->vflip)
@@ -1726,8 +1798,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int i;
-	u8 reg1, reg17;
+	u8 reg1, reg2, reg17;
 	const u8 *sn9c1xx;
+	const u8 (*init)[8];
 	int mode;
 	static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
 	static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
@@ -1743,8 +1816,26 @@ static int sd_start(struct gspca_dev *gspca_dev)
 			0x21);		/* JPEG 422 */
 	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
 
-	sn9c1xx = sn_tb[(int) sd->sensor];
-	configure_gpio(gspca_dev, sn9c1xx);
+	/* initialize the bridge */
+	sn9c1xx = sn_tb[sd->sensor];
+	bridge_init(gspca_dev, sn9c1xx);
+
+	/* initialize the sensor */
+	i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
+
+	switch (sd->sensor) {
+	case SENSOR_OM6802:
+		reg2 = 0x71;
+		break;
+	case SENSOR_SP80708:
+		reg2 = 0x62;
+		break;
+	default:
+		reg2 = 0x40;
+		break;
+	}
+	reg_w1(gspca_dev, 0x02, reg2);
+	reg_w1(gspca_dev, 0x02, reg2);
 
 	reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
 	reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
@@ -1771,6 +1862,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
 	case SENSOR_OV7660:
 		reg17 = 0xa0;
 		break;
+	case SENSOR_PO1030:
+		reg17 = 0xa0;
+		break;
 	default:
 		reg17 = 0x60;
 		break;
@@ -1791,6 +1885,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		reg_w1(gspca_dev, 0x9a, 0x07);
 		reg_w1(gspca_dev, 0x99, 0x59);
 		break;
+	case SENSOR_OM6802:
+		reg_w1(gspca_dev, 0x9a, 0x08);
+		reg_w1(gspca_dev, 0x99, 0x10);
+		break;
 	case SENSOR_OV7648:
 		reg_w1(gspca_dev, 0x9a, 0x0a);
 		reg_w1(gspca_dev, 0x99, 0x60);
@@ -1806,21 +1904,20 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		break;
 	}
 
-	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+	reg_w1(gspca_dev, 0x05, sn9c1xx[5]);	/* red */
+	reg_w1(gspca_dev, 0x07, sn9c1xx[7]);	/* green */
+	reg_w1(gspca_dev, 0x06, sn9c1xx[6]);	/* blue */
+
+	init = NULL;
+	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
 	if (mode)
 		reg1 = 0x46;	/* 320x240: clk 48Mhz, video trf enable */
 	else
 		reg1 = 0x06;	/* 640x480: clk 24Mhz, video trf enable */
 	reg17 = 0x61;		/* 0x:20: enable sensor clock */
 	switch (sd->sensor) {
-	case SENSOR_HV7131R:
-		hv7131R_InitSensor(gspca_dev);
-		break;
-	case SENSOR_MI0360:
-		mi0360_InitSensor(gspca_dev);
-		break;
 	case SENSOR_MO4000:
-		mo4000_InitSensor(gspca_dev);
 		if (mode) {
 /*			reg1 = 0x46;	 * 320 clk 48Mhz 60fp/s */
 			reg1 = 0x06;	/* clk 24Mz */
@@ -1830,7 +1927,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		}
 		break;
 	case SENSOR_MT9V111:
-		mt9v111_InitSensor(gspca_dev);
+		init = mt9v111_sensor_param1;
 		if (mode) {
 			reg1 = 0x04;	/* 320 clk 48Mhz */
 		} else {
@@ -1839,22 +1936,21 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		}
 		break;
 	case SENSOR_OM6802:
-		om6802_InitSensor(gspca_dev);
+		init = om6802_sensor_param1;
 		reg17 = 0x64;		/* 640 MCKSIZE */
 		break;
 	case SENSOR_OV7630:
-		ov7630_InitSensor(gspca_dev);
 		setvflip(sd);
 		reg17 = 0xe2;
 		reg1 = 0x44;
 		break;
 	case SENSOR_OV7648:
-		ov7648_InitSensor(gspca_dev);
+		init = ov7648_sensor_param1;
 		reg17 = 0x21;
 /*		reg1 = 0x42;		 * 42 - 46? */
 		break;
 	case SENSOR_OV7660:
-		ov7660_InitSensor(gspca_dev);
+		init = ov7660_sensor_param1;
 		if (sd->bridge == BRIDGE_SN9C120) {
 			if (mode) {		/* 320x240 - 160x120 */
 				reg17 = 0xa2;
@@ -1866,9 +1962,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
 					 * inverse power down */
 		}
 		break;
+	case SENSOR_PO1030:
+		init = po1030_sensor_param1;
+		reg17 = 0xa2;
+		reg1 = 0x44;
+		break;
 	default:
 /*	case SENSOR_SP80708: */
-		sp80708_InitSensor(gspca_dev);
+		init = sp80708_sensor_param1;
 		if (mode) {
 /*??			reg1 = 0x04;	 * 320 clk 48Mhz */
 		} else {
@@ -1877,6 +1978,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		}
 		break;
 	}
+
+	/* more sensor initialization - param1 */
+	if (init != NULL) {
+		i2c_w_seq(gspca_dev, init);
+/*		init = NULL; */
+	}
+
 	reg_w(gspca_dev, 0xc0, C0, 6);
 	reg_w(gspca_dev, 0xca, CA, 4);
 	switch (sd->sensor) {
@@ -1891,6 +1999,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		break;
 	}
 
+
 	/* here change size mode 0 -> VGA; 1 -> CIF */
 	sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40;
 	reg_w1(gspca_dev, 0x18, sd->reg18);
@@ -1898,6 +2007,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 	reg_w1(gspca_dev, 0x17, reg17);
 	reg_w1(gspca_dev, 0x01, reg1);
+
 	switch (sd->sensor) {
 	case SENSOR_OV7630:
 		setvflip(sd);
@@ -1937,14 +2047,11 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 		/* fall thru */
 	case SENSOR_MT9V111:
 	case SENSOR_OV7630:
+	case SENSOR_PO1030:
 		data = 0x29;
 		break;
-	default:
-/*	case SENSOR_MO4000: */
-/*	case SENSOR_OV7660: */
-		break;
 	}
-	sn9c1xx = sn_tb[(int) sd->sensor];
+	sn9c1xx = sn_tb[sd->sensor];
 	reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
 	reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
 	reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
@@ -1987,11 +2094,19 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 			sd->exposure = setexposure(gspca_dev,
 					(unsigned int) (expotimes << 8));
 			break;
+		case SENSOR_OM6802:
+			expotimes = sd->exposure;
+			expotimes += (luma_mean - delta) >> 2;
+			if (expotimes < 0)
+				expotimes = 0;
+			sd->exposure = setexposure(gspca_dev,
+						   (unsigned int) expotimes);
+			setredblue(gspca_dev);
+			break;
 		default:
 /*		case SENSOR_MO4000: */
 /*		case SENSOR_MI0360: */
 /*		case SENSOR_MT9V111: */
-/*		case SENSOR_OM6802: */
 			expotimes = sd->exposure;
 			expotimes += (luma_mean - delta) >> 6;
 			if (expotimes < 0)
@@ -2007,7 +2122,6 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 /* scan the URB packets */
 /* 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 */
 			int len)			/* iso packet length */
 {
@@ -2019,7 +2133,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 
 		/* end of frame */
 		gspca_frame_add(gspca_dev, LAST_PACKET,
-				frame, data, sof + 2);
+				data, sof + 2);
 		if (sd->ag_cnt < 0)
 			return;
 /* w1 w2 w3 */
@@ -2042,10 +2156,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	if (gspca_dev->last_packet_type == LAST_PACKET) {
 
 		/* put the JPEG 422 header */
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
 			sd->jpeg_hdr, JPEG_HDR_SZ);
 	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -2295,69 +2409,69 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-#define BSI(bridge, sensor, i2c_addr) \
+#define BS(bridge, sensor) \
 	.driver_info = (BRIDGE_ ## bridge << 16) \
-			| (SENSOR_ ## sensor << 8) \
-			| (i2c_addr)
+			| SENSOR_ ## sensor
 static const __devinitdata struct usb_device_id device_table[] = {
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
-	{USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)},
-	{USB_DEVICE(0x0458, 0x702e), BSI(SN9C120, OV7660, 0x21)},
+	{USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)},
+	{USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)},
 #endif
-	{USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
-	{USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
-	{USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
-	{USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
-	{USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
-	{USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
-	{USB_DEVICE(0x06f8, 0x3008), BSI(SN9C105, OV7660, 0x21)},
-	{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)},
-/* bw600.inf:
-	{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */
-/*	{USB_DEVICE(0x0c45, 0x603a), BSI(SN9C102P, OV7648, 0x??)}, */
-/*	{USB_DEVICE(0x0c45, 0x607a), BSI(SN9C102P, OV7648, 0x??)}, */
-	{USB_DEVICE(0x0c45, 0x607c), BSI(SN9C102P, HV7131R, 0x11)},
-/*	{USB_DEVICE(0x0c45, 0x607e), BSI(SN9C102P, OV7630, 0x??)}, */
-	{USB_DEVICE(0x0c45, 0x60c0), BSI(SN9C105, MI0360, 0x5d)},
-/*	{USB_DEVICE(0x0c45, 0x60c8), BSI(SN9C105, OM6802, 0x??)}, */
-/*	{USB_DEVICE(0x0c45, 0x60cc), BSI(SN9C105, HV7131GP, 0x??)}, */
-	{USB_DEVICE(0x0c45, 0x60ec), BSI(SN9C105, MO4000, 0x21)},
-/*	{USB_DEVICE(0x0c45, 0x60ef), BSI(SN9C105, ICM105C, 0x??)}, */
-/*	{USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */
-	{USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)},
+	{USB_DEVICE(0x045e, 0x00f5), BS(SN9C105, OV7660)},
+	{USB_DEVICE(0x045e, 0x00f7), BS(SN9C105, OV7660)},
+	{USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)},
+	{USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)},
+	{USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)},
+	{USB_DEVICE(0x06f8, 0x3004), BS(SN9C105, OV7660)},
+	{USB_DEVICE(0x06f8, 0x3008), BS(SN9C105, OV7660)},
+/*	{USB_DEVICE(0x0c45, 0x603a), BS(SN9C102P, OV7648)}, */
+	{USB_DEVICE(0x0c45, 0x6040), BS(SN9C102P, HV7131R)},
+/*	{USB_DEVICE(0x0c45, 0x607a), BS(SN9C102P, OV7648)}, */
+/*	{USB_DEVICE(0x0c45, 0x607b), BS(SN9C102P, OV7660)}, */
+	{USB_DEVICE(0x0c45, 0x607c), BS(SN9C102P, HV7131R)},
+/*	{USB_DEVICE(0x0c45, 0x607e), BS(SN9C102P, OV7630)}, */
+	{USB_DEVICE(0x0c45, 0x60c0), BS(SN9C105, MI0360)},
+/*	{USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */
+/*	{USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */
+/*	{USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */
+	{USB_DEVICE(0x0c45, 0x60ec), BS(SN9C105, MO4000)},
+/*	{USB_DEVICE(0x0c45, 0x60ef), BS(SN9C105, ICM105C)}, */
+/*	{USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */
+	{USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)},
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
-	{USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)},
-	{USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
+	{USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)},
+	{USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)},
 #endif
-	{USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/
-/*	{USB_DEVICE(0x0c45, 0x6102), BSI(SN9C120, PO2030N, ??)}, */
-/*	{USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6802, 0x21)}, */
-	{USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/
-	{USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/
-	{USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/
-	{USB_DEVICE(0x0c45, 0x610e), BSI(SN9C120, OV7630, 0x21)}, /*sn9c128*/
-/*	{USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
-/*	{USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
-	{USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
+	{USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)},	/*sn9c128*/
+/*	{USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, P1030xC)}, */
+/*	{USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */
+	{USB_DEVICE(0x0c45, 0x610a), BS(SN9C120, OV7648)},	/*sn9c128*/
+	{USB_DEVICE(0x0c45, 0x610b), BS(SN9C120, OV7660)},	/*sn9c128*/
+	{USB_DEVICE(0x0c45, 0x610c), BS(SN9C120, HV7131R)},	/*sn9c128*/
+	{USB_DEVICE(0x0c45, 0x610e), BS(SN9C120, OV7630)},	/*sn9c128*/
+/*	{USB_DEVICE(0x0c45, 0x610f), BS(SN9C120, S5K53BEB)}, */
+/*	{USB_DEVICE(0x0c45, 0x6122), BS(SN9C110, ICM105C)}, */
+/*	{USB_DEVICE(0x0c45, 0x6123), BS(SN9C110, SanyoCCD)}, */
+	{USB_DEVICE(0x0c45, 0x6128), BS(SN9C120, OM6802)},	/*sn9c325?*/
 /*bw600.inf:*/
-	{USB_DEVICE(0x0c45, 0x612a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c110?*/
-	{USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)},
-	{USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)},
-/*	{USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */
+	{USB_DEVICE(0x0c45, 0x612a), BS(SN9C120, OV7648)},	/*sn9c325?*/
+	{USB_DEVICE(0x0c45, 0x612c), BS(SN9C110, MO4000)},
+	{USB_DEVICE(0x0c45, 0x612e), BS(SN9C110, OV7630)},
+/*	{USB_DEVICE(0x0c45, 0x612f), BS(SN9C110, ICM105C)}, */
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
-	{USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
+	{USB_DEVICE(0x0c45, 0x6130), BS(SN9C120, MI0360)},
 #endif
-/*	{USB_DEVICE(0x0c45, 0x6132), BSI(SN9C120, OV7670, 0x21)}, */
-	{USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
-	{USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)},
+/*	{USB_DEVICE(0x0c45, 0x6132), BS(SN9C120, OV7670)}, */
+	{USB_DEVICE(0x0c45, 0x6138), BS(SN9C120, MO4000)},
+	{USB_DEVICE(0x0c45, 0x613a), BS(SN9C120, OV7648)},
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
-	{USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
+	{USB_DEVICE(0x0c45, 0x613b), BS(SN9C120, OV7660)},
 #endif
-	{USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
-	{USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x21)},
-/*	{USB_DEVICE(0x0c45, 0x6142), BSI(SN9C120, PO2030N, ??)}, *sn9c120b*/
-	{USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)}, /*sn9c120b*/
-	{USB_DEVICE(0x0c45, 0x6148), BSI(SN9C120, OM6802, 0x21)}, /*sn9c120b*/
+	{USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)},
+	{USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)},
+/*	{USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)},	 *sn9c120b*/
+	{USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)},	/*sn9c120b*/
+	{USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)},	/*sn9c120b*/
 	{}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index 7dbd5eea6cc0..fe46868a87f2 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -899,8 +899,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 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;
@@ -913,11 +912,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 /*			gspca_dev->last_packet_type = DISCARD_PACKET; */
 			return;
 		}
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+		gspca_frame_add(gspca_dev, LAST_PACKET,
 					ffd9, 2);
 
 		/* put the JPEG header in the new frame */
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
 			sd->jpeg_hdr, JPEG_HDR_SZ);
 
 		data += SPCA500_OFFSET_DATA;
@@ -931,7 +930,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	i = 0;
 	do {
 		if (data[i] == 0xff) {
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			gspca_frame_add(gspca_dev, INTER_PACKET,
 					data, i + 1);
 			len -= i;
 			data += i;
@@ -940,7 +939,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		}
 		i++;
 	} while (i < len);
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static void setbrightness(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
index 66f9f0056146..6761a3048a98 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/video/gspca/spca501.c
@@ -2032,20 +2032,15 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 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]) {
 	case 0:				/* start of frame */
-		frame = gspca_frame_add(gspca_dev,
-					LAST_PACKET,
-					frame,
-					data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 		data += SPCA501_OFFSET_DATA;
 		len -= SPCA501_OFFSET_DATA;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-				data, len);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 		return;
 	case 0xff:			/* drop */
 /*		gspca_dev->last_packet_type = DISCARD_PACKET; */
@@ -2053,8 +2048,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	}
 	data++;
 	len--;
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-			data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
index ea8c9fe2e961..0f9232ff1281 100644
--- a/drivers/media/video/gspca/spca505.c
+++ b/drivers/media/video/gspca/spca505.c
@@ -739,26 +739,22 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
 	switch (data[0]) {
 	case 0:				/* start of frame */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 		data += SPCA50X_OFFSET_DATA;
 		len -= SPCA50X_OFFSET_DATA;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-				data, len);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 		break;
 	case 0xff:			/* drop */
 		break;
 	default:
 		data += 1;
 		len -= 1;
-		gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-				data, len);
+		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 		break;
 	}
 }
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
index a199298a6419..ab28cc23e415 100644
--- a/drivers/media/video/gspca/spca506.c
+++ b/drivers/media/video/gspca/spca506.c
@@ -543,18 +543,15 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 }
 
 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]) {
 	case 0:				/* start of frame */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 		data += SPCA50X_OFFSET_DATA;
 		len -= SPCA50X_OFFSET_DATA;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-				data, len);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 		break;
 	case 0xff:			/* drop */
 /*		gspca_dev->last_packet_type = DISCARD_PACKET; */
@@ -562,8 +559,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	default:
 		data += 1;
 		len -= 1;
-		gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-				data, len);
+		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 		break;
 	}
 }
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 9696c4caf5c9..4d8e6cf75d55 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1447,26 +1447,22 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
 	switch (data[0]) {
 	case 0:				/* start of frame */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 		data += SPCA508_OFFSET_DATA;
 		len -= SPCA508_OFFSET_DATA;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-				data, len);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 		break;
 	case 0xff:			/* drop */
 		break;
 	default:
 		data += 1;
 		len -= 1;
-		gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-				data, len);
+		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 		break;
 	}
 }
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 27e82b35f3e7..58c2f0039af1 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -779,8 +779,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 }
 
 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;
@@ -788,12 +787,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	len--;
 	switch (*data++) {			/* sequence number */
 	case 0:					/* start of frame */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 		if (data[1] & 0x10) {
 			/* compressed bayer */
-			gspca_frame_add(gspca_dev, FIRST_PACKET,
-					frame, data, len);
+			gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 		} else {
 			/* raw bayer (with a header, which we skip) */
 			if (sd->chip_revision == Rev012A) {
@@ -803,14 +800,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 				data += 16;
 				len -= 16;
 			}
-			gspca_frame_add(gspca_dev, FIRST_PACKET,
-						frame, data, len);
+			gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 		}
 		return;
 	case 0xff:			/* drop (empty mpackets) */
 		return;
 	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 /* rev 72a only */
diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c
index 715a68f0156e..1fcaca6a87f7 100644
--- a/drivers/media/video/gspca/sq905.c
+++ b/drivers/media/video/gspca/sq905.c
@@ -168,18 +168,22 @@ static int sq905_ack_frame(struct gspca_dev *gspca_dev)
  *  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)
+sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock)
 {
 	int ret;
 	int act_len;
 
 	gspca_dev->usb_buf[0] = '\0';
+	if (need_lock)
+		mutex_lock(&gspca_dev->usb_lock);
 	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 (need_lock)
+		mutex_unlock(&gspca_dev->usb_lock);
 	if (ret < 0) {
 		PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret);
 		return ret;
@@ -210,11 +214,9 @@ 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;
@@ -222,7 +224,6 @@ static void sq905_dostream(struct work_struct *work)
 	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;
@@ -232,28 +233,22 @@ static void sq905_dostream(struct work_struct *work)
 			+ 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) {
+		/* Note we do not check for gspca_dev->streaming here, as
+		   we must finish reading an entire frame, otherwise the
+		   next time we stream we start reading in the middle of a
+		   frame. */
+		while (bytes_left > 0 && gspca_dev->present) {
 			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);
+			ret = sq905_read_data(gspca_dev, buffer, data_len, 1);
 			if (ret < 0)
 				goto quit_stream;
-			mutex_unlock(&gspca_dev->usb_lock);
-			PDEBUG(D_STREAM,
+			PDEBUG(D_PACK,
 				"Got %d bytes out of %d for frame",
 				data_len, bytes_left);
 			bytes_left -= data_len;
@@ -270,34 +265,30 @@ static void sq905_dostream(struct work_struct *work)
 			} 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;
-			}
+			gspca_frame_add(gspca_dev, packet_type,
+					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)
+				gspca_frame_add(gspca_dev, LAST_PACKET,
+						NULL, 0);
+		}
+		if (gspca_dev->present) {
+			/* acknowledge the frame */
+			mutex_lock(&gspca_dev->usb_lock);
+			ret = sq905_ack_frame(gspca_dev);
+			mutex_unlock(&gspca_dev->usb_lock);
+			if (ret < 0)
+				goto quit_stream;
 		}
-		/* 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)
+	if (gspca_dev->present) {
+		mutex_lock(&gspca_dev->usb_lock);
 		sq905_command(gspca_dev, SQ905_CLEAR);
-	mutex_unlock(&gspca_dev->usb_lock);
+		mutex_unlock(&gspca_dev->usb_lock);
+	}
 	kfree(buffer);
 }
 
@@ -346,7 +337,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 	ret = sq905_command(gspca_dev, SQ905_ID);
 	if (ret < 0)
 		return ret;
-	ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4);
+	ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4, 0);
 	if (ret < 0)
 		return ret;
 	/* usb_buf is allocated with kmalloc so is aligned.
diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
index 916892505432..d70b156872d6 100644
--- a/drivers/media/video/gspca/sq905c.c
+++ b/drivers/media/video/gspca/sq905c.c
@@ -115,11 +115,9 @@ 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;
@@ -131,8 +129,6 @@ static void sq905c_dostream(struct work_struct *work)
 	}
 
 	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),
@@ -149,17 +145,11 @@ static void sq905c_dostream(struct work_struct *work)
 		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) {
+		gspca_frame_add(gspca_dev, packet_type,
+				buffer, FRAME_HEADER_LEN);
+		while (bytes_left > 0 && gspca_dev->present) {
 			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,
@@ -174,19 +164,16 @@ static void sq905c_dostream(struct work_struct *work)
 				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;
+			gspca_frame_add(gspca_dev, packet_type,
+					buffer, data_len);
 		}
 	}
 quit_stream:
-	mutex_lock(&gspca_dev->usb_lock);
-	if (gspca_dev->present)
+	if (gspca_dev->present) {
+		mutex_lock(&gspca_dev->usb_lock);
 		sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
-	mutex_unlock(&gspca_dev->usb_lock);
+		mutex_unlock(&gspca_dev->usb_lock);
+	}
 	kfree(buffer);
 }
 
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 47628964801e..8e23320d7ab7 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -418,8 +418,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 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;
@@ -435,11 +434,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	 *		(without ending - ff d9)
 	 */
 	if (data[0] == 0xff && data[1] == 0xfe) {
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					ffd9, 2);
+		gspca_frame_add(gspca_dev, LAST_PACKET,
+				ffd9, 2);
 
 		/* put the JPEG 411 header */
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
 			sd->jpeg_hdr, JPEG_HDR_SZ);
 
 		/* beginning of the frame */
@@ -447,7 +446,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		data += STKHDRSZ;
 		len -= STKHDRSZ;
 	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/gspca/stv0680.c b/drivers/media/video/gspca/stv0680.c
new file mode 100644
index 000000000000..2a69d7ccb50d
--- /dev/null
+++ b/drivers/media/video/gspca/stv0680.c
@@ -0,0 +1,364 @@
+/*
+ * STV0680 USB Camera Driver
+ *
+ * Copyright (C) 2009 Hans de Goede <hdgoede@redhat.com>
+ *
+ * This module is adapted from the in kernel v4l1 stv680 driver:
+ *
+ *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
+ *
+ * Thanks to STMicroelectronics for information on the usb commands, and
+ * to Steve Miller at STM for his help and encouragement while I was
+ * writing this driver.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define MODULE_NAME "stv0680"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_DESCRIPTION("STV0680 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+	struct v4l2_pix_format mode;
+	u8 orig_mode;
+	u8 video_mode;
+	u8 current_mode;
+};
+
+/* V4L2 controls supported by the driver */
+static struct ctrl sd_ctrls[] = {
+};
+
+static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,
+		       int size)
+{
+	int ret = -1;
+	u8 req_type = 0;
+
+	switch (set) {
+	case 0: /*  0xc1  */
+		req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+		break;
+	case 1: /*  0x41  */
+		req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+		break;
+	case 2:	/*  0x80  */
+		req_type = USB_DIR_IN | USB_RECIP_DEVICE;
+		break;
+	case 3:	/*  0x40  */
+		req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+		break;
+	}
+
+	ret = usb_control_msg(gspca_dev->dev,
+			      usb_rcvctrlpipe(gspca_dev->dev, 0),
+			      req, req_type,
+			      val, 0, gspca_dev->usb_buf, size, 500);
+
+	if ((ret < 0) && (req != 0x0a))
+		PDEBUG(D_ERR,
+		       "usb_control_msg error %i, request = 0x%x, error = %i",
+		       set, req, ret);
+
+	return ret;
+}
+
+static int stv0680_handle_error(struct gspca_dev *gspca_dev, int ret)
+{
+	stv_sndctrl(gspca_dev, 0, 0x80, 0, 0x02); /* Get Last Error */
+	PDEBUG(D_ERR, "last error: %i,  command = 0x%x",
+	       gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+	return ret;
+}
+
+static int stv0680_get_video_mode(struct gspca_dev *gspca_dev)
+{
+	/* Note not sure if this init of usb_buf is really necessary */
+	memset(gspca_dev->usb_buf, 0, 8);
+	gspca_dev->usb_buf[0] = 0x0f;
+
+	if (stv_sndctrl(gspca_dev, 0, 0x87, 0, 0x08) != 0x08) {
+		PDEBUG(D_ERR, "Get_Camera_Mode failed");
+		return stv0680_handle_error(gspca_dev, -EIO);
+	}
+
+	return gspca_dev->usb_buf[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */
+}
+
+static int stv0680_set_video_mode(struct gspca_dev *gspca_dev, u8 mode)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->current_mode == mode)
+		return 0;
+
+	memset(gspca_dev->usb_buf, 0, 8);
+	gspca_dev->usb_buf[0] = mode;
+
+	if (stv_sndctrl(gspca_dev, 3, 0x07, 0x0100, 0x08) != 0x08) {
+		PDEBUG(D_ERR, "Set_Camera_Mode failed");
+		return stv0680_handle_error(gspca_dev, -EIO);
+	}
+
+	/* Verify we got what we've asked for */
+	if (stv0680_get_video_mode(gspca_dev) != mode) {
+		PDEBUG(D_ERR, "Error setting camera video mode!");
+		return -EIO;
+	}
+
+	sd->current_mode = mode;
+
+	return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	int ret;
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam = &gspca_dev->cam;
+
+	/* ping camera to be sure STV0680 is present */
+	if (stv_sndctrl(gspca_dev, 0, 0x88, 0x5678, 0x02) != 0x02 ||
+	    gspca_dev->usb_buf[0] != 0x56 || gspca_dev->usb_buf[1] != 0x78) {
+		PDEBUG(D_ERR, "STV(e): camera ping failed!!");
+		return stv0680_handle_error(gspca_dev, -ENODEV);
+	}
+
+	/* get camera descriptor */
+	if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x09) != 0x09)
+		return stv0680_handle_error(gspca_dev, -ENODEV);
+
+	if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x22) != 0x22 ||
+	    gspca_dev->usb_buf[7] != 0xa0 || gspca_dev->usb_buf[8] != 0x23) {
+		PDEBUG(D_ERR, "Could not get descriptor 0200.");
+		return stv0680_handle_error(gspca_dev, -ENODEV);
+	}
+	if (stv_sndctrl(gspca_dev, 0, 0x8a, 0, 0x02) != 0x02)
+		return stv0680_handle_error(gspca_dev, -ENODEV);
+	if (stv_sndctrl(gspca_dev, 0, 0x8b, 0, 0x24) != 0x24)
+		return stv0680_handle_error(gspca_dev, -ENODEV);
+	if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10)
+		return stv0680_handle_error(gspca_dev, -ENODEV);
+
+	if (!(gspca_dev->usb_buf[7] & 0x09)) {
+		PDEBUG(D_ERR, "Camera supports neither CIF nor QVGA mode");
+		return -ENODEV;
+	}
+	if (gspca_dev->usb_buf[7] & 0x01)
+		PDEBUG(D_PROBE, "Camera supports CIF mode");
+	if (gspca_dev->usb_buf[7] & 0x02)
+		PDEBUG(D_PROBE, "Camera supports VGA mode");
+	if (gspca_dev->usb_buf[7] & 0x08)
+		PDEBUG(D_PROBE, "Camera supports QVGA mode");
+
+	if (gspca_dev->usb_buf[7] & 0x01)
+		sd->video_mode = 0x00; /* CIF */
+	else
+		sd->video_mode = 0x03; /* QVGA */
+
+	/* FW rev, ASIC rev, sensor ID  */
+	PDEBUG(D_PROBE, "Firmware rev is %i.%i",
+	       gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+	PDEBUG(D_PROBE, "ASIC rev is %i.%i",
+	       gspca_dev->usb_buf[2], gspca_dev->usb_buf[3]);
+	PDEBUG(D_PROBE, "Sensor ID is %i",
+	       (gspca_dev->usb_buf[4]*16) + (gspca_dev->usb_buf[5]>>4));
+
+
+	ret = stv0680_get_video_mode(gspca_dev);
+	if (ret < 0)
+		return ret;
+	sd->current_mode = sd->orig_mode = ret;
+
+	ret = stv0680_set_video_mode(gspca_dev, sd->video_mode);
+	if (ret < 0)
+		return ret;
+
+	/* Get mode details */
+	if (stv_sndctrl(gspca_dev, 0, 0x8f, 0, 0x10) != 0x10)
+		return stv0680_handle_error(gspca_dev, -EIO);
+
+	cam->bulk = 1;
+	cam->bulk_nurbs = 1; /* The cam cannot handle more */
+	cam->bulk_size = (gspca_dev->usb_buf[0] << 24) |
+			 (gspca_dev->usb_buf[1] << 16) |
+			 (gspca_dev->usb_buf[2] << 8) |
+			 (gspca_dev->usb_buf[3]);
+	sd->mode.width = (gspca_dev->usb_buf[4] << 8) |
+			 (gspca_dev->usb_buf[5]);  /* 322, 356, 644 */
+	sd->mode.height = (gspca_dev->usb_buf[6] << 8) |
+			  (gspca_dev->usb_buf[7]); /* 242, 292, 484 */
+	sd->mode.pixelformat = V4L2_PIX_FMT_STV0680;
+	sd->mode.field = V4L2_FIELD_NONE;
+	sd->mode.bytesperline = sd->mode.width;
+	sd->mode.sizeimage = cam->bulk_size;
+	sd->mode.colorspace = V4L2_COLORSPACE_SRGB;
+
+	/* origGain = gspca_dev->usb_buf[12]; */
+
+	cam->cam_mode = &sd->mode;
+	cam->nmodes = 1;
+
+
+	ret = stv0680_set_video_mode(gspca_dev, sd->orig_mode);
+	if (ret < 0)
+		return ret;
+
+	if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 ||
+	    gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) {
+		PDEBUG(D_ERR, "Could not get descriptor 0100.");
+		return stv0680_handle_error(gspca_dev, -EIO);
+	}
+
+	return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	int ret;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	ret = stv0680_set_video_mode(gspca_dev, sd->video_mode);
+	if (ret < 0)
+		return ret;
+
+	if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10)
+		return stv0680_handle_error(gspca_dev, -EIO);
+
+	/* Start stream at:
+	   0x0000 = CIF (352x288)
+	   0x0100 = VGA (640x480)
+	   0x0300 = QVGA (320x240) */
+	if (stv_sndctrl(gspca_dev, 1, 0x09, sd->video_mode << 8, 0x0) != 0x0)
+		return stv0680_handle_error(gspca_dev, -EIO);
+
+	return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	/* This is a high priority command; it stops all lower order cmds */
+	if (stv_sndctrl(gspca_dev, 1, 0x04, 0x0000, 0x0) != 0x0)
+		stv0680_handle_error(gspca_dev, -EIO);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (!sd->gspca_dev.present)
+		return;
+
+	stv0680_set_video_mode(gspca_dev, sd->orig_mode);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,
+			int len)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* Every now and then the camera sends a 16 byte packet, no idea
+	   what it contains, but it is not image data, when this
+	   happens the frame received before this packet is corrupt,
+	   so discard it. */
+	if (len != sd->mode.sizeimage) {
+		gspca_dev->last_packet_type = DISCARD_PACKET;
+		return;
+	}
+
+	/* Finish the previous frame, we do this upon reception of the next
+	   packet, even though it is already complete so that the strange 16
+	   byte packets send after a corrupt frame can discard it. */
+	gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+
+	/* Store the just received frame */
+	gspca_frame_add(gspca_dev, FIRST_PACKET, 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,
+	.stop0 = sd_stop0,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x0553, 0x0202)},
+	{USB_DEVICE(0x041e, 0x4007)},
+	{}
+};
+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)
+{
+	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/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index bfae63f5584c..5d0241bb1611 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -312,8 +312,7 @@ out:
  * The 0005 and 0100 chunks seem to appear only in compressed stream.
  */
 static void stv06xx_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;
@@ -366,7 +365,7 @@ frame_data:
 				sd->to_skip -= skip;
 			}
 
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			gspca_frame_add(gspca_dev, INTER_PACKET,
 					data, chunk_len);
 			break;
 
@@ -378,7 +377,7 @@ frame_data:
 
 			/* Create a new frame, chunk length should be zero */
 			gspca_frame_add(gspca_dev, FIRST_PACKET,
-					frame, data, 0);
+					NULL, 0);
 
 			if (sd->bridge == BRIDGE_ST6422)
 				sd->to_skip = gspca_dev->width * 4;
@@ -394,8 +393,8 @@ frame_data:
 			PDEBUG(D_PACK, "End of frame detected");
 
 			/* Complete the last frame (if any) */
-			frame = gspca_frame_add(gspca_dev, LAST_PACKET,
-						frame, data, 0);
+			gspca_frame_add(gspca_dev, LAST_PACKET,
+					NULL, 0);
 
 			if (chunk_len)
 				PDEBUG(D_ERR, "Chunk length is "
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 1a9af2ebdbef..72bf3b4f0a31 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -1116,7 +1116,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
@@ -1186,11 +1185,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		break;
 	}
 	if (sof) {		/* start of frame */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					ffd9, 2);
+		gspca_frame_add(gspca_dev, LAST_PACKET,
+				ffd9, 2);
 
 		/* put the JPEG header in the new frame */
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
 			sd->jpeg_hdr, JPEG_HDR_SZ);
 	}
 
@@ -1198,7 +1197,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	i = 0;
 	do {
 		if (data[i] == 0xff) {
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			gspca_frame_add(gspca_dev, INTER_PACKET,
 					data, i + 1);
 			len -= i;
 			data += i;
@@ -1207,7 +1206,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		}
 		i++;
 	} while (i < len);
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 1d321c30d22f..55ef6a744427 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -938,7 +938,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
@@ -956,9 +955,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		/* extra bytes....., could be processed too but would be
 		 * a waste of time, right now leave the application and
 		 * libjpeg do it for ourserlves.. */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+		gspca_frame_add(gspca_dev, LAST_PACKET,
 					ffd9, 2);
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 		return;
 	}
 
@@ -967,7 +966,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		 * other's do not include it... */
 		len -= 2;
 	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index 4b44dde9f8b8..b74a3b6489c7 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -398,8 +398,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 }
 
 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;
@@ -424,9 +423,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	 * - 4 bytes
 	 */
 	gspca_frame_add(gspca_dev, packet_type0,
-			frame, data + 2, gspca_dev->width);
+			data + 2, gspca_dev->width);
 	gspca_frame_add(gspca_dev, packet_type1,
-			frame, data + gspca_dev->width + 5, gspca_dev->width);
+			data + gspca_dev->width + 5, gspca_dev->width);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 589042f6adbe..c090efcd8045 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -2987,7 +2987,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
 			u8 *data,			/* isoc packet */
 			int len)			/* iso pkt length */
 {
@@ -2996,21 +2995,25 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	if (data[0] == 0xff && data[1] == 0xd8) {
 		PDEBUG(D_PACK,
 			"vc032x header packet found len %d", len);
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-						data, 0);
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 		data += sd->image_offset;
 		len -= sd->image_offset;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-				data, len);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
 		return;
 	}
 
 	/* The vc0321 sends some additional data after sending the complete
 	 * frame, we ignore this. */
-	if (sd->bridge == BRIDGE_VC0321
-	    && len > frame->v4l2_buf.length - (frame->data_end - frame->data))
-		len = frame->v4l2_buf.length - (frame->data_end - frame->data);
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	if (sd->bridge == BRIDGE_VC0321) {
+		struct gspca_frame *frame;
+		int l;
+
+		frame = gspca_get_i_frame(gspca_dev);
+		l = frame->data_end - frame->data;
+		if (len > frame->v4l2_buf.length - l)
+			len = frame->v4l2_buf.length - l;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -3092,6 +3095,8 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
 
 	switch (menu->id) {
 	case V4L2_CID_POWER_LINE_FREQUENCY:
+		if (menu->index >= ARRAY_SIZE(freq_nm))
+			break;
 		strcpy((char *) menu->name, freq_nm[menu->index]);
 		return 0;
 	}
diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c
new file mode 100644
index 000000000000..2fffe203bed8
--- /dev/null
+++ b/drivers/media/video/gspca/w996Xcf.c
@@ -0,0 +1,609 @@
+/**
+ *
+ * GSPCA sub driver for W996[78]CF JPEG USB Dual Mode Camera Chip.
+ *
+ * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This module is adapted from the in kernel v4l1 w9968cf driver:
+ *
+ * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>
+ *
+ * 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
+ *
+ */
+
+/* Note this is not a stand alone driver, it gets included in ov519.c, this
+   is a bit of a hack, but it needs the driver code for a lot of different
+   ov sensors which is already present in ov519.c (the old v4l1 driver used
+   the ovchipcam framework). When we have the time we really should move
+   the sensor drivers to v4l2 sub drivers, and properly split of this
+   driver from ov519.c */
+
+/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
+#define CONEX_CAM
+#include "jpeg.h"
+
+#define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
+
+#define Y_QUANTABLE (sd->jpeg_hdr + JPEG_QT0_OFFSET)
+#define UV_QUANTABLE (sd->jpeg_hdr + JPEG_QT1_OFFSET)
+
+static const struct v4l2_pix_format w9968cf_vga_mode[] = {
+	{160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
+		.bytesperline = 160 * 2,
+		.sizeimage = 160 * 120 * 2,
+		.colorspace = V4L2_COLORSPACE_JPEG},
+	{176, 144, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
+		.bytesperline = 176 * 2,
+		.sizeimage = 176 * 144 * 2,
+		.colorspace = V4L2_COLORSPACE_JPEG},
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320 * 2,
+		.sizeimage = 320 * 240 * 2,
+		.colorspace = V4L2_COLORSPACE_JPEG},
+	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 352 * 2,
+		.sizeimage = 352 * 288 * 2,
+		.colorspace = V4L2_COLORSPACE_JPEG},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640 * 2,
+		.sizeimage = 640 * 480 * 2,
+		.colorspace = V4L2_COLORSPACE_JPEG},
+};
+
+static int reg_w(struct sd *sd, __u16 index, __u16 value);
+
+/*--------------------------------------------------------------------------
+  Write 64-bit data to the fast serial bus registers.
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_fsb(struct sd *sd, u16* data)
+{
+	struct usb_device* udev = sd->gspca_dev.dev;
+	u16 value;
+	int ret;
+
+	value = *data++;
+	memcpy(sd->gspca_dev.usb_buf, data, 6);
+
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
+			      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+			      value, 0x06, sd->gspca_dev.usb_buf, 6, 500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "Write FSB registers failed (%d)", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*--------------------------------------------------------------------------
+  Write data to the serial bus control register.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_sb(struct sd *sd, u16 value)
+{
+	int ret;
+
+	/* We don't use reg_w here, as that would cause all writes when
+	   bitbanging i2c to be logged, making the logs impossible to read */
+	ret = usb_control_msg(sd->gspca_dev.dev,
+		usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+		0,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value, 0x01, NULL, 0, 500);
+
+	udelay(W9968CF_I2C_BUS_DELAY);
+
+	if (ret < 0) {
+		PDEBUG(D_ERR, "Write SB reg [01] %04x failed", value);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*--------------------------------------------------------------------------
+  Read data from the serial bus control register.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_read_sb(struct sd *sd)
+{
+	int ret;
+
+	/* We don't use reg_r here, as the w9968cf is special and has 16
+	   bit registers instead of 8 bit */
+	ret = usb_control_msg(sd->gspca_dev.dev,
+			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+			1,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0, 0x01, sd->gspca_dev.usb_buf, 2, 500);
+	if (ret >= 0)
+		ret = sd->gspca_dev.usb_buf[0] |
+		      (sd->gspca_dev.usb_buf[1] << 8);
+	else
+		PDEBUG(D_ERR, "Read SB reg [01] failed");
+
+	udelay(W9968CF_I2C_BUS_DELAY);
+
+	return ret;
+}
+
+/*--------------------------------------------------------------------------
+  Upload quantization tables for the JPEG compression.
+  This function is called by w9968cf_start_transfer().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_upload_quantizationtables(struct sd *sd)
+{
+	u16 a, b;
+	int ret = 0, i, j;
+
+	ret += reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */
+
+	for (i = 0, j = 0; i < 32; i++, j += 2) {
+		a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
+		b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
+		ret += reg_w(sd, 0x40+i, a);
+		ret += reg_w(sd, 0x60+i, b);
+	}
+	ret += reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */
+
+	return ret;
+}
+
+/****************************************************************************
+ * Low-level I2C I/O functions.                                             *
+ * The adapter supports the following I2C transfer functions:               *
+ * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only)           *
+ * i2c_adap_read_byte_data()                                                *
+ * i2c_adap_read_byte()                                                     *
+ ****************************************************************************/
+
+static int w9968cf_smbus_start(struct sd *sd)
+{
+	int ret = 0;
+
+	ret += w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+	ret += w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+
+	return ret;
+}
+
+static int w9968cf_smbus_stop(struct sd *sd)
+{
+	int ret = 0;
+
+	ret += w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+	ret += w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+	ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+
+	return ret;
+}
+
+static int w9968cf_smbus_write_byte(struct sd *sd, u8 v)
+{
+	u8 bit;
+	int ret = 0, sda;
+
+	for (bit = 0 ; bit < 8 ; bit++) {
+		sda = (v & 0x80) ? 2 : 0;
+		v <<= 1;
+		/* SDE=1, SDA=sda, SCL=0 */
+		ret += w9968cf_write_sb(sd, 0x10 | sda);
+		/* SDE=1, SDA=sda, SCL=1 */
+		ret += w9968cf_write_sb(sd, 0x11 | sda);
+		/* SDE=1, SDA=sda, SCL=0 */
+		ret += w9968cf_write_sb(sd, 0x10 | sda);
+	}
+
+	return ret;
+}
+
+static int w9968cf_smbus_read_byte(struct sd *sd, u8* v)
+{
+	u8 bit;
+	int ret = 0;
+
+	/* No need to ensure SDA is high as we are always called after
+	   read_ack which ends with SDA high */
+	*v = 0;
+	for (bit = 0 ; bit < 8 ; bit++) {
+		*v <<= 1;
+		/* SDE=1, SDA=1, SCL=1 */
+		ret += w9968cf_write_sb(sd, 0x0013);
+		*v |= (w9968cf_read_sb(sd) & 0x0008) ? 1 : 0;
+		/* SDE=1, SDA=1, SCL=0 */
+		ret += w9968cf_write_sb(sd, 0x0012);
+	}
+
+	return ret;
+}
+
+static int w9968cf_smbus_write_nack(struct sd *sd)
+{
+	int ret = 0;
+
+	/* No need to ensure SDA is high as we are always called after
+	   read_byte which ends with SDA high */
+	ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+	ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+
+	return ret;
+}
+
+static int w9968cf_smbus_read_ack(struct sd *sd)
+{
+	int ret = 0, sda;
+
+	/* Ensure SDA is high before raising clock to avoid a spurious stop */
+	ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+	ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+	sda = w9968cf_read_sb(sd);
+	ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+	if (sda < 0)
+		ret += sda;
+	else if (sda & 0x08) {
+		PDEBUG(D_USBI, "Did not receive i2c ACK");
+		ret += -1;
+	}
+
+	return ret;
+}
+
+/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
+static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
+{
+	u16* data = (u16 *)sd->gspca_dev.usb_buf;
+	int ret = 0;
+
+	data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0);
+	data[0] |= (sd->sensor_addr & 0x40) ? 0x4000 : 0x0;
+	data[1] = 0x2082 | ((sd->sensor_addr & 0x40) ? 0x0005 : 0x0);
+	data[1] |= (sd->sensor_addr & 0x20) ? 0x0150 : 0x0;
+	data[1] |= (sd->sensor_addr & 0x10) ? 0x5400 : 0x0;
+	data[2] = 0x8208 | ((sd->sensor_addr & 0x08) ? 0x0015 : 0x0);
+	data[2] |= (sd->sensor_addr & 0x04) ? 0x0540 : 0x0;
+	data[2] |= (sd->sensor_addr & 0x02) ? 0x5000 : 0x0;
+	data[3] = 0x1d20 | ((sd->sensor_addr & 0x02) ? 0x0001 : 0x0);
+	data[3] |= (sd->sensor_addr & 0x01) ? 0x0054 : 0x0;
+
+	ret += w9968cf_write_fsb(sd, data);
+
+	data[0] = 0x8208 | ((reg & 0x80) ? 0x0015 : 0x0);
+	data[0] |= (reg & 0x40) ? 0x0540 : 0x0;
+	data[0] |= (reg & 0x20) ? 0x5000 : 0x0;
+	data[1] = 0x0820 | ((reg & 0x20) ? 0x0001 : 0x0);
+	data[1] |= (reg & 0x10) ? 0x0054 : 0x0;
+	data[1] |= (reg & 0x08) ? 0x1500 : 0x0;
+	data[1] |= (reg & 0x04) ? 0x4000 : 0x0;
+	data[2] = 0x2082 | ((reg & 0x04) ? 0x0005 : 0x0);
+	data[2] |= (reg & 0x02) ? 0x0150 : 0x0;
+	data[2] |= (reg & 0x01) ? 0x5400 : 0x0;
+	data[3] = 0x001d;
+
+	ret += w9968cf_write_fsb(sd, data);
+
+	data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
+	data[0] |= (value & 0x40) ? 0x0540 : 0x0;
+	data[0] |= (value & 0x20) ? 0x5000 : 0x0;
+	data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
+	data[1] |= (value & 0x10) ? 0x0054 : 0x0;
+	data[1] |= (value & 0x08) ? 0x1500 : 0x0;
+	data[1] |= (value & 0x04) ? 0x4000 : 0x0;
+	data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
+	data[2] |= (value & 0x02) ? 0x0150 : 0x0;
+	data[2] |= (value & 0x01) ? 0x5400 : 0x0;
+	data[3] = 0xfe1d;
+
+	ret += w9968cf_write_fsb(sd, data);
+
+	if (!ret)
+		PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+	else
+		PDEBUG(D_ERR, "i2c 0x%02x -> [0x%02x] failed", value, reg);
+
+	return ret;
+}
+
+/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
+static int w9968cf_i2c_r(struct sd *sd, u8 reg)
+{
+	int ret = 0;
+	u8 value;
+
+	/* Fast serial bus data control disable */
+	ret += w9968cf_write_sb(sd, 0x0013); /* don't change ! */
+
+	ret += w9968cf_smbus_start(sd);
+	ret += w9968cf_smbus_write_byte(sd, sd->sensor_addr);
+	ret += w9968cf_smbus_read_ack(sd);
+	ret += w9968cf_smbus_write_byte(sd, reg);
+	ret += w9968cf_smbus_read_ack(sd);
+	ret += w9968cf_smbus_stop(sd);
+	ret += w9968cf_smbus_start(sd);
+	ret += w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1);
+	ret += w9968cf_smbus_read_ack(sd);
+	ret += w9968cf_smbus_read_byte(sd, &value);
+	/* signal we don't want to read anymore, the v4l1 driver used to
+	   send an ack here which is very wrong! (and then fixed
+	   the issues this gave by retrying reads) */
+	ret += w9968cf_smbus_write_nack(sd);
+	ret += w9968cf_smbus_stop(sd);
+
+	/* Fast serial bus data control re-enable */
+	ret += w9968cf_write_sb(sd, 0x0030);
+
+	if (!ret) {
+		ret = value;
+		PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+	} else
+		PDEBUG(D_ERR, "i2c read [0x%02x] failed", reg);
+
+	return ret;
+}
+
+
+/*--------------------------------------------------------------------------
+  Turn on the LED on some webcams. A beep should be heard too.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_configure(struct sd *sd)
+{
+	int ret = 0;
+
+	ret += reg_w(sd, 0x00, 0xff00); /* power-down */
+	ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */
+	ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */
+	ret += reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */
+	ret += reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */
+	ret += reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */
+	ret += reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */
+
+	if (ret)
+		PDEBUG(D_ERR, "Couldn't turn on the LED");
+
+	sd->stopped = 1;
+
+	return ret;
+}
+
+static int w9968cf_init(struct sd *sd)
+{
+	int ret = 0;
+	unsigned long hw_bufsize = sd->sif ? (352 * 288 * 2) : (640 * 480 * 2),
+		      y0 = 0x0000,
+		      u0 = y0 + hw_bufsize/2,
+		      v0 = u0 + hw_bufsize/4,
+		      y1 = v0 + hw_bufsize/4,
+		      u1 = y1 + hw_bufsize/2,
+		      v1 = u1 + hw_bufsize/4;
+
+	ret += reg_w(sd, 0x00, 0xff00); /* power off */
+	ret += reg_w(sd, 0x00, 0xbf10); /* power on */
+
+	ret += reg_w(sd, 0x03, 0x405d); /* DRAM timings */
+	ret += reg_w(sd, 0x04, 0x0030); /* SDRAM timings */
+
+	ret += reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */
+	ret += reg_w(sd, 0x21, y0 >> 16);    /* Y buf.0, high */
+	ret += reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */
+	ret += reg_w(sd, 0x25, u0 >> 16);    /* U buf.0, high */
+	ret += reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */
+	ret += reg_w(sd, 0x29, v0 >> 16);    /* V buf.0, high */
+
+	ret += reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */
+	ret += reg_w(sd, 0x23, y1 >> 16);    /* Y buf.1, high */
+	ret += reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */
+	ret += reg_w(sd, 0x27, u1 >> 16);    /* U buf.1, high */
+	ret += reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */
+	ret += reg_w(sd, 0x2b, v1 >> 16);    /* V buf.1, high */
+
+	ret += reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */
+	ret += reg_w(sd, 0x33, y1 >> 16);    /* JPEG buf 0 high */
+
+	ret += reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */
+	ret += reg_w(sd, 0x35, y1 >> 16);    /* JPEG bug 1 high */
+
+	ret += reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */
+	ret += reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/
+	ret += reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */
+	ret += reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */
+
+	return ret;
+}
+
+static int w9968cf_set_crop_window(struct sd *sd)
+{
+	int ret = 0, start_cropx, start_cropy,  x, y, fw, fh, cw, ch,
+	    max_width, max_height;
+
+	if (sd->sif) {
+		max_width  = 352;
+		max_height = 288;
+	} else {
+		max_width  = 640;
+		max_height = 480;
+	}
+
+	if (sd->sensor == SEN_OV7620) {
+		/* Sigh, this is dependend on the clock / framerate changes
+		   made by the frequency control, sick. */
+		if (sd->freq == 1) {
+			start_cropx = 277;
+			start_cropy = 37;
+		} else {
+			start_cropx = 105;
+			start_cropy = 37;
+		}
+	} else {
+		start_cropx = 320;
+		start_cropy = 35;
+	}
+
+	/* Work around to avoid FP arithmetics */
+	#define SC(x) ((x) << 10)
+
+	/* Scaling factors */
+	fw = SC(sd->gspca_dev.width) / max_width;
+	fh = SC(sd->gspca_dev.height) / max_height;
+
+	cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width)/fh;
+	ch = (fw >= fh) ? SC(sd->gspca_dev.height)/fw : max_height;
+
+	sd->sensor_width = max_width;
+	sd->sensor_height = max_height;
+
+	x = (max_width - cw) / 2;
+	y = (max_height - ch) / 2;
+
+	ret += reg_w(sd, 0x10, start_cropx + x);
+	ret += reg_w(sd, 0x11, start_cropy + y);
+	ret += reg_w(sd, 0x12, start_cropx + x + cw);
+	ret += reg_w(sd, 0x13, start_cropy + y + ch);
+
+	return ret;
+}
+
+static int w9968cf_mode_init_regs(struct sd *sd)
+{
+	int ret = 0, val, vs_polarity, hs_polarity;
+
+	ret += w9968cf_set_crop_window(sd);
+
+	ret += reg_w(sd, 0x14, sd->gspca_dev.width);
+	ret += reg_w(sd, 0x15, sd->gspca_dev.height);
+
+	/* JPEG width & height */
+	ret += reg_w(sd, 0x30, sd->gspca_dev.width);
+	ret += reg_w(sd, 0x31, sd->gspca_dev.height);
+
+	/* Y & UV frame buffer strides (in WORD) */
+	if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
+	    V4L2_PIX_FMT_JPEG) {
+		ret += reg_w(sd, 0x2c, sd->gspca_dev.width/2);
+		ret += reg_w(sd, 0x2d, sd->gspca_dev.width/4);
+	} else
+		ret += reg_w(sd, 0x2c, sd->gspca_dev.width);
+
+	ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */
+	ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */
+
+	/* Transfer size in WORDS (for UYVY format only) */
+	val = sd->gspca_dev.width * sd->gspca_dev.height;
+	ret += reg_w(sd, 0x3d, val & 0xffff); /* low bits */
+	ret += reg_w(sd, 0x3e, val >> 16);    /* high bits */
+
+	if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
+	    V4L2_PIX_FMT_JPEG) {
+		/* We may get called multiple times (usb isoc bw negotiat.) */
+		if (!sd->jpeg_hdr)
+			sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+		if (!sd->jpeg_hdr)
+			return -ENOMEM;
+
+		jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height,
+			    sd->gspca_dev.width, 0x22); /* JPEG 420 */
+		jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+		ret += w9968cf_upload_quantizationtables(sd);
+	}
+
+	/* Video Capture Control Register */
+	if (sd->sensor == SEN_OV7620) {
+		/* Seems to work around a bug in the image sensor */
+		vs_polarity = 1;
+		hs_polarity = 1;
+	} else {
+		vs_polarity = 1;
+		hs_polarity = 0;
+	}
+
+	val = (vs_polarity << 12) | (hs_polarity << 11);
+
+	/* NOTE: We may not have enough memory to do double buffering while
+	   doing compression (amount of memory differs per model cam).
+	   So we use the second image buffer also as jpeg stream buffer
+	   (see w9968cf_init), and disable double buffering. */
+	if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
+	    V4L2_PIX_FMT_JPEG) {
+		/* val |= 0x0002; YUV422P */
+		val |= 0x0003; /* YUV420P */
+	} else
+		val |= 0x0080; /* Enable HW double buffering */
+
+	/* val |= 0x0020; enable clamping */
+	/* val |= 0x0008; enable (1-2-1) filter */
+	/* val |= 0x000c; enable (2-3-6-3-2) filter */
+
+	val |= 0x8000; /* capt. enable */
+
+	ret += reg_w(sd, 0x16, val);
+
+	sd->gspca_dev.empty_packet = 0;
+
+	return ret;
+}
+
+static void w9968cf_stop0(struct sd *sd)
+{
+	if (sd->gspca_dev.present) {
+		reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */
+		reg_w(sd, 0x16, 0x0000); /* stop video capture */
+	}
+
+	kfree(sd->jpeg_hdr);
+	sd->jpeg_hdr = NULL;
+}
+
+/* The w9968cf docs say that a 0 sized packet means EOF (and also SOF
+   for the next frame). This seems to simply not be true when operating
+   in JPEG mode, in this case there may be empty packets within the
+   frame. So in JPEG mode use the JPEG SOI marker to detect SOF.
+
+   Note to make things even more interesting the w9968cf sends *PLANAR* jpeg,
+   to be precise it sends: SOI, SOF, DRI, SOS, Y-data, SOS, U-data, SOS,
+   V-data, EOI. */
+static void w9968cf_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (w9968cf_vga_mode[gspca_dev->curr_mode].pixelformat ==
+	    V4L2_PIX_FMT_JPEG) {
+		if (len >= 2 &&
+		    data[0] == 0xff &&
+		    data[1] == 0xd8) {
+			gspca_frame_add(gspca_dev, LAST_PACKET,
+					NULL, 0);
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+					sd->jpeg_hdr, JPEG_HDR_SZ);
+			/* Strip the ff d8, our own header (which adds
+			   huffman and quantization tables) already has this */
+			len -= 2;
+			data += 2;
+		}
+	} else {
+		/* In UYVY mode an empty packet signals EOF */
+		if (gspca_dev->empty_packet) {
+			gspca_frame_add(gspca_dev, LAST_PACKET,
+						NULL, 0);
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+					NULL, 0);
+			gspca_dev->empty_packet = 0;
+		}
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 49c3c1226e0e..69e5dc4fc9de 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -61,17 +61,18 @@ struct sd {
 #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
+#define SENSOR_MI0360SOC 9
+#define SENSOR_OV7620 10
+/*#define SENSOR_OV7648 10 - same values */
+#define SENSOR_OV7630C 11
+#define SENSOR_PAS106 12
+#define SENSOR_PAS202B 13
+#define SENSOR_PB0330 14	/* (MI0360) */
+#define SENSOR_PO2030 15
+#define SENSOR_TAS5130CK 16
+#define SENSOR_TAS5130CXX 17
+#define SENSOR_TAS5130C_VF0250 18
+#define SENSOR_MAX 19
 	unsigned short chip_revision;
 
 	u8 *jpeg_hdr;
@@ -420,9 +421,7 @@ static const struct usb_action adcm2700_NoFliker[] = {
 	{0xaa, 0xfe, 0x0010},				/* 00,fe,10,aa */
 	{}
 };
-static const struct usb_action cs2102_Initial[] = {
-	{0xa1, 0x01, 0x0008},
-	{0xa1, 0x01, 0x0008},
+static const struct usb_action cs2102_Initial[] = {	/* 320x240 */
 	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
 	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
 	{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
@@ -471,88 +470,10 @@ static const struct usb_action cs2102_Initial[] = {
 	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
 	{0xa0, 0x68, ZC3XX_R18D_YTARGET},
 	{0xa0, 0x00, 0x01ad},
-	{0xa1, 0x01, 0x0002},
-	{0xa1, 0x01, 0x0008},
-	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
-	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
-	{0xa1, 0x01, 0x01c8},
-	{0xa1, 0x01, 0x01c9},
-	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
-	{0xa0, 0x24, ZC3XX_R120_GAMMA00},	/* gamma 5 */
-	{0xa0, 0x44, ZC3XX_R121_GAMMA01},
-	{0xa0, 0x64, ZC3XX_R122_GAMMA02},
-	{0xa0, 0x84, ZC3XX_R123_GAMMA03},
-	{0xa0, 0x9d, ZC3XX_R124_GAMMA04},
-	{0xa0, 0xb2, ZC3XX_R125_GAMMA05},
-	{0xa0, 0xc4, ZC3XX_R126_GAMMA06},
-	{0xa0, 0xd3, ZC3XX_R127_GAMMA07},
-	{0xa0, 0xe0, ZC3XX_R128_GAMMA08},
-	{0xa0, 0xeb, ZC3XX_R129_GAMMA09},
-	{0xa0, 0xf4, ZC3XX_R12A_GAMMA0A},
-	{0xa0, 0xfb, ZC3XX_R12B_GAMMA0B},
-	{0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
-	{0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
-	{0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
-	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
-	{0xa0, 0x18, ZC3XX_R130_GAMMA10},
-	{0xa0, 0x20, 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, 0x0e, ZC3XX_R137_GAMMA17},
-	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
-	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
-	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
-	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
-	{0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
-	{0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
-	{0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
-	{0xa0, 0x01, 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},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-	{0xaa, 0x23, 0x0001},
-	{0xaa, 0x24, 0x0055},
-	{0xaa, 0x25, 0x00cc},
-	{0xaa, 0x21, 0x003f},
-	{0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH},
-	{0xa0, 0xab, ZC3XX_R191_EXPOSURELIMITMID},
-	{0xa0, 0x98, ZC3XX_R192_EXPOSURELIMITLOW},
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
-	{0xa0, 0x30, ZC3XX_R196_ANTIFLICKERMID},
-	{0xa0, 0xd4, ZC3XX_R197_ANTIFLICKERLOW},
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
-	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
-	{0xa0, 0x39, ZC3XX_R01D_HSYNC_0},
-	{0xa0, 0x70, ZC3XX_R01E_HSYNC_1},
-	{0xa0, 0xb0, ZC3XX_R01F_HSYNC_2},
-	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
-	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x40, ZC3XX_R116_RGAIN},
-	{0xa0, 0x40, ZC3XX_R117_GGAIN},
-	{0xa0, 0x40, ZC3XX_R118_BGAIN},
 	{}
 };
 
-static const struct usb_action cs2102_InitialScale[] = {
-	{0xa1, 0x01, 0x0008},
-	{0xa1, 0x01, 0x0008},
+static const struct usb_action cs2102_InitialScale[] = {	/* 640x480 */
 	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
 	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
 	{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
@@ -601,57 +522,75 @@ static const struct usb_action cs2102_InitialScale[] = {
 	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
 	{0xa0, 0x68, ZC3XX_R18D_YTARGET},
 	{0xa0, 0x00, 0x01ad},
-	{0xa1, 0x01, 0x0002},
-	{0xa1, 0x01, 0x0008},
-	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
-	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
-	{0xa1, 0x01, 0x01c8},
-	{0xa1, 0x01, 0x01c9},
-	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
-	{0xa0, 0x24, ZC3XX_R120_GAMMA00},	/* gamma 5 */
-	{0xa0, 0x44, ZC3XX_R121_GAMMA01},
-	{0xa0, 0x64, ZC3XX_R122_GAMMA02},
-	{0xa0, 0x84, ZC3XX_R123_GAMMA03},
-	{0xa0, 0x9d, ZC3XX_R124_GAMMA04},
-	{0xa0, 0xb2, ZC3XX_R125_GAMMA05},
-	{0xa0, 0xc4, ZC3XX_R126_GAMMA06},
-	{0xa0, 0xd3, ZC3XX_R127_GAMMA07},
-	{0xa0, 0xe0, ZC3XX_R128_GAMMA08},
-	{0xa0, 0xeb, ZC3XX_R129_GAMMA09},
-	{0xa0, 0xf4, ZC3XX_R12A_GAMMA0A},
-	{0xa0, 0xfb, ZC3XX_R12B_GAMMA0B},
-	{0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
-	{0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
-	{0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
-	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
-	{0xa0, 0x18, ZC3XX_R130_GAMMA10},
-	{0xa0, 0x20, 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, 0x0e, ZC3XX_R137_GAMMA17},
-	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
-	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
-	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
-	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
-	{0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
-	{0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
-	{0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
-	{0xa0, 0x01, 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},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+static const struct usb_action cs2102_50HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x23, 0x0001},
+	{0xaa, 0x24, 0x005f},
+	{0xaa, 0x25, 0x0090},
+	{0xaa, 0x21, 0x00dd},
+	{0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0xbf, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x3a, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x98, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xdd, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xe4, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf0, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{}
+};
+static const struct usb_action cs2102_50HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x23, 0x0000},
+	{0xaa, 0x24, 0x00af},
+	{0xaa, 0x25, 0x00c8},
+	{0xaa, 0x21, 0x0068},
+	{0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x5f, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x90, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x1d, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x4c, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x68, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xe3, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf0, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{}
+};
+static const struct usb_action cs2102_60HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x23, 0x0001},
+	{0xaa, 0x24, 0x0055},
+	{0xaa, 0x25, 0x00cc},
+	{0xaa, 0x21, 0x003f},
+	{0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0xab, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x98, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x30, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0xd4, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x39, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x70, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xb0, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{}
+};
+static const struct usb_action cs2102_60HZScale[] = {
 	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
 	{0xaa, 0x23, 0x0000},
 	{0xaa, 0x24, 0x00aa},
@@ -671,162 +610,50 @@ static const struct usb_action cs2102_InitialScale[] = {
 	{0xa0, 0xa5, ZC3XX_R01E_HSYNC_1},
 	{0xa0, 0xf0, ZC3XX_R01F_HSYNC_2},
 	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
-	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x40, ZC3XX_R116_RGAIN},
-	{0xa0, 0x40, ZC3XX_R117_GGAIN},
-	{0xa0, 0x40, ZC3XX_R118_BGAIN},
-	{}
-};
-static const struct usb_action cs2102_50HZ[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xaa, 0x0f, 0x008c}, /* 00,0f,8c,aa */
-	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
-	{0xaa, 0x04, 0x00ac}, /* 00,04,ac,aa */
-	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
-	{0xaa, 0x11, 0x00ac}, /* 00,11,ac,aa */
-	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
-	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
-	{0xaa, 0x1d, 0x00ac}, /* 00,1d,ac,aa */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
-	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x42, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,42,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
-	{0xa0, 0x8c, ZC3XX_R01D_HSYNC_0}, /* 00,1d,8c,cc */
-	{0xa0, 0xb0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,b0,cc */
-	{0xa0, 0xd0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,d0,cc */
-	{}
-};
-static const struct usb_action cs2102_50HZScale[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xaa, 0x0f, 0x0093}, /* 00,0f,93,aa */
-	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
-	{0xaa, 0x04, 0x00a1}, /* 00,04,a1,aa */
-	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
-	{0xaa, 0x11, 0x00a1}, /* 00,11,a1,aa */
-	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
-	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
-	{0xaa, 0x1d, 0x00a1}, /* 00,1d,a1,aa */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
-	{0xa0, 0xf7, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f7,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
-	{0xa0, 0x93, ZC3XX_R01D_HSYNC_0}, /* 00,1d,93,cc */
-	{0xa0, 0xb0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,b0,cc */
-	{0xa0, 0xd0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,d0,cc */
-	{}
-};
-static const struct usb_action cs2102_60HZ[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xaa, 0x0f, 0x005d}, /* 00,0f,5d,aa */
-	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
-	{0xaa, 0x04, 0x00aa}, /* 00,04,aa,aa */
-	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
-	{0xaa, 0x11, 0x00aa}, /* 00,11,aa,aa */
-	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
-	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
-	{0xaa, 0x1d, 0x00aa}, /* 00,1d,aa,aa */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
-	{0xa0, 0xe4, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e4,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3a,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
-	{0xa0, 0x5d, ZC3XX_R01D_HSYNC_0}, /* 00,1d,5d,cc */
-	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
-	{0xa0, 0xd0, 0x00c8}, /* 00,c8,d0,cc */
-	{}
-};
-static const struct usb_action cs2102_60HZScale[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xaa, 0x0f, 0x00b7}, /* 00,0f,b7,aa */
-	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
-	{0xaa, 0x04, 0x00be}, /* 00,04,be,aa */
-	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
-	{0xaa, 0x11, 0x00be}, /* 00,11,be,aa */
-	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
-	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
-	{0xaa, 0x1d, 0x00be}, /* 00,1d,be,aa */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
-	{0xa0, 0xfc, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,fc,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x69, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,69,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
-	{0xa0, 0xb7, ZC3XX_R01D_HSYNC_0}, /* 00,1d,b7,cc */
-	{0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
-	{0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */
 	{}
 };
 static const struct usb_action cs2102_NoFliker[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */
-	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
-	{0xaa, 0x04, 0x0080}, /* 00,04,80,aa */
-	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
-	{0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
-	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
-	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
-	{0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
-	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
-	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
-	{0xa0, 0x59, ZC3XX_R01D_HSYNC_0}, /* 00,1d,59,cc */
-	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
-	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x23, 0x0001},
+	{0xaa, 0x24, 0x005f},
+	{0xaa, 0x25, 0x0000},
+	{0xaa, 0x21, 0x0001},
+	{0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0xbf, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x80, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x01, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x40, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xa0, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
 	{}
 };
 static const struct usb_action cs2102_NoFlikerScale[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */
-	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
-	{0xaa, 0x04, 0x0080}, /* 00,04,80,aa */
-	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
-	{0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
-	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
-	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
-	{0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
-	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
-	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
-	{0xa0, 0x59, ZC3XX_R01D_HSYNC_0}, /* 00,1d,59,cc */
-	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
-	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x23, 0x0000},
+	{0xaa, 0x24, 0x00af},
+	{0xaa, 0x25, 0x0080},
+	{0xaa, 0x21, 0x0001},
+	{0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x5f, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x80, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x01, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x40, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xa0, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
 	{}
 };
 
@@ -4409,170 +4236,80 @@ static const struct usb_action pas202b_NoFlikerScale[] = {
 	{}
 };
 
-static const struct usb_action pb03303x_Initial[] = {
+/* mi0360soc and pb0330 from vm30x.inf for 0ac8:301b and 0ac8:303b 07/02/13 */
+static const struct usb_action mi0360soc_Initial[] = {	/* 640x480 */
 	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
 	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
 	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
-	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
 	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
 	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
 	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
 	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
-	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},	/* 8b -> dc */
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
 	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
-	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
-	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},	/*jfm: was 03*/
+/*	{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, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xdd, 0x00, 0x0200},
 	{0xaa, 0x01, 0x0001},
 	{0xaa, 0x06, 0x0000},
 	{0xaa, 0x08, 0x0483},
 	{0xaa, 0x01, 0x0004},
 	{0xaa, 0x08, 0x0006},
 	{0xaa, 0x02, 0x0011},
-	{0xaa, 0x03, 0x01e7},
-	{0xaa, 0x04, 0x0287},
+	{0xaa, 0x03, 0x01e5},			/*jfm: was 01e7*/
+	{0xaa, 0x04, 0x0285},			/*jfm: was 0287*/
 	{0xaa, 0x07, 0x3002},
-	{0xaa, 0x20, 0x1100},
-	{0xaa, 0x35, 0x0050},
+	{0xaa, 0x20, 0x5100},			/*jfm: was 1100*/
+	{0xaa, 0x35, 0x507f},			/*jfm: was 0050*/
 	{0xaa, 0x30, 0x0005},
 	{0xaa, 0x31, 0x0000},
 	{0xaa, 0x58, 0x0078},
 	{0xaa, 0x62, 0x0411},
 	{0xaa, 0x2b, 0x0028},
-	{0xaa, 0x2c, 0x0030},
-	{0xaa, 0x2d, 0x0030},
-	{0xaa, 0x2e, 0x0028},
+	{0xaa, 0x2c, 0x007f},			/*jfm: was 0030*/
+	{0xaa, 0x2d, 0x007f},			/*jfm: was 0030*/
+	{0xaa, 0x2e, 0x007f},			/*jfm: was 0030*/
 	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
-	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /*jfm: was 37*/
 	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
 	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
 	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
-	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x09, 0x01ad},			/*jfm: was 00*/
 	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
 	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
 	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
 	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
 	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
-	{0xa0, 0x78, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x6c, ZC3XX_R18D_YTARGET},	/* jfm: was 78 */
 	{0xa0, 0x61, ZC3XX_R116_RGAIN},
 	{0xa0, 0x65, ZC3XX_R118_BGAIN},
-
-	{0xa1, 0x01, 0x0002},
-	{0xa0, 0x09, 0x01ad},
-	{0xa0, 0x15, 0x01ae},
-	{0xa0, 0x0d, 0x003a},
-	{0xa0, 0x02, 0x003b},
-	{0xa0, 0x00, 0x0038},
-	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
-	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
-	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
-	{0xa0, 0x50, ZC3XX_R10E_RGB11},
-	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
-	{0xa0, 0xf8, ZC3XX_R110_RGB20},
-	{0xa0, 0xf8, ZC3XX_R111_RGB21},
-	{0xa0, 0x50, ZC3XX_R112_RGB22},
-
-	{0xa1, 0x01, 0x0008},
-	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
-	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},
-	{0xa1, 0x01, 0x01c8},
-	{0xa1, 0x01, 0x01c9},
-	{0xa1, 0x01, 0x01ca},
-	{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, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
-	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
-	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
-	{0xa0, 0x50, ZC3XX_R10E_RGB11},
-	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
-	{0xa0, 0xf8, ZC3XX_R110_RGB20},
-	{0xa0, 0xf8, ZC3XX_R111_RGB21},
-	{0xa0, 0x50, ZC3XX_R112_RGB22},
-
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-	{0xaa, 0x05, 0x0009},
-	{0xaa, 0x09, 0x0134},
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
-	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
-	{0xa0, 0xec, ZC3XX_R192_EXPOSURELIMITLOW},
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
-	{0xa0, 0x9c, ZC3XX_R197_ANTIFLICKERLOW},
-	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
-	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
-	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
-	{0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
-	{0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
-	{0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
-	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
-	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x09, 0x01ad},
-	{0xa0, 0x15, 0x01ae},
-	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
 	{}
 };
-
-static const struct usb_action pb03303x_InitialScale[] = {
+static const struct usb_action mi0360soc_InitialScale[] = {	/* 320x240 */
 	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
 	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
 	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
-	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
 	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
 	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
 	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
 	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
-	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},	/* 8b -> dc */
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
 	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
-	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
-	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},	/*jfm: was 03*/
+/*	{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, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xdd, 0x00, 0x0200},
 	{0xaa, 0x01, 0x0001},
 	{0xaa, 0x06, 0x0000},
 	{0xaa, 0x08, 0x0483},
@@ -4582,111 +4319,111 @@ static const struct usb_action pb03303x_InitialScale[] = {
 	{0xaa, 0x03, 0x01e7},
 	{0xaa, 0x04, 0x0287},
 	{0xaa, 0x07, 0x3002},
-	{0xaa, 0x20, 0x1100},
-	{0xaa, 0x35, 0x0050},
+	{0xaa, 0x20, 0x5100},			/*jfm: was 1100*/
+	{0xaa, 0x35, 0x007f},			/*jfm: was 0050*/
 	{0xaa, 0x30, 0x0005},
 	{0xaa, 0x31, 0x0000},
 	{0xaa, 0x58, 0x0078},
 	{0xaa, 0x62, 0x0411},
-	{0xaa, 0x2b, 0x0028},
-	{0xaa, 0x2c, 0x0030},
-	{0xaa, 0x2d, 0x0030},
-	{0xaa, 0x2e, 0x0028},
+	{0xaa, 0x2b, 0x007f},			/*jfm: was 28*/
+	{0xaa, 0x2c, 0x007f},			/*jfm: was 30*/
+	{0xaa, 0x2d, 0x007f},			/*jfm: was 30*/
+	{0xaa, 0x2e, 0x007f},			/*jfm: was 28*/
 	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
-	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},	/*jfm: was 37*/
 	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
 	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
 	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
-	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x09, 0x01ad},			/*jfm: was 00*/
 	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
 	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
 	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
 	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
 	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
-	{0xa0, 0x78, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x6c, ZC3XX_R18D_YTARGET},	/*jfm: was 78*/
 	{0xa0, 0x61, ZC3XX_R116_RGAIN},
 	{0xa0, 0x65, ZC3XX_R118_BGAIN},
-
-	{0xa1, 0x01, 0x0002},
-
-	{0xa0, 0x09, 0x01ad},
-	{0xa0, 0x15, 0x01ae},
-
-	{0xa0, 0x0d, 0x003a},
-	{0xa0, 0x02, 0x003b},
-	{0xa0, 0x00, 0x0038},
-	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
-	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
-	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
-	{0xa0, 0x50, ZC3XX_R10E_RGB11},
-	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
-	{0xa0, 0xf8, ZC3XX_R110_RGB20},
-	{0xa0, 0xf8, ZC3XX_R111_RGB21},
-	{0xa0, 0x50, ZC3XX_R112_RGB22},
-
-	{0xa1, 0x01, 0x0008},
-	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
-	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
-	{0xa1, 0x01, 0x01c8},
-	{0xa1, 0x01, 0x01c9},
-	{0xa1, 0x01, 0x01ca},
-	{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, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
-	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
-	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
-	{0xa0, 0x50, ZC3XX_R10E_RGB11},
-	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
-	{0xa0, 0xf8, ZC3XX_R110_RGB20},
-	{0xa0, 0xf8, ZC3XX_R111_RGB21},
-	{0xa0, 0x50, ZC3XX_R112_RGB22},
-
-	{0xa1, 0x01, 0x0180},
+	{}
+};
+static const struct usb_action mi360soc_AE50HZ[] = {
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x0562},
+	{0xbb, 0x01, 0x09aa},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x9b, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+static const struct usb_action mi360soc_AE50HZScale[] = {
 	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x0509},
+	{0xbb, 0x01, 0x0934},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+static const struct usb_action mi360soc_AE60HZ[] = {
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x053d},
+	{0xbb, 0x01, 0x096e},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xdd, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+static const struct usb_action mi360soc_AE60HZScale[] = {
 	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
 	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-	{0xaa, 0x05, 0x0009},
-	{0xaa, 0x09, 0x0134},
+	{0xbb, 0x00, 0x0509},
+	{0xbb, 0x01, 0x0983},
 	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
 	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
-	{0xa0, 0xec, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x8f, ZC3XX_R192_EXPOSURELIMITLOW},
 	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
 	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
-	{0xa0, 0x9c, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW},
 	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
 	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
 	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
@@ -4696,20 +4433,60 @@ static const struct usb_action pb03303x_InitialScale[] = {
 	{0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
 	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
 	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x09, 0x01ad},
-	{0xa0, 0x15, 0x01ae},
-	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0180},
+	{}
+};
+static const struct usb_action mi360soc_AENoFliker[] = {
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x0509},
+	{0xbb, 0x01, 0x0960},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x09, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x40, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xe0, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
 	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
 	{}
 };
-static const struct usb_action pb0330xx_Initial[] = {
-	{0xa1, 0x01, 0x0008},
-	{0xa1, 0x01, 0x0008},
+static const struct usb_action mi360soc_AENoFlikerScale[] = {
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x0534},
+	{0xbb, 0x02, 0x0960},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x34, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x60, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xe0, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+
+static const struct usb_action pb0330_Initial[] = {	/* 640x480 */
 	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
 	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
 	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
-	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
 	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
 	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
 	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
@@ -4721,11 +4498,12 @@ static const struct usb_action pb0330xx_Initial[] = {
 	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
 	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
 	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xdd, 0x00, 0x0200},
 	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
 	{0xaa, 0x01, 0x0006},
 	{0xaa, 0x02, 0x0011},
-	{0xaa, 0x03, 0x01e7},
-	{0xaa, 0x04, 0x0287},
+	{0xaa, 0x03, 0x01e5},			/*jfm: was 1e7*/
+	{0xaa, 0x04, 0x0285},			/*jfm: was 0287*/
 	{0xaa, 0x06, 0x0003},
 	{0xaa, 0x07, 0x3002},
 	{0xaa, 0x20, 0x1100},
@@ -4743,88 +4521,21 @@ static const struct usb_action pb0330xx_Initial[] = {
 	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
 	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
 	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
-	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x09, 0x01ad},			/*jfm: was 00 */
+	{0xa0, 0x15, 0x01ae},
 	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
 	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
 	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
 	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
 	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
-	{0xa0, 0x6c, ZC3XX_R18D_YTARGET},
-	{0xa1, 0x01, 0x0002},
-	{0xa0, 0x09, 0x01ad},
-	{0xa0, 0x15, 0x01ae},
-	{0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
-	{0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
-	{0xa1, 0x01, 0x0091},
-	{0xa1, 0x01, 0x0095},
-	{0xa1, 0x01, 0x0096},
-	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
-	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
-	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
-	{0xa0, 0x50, ZC3XX_R10E_RGB11},
-	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
-	{0xa0, 0xf8, ZC3XX_R110_RGB20},
-	{0xa0, 0xf8, ZC3XX_R111_RGB21},
-	{0xa0, 0x50, ZC3XX_R112_RGB22},
-	{0xa1, 0x01, 0x0008},
-	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
-	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
-	{0xa1, 0x01, 0x01c8},
-	{0xa1, 0x01, 0x01c9},
-	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
-
-	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
-	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
-	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
-	{0xa0, 0x50, ZC3XX_R10E_RGB11},
-	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
-	{0xa0, 0xf8, ZC3XX_R110_RGB20},
-	{0xa0, 0xf8, ZC3XX_R111_RGB21},
-	{0xa0, 0x50, ZC3XX_R112_RGB22},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-	{0xaa, 0x05, 0x0066},
-	{0xaa, 0x09, 0x02b2},
-	{0xaa, 0x10, 0x0002},
-
-	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
-	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
-	{0xa0, 0x8c, ZC3XX_R192_EXPOSURELIMITLOW},
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
-	{0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW},
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
-	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
-	{0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
-	{0xa0, 0xf0, ZC3XX_R01E_HSYNC_1},
-	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2},
-	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
-	{0xa0, 0x09, 0x01ad},
-	{0xa0, 0x15, 0x01ae},
-	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0008},
-	{0xa1, 0x01, 0x0007},
-/*	{0xa0, 0x30, 0x0007}, */
-/*	{0xa0, 0x00, 0x0007}, */
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},	/*jfm: was 6c*/
 	{}
 };
-
-static const struct usb_action pb0330xx_InitialScale[] = {
-	{0xa1, 0x01, 0x0008},
-	{0xa1, 0x01, 0x0008},
+static const struct usb_action pb0330_InitialScale[] = {	/* 320x240 */
 	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
 	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
 	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
-	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},	/* 10 */
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
 	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
 	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
 	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
@@ -4836,6 +4547,7 @@ static const struct usb_action pb0330xx_InitialScale[] = {
 	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
 	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
 	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xdd, 0x00, 0x0200},
 	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
 	{0xaa, 0x01, 0x0006},
 	{0xaa, 0x02, 0x0011},
@@ -4858,53 +4570,43 @@ static const struct usb_action pb0330xx_InitialScale[] = {
 	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
 	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
 	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
-	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
 	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
 	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
 	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
 	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
 	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
-	{0xa0, 0x6c, ZC3XX_R18D_YTARGET},
-	{0xa1, 0x01, 0x0002},
-	{0xa0, 0x09, 0x01ad},
-	{0xa0, 0x15, 0x01ae},
-	{0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
-	{0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
-	{0xa1, 0x01, 0x0091},
-	{0xa1, 0x01, 0x0095},
-	{0xa1, 0x01, 0x0096},
-	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
-	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
-	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
-	{0xa0, 0x50, ZC3XX_R10E_RGB11},
-	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
-	{0xa0, 0xf8, ZC3XX_R110_RGB20},
-	{0xa0, 0xf8, ZC3XX_R111_RGB21},
-	{0xa0, 0x50, ZC3XX_R112_RGB22},
-	{0xa1, 0x01, 0x0008},
-	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
-	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
-	{0xa1, 0x01, 0x01c8},
-	{0xa1, 0x01, 0x01c9},
-	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
-
-	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
-	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
-	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
-	{0xa0, 0x50, ZC3XX_R10E_RGB11},
-	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
-	{0xa0, 0xf8, ZC3XX_R110_RGB20},
-	{0xa0, 0xf8, ZC3XX_R111_RGB21},
-	{0xa0, 0x50, ZC3XX_R112_RGB22},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},	/*jfm: was 6c*/
+	{}
+};
+static const struct usb_action pb0330_50HZ[] = {
 	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-	{0xaa, 0x05, 0x0066},
-	{0xaa, 0x09, 0x02b2},
-	{0xaa, 0x10, 0x0002},
+	{0xbb, 0x00, 0x055c},
+	{0xbb, 0x01, 0x09aa},
+	{0xbb, 0x00, 0x1001},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xc4, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x5c, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{}
+};
+static const struct usb_action pb0330_50HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x0566},
+	{0xbb, 0x02, 0x09b2},
+	{0xbb, 0x00, 0x1002},
 	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
 	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
 	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
@@ -4912,124 +4614,102 @@ static const struct usb_action pb0330xx_InitialScale[] = {
 	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
 	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
 	{0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW},
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE},
 	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
 	{0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
 	{0xa0, 0xf0, ZC3XX_R01E_HSYNC_1},
 	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2},
 	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
-	{0xa0, 0x09, 0x01ad},
-	{0xa0, 0x15, 0x01ae},
-	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0008},
-	{0xa1, 0x01, 0x0007},
-/*	{0xa0, 0x30, 0x0007}, */
-/*	{0xa0, 0x00, 0x0007}, */
-	{}
-};
-static const struct usb_action pb0330_50HZ[] = {
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
-	{0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,ee,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x46, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,46,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
-	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
-	{0xa0, 0x68, ZC3XX_R01D_HSYNC_0}, /* 00,1d,68,cc */
-	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
-	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
-	{}
-};
-static const struct usb_action pb0330_50HZScale[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
-	{0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,a0,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x7a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7a,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
-	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
-	{0xa0, 0xe5, ZC3XX_R01D_HSYNC_0}, /* 00,1d,e5,cc */
-	{0xa0, 0xf0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f0,cc */
-	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */
 	{}
 };
 static const struct usb_action pb0330_60HZ[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
-	{0xa0, 0xdd, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,dd,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3d,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
-	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
-	{0xa0, 0x43, ZC3XX_R01D_HSYNC_0}, /* 00,1d,43,cc */
-	{0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */
-	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x0535},
+	{0xbb, 0x01, 0x0974},
+	{0xbb, 0x00, 0x1001},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xfe, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x3e, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x35, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x50, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xd0, ZC3XX_R020_HSYNC_3},
 	{}
 };
 static const struct usb_action pb0330_60HZScale[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
-	{0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,a0,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x7a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7a,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
-	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
-	{0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, /* 00,1d,41,cc */
-	{0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */
-	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x0535},
+	{0xbb, 0x02, 0x096c},
+	{0xbb, 0x00, 0x1002},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xc0, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x7c, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x35, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x50, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xd0, ZC3XX_R020_HSYNC_3},
 	{}
 };
 static const struct usb_action pb0330_NoFliker[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
-	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
-	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
-	{0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, /* 00,1d,09,cc */
-	{0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */
-	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x0509},
+	{0xbb, 0x02, 0x0940},
+	{0xbb, 0x00, 0x1002},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x09, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x40, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xe0, ZC3XX_R020_HSYNC_3},
 	{}
 };
 static const struct usb_action pb0330_NoFlikerScale[] = {
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
-	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},	/* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},	/* 01,8f,20,cc */
-	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
-	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
-	{0xa0, 0x09, ZC3XX_R01D_HSYNC_0},	/* 00,1d,09,cc */
-	{0xa0, 0x40, ZC3XX_R01E_HSYNC_1},	/* 00,1e,40,cc */
-	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2},	/* 00,1f,90,cc */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xbb, 0x00, 0x0535},
+	{0xbb, 0x01, 0x0980},
+	{0xbb, 0x00, 0x1001},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x35, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x60, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xe0, ZC3XX_R020_HSYNC_3},
 	{}
 };
 
@@ -5655,7 +5335,7 @@ static const struct usb_action tas5130CK_InitialScale[] = {
 	{}
 };
 
-static const struct usb_action tas5130cxx_Initial[] = {
+static const struct usb_action tas5130cxx_InitialScale[] = {	/* 320x240 */
 	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
 	{0xa0, 0x50, ZC3XX_R002_CLOCKSELECT},
 	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -5684,74 +5364,19 @@ static const struct usb_action tas5130cxx_Initial[] = {
 	{0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
 	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
 	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
-	{0xa0, 0x68, ZC3XX_R18D_YTARGET},
-	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x95, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN},
 	{0xa0, 0x00, 0x01ad},
 	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
 	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
 	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
 	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
-	{0xa1, 0x01, 0x0002},
-	{0xa1, 0x01, 0x0008},
-	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
-	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
-	{0xa1, 0x01, 0x01c8},
-	{0xa1, 0x01, 0x01c9},
-	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
-
-	{0xa0, 0x68, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xec, ZC3XX_R10B_RGB01},
-	{0xa0, 0xec, ZC3XX_R10C_RGB02},
-	{0xa0, 0xec, ZC3XX_R10D_RGB10},
-	{0xa0, 0x68, ZC3XX_R10E_RGB11},
-	{0xa0, 0xec, ZC3XX_R10F_RGB12},
-	{0xa0, 0xec, ZC3XX_R110_RGB20},
-	{0xa0, 0xec, ZC3XX_R111_RGB21},
-	{0xa0, 0x68, ZC3XX_R112_RGB22},
-
-	{0xa1, 0x01, 0x018d},
-	{0xa0, 0x90, ZC3XX_R18D_YTARGET},	/* 90 */
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-
-	{0xaa, 0xa3, 0x0001},
-	{0xaa, 0xa4, 0x0077},
-	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
-	{0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW},
-
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 00 */
-	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},	/* 03 */
-	{0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW},	/* e8 */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 0 */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 0 */
-	{0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW},	/* 7d */
-
-	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
-	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
-	{0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* 08 */
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},	/* 24 */
-	{0xa0, 0xf0, ZC3XX_R01D_HSYNC_0},
-	{0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
-	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2},
-	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
-	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH},
-	{0xa0, 0xc0, ZC3XX_R0A0_MAXXLOW},
-	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},	/* 50 */
-	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
 	{}
 };
-static const struct usb_action tas5130cxx_InitialScale[] = {
-/*??	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, */
+static const struct usb_action tas5130cxx_Initial[] = {	/* 640x480 */
 	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
 	{0xa0, 0x40, ZC3XX_R002_CLOCKSELECT},
-
 	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
-	{0xa1, 0x01, 0x0008},
-
 	{0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT},
 	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
 	{0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING},
@@ -5775,63 +5400,13 @@ static const struct usb_action tas5130cxx_InitialScale[] = {
 	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
 	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
 	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
-	{0xa0, 0x68, ZC3XX_R18D_YTARGET},
-	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x95, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN},
 	{0xa0, 0x00, 0x01ad},
 	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
 	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
 	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
 	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
-	{0xa1, 0x01, 0x0002},
-	{0xa1, 0x01, 0x0008},
-
-	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
-	{0xa1, 0x01, 0x0008},	/* clock ? */
-	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
-	{0xa1, 0x01, 0x01c8},
-	{0xa1, 0x01, 0x01c9},
-	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
-
-	{0xa0, 0x68, ZC3XX_R10A_RGB00},	/* matrix */
-	{0xa0, 0xec, ZC3XX_R10B_RGB01},
-	{0xa0, 0xec, ZC3XX_R10C_RGB02},
-	{0xa0, 0xec, ZC3XX_R10D_RGB10},
-	{0xa0, 0x68, ZC3XX_R10E_RGB11},
-	{0xa0, 0xec, ZC3XX_R10F_RGB12},
-	{0xa0, 0xec, ZC3XX_R110_RGB20},
-	{0xa0, 0xec, ZC3XX_R111_RGB21},
-	{0xa0, 0x68, ZC3XX_R112_RGB22},
-
-	{0xa1, 0x01, 0x018d},
-	{0xa0, 0x90, ZC3XX_R18D_YTARGET},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-	{0xaa, 0xa3, 0x0001},
-	{0xaa, 0xa4, 0x0063},
-	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
-	{0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW},
-	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
-	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
-	{0xa0, 0x38, ZC3XX_R192_EXPOSURELIMITLOW},
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
-	{0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW},
-	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
-	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
-	{0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF},
-	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
-	{0xa0, 0xd3, ZC3XX_R01D_HSYNC_0},
-	{0xa0, 0xda, ZC3XX_R01E_HSYNC_1},
-	{0xa0, 0xea, ZC3XX_R01F_HSYNC_2},
-	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
-	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH},
-	{0xa0, 0x4c, ZC3XX_R0A0_MAXXLOW},
-	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
-	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-	{0xa1, 0x01, 0x0180},
-	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
 	{}
 };
 static const struct usb_action tas5130cxx_50HZ[] = {
@@ -5841,20 +5416,22 @@ static const struct usb_action tas5130cxx_50HZ[] = {
 	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
 	{0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,63,cc */
 	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */
-	{0xa0, 0x38, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,38,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xfe, ZC3XX_R192_EXPOSURELIMITLOW},
 	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
 	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
 	{0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
-	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
 	{0xa0, 0xd3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,d3,cc */
 	{0xa0, 0xda, ZC3XX_R01E_HSYNC_1}, /* 00,1e,da,cc */
 	{0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */
 	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
 	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+	{0xa0, 0x4c, ZC3XX_R0A0_MAXXLOW},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
 	{}
 };
 static const struct usb_action tas5130cxx_50HZScale[] = {
@@ -5864,20 +5441,22 @@ static const struct usb_action tas5130cxx_50HZScale[] = {
 	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
 	{0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */
 	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */
-	{0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e8,cc */
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xd0, ZC3XX_R192_EXPOSURELIMITLOW},
 	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
 	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
 	{0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */
-	{0xa0, 0x14, ZC3XX_R18C_AEFREEZE}, /* 01,8c,14,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
-	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
 	{0xa0, 0xf0, ZC3XX_R01D_HSYNC_0}, /* 00,1d,f0,cc */
 	{0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f4,cc */
 	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */
 	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
 	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+	{0xa0, 0xc0, ZC3XX_R0A0_MAXXLOW},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
 	{}
 };
 static const struct usb_action tas5130cxx_60HZ[] = {
@@ -5887,20 +5466,22 @@ static const struct usb_action tas5130cxx_60HZ[] = {
 	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
 	{0xa0, 0x36, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,36,cc */
 	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,01,cc */
-	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+	{0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x54, ZC3XX_R192_EXPOSURELIMITLOW},
 	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
 	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
 	{0xa0, 0x3e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3e,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
-	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
 	{0xa0, 0xca, ZC3XX_R01D_HSYNC_0}, /* 00,1d,ca,cc */
 	{0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
 	{0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
 	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
 	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+	{0xa0, 0x28, ZC3XX_R0A0_MAXXLOW},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
 	{}
 };
 static const struct usb_action tas5130cxx_60HZScale[] = {
@@ -5910,20 +5491,22 @@ static const struct usb_action tas5130cxx_60HZScale[] = {
 	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
 	{0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */
 	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */
-	{0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e8,cc */
+	{0xa0, 0x09, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x47, ZC3XX_R192_EXPOSURELIMITLOW},
 	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
 	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
 	{0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */
-	{0xa0, 0x14, ZC3XX_R18C_AEFREEZE}, /* 01,8c,14,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
-	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
-	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
 	{0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */
 	{0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
 	{0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
 	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
 	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+	{0xa0, 0x20, ZC3XX_R0A0_MAXXLOW},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
 	{}
 };
 static const struct usb_action tas5130cxx_NoFliker[] = {
@@ -5933,13 +5516,13 @@ static const struct usb_action tas5130cxx_NoFliker[] = {
 	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
 	{0xa0, 0x40, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,40,cc */
 	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,01,cc */
-	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
 	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
 	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
 	{0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */
@@ -5947,6 +5530,8 @@ static const struct usb_action tas5130cxx_NoFliker[] = {
 	{0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
 	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
 	{0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */
+	{0xa0, 0xf0, ZC3XX_R0A0_MAXXLOW},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
 	{}
 };
 
@@ -5957,13 +5542,13 @@ static const struct usb_action tas5130cxx_NoFlikerScale[] = {
 	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
 	{0xa0, 0x90, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,90,cc */
 	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
-	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */
-	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
-	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
-	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
-	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
-	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
-	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0a, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
 	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
 	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
 	{0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */
@@ -5971,6 +5556,8 @@ static const struct usb_action tas5130cxx_NoFlikerScale[] = {
 	{0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
 	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
 	{0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */
+	{0xa0, 0xf0, ZC3XX_R0A0_MAXXLOW},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
 	{}
 };
 
@@ -6303,8 +5890,10 @@ static __u16 i2c_read(struct gspca_dev *gspca_dev,
 
 	reg_w_i(gspca_dev->dev, reg, 0x0092);
 	reg_w_i(gspca_dev->dev, 0x02, 0x0090);		/* <- read command */
-	msleep(25);
+	msleep(20);
 	retbyte = reg_r_i(gspca_dev, 0x0091);		/* read status */
+	if (retbyte != 0x00)
+		err("i2c_r status error %02x", retbyte);
 	retval = reg_r_i(gspca_dev, 0x0095);		/* read Lowbyte */
 	retval |= reg_r_i(gspca_dev, 0x0096) << 8;	/* read Hightbyte */
 	PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)",
@@ -6323,8 +5912,10 @@ static __u8 i2c_write(struct gspca_dev *gspca_dev,
 	reg_w_i(gspca_dev->dev, valL, 0x93);
 	reg_w_i(gspca_dev->dev, valH, 0x94);
 	reg_w_i(gspca_dev->dev, 0x01, 0x90);		/* <- write command */
-	msleep(15);
+	msleep(1);
 	retbyte = reg_r_i(gspca_dev, 0x0091);		/* read status */
+	if (retbyte != 0x00)
+		err("i2c_w status error %02x", retbyte);
 	PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)",
 			reg, valH, valL, retbyte);
 	return retbyte;
@@ -6359,7 +5950,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
 			break;
 		}
 		action++;
-/*		msleep(1); */
+		msleep(1);
 	}
 }
 
@@ -6380,11 +5971,13 @@ static void setmatrix(struct gspca_dev *gspca_dev)
 		{0x4c, 0xf5, 0xff, 0xf9, 0x51, 0xf5, 0xfb, 0xed, 0x5f};
 	static const __u8 po2030_matrix[9] =
 		{0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60};
+	static const u8 tas5130c_matrix[9] =
+		{0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68};
 	static const __u8 vf0250_matrix[9] =
 		{0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
 	static const __u8 *matrix_tb[SENSOR_MAX] = {
 		adcm2700_matrix, /* SENSOR_ADCM2700 0 */
-		NULL,		/* SENSOR_CS2102 1 */
+		ov7620_matrix,	/* SENSOR_CS2102 1 */
 		NULL,		/* SENSOR_CS2102K 2 */
 		gc0305_matrix,	/* SENSOR_GC0305 3 */
 		NULL,		/* SENSOR_HDCS2020b 4 */
@@ -6392,15 +5985,16 @@ static void setmatrix(struct gspca_dev *gspca_dev)
 		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 */
+		gc0305_matrix,	/* SENSOR_MI0360SOC 9 */
+		ov7620_matrix,	/* SENSOR_OV7620 10 */
+		NULL,		/* SENSOR_OV7630C 11 */
+		NULL,		/* SENSOR_PAS106 12 */
+		pas202b_matrix,	/* SENSOR_PAS202B 13 */
+		gc0305_matrix,	/* SENSOR_PB0330 14 */
+		po2030_matrix,	/* SENSOR_PO2030 15 */
+		NULL,		/* SENSOR_TAS5130CK 16 */
+		tas5130c_matrix, /* SENSOR_TAS5130CXX 17 */
+		vf0250_matrix,	/* SENSOR_TAS5130C_VF0250 18 */
 	};
 
 	matrix = matrix_tb[sd->sensor];
@@ -6640,39 +6234,43 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
 		{MC501CB_NoFliker, MC501CB_NoFlikerScale,
 		 MC501CB_50HZ, MC501CB_50HZScale,
 		 MC501CB_60HZ, MC501CB_60HZScale},
-/* SENSOR_OV7620 9 */
+/* SENSOR_MI0360SOC 9 */
+		{mi360soc_AENoFlikerScale, mi360soc_AENoFliker,
+		 mi360soc_AE50HZScale, mi360soc_AE50HZ,
+		 mi360soc_AE60HZScale, mi360soc_AE60HZ},
+/* SENSOR_OV7620 10 */
 		{OV7620_NoFliker, OV7620_NoFliker,
 		 OV7620_50HZ, OV7620_50HZ,
 		 OV7620_60HZ, OV7620_60HZ},
-/* SENSOR_OV7630C 10 */
+/* SENSOR_OV7630C 11 */
 		{NULL, NULL,
 		 NULL, NULL,
 		 NULL, NULL},
-/* SENSOR_PAS106 11 */
+/* SENSOR_PAS106 12 */
 		{pas106b_NoFliker, pas106b_NoFliker,
 		 pas106b_50HZ, pas106b_50HZ,
 		 pas106b_60HZ, pas106b_60HZ},
-/* SENSOR_PAS202B 12 */
+/* SENSOR_PAS202B 13 */
 		{pas202b_NoFlikerScale, pas202b_NoFliker,
 		 pas202b_50HZScale, pas202b_50HZ,
 		 pas202b_60HZScale, pas202b_60HZ},
-/* SENSOR_PB0330 13 */
-		{pb0330_NoFliker, pb0330_NoFlikerScale,
-		 pb0330_50HZ, pb0330_50HZScale,
-		 pb0330_60HZ, pb0330_60HZScale},
-/* SENSOR_PO2030 14 */
+/* SENSOR_PB0330 14 */
+		{pb0330_NoFlikerScale, pb0330_NoFliker,
+		 pb0330_50HZScale, pb0330_50HZ,
+		 pb0330_60HZScale, pb0330_60HZ},
+/* SENSOR_PO2030 15 */
 		{PO2030_NoFliker, PO2030_NoFliker,
 		 PO2030_50HZ, PO2030_50HZ,
 		 PO2030_60HZ, PO2030_60HZ},
-/* SENSOR_TAS5130CK 15 */
-		{tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
-		 tas5130cxx_50HZ, tas5130cxx_50HZScale,
-		 tas5130cxx_60HZ, tas5130cxx_60HZScale},
-/* SENSOR_TAS5130CXX 16 */
-		{tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
-		 tas5130cxx_50HZ, tas5130cxx_50HZScale,
-		 tas5130cxx_60HZ, tas5130cxx_60HZScale},
-/* SENSOR_TAS5130C_VF0250 17 */
+/* SENSOR_TAS5130CK 16 */
+		{tas5130cxx_NoFlikerScale, tas5130cxx_NoFliker,
+		 tas5130cxx_50HZScale, tas5130cxx_50HZ,
+		 tas5130cxx_60HZScale, tas5130cxx_60HZ},
+/* SENSOR_TAS5130CXX 17 */
+		{tas5130cxx_NoFlikerScale, tas5130cxx_NoFliker,
+		 tas5130cxx_50HZScale, tas5130cxx_50HZ,
+		 tas5130cxx_60HZScale, tas5130cxx_60HZ},
+/* SENSOR_TAS5130C_VF0250 18 */
 		{tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
 		 tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
 		 tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
@@ -6729,6 +6327,7 @@ static void send_unknown(struct usb_device *dev, int sensor)
 	case SENSOR_ADCM2700:
 	case SENSOR_GC0305:
 	case SENSOR_OV7620:
+	case SENSOR_MI0360SOC:
 	case SENSOR_PB0330:
 	case SENSOR_PO2030:
 		reg_w(dev, 0x0d, 0x003a);
@@ -6820,7 +6419,7 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev)
 	start_2wr_probe(dev, 0x0e);		/* PAS202BCB */
 	reg_w(dev, 0x08, 0x008d);
 	i2c_write(gspca_dev, 0x03, 0xaa, 0x00);
-	msleep(500);
+	msleep(50);
 	retword = i2c_read(gspca_dev, 0x03);
 	if (retword != 0)
 		return 0x0e;			/* PAS202BCB */
@@ -6863,7 +6462,8 @@ struct sensor_by_chipset_revision {
 	__u8 internal_sensor_id;
 };
 static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
-	{0xc001, 0x13},		/* MI0360 */
+	{0xc000, 0x12},		/* TAS5130C */
+	{0xc001, 0x13},		/* MI0360SOC */
 	{0xe001, 0x13},
 	{0x8001, 0x13},
 	{0x8000, 0x14},		/* CS2102K */
@@ -6963,7 +6563,6 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
 	reg_w(dev, 0x01, 0x0001);
 	reg_w(dev, 0xee, 0x008b);
 	reg_w(dev, 0x03, 0x0012);
-/*	msleep(150); */
 	reg_w(dev, 0x01, 0x0012);
 	reg_w(dev, 0x05, 0x0012);
 	retword = i2c_read(gspca_dev, 0x00) << 8;	/* ID 0 */
@@ -7025,7 +6624,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	int vga = 1;		/* 1: vga, 0: sif */
 	static const __u8 gamma[SENSOR_MAX] = {
 		4,	/* SENSOR_ADCM2700 0 */
-		5,	/* SENSOR_CS2102 1 */
+		4,	/* SENSOR_CS2102 1 */
 		5,	/* SENSOR_CS2102K 2 */
 		4,	/* SENSOR_GC0305 3 */
 		4,	/* SENSOR_HDCS2020b 4 */
@@ -7033,15 +6632,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
 		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 */
+		4,	/* SENSOR_MI0360SOC 9 */
+		3,	/* SENSOR_OV7620 10 */
+		4,	/* SENSOR_OV7630C 11 */
+		4,	/* SENSOR_PAS106 12 */
+		4,	/* SENSOR_PAS202B 13 */
+		4,	/* SENSOR_PB0330 14 */
+		4,	/* SENSOR_PO2030 15 */
+		4,	/* SENSOR_TAS5130CK 16 */
+		3,	/* SENSOR_TAS5130CXX 17 */
+		3,	/* SENSOR_TAS5130C_VF0250 18 */
 	};
 
 	/* define some sensors from the vendor/product */
@@ -7103,7 +6703,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 			break;
 		case 0x10:
 		case 0x12:
-			PDEBUG(D_PROBE, "Find Sensor TAS5130");
+			PDEBUG(D_PROBE, "Find Sensor TAS5130C");
 			sd->sensor = SENSOR_TAS5130CXX;
 			break;
 		case 0x11:
@@ -7112,9 +6712,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
 			break;
 		case 0x13:
 			PDEBUG(D_PROBE,
-				"Find Sensor MI0360. Chip revision %x",
+				"Find Sensor MI0360SOC. Chip revision %x",
 				sd->chip_revision);
-			sd->sensor = SENSOR_PB0330;
+			sd->sensor = SENSOR_MI0360SOC;
 			break;
 		case 0x14:
 			PDEBUG(D_PROBE,
@@ -7228,17 +6828,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		{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},			/* 14 */
-		{tas5130CK_InitialScale, tas5130CK_Initial},	/* 15 */
-		{tas5130cxx_InitialScale, tas5130cxx_Initial},	/* 16 */
+		{mi0360soc_Initial, mi0360soc_InitialScale},	/* 9 */
+		{OV7620_mode0, OV7620_mode1},			/* 10 */
+		{ov7630c_InitialScale, ov7630c_Initial},	/* 11 */
+		{pas106b_InitialScale, pas106b_Initial},	/* 12 */
+		{pas202b_Initial, pas202b_InitialScale},	/* 13 */
+		{pb0330_Initial, pb0330_InitialScale},		/* 14 */
+		{PO2030_mode0, PO2030_mode1},			/* 15 */
+		{tas5130CK_InitialScale, tas5130CK_Initial},	/* 16 */
+		{tas5130cxx_Initial, tas5130cxx_InitialScale},	/* 17 */
 		{tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial},
-								/* 17 */
+								/* 18 */
 	};
 
 	/* create the JPEG header */
@@ -7258,19 +6858,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
 	case SENSOR_PAS106:
 		usb_exchange(gspca_dev, pas106b_Initial_com);
 		break;
-	case SENSOR_PB0330:
-		if (mode) {
-			if (sd->chip_revision == 0xc001
-			    || sd->chip_revision == 0xe001
-			    || sd->chip_revision == 0x8001)
-				zc3_init = pb03303x_Initial;
-		} else {
-			if (sd->chip_revision == 0xc001
-			    || sd->chip_revision == 0xe001
-			    || sd->chip_revision == 0x8001)
-				zc3_init = pb03303x_InitialScale;
-		}
-		break;
 	}
 	usb_exchange(gspca_dev, zc3_init);
 
@@ -7310,10 +6897,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 	/* set the gamma tables when not set */
 	switch (sd->sensor) {
-	case SENSOR_CS2102:		/* gamma set in xxx_Initial */
-	case SENSOR_CS2102K:
+	case SENSOR_CS2102K:		/* gamma set in xxx_Initial */
 	case SENSOR_HDCS2020b:
-	case SENSOR_PB0330:		/* pb with chip_revision - see above */
 	case SENSOR_OV7630C:
 	case SENSOR_TAS5130CK:
 		break;
@@ -7365,7 +6950,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 	setautogain(gspca_dev);
 	switch (sd->sensor) {
 	case SENSOR_PO2030:
-		msleep(500);
+		msleep(50);
 		reg_r(gspca_dev, 0x0008);
 		reg_r(gspca_dev, 0x0007);
 		/*fall thru*/
@@ -7389,17 +6974,16 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,
-			__u8 *data,
+			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);
+		gspca_frame_add(gspca_dev, LAST_PACKET,
+					NULL, 0);
 		/* put the JPEG header in the new frame */
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
 			sd->jpeg_hdr, JPEG_HDR_SZ);
 
 		/* remove the webcam's header:
@@ -7411,7 +6995,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		data += 18;
 		len -= 18;
 	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index 2eb9dc2ebe59..b5439cabb381 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -139,7 +139,7 @@ int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
 		urb = usb_alloc_urb(0, GFP_KERNEL);
 		if (!urb) {
 			v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n");
-			goto exit;
+			goto exit_urb;
 		}
 		buf->urb = urb;
 
@@ -148,7 +148,7 @@ int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
 		if (!mem) {
 			v4l2_err(&dev->v4l2_dev,
 				 "cannot allocate usb transfer buffer\n");
-			goto exit;
+			goto exit_urb_buffer;
 		}
 
 		usb_fill_bulk_urb(buf->urb, dev->udev,
@@ -161,6 +161,10 @@ int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
 		list_add_tail(&buf->buff_list, &dev->free_buff_list);
 	}
 	return 0;
+exit_urb_buffer:
+	usb_free_urb(urb);
+exit_urb:
+	kfree(buf);
 exit:
 	hdpvr_free_buffers(dev);
 	return retval;
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index 71c211402eb5..60d992ee2589 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -251,7 +251,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
 
 	DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
 
-	if (input < 0 || input >= HEXIUM_INPUTS)
+	if (input >= HEXIUM_INPUTS)
 		return -EINVAL;
 
 	hexium->cur_input = input;
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index 39d65ca41c62..938a1f8f880a 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -350,7 +350,7 @@ 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)
+	if (input >= HEXIUM_INPUTS)
 		return -EINVAL;
 
 	hexium->cur_input = input;
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 247d3115a9b7..64360d26b32d 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -275,7 +275,7 @@ static void ir_key_poll(struct IR_i2c *ir)
 	if (0 == rc) {
 		ir_input_nokey(ir->input, &ir->ir);
 	} else {
-		ir_input_keydown(ir->input, &ir->ir, ir_key, ir_raw);
+		ir_input_keydown(ir->input, &ir->ir, ir_key);
 	}
 }
 
@@ -299,7 +299,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 	struct ir_scancode_table *ir_codes = NULL;
 	const char *name = NULL;
-	int ir_type;
+	int ir_type = 0;
 	struct IR_i2c *ir;
 	struct input_dev *input_dev;
 	struct i2c_adapter *adap = client->adapter;
@@ -353,10 +353,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		ir_type     = IR_TYPE_RC5;
 		ir_codes    = &ir_codes_fusionhdtv_mce_table;
 		break;
-	case 0x7a:
 	case 0x47:
 	case 0x71:
-	case 0x2d:
 		if (adap->id == I2C_HW_B_CX2388x ||
 		    adap->id == I2C_HW_B_CX2341X) {
 			/* Handled by cx88-input */
@@ -381,10 +379,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		ir_type     = IR_TYPE_OTHER;
 		ir_codes    = &ir_codes_avermedia_cardbus_table;
 		break;
-	default:
-		dprintk(1, DEVNAME ": Unsupported i2c address 0x%02x\n", addr);
-		err = -ENODEV;
-		goto err_out_free;
 	}
 
 	/* Let the caller override settings */
@@ -427,7 +421,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	}
 
 	/* Make sure we are all setup before going on */
-	if (!name || !ir->get_key || !ir_codes) {
+	if (!name || !ir->get_key || !ir_type || !ir_codes) {
 		dprintk(1, DEVNAME ": Unsupported device at address 0x%02x\n",
 			addr);
 		err = -ENODEV;
@@ -443,7 +437,10 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		 dev_name(&client->dev));
 
 	/* init + register input device */
-	ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
+	err = ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
+	if (err < 0)
+		goto err_out_free;
+
 	input_dev->id.bustype = BUS_I2C;
 	input_dev->name       = ir->name;
 	input_dev->phys       = ir->phys;
@@ -462,6 +459,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	return 0;
 
  err_out_free:
+	ir_input_free(input_dev);
 	input_free_device(input_dev);
 	kfree(ir);
 	return err;
@@ -475,6 +473,7 @@ static int ir_remove(struct i2c_client *client)
 	cancel_delayed_work_sync(&ir->work);
 
 	/* unregister device */
+	ir_input_free(ir->input);
 	input_unregister_device(ir->input);
 
 	/* free memory */
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 4873b6ca5801..79d0fe4990d6 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -136,7 +136,8 @@ static const struct ivtv_card ivtv_card_pvr350 = {
 	.hw_audio = IVTV_HW_MSP34XX,
 	.hw_audio_ctrl = IVTV_HW_MSP34XX,
 	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 |
-		  IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER,
+		  IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER |
+		  IVTV_HW_I2C_IR_RX_HAUP_EXT | IVTV_HW_I2C_IR_RX_HAUP_INT,
 	.video_inputs = {
 		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
 		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
@@ -199,7 +200,9 @@ static const struct ivtv_card ivtv_card_pvr150 = {
 	.hw_audio_ctrl = IVTV_HW_CX25840,
 	.hw_muxer = IVTV_HW_WM8775,
 	.hw_all = IVTV_HW_WM8775 | IVTV_HW_CX25840 |
-		  IVTV_HW_TVEEPROM | IVTV_HW_TUNER,
+		  IVTV_HW_TVEEPROM | IVTV_HW_TUNER |
+		  IVTV_HW_I2C_IR_RX_HAUP_EXT | IVTV_HW_I2C_IR_RX_HAUP_INT |
+		  IVTV_HW_Z8F0811_IR_HAUP,
 	.video_inputs = {
 		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE7 },
 		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO1    },
@@ -955,7 +958,8 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
 	.hw_video = IVTV_HW_CX25840,
 	.hw_audio = IVTV_HW_CX25840,
 	.hw_audio_ctrl = IVTV_HW_CX25840,
-	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739 |
+		  IVTV_HW_I2C_IR_RX_AVER,
 	.video_inputs = {
 		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
 		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
@@ -965,6 +969,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
 		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
 	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5 },
 	/* enable line-in */
 	.gpio_init = { .direction = 0xe000, .initial_value = 0x4000 },
 	.xceive_pin = 10,
@@ -1025,13 +1030,15 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = {
 /* AVerMedia UltraTV 1500 MCE (newer non-cx88 version, M113 variant) card */
 
 static const struct ivtv_card_pci_info ivtv_pci_aver_ultra1500mce[] = {
-	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc019 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc019 }, /* NTSC */
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc01b }, /* PAL/SECAM */
 	{ 0, 0, 0 }
 };
 
 static const struct ivtv_card ivtv_card_aver_ultra1500mce = {
 	.type = IVTV_CARD_AVER_ULTRA1500MCE,
 	.name = "AVerMedia UltraTV 1500 MCE / AVerTV M113 Philips Tuner",
+	.comment = "For non-NTSC tuners, use the pal= or secam= module options",
 	.v4l2_capabilities = IVTV_CAP_ENCODER,
 	.hw_video = IVTV_HW_CX25840,
 	.hw_audio = IVTV_HW_CX25840,
@@ -1058,6 +1065,7 @@ static const struct ivtv_card ivtv_card_aver_ultra1500mce = {
 	.tuners = {
 		/* The UltraTV 1500 MCE has a Philips FM1236 MK5 TV/FM tuner */
 		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216MK5 },
 	},
 	.pci_list = ivtv_pci_aver_ultra1500mce,
 	.i2c = &ivtv_i2c_std,
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index e99a0a255578..6148827ec885 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -87,26 +87,43 @@
 #define IVTV_PCI_ID_GOTVIEW1		0xffac
 #define IVTV_PCI_ID_GOTVIEW2 		0xffad
 
-/* hardware flags, no gaps allowed, IVTV_HW_GPIO must always be last */
-#define IVTV_HW_CX25840   (1 << 0)
-#define IVTV_HW_SAA7115   (1 << 1)
-#define IVTV_HW_SAA7127   (1 << 2)
-#define IVTV_HW_MSP34XX   (1 << 3)
-#define IVTV_HW_TUNER     (1 << 4)
-#define IVTV_HW_WM8775    (1 << 5)
-#define IVTV_HW_CS53L32A  (1 << 6)
-#define IVTV_HW_TVEEPROM  (1 << 7)
-#define IVTV_HW_SAA7114   (1 << 8)
-#define IVTV_HW_UPD64031A (1 << 9)
-#define IVTV_HW_UPD6408X  (1 << 10)
-#define IVTV_HW_SAA717X   (1 << 11)
-#define IVTV_HW_WM8739    (1 << 12)
-#define IVTV_HW_VP27SMPX  (1 << 13)
-#define IVTV_HW_M52790    (1 << 14)
-#define IVTV_HW_GPIO      (1 << 15)
+/* hardware flags, no gaps allowed */
+#define IVTV_HW_CX25840			(1 << 0)
+#define IVTV_HW_SAA7115			(1 << 1)
+#define IVTV_HW_SAA7127			(1 << 2)
+#define IVTV_HW_MSP34XX			(1 << 3)
+#define IVTV_HW_TUNER			(1 << 4)
+#define IVTV_HW_WM8775			(1 << 5)
+#define IVTV_HW_CS53L32A		(1 << 6)
+#define IVTV_HW_TVEEPROM		(1 << 7)
+#define IVTV_HW_SAA7114			(1 << 8)
+#define IVTV_HW_UPD64031A		(1 << 9)
+#define IVTV_HW_UPD6408X		(1 << 10)
+#define IVTV_HW_SAA717X			(1 << 11)
+#define IVTV_HW_WM8739			(1 << 12)
+#define IVTV_HW_VP27SMPX		(1 << 13)
+#define IVTV_HW_M52790			(1 << 14)
+#define IVTV_HW_GPIO			(1 << 15)
+#define IVTV_HW_I2C_IR_RX_AVER		(1 << 16)
+#define IVTV_HW_I2C_IR_RX_HAUP_EXT	(1 << 17) /* External before internal */
+#define IVTV_HW_I2C_IR_RX_HAUP_INT	(1 << 18)
+#define IVTV_HW_Z8F0811_IR_TX_HAUP	(1 << 19)
+#define IVTV_HW_Z8F0811_IR_RX_HAUP	(1 << 20)
+
+#define IVTV_HW_Z8F0811_IR_HAUP	(IVTV_HW_Z8F0811_IR_RX_HAUP | \
+				 IVTV_HW_Z8F0811_IR_TX_HAUP)
 
 #define IVTV_HW_SAA711X   (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
 
+#define IVTV_HW_IR_RX_ANY (IVTV_HW_I2C_IR_RX_AVER | \
+			   IVTV_HW_I2C_IR_RX_HAUP_EXT | \
+			   IVTV_HW_I2C_IR_RX_HAUP_INT | \
+			   IVTV_HW_Z8F0811_IR_RX_HAUP)
+
+#define IVTV_HW_IR_TX_ANY (IVTV_HW_Z8F0811_IR_TX_HAUP)
+
+#define IVTV_HW_IR_ANY	  (IVTV_HW_IR_RX_ANY | IVTV_HW_IR_TX_ANY)
+
 /* video inputs */
 #define	IVTV_CARD_INPUT_VID_TUNER	1
 #define	IVTV_CARD_INPUT_SVIDEO1 	2
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 7cdbc1a8f218..347c3344f56d 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -91,10 +91,15 @@ static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
 				     -1, -1, -1, -1, -1, -1, -1, -1,
 				     -1, -1, -1, -1, -1, -1, -1, -1,
 				     -1, -1, -1, -1, -1, -1, -1, -1 };
+static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+					       -1, -1, -1, -1, -1, -1, -1, -1,
+					       -1, -1, -1, -1, -1, -1, -1, -1,
+					       -1, -1, -1, -1, -1, -1, -1, -1 };
 
 static unsigned int cardtype_c = 1;
 static unsigned int tuner_c = 1;
 static unsigned int radio_c = 1;
+static unsigned int i2c_clock_period_c = 1;
 static char pal[] = "---";
 static char secam[] = "--";
 static char ntsc[] = "-";
@@ -151,6 +156,7 @@ module_param(dec_vbi_buffers, int, 0644);
 
 module_param(tunertype, int, 0644);
 module_param(newi2c, int, 0644);
+module_param_array(i2c_clock_period, int, &i2c_clock_period_c, 0644);
 
 MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
 			"\t\t\tsee tuner.h for values");
@@ -245,6 +251,10 @@ MODULE_PARM_DESC(newi2c,
 		 "Use new I2C implementation\n"
 		 "\t\t\t-1 is autodetect, 0 is off, 1 is on\n"
 		 "\t\t\tDefault is autodetect");
+MODULE_PARM_DESC(i2c_clock_period,
+		 "Period of SCL for the I2C bus controlled by the CX23415/6\n"
+		 "\t\t\tMin: 10 usec (100 kHz), Max: 4500 usec (222 Hz)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_I2C_CLOCK_PERIOD));
 
 MODULE_PARM_DESC(ivtv_first_minor, "Set device node number assigned to first card");
 
@@ -600,6 +610,15 @@ static void ivtv_process_options(struct ivtv *itv)
 	itv->options.cardtype = cardtype[itv->instance];
 	itv->options.tuner = tuner[itv->instance];
 	itv->options.radio = radio[itv->instance];
+
+	itv->options.i2c_clock_period = i2c_clock_period[itv->instance];
+	if (itv->options.i2c_clock_period == -1)
+		itv->options.i2c_clock_period = IVTV_DEFAULT_I2C_CLOCK_PERIOD;
+	else if (itv->options.i2c_clock_period < 10)
+		itv->options.i2c_clock_period = 10;
+	else if (itv->options.i2c_clock_period > 4500)
+		itv->options.i2c_clock_period = 4500;
+
 	itv->options.newi2c = newi2c;
 	if (tunertype < -1 || tunertype > 1) {
 		IVTV_WARN("Invalid tunertype argument, will autodetect instead\n");
@@ -865,6 +884,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
 			itv->hw_flags |= device;
 	}
 
+	/* probe for legacy IR controllers that aren't in card definitions */
+	if ((itv->hw_flags & IVTV_HW_IR_ANY) == 0)
+		ivtv_i2c_new_ir_legacy(itv);
+
 	if (itv->card->hw_all & IVTV_HW_CX25840)
 		itv->sd_video = ivtv_find_hw(itv, IVTV_HW_CX25840);
 	else if (itv->card->hw_all & IVTV_HW_SAA717X)
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 440f7328a7ed..e4816da6482b 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -64,6 +64,7 @@
 #include <media/v4l2-device.h>
 #include <media/tuner.h>
 #include <media/cx2341x.h>
+#include <media/ir-kbd-i2c.h>
 
 #include <linux/ivtv.h>
 
@@ -176,12 +177,16 @@ extern int ivtv_debug;
 
 #define IVTV_MAX_PGM_INDEX (400)
 
+/* Default I2C SCL period in microseconds */
+#define IVTV_DEFAULT_I2C_CLOCK_PERIOD	20
+
 struct ivtv_options {
 	int kilobytes[IVTV_MAX_STREAMS];        /* size in kilobytes of each stream */
 	int cardtype;				/* force card type on load */
 	int tuner;				/* set tuner on load */
 	int radio;				/* enable/disable radio */
 	int newi2c;				/* new I2C algorithm */
+	int i2c_clock_period;			/* period of SCL for I2C bus */
 };
 
 /* ivtv-specific mailbox template */
@@ -677,6 +682,7 @@ struct ivtv {
 	int i2c_state;                  /* i2c bit state */
 	struct mutex i2c_bus_lock;      /* lock i2c bus */
 
+	struct IR_i2c_init_data ir_i2c_init_data;
 
 	/* Program Index information */
 	u32 pgm_info_offset;            /* start of pgm info in encoder memory */
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index b9c71e61f7d6..2ee03c2a1b58 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -88,6 +88,11 @@
 #define IVTV_UPD64083_I2C_ADDR 		0x5c
 #define IVTV_VP27SMPX_I2C_ADDR      	0x5b
 #define IVTV_M52790_I2C_ADDR      	0x48
+#define IVTV_AVERMEDIA_IR_RX_I2C_ADDR	0x40
+#define IVTV_HAUP_EXT_IR_RX_I2C_ADDR 	0x1a
+#define IVTV_HAUP_INT_IR_RX_I2C_ADDR 	0x18
+#define IVTV_Z8F0811_IR_TX_I2C_ADDR	0x70
+#define IVTV_Z8F0811_IR_RX_I2C_ADDR	0x71
 
 /* This array should match the IVTV_HW_ defines */
 static const u8 hw_addrs[] = {
@@ -106,7 +111,12 @@ static const u8 hw_addrs[] = {
 	IVTV_WM8739_I2C_ADDR,
 	IVTV_VP27SMPX_I2C_ADDR,
 	IVTV_M52790_I2C_ADDR,
-	0 		/* IVTV_HW_GPIO dummy driver ID */
+	0,				/* IVTV_HW_GPIO dummy driver ID */
+	IVTV_AVERMEDIA_IR_RX_I2C_ADDR,	/* IVTV_HW_I2C_IR_RX_AVER */
+	IVTV_HAUP_EXT_IR_RX_I2C_ADDR,	/* IVTV_HW_I2C_IR_RX_HAUP_EXT */
+	IVTV_HAUP_INT_IR_RX_I2C_ADDR,	/* IVTV_HW_I2C_IR_RX_HAUP_INT */
+	IVTV_Z8F0811_IR_TX_I2C_ADDR,	/* IVTV_HW_Z8F0811_IR_TX_HAUP */
+	IVTV_Z8F0811_IR_RX_I2C_ADDR,	/* IVTV_HW_Z8F0811_IR_RX_HAUP */
 };
 
 /* This array should match the IVTV_HW_ defines */
@@ -126,7 +136,12 @@ static const char *hw_modules[] = {
 	"wm8739",
 	"vp27smpx",
 	"m52790",
-	NULL
+	NULL,
+	NULL,		/* IVTV_HW_I2C_IR_RX_AVER */
+	NULL,		/* IVTV_HW_I2C_IR_RX_HAUP_EXT */
+	NULL,		/* IVTV_HW_I2C_IR_RX_HAUP_INT */
+	NULL,		/* IVTV_HW_Z8F0811_IR_TX_HAUP */
+	NULL,		/* IVTV_HW_Z8F0811_IR_RX_HAUP */
 };
 
 /* This array should match the IVTV_HW_ defines */
@@ -147,8 +162,95 @@ static const char * const hw_devicenames[] = {
 	"vp27smpx",
 	"m52790",
 	"gpio",
+	"ir_video",		/* IVTV_HW_I2C_IR_RX_AVER */
+	"ir_video",		/* IVTV_HW_I2C_IR_RX_HAUP_EXT */
+	"ir_video",		/* IVTV_HW_I2C_IR_RX_HAUP_INT */
+	"ir_tx_z8f0811_haup",	/* IVTV_HW_Z8F0811_IR_TX_HAUP */
+	"ir_rx_z8f0811_haup",	/* IVTV_HW_Z8F0811_IR_RX_HAUP */
 };
 
+static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adap = &itv->i2c_adap;
+	struct IR_i2c_init_data *init_data = &itv->ir_i2c_init_data;
+	unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
+
+	/* Only allow one IR transmitter to be registered per board */
+	if (hw & IVTV_HW_IR_TX_ANY) {
+		if (itv->hw_flags & IVTV_HW_IR_TX_ANY)
+			return -1;
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		strlcpy(info.type, type, I2C_NAME_SIZE);
+		return i2c_new_probed_device(adap, &info, addr_list) == NULL
+								     ? -1 : 0;
+	}
+
+	/* Only allow one IR receiver to be registered per board */
+	if (itv->hw_flags & IVTV_HW_IR_RX_ANY)
+		return -1;
+
+	/* Our default information for ir-kbd-i2c.c to use */
+	switch (hw) {
+	case IVTV_HW_I2C_IR_RX_AVER:
+		init_data->ir_codes = &ir_codes_avermedia_cardbus_table;
+		init_data->internal_get_key_func =
+					IR_KBD_GET_KEY_AVERMEDIA_CARDBUS;
+		init_data->type = IR_TYPE_OTHER;
+		init_data->name = "AVerMedia AVerTV card";
+		break;
+	case IVTV_HW_I2C_IR_RX_HAUP_EXT:
+	case IVTV_HW_I2C_IR_RX_HAUP_INT:
+		/* Default to old black remote */
+		init_data->ir_codes = &ir_codes_rc5_tv_table;
+		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
+		init_data->type = IR_TYPE_RC5;
+		init_data->name = itv->card_name;
+		break;
+	case IVTV_HW_Z8F0811_IR_RX_HAUP:
+		/* Default to grey remote */
+		init_data->ir_codes = &ir_codes_hauppauge_new_table;
+		init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+		init_data->type = IR_TYPE_RC5;
+		init_data->name = itv->card_name;
+		break;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.platform_data = init_data;
+	strlcpy(info.type, type, I2C_NAME_SIZE);
+
+	return i2c_new_probed_device(adap, &info, addr_list) == NULL ? -1 : 0;
+}
+
+/* Instantiate the IR receiver device using probing -- undesirable */
+struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv)
+{
+	struct i2c_board_info info;
+	/*
+	 * The external IR receiver is at i2c address 0x34.
+	 * The internal IR receiver is at i2c address 0x30.
+	 *
+	 * In theory, both can be fitted, and Hauppauge suggests an external
+	 * overrides an internal.  That's why we probe 0x1a (~0x34) first. CB
+	 *
+	 * Some of these addresses we probe may collide with other i2c address
+	 * allocations, so this function must be called after all other i2c
+	 * devices we care about are registered.
+	 */
+	const unsigned short addr_list[] = {
+		0x1a,	/* Hauppauge IR external - collides with WM8739 */
+		0x18,	/* Hauppauge IR internal */
+		0x71,	/* Hauppauge IR (PVR150) */
+		0x6b,	/* Adaptec IR */
+		I2C_CLIENT_END
+	};
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+	return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list);
+}
+
 int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
 {
 	struct v4l2_subdev *sd;
@@ -178,8 +280,15 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
 			sd->grp_id = 1 << idx;
 		return sd ? 0 : -1;
 	}
+
+	if (hw & IVTV_HW_IR_ANY)
+		return ivtv_i2c_new_ir(itv, hw, type, hw_addrs[idx]);
+
+	/* Is it not an I2C device or one we do not wish to register? */
 	if (!hw_addrs[idx])
 		return -1;
+
+	/* It's an I2C device other than an analog tuner or IR chip */
 	if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
 		sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
 				adap, mod, type, 0, I2C_ADDRS(hw_addrs[idx]));
@@ -564,20 +673,22 @@ static struct i2c_adapter ivtv_i2c_adap_template = {
 	.owner = THIS_MODULE,
 };
 
+#define IVTV_ALGO_BIT_TIMEOUT	(2)	/* seconds */
+
 static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
 	.setsda		= ivtv_setsda_old,
 	.setscl		= ivtv_setscl_old,
 	.getsda		= ivtv_getsda_old,
 	.getscl		= ivtv_getscl_old,
-	.udelay		= 10,
-	.timeout	= 200,
+	.udelay		= IVTV_DEFAULT_I2C_CLOCK_PERIOD / 2,  /* microseconds */
+	.timeout	= IVTV_ALGO_BIT_TIMEOUT * HZ,         /* jiffies */
 };
 
 static struct i2c_client ivtv_i2c_client_template = {
 	.name = "ivtv internal",
 };
 
-/* init + register i2c adapter + instantiate IR receiver */
+/* init + register i2c adapter */
 int init_ivtv_i2c(struct ivtv *itv)
 {
 	int retval;
@@ -585,11 +696,10 @@ int init_ivtv_i2c(struct ivtv *itv)
 	IVTV_DEBUG_I2C("i2c init\n");
 
 	/* Sanity checks for the I2C hardware arrays. They must be the
-	 * same size and GPIO must be the last entry.
+	 * same size.
 	 */
 	if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
-	    ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_modules) ||
-	    IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1))) {
+	    ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_modules)) {
 		IVTV_ERR("Mismatched I2C hardware arrays\n");
 		return -ENODEV;
 	}
@@ -602,6 +712,7 @@ int init_ivtv_i2c(struct ivtv *itv)
 		memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
 		       sizeof(struct i2c_algo_bit_data));
 	}
+	itv->i2c_algo.udelay = itv->options.i2c_clock_period / 2;
 	itv->i2c_algo.data = itv;
 	itv->i2c_adap.algo_data = &itv->i2c_algo;
 
@@ -623,32 +734,6 @@ int init_ivtv_i2c(struct ivtv *itv)
 	else
 		retval = i2c_bit_add_bus(&itv->i2c_adap);
 
-	/* Instantiate the IR receiver device, if present */
-	if (retval == 0) {
-		struct i2c_board_info info;
-		/* The external IR receiver is at i2c address 0x34 (0x35 for
-		   reads).  Future Hauppauge cards will have an internal
-		   receiver at 0x30 (0x31 for reads).  In theory, both can be
-		   fitted, and Hauppauge suggest an external overrides an
-		   internal.
-
-		   That's why we probe 0x1a (~0x34) first. CB
-		*/
-		const unsigned short addr_list[] = {
-			0x1a,	/* Hauppauge IR external */
-			0x18,	/* Hauppauge IR internal */
-			0x71,	/* Hauppauge IR (PVR150) */
-			0x64,	/* Pixelview IR */
-			0x30,	/* KNC ONE IR */
-			0x6b,	/* Adaptec IR */
-			I2C_CLIENT_END
-		};
-
-		memset(&info, 0, sizeof(struct i2c_board_info));
-		strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-		i2c_new_probed_device(&itv->i2c_adap, &info, addr_list);
-	}
-
 	return retval;
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
index 396928a06a54..9332920ca4ff 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/drivers/media/video/ivtv/ivtv-i2c.h
@@ -21,6 +21,7 @@
 #ifndef IVTV_I2C_H
 #define IVTV_I2C_H
 
+struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv);
 int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
 struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw);
 
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 3454070e63f0..c1fc6dc776f5 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -478,7 +478,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
 
 	DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
 
-	if (input < 0 || input >= MXB_INPUTS)
+	if (input >= MXB_INPUTS)
 		return -EINVAL;
 
 	mxb->cur_input = input;
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
new file mode 100644
index 000000000000..c81ae2192887
--- /dev/null
+++ b/drivers/media/video/ov9640.c
@@ -0,0 +1,801 @@
+/*
+ * OmniVision OV96xx Camera Driver
+ *
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on ov772x camera driver:
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.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/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/soc_camera.h>
+
+#include "ov9640.h"
+
+/* default register setup */
+static const struct ov9640_reg ov9640_regs_dflt[] = {
+	{ OV9640_COM5,	OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP },
+	{ OV9640_COM6,	OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS |
+			OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN },
+	{ OV9640_PSHFT,	OV9640_PSHFT_VAL(0x01) },
+	{ OV9640_ACOM,	OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD },
+	{ OV9640_TSLB,	OV9640_TSLB_YUYV_UYVY },
+	{ OV9640_COM16,	OV9640_COM16_RB_AVG },
+
+	/* Gamma curve P */
+	{ 0x6c, 0x40 },	{ 0x6d, 0x30 },	{ 0x6e, 0x4b },	{ 0x6f, 0x60 },
+	{ 0x70, 0x70 },	{ 0x71, 0x70 },	{ 0x72, 0x70 },	{ 0x73, 0x70 },
+	{ 0x74, 0x60 },	{ 0x75, 0x60 },	{ 0x76, 0x50 },	{ 0x77, 0x48 },
+	{ 0x78, 0x3a },	{ 0x79, 0x2e },	{ 0x7a, 0x28 },	{ 0x7b, 0x22 },
+
+	/* Gamma curve T */
+	{ 0x7c, 0x04 },	{ 0x7d, 0x07 },	{ 0x7e, 0x10 },	{ 0x7f, 0x28 },
+	{ 0x80, 0x36 },	{ 0x81, 0x44 },	{ 0x82, 0x52 },	{ 0x83, 0x60 },
+	{ 0x84, 0x6c },	{ 0x85, 0x78 },	{ 0x86, 0x8c },	{ 0x87, 0x9e },
+	{ 0x88, 0xbb },	{ 0x89, 0xd2 },	{ 0x8a, 0xe6 },
+};
+
+/* Configurations
+ * NOTE: for YUV, alter the following registers:
+ * 		COM12 |= OV9640_COM12_YUV_AVG
+ *
+ *	 for RGB, alter the following registers:
+ *	 	COM7  |= OV9640_COM7_RGB
+ *	 	COM13 |= OV9640_COM13_RGB_AVG
+ *	 	COM15 |= proper RGB color encoding mode
+ */
+static const struct ov9640_reg ov9640_regs_qqcif[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) },
+	{ OV9640_COM1,	OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
+	{ OV9640_COM4,	OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+	{ OV9640_COM7,	OV9640_COM7_QCIF },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qqvga[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
+	{ OV9640_COM1,	OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
+	{ OV9640_COM4,	OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+	{ OV9640_COM7,	OV9640_COM7_QVGA },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qcif[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
+	{ OV9640_COM4,	OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+	{ OV9640_COM7,	OV9640_COM7_QCIF },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qvga[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
+	{ OV9640_COM4,	OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+	{ OV9640_COM7,	OV9640_COM7_QVGA },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_cif[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
+	{ OV9640_COM3,	OV9640_COM3_VP },
+	{ OV9640_COM7,	OV9640_COM7_CIF },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_vga[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
+	{ OV9640_COM3,	OV9640_COM3_VP },
+	{ OV9640_COM7,	OV9640_COM7_VGA },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_sxga[] = {
+	{ OV9640_CLKRC,	OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
+	{ OV9640_COM3,	OV9640_COM3_VP },
+	{ OV9640_COM7,	0 },
+	{ OV9640_COM12,	OV9640_COM12_RSVD },
+	{ OV9640_COM13,	OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+	{ OV9640_COM15,	OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_yuv[] = {
+	{ OV9640_MTX1,	0x58 },
+	{ OV9640_MTX2,	0x48 },
+	{ OV9640_MTX3,	0x10 },
+	{ OV9640_MTX4,	0x28 },
+	{ OV9640_MTX5,	0x48 },
+	{ OV9640_MTX6,	0x70 },
+	{ OV9640_MTX7,	0x40 },
+	{ OV9640_MTX8,	0x40 },
+	{ OV9640_MTX9,	0x40 },
+	{ OV9640_MTXS,	0x0f },
+};
+
+static const struct ov9640_reg ov9640_regs_rgb[] = {
+	{ OV9640_MTX1,	0x71 },
+	{ OV9640_MTX2,	0x3e },
+	{ OV9640_MTX3,	0x0c },
+	{ OV9640_MTX4,	0x33 },
+	{ OV9640_MTX5,	0x72 },
+	{ OV9640_MTX6,	0x00 },
+	{ OV9640_MTX7,	0x2b },
+	{ OV9640_MTX8,	0x66 },
+	{ OV9640_MTX9,	0xd2 },
+	{ OV9640_MTXS,	0x65 },
+};
+
+/*
+ * TODO: this sensor also supports RGB555 and RGB565 formats, but support for
+ * them has not yet been sufficiently tested and so it is not included with
+ * this version of the driver. To test and debug these formats add two entries
+ * to the below array, see ov722x.c for an example.
+ */
+static const struct soc_camera_data_format ov9640_fmt_lists[] = {
+	{
+		.name		= "UYVY",
+		.fourcc		= V4L2_PIX_FMT_UYVY,
+		.depth		= 16,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+	},
+};
+
+static const struct v4l2_queryctrl ov9640_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,
+	},
+};
+
+/* read a register */
+static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+	int ret;
+	u8 data = reg;
+	struct i2c_msg msg = {
+		.addr	= client->addr,
+		.flags	= 0,
+		.len	= 1,
+		.buf	= &data,
+	};
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		goto err;
+
+	msg.flags = I2C_M_RD;
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		goto err;
+
+	*val = data;
+	return 0;
+
+err:
+	dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
+	return ret;
+}
+
+/* write a register */
+static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val)
+{
+	int ret;
+	u8 _val;
+	unsigned char data[2] = { reg, val };
+	struct i2c_msg msg = {
+		.addr	= client->addr,
+		.flags	= 0,
+		.len	= 2,
+		.buf	= data,
+	};
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
+		return ret;
+	}
+
+	/* we have to read the register back ... no idea why, maybe HW bug */
+	ret = ov9640_reg_read(client, reg, &_val);
+	if (ret)
+		dev_err(&client->dev,
+			"Failed reading back register 0x%02x!\n", reg);
+
+	return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset)
+{
+	u8 val;
+	int ret;
+
+	ret = ov9640_reg_read(client, reg, &val);
+	if (ret) {
+		dev_err(&client->dev,
+			"[Read]-Modify-Write of register %02x failed!\n", reg);
+		return val;
+	}
+
+	val |= set;
+	val &= ~unset;
+
+	ret = ov9640_reg_write(client, reg, val);
+	if (ret)
+		dev_err(&client->dev,
+			"Read-Modify-[Write] of register %02x failed!\n", reg);
+
+	return ret;
+}
+
+/* Soft reset the camera. This has nothing to do with the RESET pin! */
+static int ov9640_reset(struct i2c_client *client)
+{
+	int ret;
+
+	ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET);
+	if (ret)
+		dev_err(&client->dev,
+			"An error occured while entering soft reset!\n");
+
+	return ret;
+}
+
+/* Start/Stop streaming from the device */
+static int ov9640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	return 0;
+}
+
+/* Alter bus settings on camera side */
+static int ov9640_set_bus_param(struct soc_camera_device *icd,
+				unsigned long flags)
+{
+	return 0;
+}
+
+/* Request bus settings on camera side */
+static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd)
+{
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+	/*
+	 * REVISIT: the camera probably can do 10 bit transfers, but I don't
+	 *          have those pins connected on my hardware.
+	 */
+	unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+		SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+		SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
+
+	return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+/* Get status of additional camera capabilities */
+static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct i2c_client *client = sd->priv;
+	struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
+					struct ov9640_priv, subdev);
+
+	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;
+}
+
+/* Set status of additional camera capabilities */
+static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct i2c_client *client = sd->priv;
+	struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
+					struct ov9640_priv, subdev);
+
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		priv->flag_vflip = ctrl->value;
+		if (ctrl->value)
+			ret = ov9640_reg_rmw(client, OV9640_MVFP,
+							OV9640_MVFP_V, 0);
+		else
+			ret = ov9640_reg_rmw(client, OV9640_MVFP,
+							0, OV9640_MVFP_V);
+		break;
+	case V4L2_CID_HFLIP:
+		priv->flag_hflip = ctrl->value;
+		if (ctrl->value)
+			ret = ov9640_reg_rmw(client, OV9640_MVFP,
+							OV9640_MVFP_H, 0);
+		else
+			ret = ov9640_reg_rmw(client, OV9640_MVFP,
+							0, OV9640_MVFP_H);
+		break;
+	}
+
+	return ret;
+}
+
+/* Get chip identification */
+static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = sd->priv;
+	struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
+					struct ov9640_priv, subdev);
+
+	id->ident	= priv->model;
+	id->revision	= priv->revision;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9640_get_register(struct v4l2_subdev *sd,
+				struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = sd->priv;
+	int ret;
+	u8 val;
+
+	if (reg->reg & ~0xff)
+		return -EINVAL;
+
+	reg->size = 1;
+
+	ret = ov9640_reg_read(client, reg->reg, &val);
+	if (ret)
+		return ret;
+
+	reg->val = (__u64)val;
+
+	return 0;
+}
+
+static int ov9640_set_register(struct v4l2_subdev *sd,
+				struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = sd->priv;
+
+	if (reg->reg & ~0xff || reg->val & ~0xff)
+		return -EINVAL;
+
+	return ov9640_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+/* select nearest higher resolution for capture */
+static void ov9640_res_roundup(u32 *width, u32 *height)
+{
+	int i;
+	enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
+	int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 };
+	int res_y[] = { 72, 120, 144, 240, 288, 480, 960 };
+
+	for (i = 0; i < ARRAY_SIZE(res_x); i++) {
+		if (res_x[i] >= *width && res_y[i] >= *height) {
+			*width = res_x[i];
+			*height = res_y[i];
+			return;
+		}
+	}
+
+	*width = res_x[SXGA];
+	*height = res_y[SXGA];
+}
+
+/* Prepare necessary register changes depending on color encoding */
+static void ov9640_alter_regs(u32 pixfmt, struct ov9640_reg_alt *alt)
+{
+	switch (pixfmt) {
+	case V4L2_PIX_FMT_UYVY:
+		alt->com12	= OV9640_COM12_YUV_AVG;
+		alt->com13	= OV9640_COM13_Y_DELAY_EN |
+					OV9640_COM13_YUV_DLY(0x01);
+		break;
+	case V4L2_PIX_FMT_RGB555:
+		alt->com7	= OV9640_COM7_RGB;
+		alt->com13	= OV9640_COM13_RGB_AVG;
+		alt->com15	= OV9640_COM15_RGB_555;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		alt->com7	= OV9640_COM7_RGB;
+		alt->com13	= OV9640_COM13_RGB_AVG;
+		alt->com15	= OV9640_COM15_RGB_565;
+		break;
+	};
+}
+
+/* Setup registers according to resolution and color encoding */
+static int ov9640_write_regs(struct i2c_client *client,
+		u32 width, u32 pixfmt, struct ov9640_reg_alt *alts)
+{
+	const struct ov9640_reg	*ov9640_regs, *matrix_regs;
+	int			ov9640_regs_len, matrix_regs_len;
+	int			i, ret;
+	u8			val;
+
+	/* select register configuration for given resolution */
+	switch (width) {
+	case W_QQCIF:
+		ov9640_regs	= ov9640_regs_qqcif;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_qqcif);
+		break;
+	case W_QQVGA:
+		ov9640_regs	= ov9640_regs_qqvga;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_qqvga);
+		break;
+	case W_QCIF:
+		ov9640_regs	= ov9640_regs_qcif;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_qcif);
+		break;
+	case W_QVGA:
+		ov9640_regs	= ov9640_regs_qvga;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_qvga);
+		break;
+	case W_CIF:
+		ov9640_regs	= ov9640_regs_cif;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_cif);
+		break;
+	case W_VGA:
+		ov9640_regs	= ov9640_regs_vga;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_vga);
+		break;
+	case W_SXGA:
+		ov9640_regs	= ov9640_regs_sxga;
+		ov9640_regs_len	= ARRAY_SIZE(ov9640_regs_sxga);
+		break;
+	default:
+		dev_err(&client->dev, "Failed to select resolution!\n");
+		return -EINVAL;
+	}
+
+	/* select color matrix configuration for given color encoding */
+	if (pixfmt == V4L2_PIX_FMT_UYVY) {
+		matrix_regs	= ov9640_regs_yuv;
+		matrix_regs_len	= ARRAY_SIZE(ov9640_regs_yuv);
+	} else {
+		matrix_regs	= ov9640_regs_rgb;
+		matrix_regs_len	= ARRAY_SIZE(ov9640_regs_rgb);
+	}
+
+	/* write register settings into the module */
+	for (i = 0; i < ov9640_regs_len; i++) {
+		val = ov9640_regs[i].val;
+
+		switch (ov9640_regs[i].reg) {
+		case OV9640_COM7:
+			val |= alts->com7;
+			break;
+		case OV9640_COM12:
+			val |= alts->com12;
+			break;
+		case OV9640_COM13:
+			val |= alts->com13;
+			break;
+		case OV9640_COM15:
+			val |= alts->com15;
+			break;
+		}
+
+		ret = ov9640_reg_write(client, ov9640_regs[i].reg, val);
+		if (ret)
+			return ret;
+	}
+
+	/* write color matrix configuration into the module */
+	for (i = 0; i < matrix_regs_len; i++) {
+		ret = ov9640_reg_write(client, matrix_regs[i].reg,
+						matrix_regs[i].val);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* program default register values */
+static int ov9640_prog_dflt(struct i2c_client *client)
+{
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) {
+		ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg,
+						ov9640_regs_dflt[i].val);
+		if (ret)
+			return ret;
+	}
+
+	/* wait for the changes to actually happen, 140ms are not enough yet */
+	mdelay(150);
+
+	return 0;
+}
+
+/* set the format we will capture in */
+static int ov9640_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+	struct i2c_client *client = sd->priv;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct ov9640_reg_alt alts = {0};
+	int ret;
+
+	ov9640_res_roundup(&pix->width, &pix->height);
+	ov9640_alter_regs(pix->pixelformat, &alts);
+
+	ov9640_reset(client);
+
+	ret = ov9640_prog_dflt(client);
+	if (ret)
+		return ret;
+
+	return ov9640_write_regs(client, pix->width, pix->pixelformat, &alts);
+}
+
+static int ov9640_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	ov9640_res_roundup(&pix->width, &pix->height);
+	pix->field  = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	a->c.left	= 0;
+	a->c.top	= 0;
+	a->c.width	= W_SXGA;
+	a->c.height	= H_SXGA;
+	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= W_SXGA;
+	a->bounds.height		= H_SXGA;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+
+
+static int ov9640_video_probe(struct soc_camera_device *icd,
+				struct i2c_client *client)
+{
+	struct ov9640_priv *priv = i2c_get_clientdata(client);
+	u8		pid, ver, midh, midl;
+	const char	*devname;
+	int		ret = 0;
+
+	/*
+	 * We must have a parent by now. And it cannot be a wrong one.
+	 * So this entire test is completely redundant.
+	 */
+	if (!icd->dev.parent ||
+	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface) {
+		dev_err(&client->dev, "Parent missing or invalid!\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	icd->formats		= ov9640_fmt_lists;
+	icd->num_formats	= ARRAY_SIZE(ov9640_fmt_lists);
+
+	/*
+	 * check and show product ID and manufacturer ID
+	 */
+
+	ret = ov9640_reg_read(client, OV9640_PID, &pid);
+	if (ret)
+		goto err;
+
+	ret = ov9640_reg_read(client, OV9640_VER, &ver);
+	if (ret)
+		goto err;
+
+	ret = ov9640_reg_read(client, OV9640_MIDH, &midh);
+	if (ret)
+		goto err;
+
+	ret = ov9640_reg_read(client, OV9640_MIDL, &midl);
+	if (ret)
+		goto err;
+
+	switch (VERSION(pid, ver)) {
+	case OV9640_V2:
+		devname		= "ov9640";
+		priv->model	= V4L2_IDENT_OV9640;
+		priv->revision	= 2;
+	case OV9640_V3:
+		devname		= "ov9640";
+		priv->model	= V4L2_IDENT_OV9640;
+		priv->revision	= 3;
+		break;
+	default:
+		dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+		 devname, pid, ver, midh, midl);
+
+err:
+	return ret;
+}
+
+static struct soc_camera_ops ov9640_ops = {
+	.set_bus_param		= ov9640_set_bus_param,
+	.query_bus_param	= ov9640_query_bus_param,
+	.controls		= ov9640_controls,
+	.num_controls		= ARRAY_SIZE(ov9640_controls),
+};
+
+static struct v4l2_subdev_core_ops ov9640_core_ops = {
+	.g_ctrl			= ov9640_g_ctrl,
+	.s_ctrl			= ov9640_s_ctrl,
+	.g_chip_ident		= ov9640_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register		= ov9640_get_register,
+	.s_register		= ov9640_set_register,
+#endif
+
+};
+
+static struct v4l2_subdev_video_ops ov9640_video_ops = {
+	.s_stream		= ov9640_s_stream,
+	.s_fmt			= ov9640_s_fmt,
+	.try_fmt		= ov9640_try_fmt,
+	.cropcap		= ov9640_cropcap,
+	.g_crop			= ov9640_g_crop,
+
+};
+
+static struct v4l2_subdev_ops ov9640_subdev_ops = {
+	.core	= &ov9640_core_ops,
+	.video	= &ov9640_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov9640_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct ov9640_priv *priv;
+	struct soc_camera_device *icd	= client->dev.platform_data;
+	struct soc_camera_link *icl;
+	int ret;
+
+	if (!icd) {
+		dev_err(&client->dev, "Missing soc-camera data!\n");
+		return -EINVAL;
+	}
+
+	icl = to_soc_camera_link(icd);
+	if (!icl) {
+		dev_err(&client->dev, "Missing platform_data for driver\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(struct ov9640_priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&client->dev,
+			"Failed to allocate memory for private data!\n");
+		return -ENOMEM;
+	}
+
+	v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops);
+
+	icd->ops	= &ov9640_ops;
+
+	ret = ov9640_video_probe(icd, client);
+
+	if (ret) {
+		icd->ops = NULL;
+		i2c_set_clientdata(client, NULL);
+		kfree(priv);
+	}
+
+	return ret;
+}
+
+static int ov9640_remove(struct i2c_client *client)
+{
+	struct ov9640_priv *priv = i2c_get_clientdata(client);
+
+	i2c_set_clientdata(client, NULL);
+	kfree(priv);
+	return 0;
+}
+
+static const struct i2c_device_id ov9640_id[] = {
+	{ "ov9640", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ov9640_id);
+
+static struct i2c_driver ov9640_i2c_driver = {
+	.driver = {
+		.name = "ov9640",
+	},
+	.probe    = ov9640_probe,
+	.remove   = ov9640_remove,
+	.id_table = ov9640_id,
+};
+
+static int __init ov9640_module_init(void)
+{
+	return i2c_add_driver(&ov9640_i2c_driver);
+}
+
+static void __exit ov9640_module_exit(void)
+{
+	i2c_del_driver(&ov9640_i2c_driver);
+}
+
+module_init(ov9640_module_init);
+module_exit(ov9640_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov9640.h b/drivers/media/video/ov9640.h
new file mode 100644
index 000000000000..f8a51b70792e
--- /dev/null
+++ b/drivers/media/video/ov9640.h
@@ -0,0 +1,209 @@
+/*
+ * OmniVision OV96xx Camera Header File
+ *
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * 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.
+ */
+
+#ifndef	__DRIVERS_MEDIA_VIDEO_OV9640_H__
+#define	__DRIVERS_MEDIA_VIDEO_OV9640_H__
+
+/* Register definitions */
+#define	OV9640_GAIN	0x00
+#define	OV9640_BLUE	0x01
+#define	OV9640_RED	0x02
+#define	OV9640_VFER	0x03
+#define	OV9640_COM1	0x04
+#define	OV9640_BAVE	0x05
+#define	OV9640_GEAVE	0x06
+#define	OV9640_RSID	0x07
+#define	OV9640_RAVE	0x08
+#define	OV9640_COM2	0x09
+#define	OV9640_PID	0x0a
+#define	OV9640_VER	0x0b
+#define	OV9640_COM3	0x0c
+#define	OV9640_COM4	0x0d
+#define	OV9640_COM5	0x0e
+#define	OV9640_COM6	0x0f
+#define	OV9640_AECH	0x10
+#define	OV9640_CLKRC	0x11
+#define	OV9640_COM7	0x12
+#define	OV9640_COM8	0x13
+#define	OV9640_COM9	0x14
+#define	OV9640_COM10	0x15
+/* 0x16 - RESERVED */
+#define	OV9640_HSTART	0x17
+#define	OV9640_HSTOP	0x18
+#define	OV9640_VSTART	0x19
+#define	OV9640_VSTOP	0x1a
+#define	OV9640_PSHFT	0x1b
+#define	OV9640_MIDH	0x1c
+#define	OV9640_MIDL	0x1d
+#define	OV9640_MVFP	0x1e
+#define	OV9640_LAEC	0x1f
+#define	OV9640_BOS	0x20
+#define	OV9640_GBOS	0x21
+#define	OV9640_GROS	0x22
+#define	OV9640_ROS	0x23
+#define	OV9640_AEW	0x24
+#define	OV9640_AEB	0x25
+#define	OV9640_VPT	0x26
+#define	OV9640_BBIAS	0x27
+#define	OV9640_GBBIAS	0x28
+/* 0x29 - RESERVED */
+#define	OV9640_EXHCH	0x2a
+#define	OV9640_EXHCL	0x2b
+#define	OV9640_RBIAS	0x2c
+#define	OV9640_ADVFL	0x2d
+#define	OV9640_ADVFH	0x2e
+#define	OV9640_YAVE	0x2f
+#define	OV9640_HSYST	0x30
+#define	OV9640_HSYEN	0x31
+#define	OV9640_HREF	0x32
+#define	OV9640_CHLF	0x33
+#define	OV9640_ARBLM	0x34
+/* 0x35..0x36 - RESERVED */
+#define	OV9640_ADC	0x37
+#define	OV9640_ACOM	0x38
+#define	OV9640_OFON	0x39
+#define	OV9640_TSLB	0x3a
+#define	OV9640_COM11	0x3b
+#define	OV9640_COM12	0x3c
+#define	OV9640_COM13	0x3d
+#define	OV9640_COM14	0x3e
+#define	OV9640_EDGE	0x3f
+#define	OV9640_COM15	0x40
+#define	OV9640_COM16	0x41
+#define	OV9640_COM17	0x42
+/* 0x43..0x4e - RESERVED */
+#define	OV9640_MTX1	0x4f
+#define	OV9640_MTX2	0x50
+#define	OV9640_MTX3	0x51
+#define	OV9640_MTX4	0x52
+#define	OV9640_MTX5	0x53
+#define	OV9640_MTX6	0x54
+#define	OV9640_MTX7	0x55
+#define	OV9640_MTX8	0x56
+#define	OV9640_MTX9	0x57
+#define	OV9640_MTXS	0x58
+/* 0x59..0x61 - RESERVED */
+#define	OV9640_LCC1	0x62
+#define	OV9640_LCC2	0x63
+#define	OV9640_LCC3	0x64
+#define	OV9640_LCC4	0x65
+#define	OV9640_LCC5	0x66
+#define	OV9640_MANU	0x67
+#define	OV9640_MANV	0x68
+#define	OV9640_HV	0x69
+#define	OV9640_MBD	0x6a
+#define	OV9640_DBLV	0x6b
+#define	OV9640_GSP	0x6c	/* ... till 0x7b */
+#define	OV9640_GST	0x7c	/* ... till 0x8a */
+
+#define	OV9640_CLKRC_DPLL_EN	0x80
+#define	OV9640_CLKRC_DIRECT	0x40
+#define	OV9640_CLKRC_DIV(x)	((x) & 0x3f)
+
+#define	OV9640_PSHFT_VAL(x)	((x) & 0xff)
+
+#define	OV9640_ACOM_2X_ANALOG	0x80
+#define	OV9640_ACOM_RSVD	0x12
+
+#define	OV9640_MVFP_V		0x10
+#define	OV9640_MVFP_H		0x20
+
+#define	OV9640_COM1_HREF_NOSKIP	0x00
+#define	OV9640_COM1_HREF_2SKIP	0x04
+#define	OV9640_COM1_HREF_3SKIP	0x08
+#define	OV9640_COM1_QQFMT	0x20
+
+#define	OV9640_COM2_SSM		0x10
+
+#define	OV9640_COM3_VP		0x04
+
+#define	OV9640_COM4_QQ_VP	0x80
+#define	OV9640_COM4_RSVD	0x40
+
+#define	OV9640_COM5_SYSCLK	0x80
+#define	OV9640_COM5_LONGEXP	0x01
+
+#define	OV9640_COM6_OPT_BLC	0x40
+#define	OV9640_COM6_ADBLC_BIAS	0x08
+#define	OV9640_COM6_FMT_RST	0x82
+#define	OV9640_COM6_ADBLC_OPTEN	0x01
+
+#define	OV9640_COM7_RAW_RGB	0x01
+#define	OV9640_COM7_RGB		0x04
+#define	OV9640_COM7_QCIF	0x08
+#define	OV9640_COM7_QVGA	0x10
+#define	OV9640_COM7_CIF		0x20
+#define	OV9640_COM7_VGA		0x40
+#define	OV9640_COM7_SCCB_RESET	0x80
+
+#define	OV9640_TSLB_YVYU_YUYV	0x04
+#define	OV9640_TSLB_YUYV_UYVY	0x08
+
+#define	OV9640_COM12_YUV_AVG	0x04
+#define	OV9640_COM12_RSVD	0x40
+
+#define	OV9640_COM13_GAMMA_NONE	0x00
+#define	OV9640_COM13_GAMMA_Y	0x40
+#define	OV9640_COM13_GAMMA_RAW	0x80
+#define	OV9640_COM13_RGB_AVG	0x20
+#define	OV9640_COM13_MATRIX_EN	0x10
+#define	OV9640_COM13_Y_DELAY_EN	0x08
+#define	OV9640_COM13_YUV_DLY(x)	((x) & 0x07)
+
+#define	OV9640_COM15_OR_00FF	0x00
+#define	OV9640_COM15_OR_01FE	0x40
+#define	OV9640_COM15_OR_10F0	0xc0
+#define	OV9640_COM15_RGB_NORM	0x00
+#define	OV9640_COM15_RGB_565	0x10
+#define	OV9640_COM15_RGB_555	0x30
+
+#define	OV9640_COM16_RB_AVG	0x01
+
+/* IDs */
+#define	OV9640_V2		0x9648
+#define	OV9640_V3		0x9649
+#define	VERSION(pid, ver)	(((pid) << 8) | ((ver) & 0xFF))
+
+/* supported resolutions */
+enum {
+	W_QQCIF	= 88,
+	W_QQVGA	= 160,
+	W_QCIF	= 176,
+	W_QVGA	= 320,
+	W_CIF	= 352,
+	W_VGA	= 640,
+	W_SXGA	= 1280
+};
+#define	H_SXGA	960
+
+/* Misc. structures */
+struct ov9640_reg_alt {
+	u8	com7;
+	u8	com12;
+	u8	com13;
+	u8	com15;
+};
+
+struct ov9640_reg {
+	u8	reg;
+	u8	val;
+};
+
+struct ov9640_priv {
+	struct v4l2_subdev		subdev;
+
+	int				model;
+	int				revision;
+
+	bool				flag_vflip;
+	bool				flag_hflip;
+};
+
+#endif	/* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index a1ad38fc49c1..73ec970ca5ca 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -14,8 +14,10 @@
  *	unless the userspace driver also doesn't work for you...
  *
  *      Changes:
- *      08/07/2003        Daniele Bellucci <bellucda@tiscali.it>
- *                        - pms_capture: report back -EFAULT
+ *	25-11-2009 	Hans Verkuil <hverkuil@xs4all.nl>
+ * 			- converted to version 2 of the V4L API.
+ *      08/07/2003      Daniele Bellucci <bellucda@tiscali.it>
+ *                      - pms_capture: report back -EFAULT
  */
 
 #include <linux/module.h>
@@ -27,175 +29,183 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
 #include <asm/io.h>
-#include <linux/videodev.h>
+
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/mutex.h>
+#include <media/v4l2-device.h>
 
-#include <asm/uaccess.h>
+MODULE_LICENSE("GPL");
 
 
 #define MOTOROLA	1
-#define PHILIPS2	2
+#define PHILIPS2	2               /* SAA7191 */
 #define PHILIPS1	3
 #define MVVMEMORYWIDTH	0x40		/* 512 bytes */
 
-struct pms_device
-{
-	struct video_device v;
-	struct video_picture picture;
-	int height;
-	int width;
-	unsigned long in_use;
-	struct mutex lock;
-};
-
-struct i2c_info
-{
+struct i2c_info {
 	u8 slave;
 	u8 sub;
 	u8 data;
 	u8 hits;
 };
 
-static int i2c_count;
-static struct i2c_info i2cinfo[64];
+struct pms {
+	struct v4l2_device v4l2_dev;
+	struct video_device vdev;
+	int height;
+	int width;
+	int depth;
+	int input;
+	s32 brightness, saturation, hue, contrast;
+	unsigned long in_use;
+	struct mutex lock;
+	int i2c_count;
+	struct i2c_info i2cinfo[64];
+
+	int decoder;
+	int standard;	/* 0 - auto 1 - ntsc 2 - pal 3 - secam */
+	v4l2_std_id std;
+	int io;
+	int data;
+	void __iomem *mem;
+};
 
-static int decoder 		= PHILIPS2;
-static int standard;	/* 0 - auto 1 - ntsc 2 - pal 3 - secam */
+static struct pms pms_card;
 
 /*
  *	I/O ports and Shared Memory
  */
 
-static int io_port		=	0x250;
-static int data_port		=	0x251;
-static int mem_base		=	0xC8000;
-static void __iomem *mem;
-static int video_nr             =       -1;
+static int io_port = 0x250;
+module_param(io_port, int, 0);
 
+static int mem_base = 0xc8000;
+module_param(mem_base, int, 0);
 
+static int video_nr = -1;
+module_param(video_nr, int, 0);
 
-static inline void mvv_write(u8 index, u8 value)
+
+static inline void mvv_write(struct pms *dev, u8 index, u8 value)
 {
-	outw(index|(value<<8), io_port);
+	outw(index | (value << 8), dev->io);
 }
 
-static inline u8 mvv_read(u8 index)
+static inline u8 mvv_read(struct pms *dev, u8 index)
 {
-	outb(index, io_port);
-	return inb(data_port);
+	outb(index, dev->io);
+	return inb(dev->data);
 }
 
-static int pms_i2c_stat(u8 slave)
+static int pms_i2c_stat(struct pms *dev, u8 slave)
 {
-	int counter;
+	int counter = 0;
 	int i;
 
-	outb(0x28, io_port);
+	outb(0x28, dev->io);
 
-	counter=0;
-	while((inb(data_port)&0x01)==0)
-		if(counter++==256)
+	while ((inb(dev->data) & 0x01) == 0)
+		if (counter++ == 256)
 			break;
 
-	while((inb(data_port)&0x01)!=0)
-		if(counter++==256)
+	while ((inb(dev->data) & 0x01) != 0)
+		if (counter++ == 256)
 			break;
 
-	outb(slave, io_port);
+	outb(slave, dev->io);
 
-	counter=0;
-	while((inb(data_port)&0x01)==0)
-		if(counter++==256)
+	counter = 0;
+	while ((inb(dev->data) & 0x01) == 0)
+		if (counter++ == 256)
 			break;
 
-	while((inb(data_port)&0x01)!=0)
-		if(counter++==256)
+	while ((inb(dev->data) & 0x01) != 0)
+		if (counter++ == 256)
 			break;
 
-	for(i=0;i<12;i++)
-	{
-		char st=inb(data_port);
-		if((st&2)!=0)
+	for (i = 0; i < 12; i++) {
+		char st = inb(dev->data);
+
+		if ((st & 2) != 0)
 			return -1;
-		if((st&1)==0)
+		if ((st & 1) == 0)
 			break;
 	}
-	outb(0x29, io_port);
-	return inb(data_port);
+	outb(0x29, dev->io);
+	return inb(dev->data);
 }
 
-static int pms_i2c_write(u16 slave, u16 sub, u16 data)
+static int pms_i2c_write(struct pms *dev, u16 slave, u16 sub, u16 data)
 {
-	int skip=0;
+	int skip = 0;
 	int count;
 	int i;
 
-	for(i=0;i<i2c_count;i++)
-	{
-		if((i2cinfo[i].slave==slave) &&
-		   (i2cinfo[i].sub == sub))
-		{
-			if(i2cinfo[i].data==data)
-				skip=1;
-			i2cinfo[i].data=data;
-			i=i2c_count+1;
+	for (i = 0; i < dev->i2c_count; i++) {
+		if ((dev->i2cinfo[i].slave == slave) &&
+		    (dev->i2cinfo[i].sub == sub)) {
+			if (dev->i2cinfo[i].data == data)
+				skip = 1;
+			dev->i2cinfo[i].data = data;
+			i = dev->i2c_count + 1;
 		}
 	}
 
-	if(i==i2c_count && i2c_count<64)
-	{
-		i2cinfo[i2c_count].slave=slave;
-		i2cinfo[i2c_count].sub=sub;
-		i2cinfo[i2c_count].data=data;
-		i2c_count++;
+	if (i == dev->i2c_count && dev->i2c_count < 64) {
+		dev->i2cinfo[dev->i2c_count].slave = slave;
+		dev->i2cinfo[dev->i2c_count].sub = sub;
+		dev->i2cinfo[dev->i2c_count].data = data;
+		dev->i2c_count++;
 	}
 
-	if(skip)
+	if (skip)
 		return 0;
 
-	mvv_write(0x29, sub);
-	mvv_write(0x2A, data);
-	mvv_write(0x28, slave);
+	mvv_write(dev, 0x29, sub);
+	mvv_write(dev, 0x2A, data);
+	mvv_write(dev, 0x28, slave);
 
-	outb(0x28, io_port);
+	outb(0x28, dev->io);
 
-	count=0;
-	while((inb(data_port)&1)==0)
-		if(count>255)
+	count = 0;
+	while ((inb(dev->data) & 1) == 0)
+		if (count > 255)
 			break;
-	while((inb(data_port)&1)!=0)
-		if(count>255)
+	while ((inb(dev->data) & 1) != 0)
+		if (count > 255)
 			break;
 
-	count=inb(data_port);
+	count = inb(dev->data);
 
-	if(count&2)
+	if (count & 2)
 		return -1;
 	return count;
 }
 
-static int pms_i2c_read(int slave, int sub)
+static int pms_i2c_read(struct pms *dev, int slave, int sub)
 {
-	int i=0;
-	for(i=0;i<i2c_count;i++)
-	{
-		if(i2cinfo[i].slave==slave && i2cinfo[i].sub==sub)
-			return i2cinfo[i].data;
+	int i;
+
+	for (i = 0; i < dev->i2c_count; i++) {
+		if (dev->i2cinfo[i].slave == slave && dev->i2cinfo[i].sub == sub)
+			return dev->i2cinfo[i].data;
 	}
 	return 0;
 }
 
 
-static void pms_i2c_andor(int slave, int sub, int and, int or)
+static void pms_i2c_andor(struct pms *dev, int slave, int sub, int and, int or)
 {
 	u8 tmp;
 
-	tmp=pms_i2c_read(slave, sub);
-	tmp = (tmp&and)|or;
-	pms_i2c_write(slave, sub, tmp);
+	tmp = pms_i2c_read(dev, slave, sub);
+	tmp = (tmp & and) | or;
+	pms_i2c_write(dev, slave, sub, tmp);
 }
 
 /*
@@ -203,100 +213,108 @@ static void pms_i2c_andor(int slave, int sub, int and, int or)
  */
 
 
-static void pms_videosource(short source)
+static void pms_videosource(struct pms *dev, short source)
 {
-	mvv_write(0x2E, source?0x31:0x30);
+	switch (dev->decoder) {
+	case MOTOROLA:
+		break;
+	case PHILIPS2:
+		pms_i2c_andor(dev, 0x8a, 0x06, 0x7f, source ? 0x80 : 0);
+		break;
+	case PHILIPS1:
+		break;
+	}
+	mvv_write(dev, 0x2E, 0x31);
+	/* Was: mvv_write(dev, 0x2E, source ? 0x31 : 0x30);
+	   But could not make this work correctly. Only Composite input
+	   worked for me. */
 }
 
-static void pms_hue(short hue)
+static void pms_hue(struct pms *dev, short hue)
 {
-	switch(decoder)
-	{
-		case MOTOROLA:
-			pms_i2c_write(0x8A, 0x00, hue);
-			break;
-		case PHILIPS2:
-			pms_i2c_write(0x8A, 0x07, hue);
-			break;
-		case PHILIPS1:
-			pms_i2c_write(0x42, 0x07, hue);
-			break;
+	switch (dev->decoder) {
+	case MOTOROLA:
+		pms_i2c_write(dev, 0x8a, 0x00, hue);
+		break;
+	case PHILIPS2:
+		pms_i2c_write(dev, 0x8a, 0x07, hue);
+		break;
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x42, 0x07, hue);
+		break;
 	}
 }
 
-static void pms_colour(short colour)
+static void pms_saturation(struct pms *dev, short sat)
 {
-	switch(decoder)
-	{
-		case MOTOROLA:
-			pms_i2c_write(0x8A, 0x00, colour);
-			break;
-		case PHILIPS1:
-			pms_i2c_write(0x42, 0x12, colour);
-			break;
+	switch (dev->decoder) {
+	case MOTOROLA:
+		pms_i2c_write(dev, 0x8a, 0x00, sat);
+		break;
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x42, 0x12, sat);
+		break;
 	}
 }
 
 
-static void pms_contrast(short contrast)
+static void pms_contrast(struct pms *dev, short contrast)
 {
-	switch(decoder)
-	{
-		case MOTOROLA:
-			pms_i2c_write(0x8A, 0x00, contrast);
-			break;
-		case PHILIPS1:
-			pms_i2c_write(0x42, 0x13, contrast);
-			break;
+	switch (dev->decoder) {
+	case MOTOROLA:
+		pms_i2c_write(dev, 0x8a, 0x00, contrast);
+		break;
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x42, 0x13, contrast);
+		break;
 	}
 }
 
-static void pms_brightness(short brightness)
+static void pms_brightness(struct pms *dev, short brightness)
 {
-	switch(decoder)
-	{
-		case MOTOROLA:
-			pms_i2c_write(0x8A, 0x00, brightness);
-			pms_i2c_write(0x8A, 0x00, brightness);
-			pms_i2c_write(0x8A, 0x00, brightness);
-			break;
-		case PHILIPS1:
-			pms_i2c_write(0x42, 0x19, brightness);
-			break;
+	switch (dev->decoder) {
+	case MOTOROLA:
+		pms_i2c_write(dev, 0x8a, 0x00, brightness);
+		pms_i2c_write(dev, 0x8a, 0x00, brightness);
+		pms_i2c_write(dev, 0x8a, 0x00, brightness);
+		break;
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x42, 0x19, brightness);
+		break;
 	}
 }
 
 
-static void pms_format(short format)
+static void pms_format(struct pms *dev, short format)
 {
 	int target;
-	standard = format;
 
-	if(decoder==PHILIPS1)
-		target=0x42;
-	else if(decoder==PHILIPS2)
-		target=0x8A;
+	dev->standard = format;
+
+	if (dev->decoder == PHILIPS1)
+		target = 0x42;
+	else if (dev->decoder == PHILIPS2)
+		target = 0x8a;
 	else
 		return;
 
-	switch(format)
-	{
-		case 0:	/* Auto */
-			pms_i2c_andor(target, 0x0D, 0xFE,0x00);
-			pms_i2c_andor(target, 0x0F, 0x3F,0x80);
-			break;
-		case 1: /* NTSC */
-			pms_i2c_andor(target, 0x0D, 0xFE, 0x00);
-			pms_i2c_andor(target, 0x0F, 0x3F, 0x40);
-			break;
-		case 2: /* PAL */
-			pms_i2c_andor(target, 0x0D, 0xFE, 0x00);
-			pms_i2c_andor(target, 0x0F, 0x3F, 0x00);
-			break;
-		case 3:	/* SECAM */
-			pms_i2c_andor(target, 0x0D, 0xFE, 0x01);
-			pms_i2c_andor(target, 0x0F, 0x3F, 0x00);
-			break;
+	switch (format) {
+	case 0:	/* Auto */
+		pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
+		pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x80);
+		break;
+	case 1: /* NTSC */
+		pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
+		pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x40);
+		break;
+	case 2: /* PAL */
+		pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
+		pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
+		break;
+	case 3:	/* SECAM */
+		pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x01);
+		pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
+		break;
 	}
 }
 
@@ -308,18 +326,17 @@ static void pms_format(short format)
  *	people need it. We also don't yet use the PMS interrupt.
  */
 
-static void pms_hstart(short start)
+static void pms_hstart(struct pms *dev, short start)
 {
-	switch(decoder)
-	{
-		case PHILIPS1:
-			pms_i2c_write(0x8A, 0x05, start);
-			pms_i2c_write(0x8A, 0x18, start);
-			break;
-		case PHILIPS2:
-			pms_i2c_write(0x42, 0x05, start);
-			pms_i2c_write(0x42, 0x18, start);
-			break;
+	switch (dev->decoder) {
+	case PHILIPS1:
+		pms_i2c_write(dev, 0x8a, 0x05, start);
+		pms_i2c_write(dev, 0x8a, 0x18, start);
+		break;
+	case PHILIPS2:
+		pms_i2c_write(dev, 0x42, 0x05, start);
+		pms_i2c_write(dev, 0x42, 0x18, start);
+		break;
 	}
 }
 
@@ -327,293 +344,271 @@ static void pms_hstart(short start)
  *	Bandpass filters
  */
 
-static void pms_bandpass(short pass)
+static void pms_bandpass(struct pms *dev, short pass)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0x8A, 0x06, 0xCF, (pass&0x03)<<4);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x06, 0xCF, (pass&0x03)<<4);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x06, 0xcf, (pass & 0x03) << 4);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x06, 0xcf, (pass & 0x03) << 4);
 }
 
-static void pms_antisnow(short snow)
+static void pms_antisnow(struct pms *dev, short snow)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0x8A, 0x06, 0xF3, (snow&0x03)<<2);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x06, 0xF3, (snow&0x03)<<2);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x06, 0xf3, (snow & 0x03) << 2);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x06, 0xf3, (snow & 0x03) << 2);
 }
 
-static void pms_sharpness(short sharp)
+static void pms_sharpness(struct pms *dev, short sharp)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0x8A, 0x06, 0xFC, sharp&0x03);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x06, 0xFC, sharp&0x03);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x06, 0xfc, sharp & 0x03);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x06, 0xfc, sharp & 0x03);
 }
 
-static void pms_chromaagc(short agc)
+static void pms_chromaagc(struct pms *dev, short agc)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0x8A, 0x0C, 0x9F, (agc&0x03)<<5);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x0C, 0x9F, (agc&0x03)<<5);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x0c, 0x9f, (agc & 0x03) << 5);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x0c, 0x9f, (agc & 0x03) << 5);
 }
 
-static void pms_vertnoise(short noise)
+static void pms_vertnoise(struct pms *dev, short noise)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0x8A, 0x10, 0xFC, noise&3);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x10, 0xFC, noise&3);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x10, 0xfc, noise & 3);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x10, 0xfc, noise & 3);
 }
 
-static void pms_forcecolour(short colour)
+static void pms_forcecolour(struct pms *dev, short colour)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0x8A, 0x0C, 0x7F, (colour&1)<<7);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x0C, 0x7, (colour&1)<<7);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x0c, 0x7f, (colour & 1) << 7);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x0c, 0x7, (colour & 1) << 7);
 }
 
-static void pms_antigamma(short gamma)
+static void pms_antigamma(struct pms *dev, short gamma)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0xB8, 0x00, 0x7F, (gamma&1)<<7);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x20, 0x7, (gamma&1)<<7);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0xb8, 0x00, 0x7f, (gamma & 1) << 7);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x20, 0x7, (gamma & 1) << 7);
 }
 
-static void pms_prefilter(short filter)
+static void pms_prefilter(struct pms *dev, short filter)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0x8A, 0x06, 0xBF, (filter&1)<<6);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x06, 0xBF, (filter&1)<<6);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x06, 0xbf, (filter & 1) << 6);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x06, 0xbf, (filter & 1) << 6);
 }
 
-static void pms_hfilter(short filter)
+static void pms_hfilter(struct pms *dev, short filter)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0xB8, 0x04, 0x1F, (filter&7)<<5);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x24, 0x1F, (filter&7)<<5);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0xb8, 0x04, 0x1f, (filter & 7) << 5);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x24, 0x1f, (filter & 7) << 5);
 }
 
-static void pms_vfilter(short filter)
+static void pms_vfilter(struct pms *dev, short filter)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0xB8, 0x08, 0x9F, (filter&3)<<5);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x28, 0x9F, (filter&3)<<5);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0xb8, 0x08, 0x9f, (filter & 3) << 5);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x28, 0x9f, (filter & 3) << 5);
 }
 
-static void pms_killcolour(short colour)
+static void pms_killcolour(struct pms *dev, short colour)
 {
-	if(decoder==PHILIPS2)
-	{
-		pms_i2c_andor(0x8A, 0x08, 0x07, (colour&0x1F)<<3);
-		pms_i2c_andor(0x8A, 0x09, 0x07, (colour&0x1F)<<3);
-	}
-	else if(decoder==PHILIPS1)
-	{
-		pms_i2c_andor(0x42, 0x08, 0x07, (colour&0x1F)<<3);
-		pms_i2c_andor(0x42, 0x09, 0x07, (colour&0x1F)<<3);
+	if (dev->decoder == PHILIPS2) {
+		pms_i2c_andor(dev, 0x8a, 0x08, 0x07, (colour & 0x1f) << 3);
+		pms_i2c_andor(dev, 0x8a, 0x09, 0x07, (colour & 0x1f) << 3);
+	} else if (dev->decoder == PHILIPS1) {
+		pms_i2c_andor(dev, 0x42, 0x08, 0x07, (colour & 0x1f) << 3);
+		pms_i2c_andor(dev, 0x42, 0x09, 0x07, (colour & 0x1f) << 3);
 	}
 }
 
-static void pms_chromagain(short chroma)
+static void pms_chromagain(struct pms *dev, short chroma)
 {
-	if(decoder==PHILIPS2)
-	{
-		pms_i2c_write(0x8A, 0x11, chroma);
-	}
-	else if(decoder==PHILIPS1)
-	{
-		pms_i2c_write(0x42, 0x11, chroma);
-	}
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_write(dev, 0x8a, 0x11, chroma);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_write(dev, 0x42, 0x11, chroma);
 }
 
 
-static void pms_spacialcompl(short data)
+static void pms_spacialcompl(struct pms *dev, short data)
 {
-	mvv_write(0x3B, data);
+	mvv_write(dev, 0x3b, data);
 }
 
-static void pms_spacialcomph(short data)
+static void pms_spacialcomph(struct pms *dev, short data)
 {
-	mvv_write(0x3A, data);
+	mvv_write(dev, 0x3a, data);
 }
 
-static void pms_vstart(short start)
+static void pms_vstart(struct pms *dev, short start)
 {
-	mvv_write(0x16, start);
-	mvv_write(0x17, (start>>8)&0x01);
+	mvv_write(dev, 0x16, start);
+	mvv_write(dev, 0x17, (start >> 8) & 0x01);
 }
 
 #endif
 
-static void pms_secamcross(short cross)
+static void pms_secamcross(struct pms *dev, short cross)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0x8A, 0x0F, 0xDF, (cross&1)<<5);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42, 0x0F, 0xDF, (cross&1)<<5);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x0f, 0xdf, (cross & 1) << 5);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x0f, 0xdf, (cross & 1) << 5);
 }
 
 
-static void pms_swsense(short sense)
+static void pms_swsense(struct pms *dev, short sense)
 {
-	if(decoder==PHILIPS2)
-	{
-		pms_i2c_write(0x8A, 0x0A, sense);
-		pms_i2c_write(0x8A, 0x0B, sense);
-	}
-	else if(decoder==PHILIPS1)
-	{
-		pms_i2c_write(0x42, 0x0A, sense);
-		pms_i2c_write(0x42, 0x0B, sense);
+	if (dev->decoder == PHILIPS2) {
+		pms_i2c_write(dev, 0x8a, 0x0a, sense);
+		pms_i2c_write(dev, 0x8a, 0x0b, sense);
+	} else if (dev->decoder == PHILIPS1) {
+		pms_i2c_write(dev, 0x42, 0x0a, sense);
+		pms_i2c_write(dev, 0x42, 0x0b, sense);
 	}
 }
 
 
-static void pms_framerate(short frr)
+static void pms_framerate(struct pms *dev, short frr)
 {
-	int fps=(standard==1)?30:25;
-	if(frr==0)
+	int fps = (dev->std & V4L2_STD_525_60) ? 30 : 25;
+
+	if (frr == 0)
 		return;
-	fps=fps/frr;
-	mvv_write(0x14,0x80|fps);
-	mvv_write(0x15,1);
+	fps = fps/frr;
+	mvv_write(dev, 0x14, 0x80 | fps);
+	mvv_write(dev, 0x15, 1);
 }
 
-static void pms_vert(u8 deciden, u8 decinum)
+static void pms_vert(struct pms *dev, u8 deciden, u8 decinum)
 {
-	mvv_write(0x1C, deciden);	/* Denominator */
-	mvv_write(0x1D, decinum);	/* Numerator */
+	mvv_write(dev, 0x1c, deciden);	/* Denominator */
+	mvv_write(dev, 0x1d, decinum);	/* Numerator */
 }
 
 /*
  *	Turn 16bit ratios into best small ratio the chipset can grok
  */
 
-static void pms_vertdeci(unsigned short decinum, unsigned short deciden)
+static void pms_vertdeci(struct pms *dev, unsigned short decinum, unsigned short deciden)
 {
-	/* Knock it down by /5 once */
-	if(decinum%5==0)
-	{
-		deciden/=5;
-		decinum/=5;
+	/* Knock it down by / 5 once */
+	if (decinum % 5 == 0) {
+		deciden /= 5;
+		decinum /= 5;
 	}
 	/*
 	 *	3's
 	 */
-	while(decinum%3==0 && deciden%3==0)
-	{
-		deciden/=3;
-		decinum/=3;
+	while (decinum % 3 == 0 && deciden % 3 == 0) {
+		deciden /= 3;
+		decinum /= 3;
 	}
 	/*
 	 *	2's
 	 */
-	while(decinum%2==0 && deciden%2==0)
-	{
-		decinum/=2;
-		deciden/=2;
+	while (decinum % 2 == 0 && deciden % 2 == 0) {
+		decinum /= 2;
+		deciden /= 2;
 	}
 	/*
 	 *	Fudgyify
 	 */
-	while(deciden>32)
-	{
-		deciden/=2;
-		decinum=(decinum+1)/2;
+	while (deciden > 32) {
+		deciden /= 2;
+		decinum = (decinum + 1) / 2;
 	}
-	if(deciden==32)
+	if (deciden == 32)
 		deciden--;
-	pms_vert(deciden,decinum);
+	pms_vert(dev, deciden, decinum);
 }
 
-static void pms_horzdeci(short decinum, short deciden)
+static void pms_horzdeci(struct pms *dev, short decinum, short deciden)
 {
-	if(decinum<=512)
-	{
-		if(decinum%5==0)
-		{
-			decinum/=5;
-			deciden/=5;
+	if (decinum <= 512) {
+		if (decinum % 5 == 0) {
+			decinum /= 5;
+			deciden /= 5;
 		}
-	}
-	else
-	{
-		decinum=512;
-		deciden=640;	/* 768 would be ideal */
+	} else {
+		decinum = 512;
+		deciden = 640;	/* 768 would be ideal */
 	}
 
-	while(((decinum|deciden)&1)==0)
-	{
-		decinum>>=1;
-		deciden>>=1;
+	while (((decinum | deciden) & 1) == 0) {
+		decinum >>= 1;
+		deciden >>= 1;
 	}
-	while(deciden>32)
-	{
-		deciden>>=1;
-		decinum=(decinum+1)>>1;
+	while (deciden > 32) {
+		deciden >>= 1;
+		decinum = (decinum + 1) >> 1;
 	}
-	if(deciden==32)
+	if (deciden == 32)
 		deciden--;
 
-	mvv_write(0x24, 0x80|deciden);
-	mvv_write(0x25, decinum);
+	mvv_write(dev, 0x24, 0x80 | deciden);
+	mvv_write(dev, 0x25, decinum);
 }
 
-static void pms_resolution(short width, short height)
+static void pms_resolution(struct pms *dev, short width, short height)
 {
 	int fg_height;
 
-	fg_height=height;
-	if(fg_height>280)
-		fg_height=280;
+	fg_height = height;
+	if (fg_height > 280)
+		fg_height = 280;
 
-	mvv_write(0x18, fg_height);
-	mvv_write(0x19, fg_height>>8);
+	mvv_write(dev, 0x18, fg_height);
+	mvv_write(dev, 0x19, fg_height >> 8);
 
-	if(standard==1)
-	{
-		mvv_write(0x1A, 0xFC);
-		mvv_write(0x1B, 0x00);
-		if(height>fg_height)
-			pms_vertdeci(240,240);
+	if (dev->std & V4L2_STD_525_60) {
+		mvv_write(dev, 0x1a, 0xfc);
+		mvv_write(dev, 0x1b, 0x00);
+		if (height > fg_height)
+			pms_vertdeci(dev, 240, 240);
 		else
-			pms_vertdeci(fg_height,240);
-	}
-	else
-	{
-		mvv_write(0x1A, 0x1A);
-		mvv_write(0x1B, 0x01);
-		if(fg_height>256)
-			pms_vertdeci(270,270);
+			pms_vertdeci(dev, fg_height, 240);
+	} else {
+		mvv_write(dev, 0x1a, 0x1a);
+		mvv_write(dev, 0x1b, 0x01);
+		if (fg_height > 256)
+			pms_vertdeci(dev, 270, 270);
 		else
-			pms_vertdeci(fg_height, 270);
+			pms_vertdeci(dev, fg_height, 270);
 	}
-	mvv_write(0x12,0);
-	mvv_write(0x13, MVVMEMORYWIDTH);
-	mvv_write(0x42, 0x00);
-	mvv_write(0x43, 0x00);
-	mvv_write(0x44, MVVMEMORYWIDTH);
+	mvv_write(dev, 0x12, 0);
+	mvv_write(dev, 0x13, MVVMEMORYWIDTH);
+	mvv_write(dev, 0x42, 0x00);
+	mvv_write(dev, 0x43, 0x00);
+	mvv_write(dev, 0x44, MVVMEMORYWIDTH);
 
-	mvv_write(0x22, width+8);
-	mvv_write(0x23, (width+8)>> 8);
+	mvv_write(dev, 0x22, width + 8);
+	mvv_write(dev, 0x23, (width + 8) >> 8);
 
-	if(standard==1)
-		pms_horzdeci(width,640);
+	if (dev->std & V4L2_STD_525_60)
+		pms_horzdeci(dev, width, 640);
 	else
-		pms_horzdeci(width+8, 768);
+		pms_horzdeci(dev, width + 8, 768);
 
-	mvv_write(0x30, mvv_read(0x30)&0xFE);
-	mvv_write(0x08, mvv_read(0x08)|0x01);
-	mvv_write(0x01, mvv_read(0x01)&0xFD);
-	mvv_write(0x32, 0x00);
-	mvv_write(0x33, MVVMEMORYWIDTH);
+	mvv_write(dev, 0x30, mvv_read(dev, 0x30) & 0xfe);
+	mvv_write(dev, 0x08, mvv_read(dev, 0x08) | 0x01);
+	mvv_write(dev, 0x01, mvv_read(dev, 0x01) & 0xfd);
+	mvv_write(dev, 0x32, 0x00);
+	mvv_write(dev, 0x33, MVVMEMORYWIDTH);
 }
 
 
@@ -621,52 +616,49 @@ static void pms_resolution(short width, short height)
  *	Set Input
  */
 
-static void pms_vcrinput(short input)
+static void pms_vcrinput(struct pms *dev, short input)
 {
-	if(decoder==PHILIPS2)
-		pms_i2c_andor(0x8A,0x0D,0x7F,(input&1)<<7);
-	else if(decoder==PHILIPS1)
-		pms_i2c_andor(0x42,0x0D,0x7F,(input&1)<<7);
+	if (dev->decoder == PHILIPS2)
+		pms_i2c_andor(dev, 0x8a, 0x0d, 0x7f, (input & 1) << 7);
+	else if (dev->decoder == PHILIPS1)
+		pms_i2c_andor(dev, 0x42, 0x0d, 0x7f, (input & 1) << 7);
 }
 
 
-static int pms_capture(struct pms_device *dev, char __user *buf, int rgb555, int count)
+static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count)
 {
 	int y;
-	int dw = 2*dev->width;
-
-	char tmp[dw+32]; /* using a temp buffer is faster than direct  */
+	int dw = 2 * dev->width;
+	char tmp[dw + 32]; /* using a temp buffer is faster than direct  */
 	int cnt = 0;
-	int len=0;
+	int len = 0;
 	unsigned char r8 = 0x5;  /* value for reg8  */
 
 	if (rgb555)
 		r8 |= 0x20; /* else use untranslated rgb = 565 */
-	mvv_write(0x08,r8); /* capture rgb555/565, init DRAM, PC enable */
+	mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */
 
 /*	printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
 
-	for (y = 0; y < dev->height; y++ )
-	{
-		writeb(0, mem);  /* synchronisiert neue Zeile */
+	for (y = 0; y < dev->height; y++) {
+		writeb(0, dev->mem);  /* synchronisiert neue Zeile */
 
 		/*
 		 *	This is in truth a fifo, be very careful as if you
 		 *	forgot this odd things will occur 8)
 		 */
 
-		memcpy_fromio(tmp, mem, dw+32); /* discard 16 word   */
+		memcpy_fromio(tmp, dev->mem, dw + 32); /* discard 16 word   */
 		cnt -= dev->height;
-		while (cnt <= 0)
-		{
+		while (cnt <= 0) {
 			/*
 			 *	Don't copy too far
 			 */
-			int dt=dw;
-			if(dt+len>count)
-				dt=count-len;
+			int dt = dw;
+			if (dt + len > count)
+				dt = count - len;
 			cnt += dev->height;
-			if (copy_to_user(buf, tmp+32, dt))
+			if (copy_to_user(buf, tmp + 32, dt))
 				return len ? len : -EFAULT;
 			buf += dt;
 			len += dt;
@@ -680,221 +672,278 @@ static int pms_capture(struct pms_device *dev, char __user *buf, int rgb555, int
  *	Video4linux interfacing
  */
 
-static long pms_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int pms_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
 {
-	struct video_device *dev = video_devdata(file);
-	struct pms_device *pd=(struct pms_device *)dev;
-
-	switch(cmd)
-	{
-		case VIDIOCGCAP:
-		{
-			struct video_capability *b = arg;
-			strcpy(b->name, "Mediavision PMS");
-			b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES;
-			b->channels = 4;
-			b->audios = 0;
-			b->maxwidth = 640;
-			b->maxheight = 480;
-			b->minwidth = 16;
-			b->minheight = 16;
-			return 0;
-		}
-		case VIDIOCGCHAN:
-		{
-			struct video_channel *v = arg;
-			if(v->channel<0 || v->channel>3)
-				return -EINVAL;
-			v->flags=0;
-			v->tuners=1;
-			/* Good question.. its composite or SVHS so.. */
-			v->type = VIDEO_TYPE_CAMERA;
-			switch(v->channel)
-			{
-				case 0:
-					strcpy(v->name, "Composite");break;
-				case 1:
-					strcpy(v->name, "SVideo");break;
-				case 2:
-					strcpy(v->name, "Composite(VCR)");break;
-				case 3:
-					strcpy(v->name, "SVideo(VCR)");break;
-			}
-			return 0;
-		}
-		case VIDIOCSCHAN:
-		{
-			struct video_channel *v = arg;
-			if(v->channel<0 || v->channel>3)
-				return -EINVAL;
-			mutex_lock(&pd->lock);
-			pms_videosource(v->channel&1);
-			pms_vcrinput(v->channel>>1);
-			mutex_unlock(&pd->lock);
-			return 0;
-		}
-		case VIDIOCGTUNER:
-		{
-			struct video_tuner *v = arg;
-			if(v->tuner)
-				return -EINVAL;
-			strcpy(v->name, "Format");
-			v->rangelow=0;
-			v->rangehigh=0;
-			v->flags= VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
-			switch(standard)
-			{
-				case 0:
-					v->mode = VIDEO_MODE_AUTO;
-					break;
-				case 1:
-					v->mode = VIDEO_MODE_NTSC;
-					break;
-				case 2:
-					v->mode = VIDEO_MODE_PAL;
-					break;
-				case 3:
-					v->mode = VIDEO_MODE_SECAM;
-					break;
-			}
-			return 0;
-		}
-		case VIDIOCSTUNER:
-		{
-			struct video_tuner *v = arg;
-			if(v->tuner)
-				return -EINVAL;
-			mutex_lock(&pd->lock);
-			switch(v->mode)
-			{
-				case VIDEO_MODE_AUTO:
-					pms_framerate(25);
-					pms_secamcross(0);
-					pms_format(0);
-					break;
-				case VIDEO_MODE_NTSC:
-					pms_framerate(30);
-					pms_secamcross(0);
-					pms_format(1);
-					break;
-				case VIDEO_MODE_PAL:
-					pms_framerate(25);
-					pms_secamcross(0);
-					pms_format(2);
-					break;
-				case VIDEO_MODE_SECAM:
-					pms_framerate(25);
-					pms_secamcross(1);
-					pms_format(2);
-					break;
-				default:
-					mutex_unlock(&pd->lock);
-					return -EINVAL;
-			}
-			mutex_unlock(&pd->lock);
-			return 0;
-		}
-		case VIDIOCGPICT:
-		{
-			struct video_picture *p = arg;
-			*p = pd->picture;
-			return 0;
-		}
-		case VIDIOCSPICT:
-		{
-			struct video_picture *p = arg;
-			if(!((p->palette==VIDEO_PALETTE_RGB565 && p->depth==16)
-			    ||(p->palette==VIDEO_PALETTE_RGB555 && p->depth==15)))
-				return -EINVAL;
-			pd->picture= *p;
+	struct pms *dev = video_drvdata(file);
 
-			/*
-			 *	Now load the card.
-			 */
+	strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card));
+	strlcpy(vcap->bus_info, "ISA", sizeof(vcap->bus_info));
+	vcap->version = KERNEL_VERSION(0, 0, 3);
+	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	return 0;
+}
 
-			mutex_lock(&pd->lock);
-			pms_brightness(p->brightness>>8);
-			pms_hue(p->hue>>8);
-			pms_colour(p->colour>>8);
-			pms_contrast(p->contrast>>8);
-			mutex_unlock(&pd->lock);
-			return 0;
-		}
-		case VIDIOCSWIN:
-		{
-			struct video_window *vw = arg;
-			if(vw->flags)
-				return -EINVAL;
-			if(vw->clipcount)
-				return -EINVAL;
-			if(vw->height<16||vw->height>480)
-				return -EINVAL;
-			if(vw->width<16||vw->width>640)
-				return -EINVAL;
-			pd->width=vw->width;
-			pd->height=vw->height;
-			mutex_lock(&pd->lock);
-			pms_resolution(pd->width, pd->height);
-			mutex_unlock(&pd->lock);			/* Ok we figured out what to use from our wide choice */
-			return 0;
-		}
-		case VIDIOCGWIN:
-		{
-			struct video_window *vw = arg;
-			memset(vw,0,sizeof(*vw));
-			vw->width=pd->width;
-			vw->height=pd->height;
-			return 0;
-		}
-		case VIDIOCKEY:
-			return 0;
-		case VIDIOCCAPTURE:
-		case VIDIOCGFBUF:
-		case VIDIOCSFBUF:
-		case VIDIOCGFREQ:
-		case VIDIOCSFREQ:
-		case VIDIOCGAUDIO:
-		case VIDIOCSAUDIO:
-			return -EINVAL;
-		default:
-			return -ENOIOCTLCMD;
+static int pms_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	static const char *inputs[4] = {
+		"Composite",
+		"S-Video",
+		"Composite (VCR)",
+		"S-Video (VCR)"
+	};
+
+	if (vin->index > 3)
+		return -EINVAL;
+	strlcpy(vin->name, inputs[vin->index], sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = V4L2_STD_ALL;
+	vin->status = 0;
+	return 0;
+}
+
+static int pms_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+	struct pms *dev = video_drvdata(file);
+
+	*inp = dev->input;
+	return 0;
+}
+
+static int pms_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	struct pms *dev = video_drvdata(file);
+
+	if (inp > 3)
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+	dev->input = inp;
+	pms_videosource(dev, inp & 1);
+	pms_vcrinput(dev, inp >> 1);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct pms *dev = video_drvdata(file);
+
+	*std = dev->std;
+	return 0;
+}
+
+static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct pms *dev = video_drvdata(file);
+	int ret = 0;
+
+	dev->std = *std;
+	mutex_lock(&dev->lock);
+	if (dev->std & V4L2_STD_NTSC) {
+		pms_framerate(dev, 30);
+		pms_secamcross(dev, 0);
+		pms_format(dev, 1);
+	} else if (dev->std & V4L2_STD_PAL) {
+		pms_framerate(dev, 25);
+		pms_secamcross(dev, 0);
+		pms_format(dev, 2);
+	} else if (dev->std & V4L2_STD_SECAM) {
+		pms_framerate(dev, 25);
+		pms_secamcross(dev, 1);
+		pms_format(dev, 2);
+	} else {
+		ret = -EINVAL;
+	}
+	/*
+	switch (v->mode) {
+	case VIDEO_MODE_AUTO:
+		pms_framerate(dev, 25);
+		pms_secamcross(dev, 0);
+		pms_format(dev, 0);
+		break;
+	}*/
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int pms_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	switch (qc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 139);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 70);
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 64);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0);
+	}
+	return -EINVAL;
+}
+
+static int pms_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct pms *dev = video_drvdata(file);
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = dev->brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = dev->contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		ctrl->value = dev->saturation;
+		break;
+	case V4L2_CID_HUE:
+		ctrl->value = dev->hue;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int pms_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct pms *dev = video_drvdata(file);
+	int ret = 0;
+
+	mutex_lock(&dev->lock);
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		dev->brightness = ctrl->value;
+		pms_brightness(dev, dev->brightness);
+		break;
+	case V4L2_CID_CONTRAST:
+		dev->contrast = ctrl->value;
+		pms_contrast(dev, dev->contrast);
+		break;
+	case V4L2_CID_SATURATION:
+		dev->saturation = ctrl->value;
+		pms_saturation(dev, dev->saturation);
+		break;
+	case V4L2_CID_HUE:
+		dev->hue = ctrl->value;
+		pms_hue(dev, dev->hue);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
 	}
+	mutex_unlock(&dev->lock);
+	return ret;
+}
+
+static int pms_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct pms *dev = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = dev->width;
+	pix->height = dev->height;
+	pix->pixelformat = dev->width == 15 ?
+			    V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB565;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 2 * dev->width;
+	pix->sizeimage = 2 * dev->width * dev->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
 	return 0;
 }
 
-static long pms_ioctl(struct file *file,
-		     unsigned int cmd, unsigned long arg)
+static int pms_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-	return video_usercopy(file, cmd, arg, pms_do_ioctl);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->height < 16 || pix->height > 480)
+		return -EINVAL;
+	if (pix->width < 16 || pix->width > 640)
+		return -EINVAL;
+	if (pix->pixelformat != V4L2_PIX_FMT_RGB555 &&
+	    pix->pixelformat != V4L2_PIX_FMT_RGB565)
+		return -EINVAL;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 2 * pix->width;
+	pix->sizeimage = 2 * pix->width * pix->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int pms_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct pms *dev = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = pms_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	mutex_lock(&dev->lock);
+	dev->width = pix->width;
+	dev->height = pix->height;
+	dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16;
+	pms_resolution(dev, dev->width, dev->height);
+	/* Ok we figured out what to use from our wide choice */
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int pms_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "RGB 5:5:5", V4L2_PIX_FMT_RGB555,
+		  { 0, 0, 0, 0 }
+		},
+		{ 0, 0, 0,
+		  "RGB 5:6:5", V4L2_PIX_FMT_RGB565,
+		  { 0, 0, 0, 0 }
+		},
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 1)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
 }
 
 static ssize_t pms_read(struct file *file, char __user *buf,
 		    size_t count, loff_t *ppos)
 {
-	struct video_device *v = video_devdata(file);
-	struct pms_device *pd=(struct pms_device *)v;
+	struct pms *dev = video_drvdata(file);
 	int len;
 
-	mutex_lock(&pd->lock);
-	len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count);
-	mutex_unlock(&pd->lock);
+	mutex_lock(&dev->lock);
+	len = pms_capture(dev, buf, (dev->depth == 15), count);
+	mutex_unlock(&dev->lock);
 	return len;
 }
 
 static int pms_exclusive_open(struct file *file)
 {
-	struct video_device *v = video_devdata(file);
-	struct pms_device *pd = (struct pms_device *)v;
+	struct pms *dev = video_drvdata(file);
 
-	return test_and_set_bit(0, &pd->in_use) ? -EBUSY : 0;
+	return test_and_set_bit(0, &dev->in_use) ? -EBUSY : 0;
 }
 
 static int pms_exclusive_release(struct file *file)
 {
-	struct video_device *v = video_devdata(file);
-	struct pms_device *pd = (struct pms_device *)v;
+	struct pms *dev = video_drvdata(file);
 
-	clear_bit(0, &pd->in_use);
+	clear_bit(0, &dev->in_use);
 	return 0;
 }
 
@@ -902,78 +951,81 @@ static const struct v4l2_file_operations pms_fops = {
 	.owner		= THIS_MODULE,
 	.open           = pms_exclusive_open,
 	.release        = pms_exclusive_release,
-	.ioctl          = pms_ioctl,
+	.ioctl		= video_ioctl2,
 	.read           = pms_read,
 };
 
-static struct video_device pms_template=
-{
-	.name		= "Mediavision PMS",
-	.fops           = &pms_fops,
-	.release 	= video_device_release_empty,
+static const struct v4l2_ioctl_ops pms_ioctl_ops = {
+	.vidioc_querycap    		    = pms_querycap,
+	.vidioc_g_input      		    = pms_g_input,
+	.vidioc_s_input      		    = pms_s_input,
+	.vidioc_enum_input   		    = pms_enum_input,
+	.vidioc_g_std 			    = pms_g_std,
+	.vidioc_s_std 			    = pms_s_std,
+	.vidioc_queryctrl 		    = pms_queryctrl,
+	.vidioc_g_ctrl  		    = pms_g_ctrl,
+	.vidioc_s_ctrl 			    = pms_s_ctrl,
+	.vidioc_enum_fmt_vid_cap 	    = pms_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap 		    = pms_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  		    = pms_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  	    = pms_try_fmt_vid_cap,
 };
 
-static struct pms_device pms_device;
-
-
 /*
  *	Probe for and initialise the Mediavision PMS
  */
 
-static int init_mediavision(void)
+static int init_mediavision(struct pms *dev)
 {
 	int id;
 	int idec, decst;
 	int i;
-
-	unsigned char i2c_defs[]={
-		0x4C,0x30,0x00,0xE8,
-		0xB6,0xE2,0x00,0x00,
-		0xFF,0xFF,0x00,0x00,
-		0x00,0x00,0x78,0x98,
-		0x00,0x00,0x00,0x00,
-		0x34,0x0A,0xF4,0xCE,
-		0xE4
+	static const unsigned char i2c_defs[] = {
+		0x4c, 0x30, 0x00, 0xe8,
+		0xb6, 0xe2, 0x00, 0x00,
+		0xff, 0xff, 0x00, 0x00,
+		0x00, 0x00, 0x78, 0x98,
+		0x00, 0x00, 0x00, 0x00,
+		0x34, 0x0a, 0xf4, 0xce,
+		0xe4
 	};
 
-	mem = ioremap(mem_base, 0x800);
-	if (!mem)
+	dev->mem = ioremap(mem_base, 0x800);
+	if (!dev->mem)
 		return -ENOMEM;
 
-	if (!request_region(0x9A01, 1, "Mediavision PMS config"))
-	{
-		printk(KERN_WARNING "mediavision: unable to detect: 0x9A01 in use.\n");
-		iounmap(mem);
+	if (!request_region(0x9a01, 1, "Mediavision PMS config")) {
+		printk(KERN_WARNING "mediavision: unable to detect: 0x9a01 in use.\n");
+		iounmap(dev->mem);
 		return -EBUSY;
 	}
-	if (!request_region(io_port, 3, "Mediavision PMS"))
-	{
-		printk(KERN_WARNING "mediavision: I/O port %d in use.\n", io_port);
-		release_region(0x9A01, 1);
-		iounmap(mem);
+	if (!request_region(dev->io, 3, "Mediavision PMS")) {
+		printk(KERN_WARNING "mediavision: I/O port %d in use.\n", dev->io);
+		release_region(0x9a01, 1);
+		iounmap(dev->mem);
 		return -EBUSY;
 	}
-	outb(0xB8, 0x9A01);		/* Unlock */
-	outb(io_port>>4, 0x9A01);	/* Set IO port */
+	outb(0xb8, 0x9a01);		/* Unlock */
+	outb(dev->io >> 4, 0x9a01);	/* Set IO port */
 
 
-	id=mvv_read(3);
-	decst=pms_i2c_stat(0x43);
+	id = mvv_read(dev, 3);
+	decst = pms_i2c_stat(dev, 0x43);
 
-	if(decst!=-1)
-		idec=2;
-	else if(pms_i2c_stat(0xb9)!=-1)
-		idec=3;
-	else if(pms_i2c_stat(0x8b)!=-1)
-		idec=1;
+	if (decst != -1)
+		idec = 2;
+	else if (pms_i2c_stat(dev, 0xb9) != -1)
+		idec = 3;
+	else if (pms_i2c_stat(dev, 0x8b) != -1)
+		idec = 1;
 	else
-		idec=0;
+		idec = 0;
 
 	printk(KERN_INFO "PMS type is %d\n", idec);
-	if(idec == 0) {
-		release_region(io_port, 3);
-		release_region(0x9A01, 1);
-		iounmap(mem);
+	if (idec == 0) {
+		release_region(dev->io, 3);
+		release_region(0x9a01, 1);
+		iounmap(dev->mem);
 		return -ENODEV;
 	}
 
@@ -981,51 +1033,50 @@ static int init_mediavision(void)
 	 *	Ok we have a PMS of some sort
 	 */
 
-	mvv_write(0x04, mem_base>>12);	/* Set the memory area */
+	mvv_write(dev, 0x04, mem_base >> 12);	/* Set the memory area */
 
 	/* Ok now load the defaults */
 
-	for(i=0;i<0x19;i++)
-	{
-		if(i2c_defs[i]==0xFF)
-			pms_i2c_andor(0x8A, i, 0x07,0x00);
+	for (i = 0; i < 0x19; i++) {
+		if (i2c_defs[i] == 0xff)
+			pms_i2c_andor(dev, 0x8a, i, 0x07, 0x00);
 		else
-			pms_i2c_write(0x8A, i, i2c_defs[i]);
+			pms_i2c_write(dev, 0x8a, i, i2c_defs[i]);
 	}
 
-	pms_i2c_write(0xB8,0x00,0x12);
-	pms_i2c_write(0xB8,0x04,0x00);
-	pms_i2c_write(0xB8,0x07,0x00);
-	pms_i2c_write(0xB8,0x08,0x00);
-	pms_i2c_write(0xB8,0x09,0xFF);
-	pms_i2c_write(0xB8,0x0A,0x00);
-	pms_i2c_write(0xB8,0x0B,0x10);
-	pms_i2c_write(0xB8,0x10,0x03);
-
-	mvv_write(0x01, 0x00);
-	mvv_write(0x05, 0xA0);
-	mvv_write(0x08, 0x25);
-	mvv_write(0x09, 0x00);
-	mvv_write(0x0A, 0x20|MVVMEMORYWIDTH);
-
-	mvv_write(0x10, 0x02);
-	mvv_write(0x1E, 0x0C);
-	mvv_write(0x1F, 0x03);
-	mvv_write(0x26, 0x06);
-
-	mvv_write(0x2B, 0x00);
-	mvv_write(0x2C, 0x20);
-	mvv_write(0x2D, 0x00);
-	mvv_write(0x2F, 0x70);
-	mvv_write(0x32, 0x00);
-	mvv_write(0x33, MVVMEMORYWIDTH);
-	mvv_write(0x34, 0x00);
-	mvv_write(0x35, 0x00);
-	mvv_write(0x3A, 0x80);
-	mvv_write(0x3B, 0x10);
-	mvv_write(0x20, 0x00);
-	mvv_write(0x21, 0x00);
-	mvv_write(0x30, 0x22);
+	pms_i2c_write(dev, 0xb8, 0x00, 0x12);
+	pms_i2c_write(dev, 0xb8, 0x04, 0x00);
+	pms_i2c_write(dev, 0xb8, 0x07, 0x00);
+	pms_i2c_write(dev, 0xb8, 0x08, 0x00);
+	pms_i2c_write(dev, 0xb8, 0x09, 0xff);
+	pms_i2c_write(dev, 0xb8, 0x0a, 0x00);
+	pms_i2c_write(dev, 0xb8, 0x0b, 0x10);
+	pms_i2c_write(dev, 0xb8, 0x10, 0x03);
+
+	mvv_write(dev, 0x01, 0x00);
+	mvv_write(dev, 0x05, 0xa0);
+	mvv_write(dev, 0x08, 0x25);
+	mvv_write(dev, 0x09, 0x00);
+	mvv_write(dev, 0x0a, 0x20 | MVVMEMORYWIDTH);
+
+	mvv_write(dev, 0x10, 0x02);
+	mvv_write(dev, 0x1e, 0x0c);
+	mvv_write(dev, 0x1f, 0x03);
+	mvv_write(dev, 0x26, 0x06);
+
+	mvv_write(dev, 0x2b, 0x00);
+	mvv_write(dev, 0x2c, 0x20);
+	mvv_write(dev, 0x2d, 0x00);
+	mvv_write(dev, 0x2f, 0x70);
+	mvv_write(dev, 0x32, 0x00);
+	mvv_write(dev, 0x33, MVVMEMORYWIDTH);
+	mvv_write(dev, 0x34, 0x00);
+	mvv_write(dev, 0x35, 0x00);
+	mvv_write(dev, 0x3a, 0x80);
+	mvv_write(dev, 0x3b, 0x10);
+	mvv_write(dev, 0x20, 0x00);
+	mvv_write(dev, 0x21, 0x00);
+	mvv_write(dev, 0x30, 0x22);
 	return 0;
 }
 
@@ -1038,53 +1089,77 @@ static int enable;
 module_param(enable, int, 0);
 #endif
 
-static int __init init_pms_cards(void)
+static int __init pms_init(void)
 {
-	printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
+	struct pms *dev = &pms_card;
+	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+	int res;
+
+	strlcpy(v4l2_dev->name, "pms", sizeof(v4l2_dev->name));
+
+	v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.03\n");
 
 #ifndef MODULE
 	if (!enable) {
-		printk(KERN_INFO "PMS: not enabled, use pms.enable=1 to "
-				 "probe\n");
+		v4l2_err(v4l2_dev,
+			"PMS: not enabled, use pms.enable=1 to probe\n");
 		return -ENODEV;
 	}
 #endif
 
-	data_port = io_port +1;
+	dev->decoder = PHILIPS2;
+	dev->io = io_port;
+	dev->data = io_port + 1;
 
-	if(init_mediavision())
-	{
-		printk(KERN_INFO "Board not found.\n");
+	if (init_mediavision(dev)) {
+		v4l2_err(v4l2_dev, "Board not found.\n");
 		return -ENODEV;
 	}
-	memcpy(&pms_device, &pms_template, sizeof(pms_template));
-	mutex_init(&pms_device.lock);
-	pms_device.height=240;
-	pms_device.width=320;
-	pms_swsense(75);
-	pms_resolution(320,240);
-	return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER, video_nr);
-}
-
-module_param(io_port, int, 0);
-module_param(mem_base, int, 0);
-module_param(video_nr, int, 0);
-MODULE_LICENSE("GPL");
 
+	res = v4l2_device_register(NULL, v4l2_dev);
+	if (res < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		return res;
+	}
 
-static void __exit shutdown_mediavision(void)
-{
-	release_region(io_port,3);
-	release_region(0x9A01, 1);
+	strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+	dev->vdev.v4l2_dev = v4l2_dev;
+	dev->vdev.fops = &pms_fops;
+	dev->vdev.ioctl_ops = &pms_ioctl_ops;
+	dev->vdev.release = video_device_release_empty;
+	video_set_drvdata(&dev->vdev, dev);
+	mutex_init(&dev->lock);
+	dev->std = V4L2_STD_NTSC_M;
+	dev->height = 240;
+	dev->width = 320;
+	dev->depth = 15;
+	dev->brightness = 139;
+	dev->contrast = 70;
+	dev->hue = 0;
+	dev->saturation = 64;
+	pms_swsense(dev, 75);
+	pms_resolution(dev, 320, 240);
+	pms_videosource(dev, 0);
+	pms_vcrinput(dev, 0);
+	if (video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+		v4l2_device_unregister(&dev->v4l2_dev);
+		release_region(dev->io, 3);
+		release_region(0x9a01, 1);
+		iounmap(dev->mem);
+		return -EINVAL;
+	}
+	return 0;
 }
 
-static void __exit cleanup_pms_module(void)
+static void __exit pms_exit(void)
 {
-	shutdown_mediavision();
-	video_unregister_device((struct video_device *)&pms_device);
-	iounmap(mem);
-}
+	struct pms *dev = &pms_card;
 
-module_init(init_pms_cards);
-module_exit(cleanup_pms_module);
+	video_unregister_device(&dev->vdev);
+	release_region(dev->io, 3);
+	release_region(0x9a01, 1);
+	iounmap(dev->mem);
+}
 
+module_init(pms_init);
+module_exit(pms_exit);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index fbe3856bdca6..ae977668c496 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -142,6 +142,9 @@ int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
 {
 	int bcnt = 0;
 	int ccnt;
+	ccnt = scnprintf(buf, acnt, "Driver hardware description: %s\n",
+			 pvr2_hdw_get_desc(hdw));
+	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 	ccnt = scnprintf(buf,acnt,"Driver state info:\n");
 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 	ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
@@ -249,11 +252,15 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
 			scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 			if (scnt && wptr) {
 				count -= scnt; buf += scnt;
-				if (debugifc_match_keyword(wptr,wlen,"prom")) {
-					pvr2_hdw_cpufw_set_enabled(hdw,!0,!0);
-				} else if (debugifc_match_keyword(wptr,wlen,
-								  "ram")) {
-					pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
+				if (debugifc_match_keyword(wptr, wlen,
+							   "prom")) {
+					pvr2_hdw_cpufw_set_enabled(hdw, 2, !0);
+				} else if (debugifc_match_keyword(wptr, wlen,
+								  "ram8k")) {
+					pvr2_hdw_cpufw_set_enabled(hdw, 0, !0);
+				} else if (debugifc_match_keyword(wptr, wlen,
+								  "ram16k")) {
+					pvr2_hdw_cpufw_set_enabled(hdw, 1, !0);
 				} else {
 					return -EINVAL;
 				}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index e4d7c13cab87..6bc16c13ccef 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -58,7 +58,7 @@ static const char *pvr2_fw1_names_29xxx[] = {
 };
 
 static const struct pvr2_device_desc pvr2_device_29xxx = {
-		.description = "WinTV PVR USB2 Model Category 29xxx",
+		.description = "WinTV PVR USB2 Model 29xxx",
 		.shortname = "29xxx",
 		.client_table.lst = pvr2_cli_29xxx,
 		.client_table.cnt = ARRAY_SIZE(pvr2_cli_29xxx),
@@ -91,7 +91,7 @@ static const char *pvr2_fw1_names_24xxx[] = {
 };
 
 static const struct pvr2_device_desc pvr2_device_24xxx = {
-		.description = "WinTV PVR USB2 Model Category 24xxx",
+		.description = "WinTV PVR USB2 Model 24xxx",
 		.shortname = "24xxx",
 		.client_table.lst = pvr2_cli_24xxx,
 		.client_table.cnt = ARRAY_SIZE(pvr2_cli_24xxx),
@@ -340,7 +340,7 @@ static const char *pvr2_fw1_names_73xxx[] = {
 };
 
 static const struct pvr2_device_desc pvr2_device_73xxx = {
-		.description = "WinTV HVR-1900 Model Category 73xxx",
+		.description = "WinTV HVR-1900 Model 73xxx",
 		.shortname = "73xxx",
 		.client_table.lst = pvr2_cli_73xxx,
 		.client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
@@ -351,6 +351,7 @@ static const struct pvr2_device_desc pvr2_device_73xxx = {
 		.flag_has_analogtuner = !0,
 		.flag_has_composite = !0,
 		.flag_has_svideo = !0,
+		.flag_fx2_16kb = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
 		.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
 		.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
@@ -445,7 +446,7 @@ static const char *pvr2_fw1_names_75xxx[] = {
 };
 
 static const struct pvr2_device_desc pvr2_device_750xx = {
-		.description = "WinTV HVR-1950 Model Category 750xx",
+		.description = "WinTV HVR-1950 Model 750xx",
 		.shortname = "750xx",
 		.client_table.lst = pvr2_cli_73xxx,
 		.client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
@@ -456,6 +457,7 @@ static const struct pvr2_device_desc pvr2_device_750xx = {
 		.flag_has_analogtuner = !0,
 		.flag_has_composite = !0,
 		.flag_has_svideo = !0,
+		.flag_fx2_16kb = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
 		.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
 		.default_std_mask = V4L2_STD_NTSC_M,
@@ -467,7 +469,7 @@ 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",
+		.description = "WinTV HVR-1950 Model 751xx",
 		.shortname = "751xx",
 		.client_table.lst = pvr2_cli_73xxx,
 		.client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx),
@@ -478,6 +480,7 @@ static const struct pvr2_device_desc pvr2_device_751xx = {
 		.flag_has_analogtuner = !0,
 		.flag_has_composite = !0,
 		.flag_has_svideo = !0,
+		.flag_fx2_16kb = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
 		.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
 		.default_std_mask = V4L2_STD_NTSC_M,
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index ea04ecf8aa39..e5b9594eb5f6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -176,6 +176,7 @@ struct pvr2_device_desc {
 	unsigned int flag_has_analogtuner:1;   /* Has analog tuner */
 	unsigned int flag_has_composite:1;     /* Has composite input */
 	unsigned int flag_has_svideo:1;        /* Has s-video input */
+	unsigned int flag_fx2_16kb:1;          /* 16KB FX2 firmware OK here */
 };
 
 extern struct usb_device_id pvr2_device_table[];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 54ac5349dee2..e046fdaec5ae 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -294,7 +294,10 @@ static int pvr2_encoder_cmd(void *ctxt,
 			pvr2_trace(
 				PVR2_TRACE_ERROR_LEGS,
 				"Giving up on command."
-				"  This is normally recovered by the driver.");
+				"  This is normally recovered via a firmware"
+				" reload and re-initialization; concern"
+				" is only warranted if this happens repeatedly"
+				" and rapidly.");
 			break;
 		}
 		wrData[0] = 0x7;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 5fcad28211d2..de5485f506b1 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -270,6 +270,7 @@ struct pvr2_hdw {
 
 	int force_dirty;        /* consider all controls dirty if true */
 	int flag_ok;            /* device in known good state */
+	int flag_modulefail;    /* true if at least one module failed to load */
 	int flag_disconnected;  /* flag_ok == 0 due to disconnect */
 	int flag_init_ok;       /* true if structure is fully initialized */
 	int fw1_state;          /* current situation with fw1 */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 13639b302700..1bbdab08fe0e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -1447,6 +1447,7 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
 	const struct firmware *fw_entry = NULL;
 	void  *fw_ptr;
 	unsigned int pipe;
+	unsigned int fwsize;
 	int ret;
 	u16 address;
 
@@ -1473,9 +1474,21 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
 	usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f));
 
 	pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
+	fwsize = fw_entry->size;
 
-	if (fw_entry->size != 0x2000){
-		pvr2_trace(PVR2_TRACE_ERROR_LEGS,"wrong fx2 firmware size");
+	if ((fwsize != 0x2000) &&
+	    (!(hdw->hdw_desc->flag_fx2_16kb && (fwsize == 0x4000)))) {
+		if (hdw->hdw_desc->flag_fx2_16kb) {
+			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+				   "Wrong fx2 firmware size"
+				   " (expected 8192 or 16384, got %u)",
+				   fwsize);
+		} else {
+			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+				   "Wrong fx2 firmware size"
+				   " (expected 8192, got %u)",
+				   fwsize);
+		}
 		release_firmware(fw_entry);
 		return -ENOMEM;
 	}
@@ -1493,7 +1506,7 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
 	   chunk. */
 
 	ret = 0;
-	for(address = 0; address < fw_entry->size; address += 0x800) {
+	for (address = 0; address < fwsize; address += 0x800) {
 		memcpy(fw_ptr, fw_entry->data + address, 0x800);
 		ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address,
 				       0, fw_ptr, 0x800, HZ);
@@ -1509,8 +1522,8 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
 
 	trace_firmware("Upload done (%d bytes sent)",ret);
 
-	/* We should have written 8192 bytes */
-	if (ret == 8192) {
+	/* We should have written fwsize bytes */
+	if (ret == fwsize) {
 		hdw->fw1_state = FW1_STATE_RELOAD;
 		return 0;
 	}
@@ -2030,7 +2043,8 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
 	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",
+			   "Module ID %u for device %s has no name?"
+			   "  The driver might have a configuration problem.",
 			   mid,
 			   hdw->hdw_desc->description);
 		return -EINVAL;
@@ -2058,7 +2072,8 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
 	if (!i2ccnt) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
 			   "Module ID %u (%s) for device %s:"
-			   " No i2c addresses",
+			   " No i2c addresses."
+			   "  The driver might have a configuration problem.",
 			   mid, fname, hdw->hdw_desc->description);
 		return -EINVAL;
 	}
@@ -2090,7 +2105,9 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
 
 	if (!sd) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-			   "Module ID %u (%s) for device %s failed to load",
+			   "Module ID %u (%s) for device %s failed to load."
+			   "  Possible missing sub-device kernel module or"
+			   " initialization failure within module.",
 			   mid, fname, hdw->hdw_desc->description);
 		return -EIO;
 	}
@@ -2132,7 +2149,10 @@ static void pvr2_hdw_load_modules(struct pvr2_hdw *hdw)
 	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);
+	if (!okFl) {
+		hdw->flag_modulefail = !0;
+		pvr2_hdw_render_useless(hdw);
+	}
 }
 
 
@@ -2334,6 +2354,20 @@ static void pvr2_hdw_setup(struct pvr2_hdw *hdw)
 				break;
 			}
 		}
+		if (hdw->flag_modulefail) {
+			pvr2_trace(
+				PVR2_TRACE_ERROR_LEGS,
+				"***WARNING*** pvrusb2 driver initialization"
+				" failed due to the failure of one or more"
+				" sub-device kernel modules.");
+			pvr2_trace(
+				PVR2_TRACE_ERROR_LEGS,
+				"You need to resolve the failing condition"
+				" before this driver can function.  There"
+				" should be some earlier messages giving more"
+				" information about the problem.");
+			break;
+		}
 		if (procreload) {
 			pvr2_trace(
 				PVR2_TRACE_ERROR_LEGS,
@@ -2419,6 +2453,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 	hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
 		   hdw,hdw_desc->description);
+	pvr2_trace(PVR2_TRACE_INFO, "Hardware description: %s",
+		hdw_desc->description);
 	if (!hdw) goto fail;
 
 	init_timer(&hdw->quiescent_timer);
@@ -3480,7 +3516,7 @@ static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw)
 
 
 void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
-				int prom_flag,
+				int mode,
 				int enable_flag)
 {
 	int ret;
@@ -3503,11 +3539,12 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
 			break;
 		}
 
-		hdw->fw_cpu_flag = (prom_flag == 0);
+		hdw->fw_cpu_flag = (mode != 2);
 		if (hdw->fw_cpu_flag) {
+			hdw->fw_size = (mode == 1) ? 0x4000 : 0x2000;
 			pvr2_trace(PVR2_TRACE_FIRMWARE,
-				   "Preparing to suck out CPU firmware");
-			hdw->fw_size = 0x2000;
+				   "Preparing to suck out CPU firmware"
+				   " (size=%u)", hdw->fw_size);
 			hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
 			if (!hdw->fw_buffer) {
 				hdw->fw_size = 0;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 7b6940554e9a..56e70eae20c1 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -219,7 +219,7 @@ int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
    this may prevent the device from running (and leaving this mode may
    imply a device reset). */
 void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *,
-				int prom_flag,
+				int mode, /* 0=8KB FX2, 1=16KB FX2, 2=PROM */
 				int enable_flag);
 
 /* Return true if we're in a mode for retrieval CPU firmware */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index a334b1a966a2..7cbe18c4ca95 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -50,6 +50,7 @@ MODULE_PARM_DESC(disable_autoload_ir_video,
 
 /* Mapping of IR schemes to known I2C addresses - if any */
 static const unsigned char ir_video_addresses[] = {
+	[PVR2_IR_SCHEME_ZILOG] = 0x71,
 	[PVR2_IR_SCHEME_29XXX] = 0x18,
 	[PVR2_IR_SCHEME_24XXX] = 0x18,
 };
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 2d8825e5b1be..6aa48e0ae731 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -913,6 +913,15 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
 }
 
 
+static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip)
+{
+	if (!dip) return;
+	if (!dip->devbase.parent) return;
+	dip->devbase.parent = NULL;
+	device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE);
+}
+
+
 static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
 {
 	if (vp->dev_video) {
@@ -943,6 +952,8 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
 	struct pvr2_v4l2 *vp;
 	vp = container_of(chp,struct pvr2_v4l2,channel);
 	if (!vp->channel.mc_head->disconnect_flag) return;
+	pvr2_v4l2_dev_disassociate_parent(vp->dev_video);
+	pvr2_v4l2_dev_disassociate_parent(vp->dev_radio);
 	if (vp->vfirst) return;
 	pvr2_v4l2_destroy_no_lock(vp);
 }
@@ -1250,12 +1261,13 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
 			       struct pvr2_v4l2 *vp,
 			       int v4l_type)
 {
+	struct usb_device *usbdev;
 	int mindevnum;
 	int unit_number;
 	int *nr_ptr = NULL;
 	dip->v4lp = vp;
 
-
+	usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw);
 	dip->v4l_type = v4l_type;
 	switch (v4l_type) {
 	case VFL_TYPE_GRABBER:
@@ -1296,6 +1308,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
 	if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
 		mindevnum = nr_ptr[unit_number];
 	}
+	dip->devbase.parent = &usbdev->dev;
 	if ((video_register_device(&dip->devbase,
 				   dip->v4l_type, mindevnum) < 0) &&
 	    (video_register_device(&dip->devbase,
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index f976df452a34..89b620f6db7b 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -68,6 +68,7 @@
 #endif
 #include <linux/vmalloc.h>
 #include <asm/io.h>
+#include <linux/kernel.h>		/* simple_strtol() */
 
 #include "pwc.h"
 #include "pwc-kiara.h"
@@ -1916,19 +1917,6 @@ disconnect_out:
 	unlock_kernel();
 }
 
-/* *grunt* We have to do atoi ourselves :-( */
-static int pwc_atoi(const char *s)
-{
-	int k = 0;
-
-	k = 0;
-	while (*s != '\0' && *s >= '0' && *s <= '9') {
-		k = 10 * k + (*s - '0');
-		s++;
-	}
-	return k;
-}
-
 
 /*
  * Initialization code & module stuff
@@ -2078,13 +2066,16 @@ static int __init usb_pwc_init(void)
 				}
 				else {
 					/* No type or serial number specified, just a number. */
-					device_hint[i].device_node = pwc_atoi(s);
+					device_hint[i].device_node =
+						simple_strtol(s, NULL, 10);
 				}
 			}
 			else {
 				/* There's a colon, so we have at least a type and a device node */
-				device_hint[i].type = pwc_atoi(s);
-				device_hint[i].device_node = pwc_atoi(colon + 1);
+				device_hint[i].type =
+					simple_strtol(s, NULL, 10);
+				device_hint[i].device_node =
+					simple_strtol(colon + 1, NULL, 10);
 				if (*dot != '\0') {
 					/* There's a serial number as well */
 					int k;
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
new file mode 100644
index 000000000000..373f2a30a677
--- /dev/null
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -0,0 +1,1219 @@
+/*
+ * Driver for RJ54N1CB0C CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.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/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+#define RJ54N1_DEV_CODE			0x0400
+#define RJ54N1_DEV_CODE2		0x0401
+#define RJ54N1_OUT_SEL			0x0403
+#define RJ54N1_XY_OUTPUT_SIZE_S_H	0x0404
+#define RJ54N1_X_OUTPUT_SIZE_S_L	0x0405
+#define RJ54N1_Y_OUTPUT_SIZE_S_L	0x0406
+#define RJ54N1_XY_OUTPUT_SIZE_P_H	0x0407
+#define RJ54N1_X_OUTPUT_SIZE_P_L	0x0408
+#define RJ54N1_Y_OUTPUT_SIZE_P_L	0x0409
+#define RJ54N1_LINE_LENGTH_PCK_S_H	0x040a
+#define RJ54N1_LINE_LENGTH_PCK_S_L	0x040b
+#define RJ54N1_LINE_LENGTH_PCK_P_H	0x040c
+#define RJ54N1_LINE_LENGTH_PCK_P_L	0x040d
+#define RJ54N1_RESIZE_N			0x040e
+#define RJ54N1_RESIZE_N_STEP		0x040f
+#define RJ54N1_RESIZE_STEP		0x0410
+#define RJ54N1_RESIZE_HOLD_H		0x0411
+#define RJ54N1_RESIZE_HOLD_L		0x0412
+#define RJ54N1_H_OBEN_OFS		0x0413
+#define RJ54N1_V_OBEN_OFS		0x0414
+#define RJ54N1_RESIZE_CONTROL		0x0415
+#define RJ54N1_INC_USE_SEL_H		0x0425
+#define RJ54N1_INC_USE_SEL_L		0x0426
+#define RJ54N1_MIRROR_STILL_MODE	0x0427
+#define RJ54N1_INIT_START		0x0428
+#define RJ54N1_SCALE_1_2_LEV		0x0429
+#define RJ54N1_SCALE_4_LEV		0x042a
+#define RJ54N1_Y_GAIN			0x04d8
+#define RJ54N1_APT_GAIN_UP		0x04fa
+#define RJ54N1_RA_SEL_UL		0x0530
+#define RJ54N1_BYTE_SWAP		0x0531
+#define RJ54N1_OUT_SIGPO		0x053b
+#define RJ54N1_FRAME_LENGTH_S_H		0x0595
+#define RJ54N1_FRAME_LENGTH_S_L		0x0596
+#define RJ54N1_FRAME_LENGTH_P_H		0x0597
+#define RJ54N1_FRAME_LENGTH_P_L		0x0598
+#define RJ54N1_IOC			0x05ef
+#define RJ54N1_TG_BYPASS		0x0700
+#define RJ54N1_PLL_L			0x0701
+#define RJ54N1_PLL_N			0x0702
+#define RJ54N1_PLL_EN			0x0704
+#define RJ54N1_RATIO_TG			0x0706
+#define RJ54N1_RATIO_T			0x0707
+#define RJ54N1_RATIO_R			0x0708
+#define RJ54N1_RAMP_TGCLK_EN		0x0709
+#define RJ54N1_OCLK_DSP			0x0710
+#define RJ54N1_RATIO_OP			0x0711
+#define RJ54N1_RATIO_O			0x0712
+#define RJ54N1_OCLK_SEL_EN		0x0713
+#define RJ54N1_CLK_RST			0x0717
+#define RJ54N1_RESET_STANDBY		0x0718
+
+#define E_EXCLK				(1 << 7)
+#define SOFT_STDBY			(1 << 4)
+#define SEN_RSTX			(1 << 2)
+#define TG_RSTX				(1 << 1)
+#define DSP_RSTX			(1 << 0)
+
+#define RESIZE_HOLD_SEL			(1 << 2)
+#define RESIZE_GO			(1 << 1)
+
+#define RJ54N1_COLUMN_SKIP		0
+#define RJ54N1_ROW_SKIP			0
+#define RJ54N1_MAX_WIDTH		1600
+#define RJ54N1_MAX_HEIGHT		1200
+
+/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */
+
+static const struct soc_camera_data_format rj54n1_colour_formats[] = {
+	{
+		.name		= "YUYV",
+		.depth		= 16,
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.colorspace	= V4L2_COLORSPACE_JPEG,
+	}, {
+		.name		= "RGB565",
+		.depth		= 16,
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+	}
+};
+
+struct rj54n1_clock_div {
+	u8 ratio_tg;
+	u8 ratio_t;
+	u8 ratio_r;
+	u8 ratio_op;
+	u8 ratio_o;
+};
+
+struct rj54n1 {
+	struct v4l2_subdev subdev;
+	struct v4l2_rect rect;	/* Sensor window */
+	unsigned short width;	/* Output window */
+	unsigned short height;
+	unsigned short resize;	/* Sensor * 1024 / resize = Output */
+	struct rj54n1_clock_div clk_div;
+	u32 fourcc;
+	unsigned short scale;
+	u8 bank;
+};
+
+struct rj54n1_reg_val {
+	u16 reg;
+	u8 val;
+};
+
+const static struct rj54n1_reg_val bank_4[] = {
+	{0x417, 0},
+	{0x42c, 0},
+	{0x42d, 0xf0},
+	{0x42e, 0},
+	{0x42f, 0x50},
+	{0x430, 0xf5},
+	{0x431, 0x16},
+	{0x432, 0x20},
+	{0x433, 0},
+	{0x434, 0xc8},
+	{0x43c, 8},
+	{0x43e, 0x90},
+	{0x445, 0x83},
+	{0x4ba, 0x58},
+	{0x4bb, 4},
+	{0x4bc, 0x20},
+	{0x4db, 4},
+	{0x4fe, 2},
+};
+
+const static struct rj54n1_reg_val bank_5[] = {
+	{0x514, 0},
+	{0x516, 0},
+	{0x518, 0},
+	{0x51a, 0},
+	{0x51d, 0xff},
+	{0x56f, 0x28},
+	{0x575, 0x40},
+	{0x5bc, 0x48},
+	{0x5c1, 6},
+	{0x5e5, 0x11},
+	{0x5e6, 0x43},
+	{0x5e7, 0x33},
+	{0x5e8, 0x21},
+	{0x5e9, 0x30},
+	{0x5ea, 0x0},
+	{0x5eb, 0xa5},
+	{0x5ec, 0xff},
+	{0x5fe, 2},
+};
+
+const static struct rj54n1_reg_val bank_7[] = {
+	{0x70a, 0},
+	{0x714, 0xff},
+	{0x715, 0xff},
+	{0x716, 0x1f},
+	{0x7FE, 0x02},
+};
+
+const static struct rj54n1_reg_val bank_8[] = {
+	{0x800, 0x00},
+	{0x801, 0x01},
+	{0x802, 0x61},
+	{0x805, 0x00},
+	{0x806, 0x00},
+	{0x807, 0x00},
+	{0x808, 0x00},
+	{0x809, 0x01},
+	{0x80A, 0x61},
+	{0x80B, 0x00},
+	{0x80C, 0x01},
+	{0x80D, 0x00},
+	{0x80E, 0x00},
+	{0x80F, 0x00},
+	{0x810, 0x00},
+	{0x811, 0x01},
+	{0x812, 0x61},
+	{0x813, 0x00},
+	{0x814, 0x11},
+	{0x815, 0x00},
+	{0x816, 0x41},
+	{0x817, 0x00},
+	{0x818, 0x51},
+	{0x819, 0x01},
+	{0x81A, 0x1F},
+	{0x81B, 0x00},
+	{0x81C, 0x01},
+	{0x81D, 0x00},
+	{0x81E, 0x11},
+	{0x81F, 0x00},
+	{0x820, 0x41},
+	{0x821, 0x00},
+	{0x822, 0x51},
+	{0x823, 0x00},
+	{0x824, 0x00},
+	{0x825, 0x00},
+	{0x826, 0x47},
+	{0x827, 0x01},
+	{0x828, 0x4F},
+	{0x829, 0x00},
+	{0x82A, 0x00},
+	{0x82B, 0x00},
+	{0x82C, 0x30},
+	{0x82D, 0x00},
+	{0x82E, 0x40},
+	{0x82F, 0x00},
+	{0x830, 0xB3},
+	{0x831, 0x00},
+	{0x832, 0xE3},
+	{0x833, 0x00},
+	{0x834, 0x00},
+	{0x835, 0x00},
+	{0x836, 0x00},
+	{0x837, 0x00},
+	{0x838, 0x00},
+	{0x839, 0x01},
+	{0x83A, 0x61},
+	{0x83B, 0x00},
+	{0x83C, 0x01},
+	{0x83D, 0x00},
+	{0x83E, 0x00},
+	{0x83F, 0x00},
+	{0x840, 0x00},
+	{0x841, 0x01},
+	{0x842, 0x61},
+	{0x843, 0x00},
+	{0x844, 0x1D},
+	{0x845, 0x00},
+	{0x846, 0x00},
+	{0x847, 0x00},
+	{0x848, 0x00},
+	{0x849, 0x01},
+	{0x84A, 0x1F},
+	{0x84B, 0x00},
+	{0x84C, 0x05},
+	{0x84D, 0x00},
+	{0x84E, 0x19},
+	{0x84F, 0x01},
+	{0x850, 0x21},
+	{0x851, 0x01},
+	{0x852, 0x5D},
+	{0x853, 0x00},
+	{0x854, 0x00},
+	{0x855, 0x00},
+	{0x856, 0x19},
+	{0x857, 0x01},
+	{0x858, 0x21},
+	{0x859, 0x00},
+	{0x85A, 0x00},
+	{0x85B, 0x00},
+	{0x85C, 0x00},
+	{0x85D, 0x00},
+	{0x85E, 0x00},
+	{0x85F, 0x00},
+	{0x860, 0xB3},
+	{0x861, 0x00},
+	{0x862, 0xE3},
+	{0x863, 0x00},
+	{0x864, 0x00},
+	{0x865, 0x00},
+	{0x866, 0x00},
+	{0x867, 0x00},
+	{0x868, 0x00},
+	{0x869, 0xE2},
+	{0x86A, 0x00},
+	{0x86B, 0x01},
+	{0x86C, 0x06},
+	{0x86D, 0x00},
+	{0x86E, 0x00},
+	{0x86F, 0x00},
+	{0x870, 0x60},
+	{0x871, 0x8C},
+	{0x872, 0x10},
+	{0x873, 0x00},
+	{0x874, 0xE0},
+	{0x875, 0x00},
+	{0x876, 0x27},
+	{0x877, 0x01},
+	{0x878, 0x00},
+	{0x879, 0x00},
+	{0x87A, 0x00},
+	{0x87B, 0x03},
+	{0x87C, 0x00},
+	{0x87D, 0x00},
+	{0x87E, 0x00},
+	{0x87F, 0x00},
+	{0x880, 0x00},
+	{0x881, 0x00},
+	{0x882, 0x00},
+	{0x883, 0x00},
+	{0x884, 0x00},
+	{0x885, 0x00},
+	{0x886, 0xF8},
+	{0x887, 0x00},
+	{0x888, 0x03},
+	{0x889, 0x00},
+	{0x88A, 0x64},
+	{0x88B, 0x00},
+	{0x88C, 0x03},
+	{0x88D, 0x00},
+	{0x88E, 0xB1},
+	{0x88F, 0x00},
+	{0x890, 0x03},
+	{0x891, 0x01},
+	{0x892, 0x1D},
+	{0x893, 0x00},
+	{0x894, 0x03},
+	{0x895, 0x01},
+	{0x896, 0x4B},
+	{0x897, 0x00},
+	{0x898, 0xE5},
+	{0x899, 0x00},
+	{0x89A, 0x01},
+	{0x89B, 0x00},
+	{0x89C, 0x01},
+	{0x89D, 0x04},
+	{0x89E, 0xC8},
+	{0x89F, 0x00},
+	{0x8A0, 0x01},
+	{0x8A1, 0x01},
+	{0x8A2, 0x61},
+	{0x8A3, 0x00},
+	{0x8A4, 0x01},
+	{0x8A5, 0x00},
+	{0x8A6, 0x00},
+	{0x8A7, 0x00},
+	{0x8A8, 0x00},
+	{0x8A9, 0x00},
+	{0x8AA, 0x7F},
+	{0x8AB, 0x03},
+	{0x8AC, 0x00},
+	{0x8AD, 0x00},
+	{0x8AE, 0x00},
+	{0x8AF, 0x00},
+	{0x8B0, 0x00},
+	{0x8B1, 0x00},
+	{0x8B6, 0x00},
+	{0x8B7, 0x01},
+	{0x8B8, 0x00},
+	{0x8B9, 0x00},
+	{0x8BA, 0x02},
+	{0x8BB, 0x00},
+	{0x8BC, 0xFF},
+	{0x8BD, 0x00},
+	{0x8FE, 0x02},
+};
+
+const static struct rj54n1_reg_val bank_10[] = {
+	{0x10bf, 0x69}
+};
+
+/* Clock dividers - these are default register values, divider = register + 1 */
+const static struct rj54n1_clock_div clk_div = {
+	.ratio_tg	= 3 /* default: 5 */,
+	.ratio_t	= 4 /* default: 1 */,
+	.ratio_r	= 4 /* default: 0 */,
+	.ratio_op	= 1 /* default: 5 */,
+	.ratio_o	= 9 /* default: 0 */,
+};
+
+static struct rj54n1 *to_rj54n1(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct rj54n1, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u16 reg)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	int ret;
+
+	/* set bank */
+	if (rj54n1->bank != reg >> 8) {
+		dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
+		ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
+		if (ret < 0)
+			return ret;
+		rj54n1->bank = reg >> 8;
+	}
+	return i2c_smbus_read_byte_data(client, reg & 0xff);
+}
+
+static int reg_write(struct i2c_client *client, const u16 reg,
+		     const u8 data)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	int ret;
+
+	/* set bank */
+	if (rj54n1->bank != reg >> 8) {
+		dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
+		ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
+		if (ret < 0)
+			return ret;
+		rj54n1->bank = reg >> 8;
+	}
+	dev_dbg(&client->dev, "[0x%x] = 0x%x\n", reg & 0xff, data);
+	return i2c_smbus_write_byte_data(client, reg & 0xff, data);
+}
+
+static int reg_set(struct i2c_client *client, const u16 reg,
+		   const u8 data, const u8 mask)
+{
+	int ret;
+
+	ret = reg_read(client, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(client, reg, (ret & ~mask) | (data & mask));
+}
+
+static int reg_write_multiple(struct i2c_client *client,
+			      const struct rj54n1_reg_val *rv, const int n)
+{
+	int i, ret;
+
+	for (i = 0; i < n; i++) {
+		ret = reg_write(client, rv->reg, rv->val);
+		if (ret < 0)
+			return ret;
+		rv++;
+	}
+
+	return 0;
+}
+
+static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	/* TODO: start / stop streaming */
+	return 0;
+}
+
+static int rj54n1_set_bus_param(struct soc_camera_device *icd,
+				unsigned long flags)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct i2c_client *client = sd->priv;
+	/* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */
+
+	if (flags & SOCAM_PCLK_SAMPLE_RISING)
+		return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4);
+	else
+		return reg_write(client, RJ54N1_OUT_SIGPO, 0);
+}
+
+static unsigned long rj54n1_query_bus_param(struct soc_camera_device *icd)
+{
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+	const unsigned long flags =
+		SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
+		SOCAM_MASTER | SOCAM_DATAWIDTH_8 |
+		SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+		SOCAM_DATA_ACTIVE_HIGH;
+
+	return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int rj54n1_set_rect(struct i2c_client *client,
+			   u16 reg_x, u16 reg_y, u16 reg_xy,
+			   u32 width, u32 height)
+{
+	int ret;
+
+	ret = reg_write(client, reg_xy,
+			((width >> 4) & 0x70) |
+			((height >> 8) & 7));
+
+	if (!ret)
+		ret = reg_write(client, reg_x, width & 0xff);
+	if (!ret)
+		ret = reg_write(client, reg_y, height & 0xff);
+
+	return ret;
+}
+
+/*
+ * Some commands, specifically certain initialisation sequences, require
+ * a commit operation.
+ */
+static int rj54n1_commit(struct i2c_client *client)
+{
+	int ret = reg_write(client, RJ54N1_INIT_START, 1);
+	msleep(10);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_INIT_START, 0);
+	return ret;
+}
+
+static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct i2c_client *client = sd->priv;
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+
+	a->c	= rj54n1->rect;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	a->bounds.left			= RJ54N1_COLUMN_SKIP;
+	a->bounds.top			= RJ54N1_ROW_SKIP;
+	a->bounds.width			= RJ54N1_MAX_WIDTH;
+	a->bounds.height		= RJ54N1_MAX_HEIGHT;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int rj54n1_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+	struct i2c_client *client = sd->priv;
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	pix->pixelformat	= rj54n1->fourcc;
+	pix->field		= V4L2_FIELD_NONE;
+	pix->width		= rj54n1->width;
+	pix->height		= rj54n1->height;
+
+	return 0;
+}
+
+/*
+ * The actual geometry configuration routine. It scales the input window into
+ * the output one, updates the window sizes and returns an error or the resize
+ * coefficient on success. Note: we only use the "Fixed Scaling" on this camera.
+ */
+static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h,
+			       u32 *out_w, u32 *out_h)
+{
+	struct i2c_client *client = sd->priv;
+	unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
+		output_w = *out_w, output_h = *out_h;
+	u16 inc_sel;
+	int ret;
+
+	ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L,
+			      RJ54N1_Y_OUTPUT_SIZE_S_L,
+			      RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h);
+	if (!ret)
+		ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_P_L,
+			      RJ54N1_Y_OUTPUT_SIZE_P_L,
+			      RJ54N1_XY_OUTPUT_SIZE_P_H, output_w, output_h);
+
+	if (ret < 0)
+		return ret;
+
+	if (output_w > input_w || output_h > input_h) {
+		input_w = output_w;
+		input_h = output_h;
+
+		resize = 1024;
+	} else {
+		unsigned int resize_x, resize_y;
+		resize_x = input_w * 1024 / output_w;
+		resize_y = input_h * 1024 / output_h;
+
+		resize = min(resize_x, resize_y);
+
+		/* Prohibited value ranges */
+		switch (resize) {
+		case 2040 ... 2047:
+			resize = 2039;
+			break;
+		case 4080 ... 4095:
+			resize = 4079;
+			break;
+		case 8160 ... 8191:
+			resize = 8159;
+			break;
+		case 16320 ... 16383:
+			resize = 16319;
+		}
+
+		input_w = output_w * resize / 1024;
+		input_h = output_h * resize / 1024;
+	}
+
+	/* Set scaling */
+	ret = reg_write(client, RJ54N1_RESIZE_HOLD_L, resize & 0xff);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESIZE_HOLD_H, resize >> 8);
+
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Configure a skipping bitmask. The sensor will select a skipping value
+	 * among set bits automatically.
+	 */
+	skip = min(resize / 1024, (unsigned)15);
+	inc_sel = 1 << skip;
+
+	if (inc_sel <= 2)
+		inc_sel = 0xc;
+	else if (resize & 1023 && skip < 15)
+		inc_sel |= 1 << (skip + 1);
+
+	ret = reg_write(client, RJ54N1_INC_USE_SEL_L, inc_sel & 0xfc);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8);
+
+	/* Start resizing */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
+				RESIZE_HOLD_SEL | RESIZE_GO | 1);
+
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(&client->dev, "resize %u, skip %u\n", resize, skip);
+
+	/* Constant taken from manufacturer's example */
+	msleep(230);
+
+	ret = reg_write(client, RJ54N1_RESIZE_CONTROL, RESIZE_HOLD_SEL | 1);
+	if (ret < 0)
+		return ret;
+
+	*in_w = input_w;
+	*in_h = input_h;
+	*out_w = output_w;
+	*out_h = output_h;
+
+	return resize;
+}
+
+static int rj54n1_set_clock(struct i2c_client *client)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	int ret;
+
+	/* Enable external clock */
+	ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY);
+	/* Leave stand-by */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK);
+
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PLL_L, 2);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PLL_N, 0x31);
+
+	/* TGCLK dividers */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_TG,
+				rj54n1->clk_div.ratio_tg);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_T,
+				rj54n1->clk_div.ratio_t);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_R,
+				rj54n1->clk_div.ratio_r);
+
+	/* Enable TGCLK & RAMP */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RAMP_TGCLK_EN, 3);
+
+	/* Disable clock output */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_OCLK_DSP, 0);
+
+	/* Set divisors */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_OP,
+				rj54n1->clk_div.ratio_op);
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RATIO_O,
+				rj54n1->clk_div.ratio_o);
+
+	/* Enable OCLK */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
+
+	/* Use PLL for Timing Generator, write 2 to reserved bits */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_TG_BYPASS, 2);
+
+	/* Take sensor out of reset */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESET_STANDBY,
+				E_EXCLK | SEN_RSTX);
+	/* Enable PLL */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_PLL_EN, 1);
+
+	/* Wait for PLL to stabilise */
+	msleep(10);
+
+	/* Enable clock to frequency divider */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_CLK_RST, 1);
+
+	if (!ret)
+		ret = reg_read(client, RJ54N1_CLK_RST);
+	if (ret != 1) {
+		dev_err(&client->dev,
+			"Resetting RJ54N1CB0C clock failed: %d!\n", ret);
+		return -EIO;
+	}
+	/* Start the PLL */
+	ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1);
+
+	/* Enable OCLK */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
+
+	return ret;
+}
+
+static int rj54n1_reg_init(struct i2c_client *client)
+{
+	int ret = rj54n1_set_clock(client);
+
+	if (!ret)
+		ret = reg_write_multiple(client, bank_7, ARRAY_SIZE(bank_7));
+	if (!ret)
+		ret = reg_write_multiple(client, bank_10, ARRAY_SIZE(bank_10));
+
+	/* Set binning divisors */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_SCALE_1_2_LEV, 3 | (7 << 4));
+	if (!ret)
+		ret = reg_write(client, RJ54N1_SCALE_4_LEV, 0xf);
+
+	/* Switch to fixed resize mode */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
+				RESIZE_HOLD_SEL | 1);
+
+	/* Set gain */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_Y_GAIN, 0x84);
+
+	/* Mirror the image back: default is upside down and left-to-right... */
+	if (!ret)
+		ret = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 3, 3);
+
+	if (!ret)
+		ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4));
+	if (!ret)
+		ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5));
+	if (!ret)
+		ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8));
+
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESET_STANDBY,
+				E_EXCLK | DSP_RSTX | SEN_RSTX);
+
+	/* Commit init */
+	if (!ret)
+		ret = rj54n1_commit(client);
+
+	/* Take DSP, TG, sensor out of reset */
+	if (!ret)
+		ret = reg_write(client, RJ54N1_RESET_STANDBY,
+				E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX);
+
+	if (!ret)
+		ret = reg_write(client, 0x7fe, 2);
+
+	/* Constant taken from manufacturer's example */
+	msleep(700);
+
+	return ret;
+}
+
+/* FIXME: streaming output only up to 800x600 is functional */
+static int rj54n1_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	pix->field = V4L2_FIELD_NONE;
+
+	if (pix->width > 800)
+		pix->width = 800;
+	if (pix->height > 600)
+		pix->height = 600;
+
+	return 0;
+}
+
+static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+	struct i2c_client *client = sd->priv;
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	unsigned int output_w, output_h,
+		input_w = rj54n1->rect.width, input_h = rj54n1->rect.height;
+	int ret;
+
+	/*
+	 * The host driver can call us without .try_fmt(), so, we have to take
+	 * care ourseleves
+	 */
+	ret = rj54n1_try_fmt(sd, f);
+
+	/*
+	 * Verify if the sensor has just been powered on. TODO: replace this
+	 * with proper PM, when a suitable API is available.
+	 */
+	if (!ret)
+		ret = reg_read(client, RJ54N1_RESET_STANDBY);
+	if (ret < 0)
+		return ret;
+
+	if (!(ret & E_EXCLK)) {
+		ret = rj54n1_reg_init(client);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_YUYV:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 0);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
+		if (!ret)
+			ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	/* Supported scales 1:1 - 1:16 */
+	if (pix->width < input_w / 16)
+		pix->width = input_w / 16;
+	if (pix->height < input_h / 16)
+		pix->height = input_h / 16;
+
+	output_w = pix->width;
+	output_h = pix->height;
+
+	ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
+	if (ret < 0)
+		return ret;
+
+	rj54n1->fourcc		= pix->pixelformat;
+	rj54n1->resize		= ret;
+	rj54n1->rect.width	= input_w;
+	rj54n1->rect.height	= input_h;
+	rj54n1->width		= output_w;
+	rj54n1->height		= output_h;
+
+	pix->width		= output_w;
+	pix->height		= output_h;
+	pix->field		= V4L2_FIELD_NONE;
+
+	return ret;
+}
+
+static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_chip_ident *id)
+{
+	struct i2c_client *client = sd->priv;
+
+	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match.addr != client->addr)
+		return -ENODEV;
+
+	id->ident	= V4L2_IDENT_RJ54N1CB0C;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int rj54n1_g_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = sd->priv;
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
+	    reg->reg < 0x400 || reg->reg > 0x1fff)
+		/* Registers > 0x0800 are only available from Sharp support */
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	reg->size = 1;
+	reg->val = reg_read(client, reg->reg);
+
+	if (reg->val > 0xff)
+		return -EIO;
+
+	return 0;
+}
+
+static int rj54n1_s_register(struct v4l2_subdev *sd,
+			     struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = sd->priv;
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
+	    reg->reg < 0x400 || reg->reg > 0x1fff)
+		/* Registers >= 0x0800 are only available from Sharp support */
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	if (reg_write(client, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+static const struct v4l2_queryctrl rj54n1_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,
+	}, {
+		.id		= V4L2_CID_GAIN,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Gain",
+		.minimum	= 0,
+		.maximum	= 127,
+		.step		= 1,
+		.default_value	= 66,
+		.flags		= V4L2_CTRL_FLAG_SLIDER,
+	},
+};
+
+static struct soc_camera_ops rj54n1_ops = {
+	.set_bus_param		= rj54n1_set_bus_param,
+	.query_bus_param	= rj54n1_query_bus_param,
+	.controls		= rj54n1_controls,
+	.num_controls		= ARRAY_SIZE(rj54n1_controls),
+};
+
+static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct i2c_client *client = sd->priv;
+	int data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		data = reg_read(client, RJ54N1_MIRROR_STILL_MODE);
+		if (data < 0)
+			return -EIO;
+		ctrl->value = !(data & 1);
+		break;
+	case V4L2_CID_HFLIP:
+		data = reg_read(client, RJ54N1_MIRROR_STILL_MODE);
+		if (data < 0)
+			return -EIO;
+		ctrl->value = !(data & 2);
+		break;
+	case V4L2_CID_GAIN:
+		data = reg_read(client, RJ54N1_Y_GAIN);
+		if (data < 0)
+			return -EIO;
+
+		ctrl->value = data / 2;
+		break;
+	}
+
+	return 0;
+}
+
+static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	int data;
+	struct i2c_client *client = sd->priv;
+	const struct v4l2_queryctrl *qctrl;
+
+	qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id);
+	if (!qctrl)
+		return -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (ctrl->value)
+			data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1);
+		else
+			data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1);
+		if (data < 0)
+			return -EIO;
+		break;
+	case V4L2_CID_HFLIP:
+		if (ctrl->value)
+			data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2);
+		else
+			data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2);
+		if (data < 0)
+			return -EIO;
+		break;
+	case V4L2_CID_GAIN:
+		if (ctrl->value > qctrl->maximum ||
+		    ctrl->value < qctrl->minimum)
+			return -EINVAL;
+		else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0)
+			return -EIO;
+		break;
+	}
+
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = {
+	.g_ctrl		= rj54n1_g_ctrl,
+	.s_ctrl		= rj54n1_s_ctrl,
+	.g_chip_ident	= rj54n1_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= rj54n1_g_register,
+	.s_register	= rj54n1_s_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = {
+	.s_stream	= rj54n1_s_stream,
+	.s_fmt		= rj54n1_s_fmt,
+	.g_fmt		= rj54n1_g_fmt,
+	.try_fmt	= rj54n1_try_fmt,
+	.g_crop		= rj54n1_g_crop,
+	.cropcap	= rj54n1_cropcap,
+};
+
+static struct v4l2_subdev_ops rj54n1_subdev_ops = {
+	.core	= &rj54n1_subdev_core_ops,
+	.video	= &rj54n1_subdev_video_ops,
+};
+
+static int rj54n1_pin_config(struct i2c_client *client)
+{
+	/*
+	 * Experimentally found out IOCTRL wired to 0. TODO: add to platform
+	 * data: 0 or 1 << 7.
+	 */
+	return reg_write(client, RJ54N1_IOC, 0);
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int rj54n1_video_probe(struct soc_camera_device *icd,
+			      struct i2c_client *client)
+{
+	int data1, data2;
+	int ret;
+
+	/* This could be a BUG_ON() or a WARN_ON(), or remove it completely */
+	if (!icd->dev.parent ||
+	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+		return -ENODEV;
+
+	/* Read out the chip version register */
+	data1 = reg_read(client, RJ54N1_DEV_CODE);
+	data2 = reg_read(client, RJ54N1_DEV_CODE2);
+
+	if (data1 != 0x51 || data2 != 0x10) {
+		ret = -ENODEV;
+		dev_info(&client->dev, "No RJ54N1CB0C found, read 0x%x:0x%x\n",
+			 data1, data2);
+		goto ei2c;
+	}
+
+	ret = rj54n1_pin_config(client);
+	if (ret < 0)
+		goto ei2c;
+
+	dev_info(&client->dev, "Detected a RJ54N1CB0C chip ID 0x%x:0x%x\n",
+		 data1, data2);
+
+ei2c:
+	return ret;
+}
+
+static int rj54n1_probe(struct i2c_client *client,
+			const struct i2c_device_id *did)
+{
+	struct rj54n1 *rj54n1;
+	struct soc_camera_device *icd = client->dev.platform_data;
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link *icl;
+	int ret;
+
+	if (!icd) {
+		dev_err(&client->dev, "RJ54N1CB0C: missing soc-camera data!\n");
+		return -EINVAL;
+	}
+
+	icl = to_soc_camera_link(icd);
+	if (!icl) {
+		dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+		return -EIO;
+	}
+
+	rj54n1 = kzalloc(sizeof(struct rj54n1), GFP_KERNEL);
+	if (!rj54n1)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops);
+
+	icd->ops		= &rj54n1_ops;
+
+	rj54n1->clk_div		= clk_div;
+	rj54n1->rect.left	= RJ54N1_COLUMN_SKIP;
+	rj54n1->rect.top	= RJ54N1_ROW_SKIP;
+	rj54n1->rect.width	= RJ54N1_MAX_WIDTH;
+	rj54n1->rect.height	= RJ54N1_MAX_HEIGHT;
+	rj54n1->width		= RJ54N1_MAX_WIDTH;
+	rj54n1->height		= RJ54N1_MAX_HEIGHT;
+	rj54n1->fourcc		= V4L2_PIX_FMT_YUYV;
+	rj54n1->resize		= 1024;
+
+	ret = rj54n1_video_probe(icd, client);
+	if (ret < 0) {
+		icd->ops = NULL;
+		i2c_set_clientdata(client, NULL);
+		kfree(rj54n1);
+		return ret;
+	}
+
+	icd->formats		= rj54n1_colour_formats;
+	icd->num_formats	= ARRAY_SIZE(rj54n1_colour_formats);
+
+	return ret;
+}
+
+static int rj54n1_remove(struct i2c_client *client)
+{
+	struct rj54n1 *rj54n1 = to_rj54n1(client);
+	struct soc_camera_device *icd = client->dev.platform_data;
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+	icd->ops = NULL;
+	if (icl->free_bus)
+		icl->free_bus(icl);
+	i2c_set_clientdata(client, NULL);
+	client->driver = NULL;
+	kfree(rj54n1);
+
+	return 0;
+}
+
+static const struct i2c_device_id rj54n1_id[] = {
+	{ "rj54n1cb0c", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rj54n1_id);
+
+static struct i2c_driver rj54n1_i2c_driver = {
+	.driver = {
+		.name = "rj54n1cb0c",
+	},
+	.probe		= rj54n1_probe,
+	.remove		= rj54n1_remove,
+	.id_table	= rj54n1_id,
+};
+
+static int __init rj54n1_mod_init(void)
+{
+	return i2c_add_driver(&rj54n1_i2c_driver);
+}
+
+static void __exit rj54n1_mod_exit(void)
+{
+	i2c_del_driver(&rj54n1_i2c_driver);
+}
+
+module_init(rj54n1_mod_init);
+module_exit(rj54n1_mod_exit);
+
+MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 03d39266d293..41765f3c7c28 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -1958,7 +1958,7 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 				if (pdword[1] >= MAX_CHANNELS)
 					break;
 				cc = G_chnmap[pdword[1]];
-				if (!(cc >= 0 && cc < MAX_CHANNELS))
+				if (cc >= MAX_CHANNELS)
 					break;
 				switch (pdword[2]) {
 				case S2255_RESPONSE_SETMODE:
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 5c24c993ac16..3bca744e43af 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -304,7 +304,7 @@ static int saa7110_s_routing(struct v4l2_subdev *sd,
 {
 	struct saa7110 *decoder = to_saa7110(sd);
 
-	if (input < 0 || input >= SAA7110_MAX_INPUT) {
+	if (input >= SAA7110_MAX_INPUT) {
 		v4l2_dbg(1, debug, sd, "input=%d not available\n", input);
 		return -EINVAL;
 	}
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 09013229d4aa..7e40d6d99dd0 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5239,6 +5239,7 @@ struct saa7134_board saa7134_boards[] = {
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
 		.inputs         = { {
 			.name = name_tv,
 			.vmux = 2,
@@ -5279,6 +5280,46 @@ struct saa7134_board saa7134_boards[] = {
 			.amux = TV,
 		},
 	},
+	[SAA7134_BOARD_ASUS_EUROPA_HYBRID] = {
+		.name           = "Asus Europa Hybrid OEM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TD1316,
+		.radio_type     = UNSET,
+		.tuner_addr	= 0x61,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 4,
+			.amux   = LINE2,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+	},
+	[SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S] = {
+		.name           = "Leadtek Winfast DTV1000S",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = { {
+			.name = name_comp1,
+			.vmux = 3,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+		} },
+	},
 
 };
 
@@ -6418,6 +6459,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
 		.subdevice    = 0x2004,
 		.driver_data  = SAA7134_BOARD_ZOLID_HYBRID_PCI,
 	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4847,
+		.driver_data  = SAA7134_BOARD_ASUS_EUROPA_HYBRID,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x107d,
+		.subdevice    = 0x6655,
+		.driver_data  = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S,
+	}, {
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -6748,6 +6801,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
 	case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
 	case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
+	case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
 		dev->has_remote = SAA7134_REMOTE_GPIO;
 		break;
 	case SAA7134_BOARD_FLYDVBS_LR300:
@@ -7079,6 +7133,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
 		/* break intentionally omitted */
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 	case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+	case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
 	{
 
 		/* The Philips EUROPA based hybrid boards have the tuner
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index c673901cb2b5..0ba7f5af0fc3 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -1032,7 +1032,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
 	saa7134_irq_video_signalchange(dev);
 
 	if (TUNER_ABSENT != dev->tuner_type)
-		saa_call_all(dev, tuner, s_standby);
+		saa_call_all(dev, core, s_power, 0);
 
 	/* register v4l devices */
 	if (saa7134_no_overlay > 0)
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index a26e997a9ce6..73739d2a63dd 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -40,6 +40,7 @@
 #include "tda1004x.h"
 #include "nxt200x.h"
 #include "tuner-xc2028.h"
+#include "xc5000.h"
 
 #include "tda10086.h"
 #include "tda826x.h"
@@ -871,6 +872,20 @@ static struct zl10353_config behold_h6_config = {
 	.disable_i2c_gate_ctrl = 1,
 };
 
+static struct xc5000_config behold_x7_tunerconfig = {
+	.i2c_address      = 0xc2>>1,
+	.if_khz           = 4560,
+	.radio_input      = XC5000_RADIO_FM1,
+};
+
+static struct zl10353_config behold_x7_config = {
+	.demod_address = 0x1e>>1,
+	.if2           = 45600,
+	.no_tuner      = 1,
+	.parallel_ts   = 1,
+	.disable_i2c_gate_ctrl = 1,
+};
+
 /* ==================================================================
  * tda10086 based DVB-S cards, helper functions
  */
@@ -1030,6 +1045,32 @@ static struct tda18271_config zolid_tda18271_config = {
 	.gate    = TDA18271_GATE_ANALOG,
 };
 
+static struct tda10048_config dtv1000s_tda10048_config = {
+	.demod_address    = 0x10 >> 1,
+	.output_mode      = TDA10048_PARALLEL_OUTPUT,
+	.fwbulkwritelen   = TDA10048_BULKWRITE_200,
+	.inversion        = TDA10048_INVERSION_ON,
+	.dtv6_if_freq_khz = TDA10048_IF_3300,
+	.dtv7_if_freq_khz = TDA10048_IF_3800,
+	.dtv8_if_freq_khz = TDA10048_IF_4300,
+	.clk_freq_khz     = TDA10048_CLK_16000,
+	.disable_gate_access = 1,
+};
+
+static struct tda18271_std_map dtv1000s_tda18271_std_map = {
+	.dvbt_6   = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.dvbt_7   = { .if_freq = 3800, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.dvbt_8   = { .if_freq = 4300, .agc_mode = 3, .std = 6,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config dtv1000s_tda18271_config = {
+	.std_map = &dtv1000s_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+};
+
 /* ==================================================================
  * Core code
  */
@@ -1116,6 +1157,7 @@ static int dvb_init(struct saa7134_dev *dev)
 		break;
 	case SAA7134_BOARD_PHILIPS_EUROPA:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+	case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
 		fe0->dvb.frontend = dvb_attach(tda10046_attach,
 					       &philips_europa_config,
 					       &dev->i2c_adap);
@@ -1482,6 +1524,15 @@ static int dvb_init(struct saa7134_dev *dev)
 				   TUNER_PHILIPS_FMD1216MEX_MK3);
 		}
 		break;
+	case SAA7134_BOARD_BEHOLD_X7:
+		fe0->dvb.frontend = dvb_attach(zl10353_attach,
+						&behold_x7_config,
+						&dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dvb_attach(xc5000_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, &behold_x7_tunerconfig);
+		}
+		break;
 	case SAA7134_BOARD_AVERMEDIA_A700_PRO:
 	case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
 		/* Zarlink ZL10313 */
@@ -1518,6 +1569,19 @@ static int dvb_init(struct saa7134_dev *dev)
 				   &zolid_tda18271_config);
 		}
 		break;
+	case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+		fe0->dvb.frontend = dvb_attach(tda10048_attach,
+					       &dtv1000s_tda10048_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			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,
+				   &dtv1000s_tda18271_config);
+		}
+		break;
 	default:
 		wprintk("Huh? unknown DVB card?\n");
 		break;
@@ -1550,7 +1614,7 @@ static int dvb_init(struct saa7134_dev *dev)
 
 	/* register everything else */
 	ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
-		&dev->pci->dev, adapter_nr, 0);
+					&dev->pci->dev, adapter_nr, 0, NULL);
 
 	/* this sequence is necessary to make the tda1004x load its firmware
 	 * and to enter analog mode of hybrid boards
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index a0e8c62e6ae1..744918b1cd47 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -102,14 +102,14 @@ static int build_key(struct saa7134_dev *dev)
 		if (data == ir->mask_keycode)
 			ir_input_nokey(ir->dev, &ir->ir);
 		else
-			ir_input_keydown(ir->dev, &ir->ir, data, data);
+			ir_input_keydown(ir->dev, &ir->ir, data);
 		return 0;
 	}
 
 	if (ir->polling) {
 		if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
 		    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
-			ir_input_keydown(ir->dev, &ir->ir, data, data);
+			ir_input_keydown(ir->dev, &ir->ir, data);
 		} else {
 			ir_input_nokey(ir->dev, &ir->ir);
 		}
@@ -117,7 +117,7 @@ static int build_key(struct saa7134_dev *dev)
 	else {	/* IRQ driven mode - handle key press and release in one go */
 		if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
 		    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
-			ir_input_keydown(ir->dev, &ir->ir, data, data);
+			ir_input_keydown(ir->dev, &ir->ir, data);
 			ir_input_nokey(ir->dev, &ir->ir);
 		}
 	}
@@ -616,6 +616,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 		mask_keycode = 0x003f00;
 		mask_keydown = 0x040000;
 		break;
+	case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+		ir_codes     = &ir_codes_winfast_table;
+		mask_keycode = 0x5f00;
+		mask_keyup   = 0x020000;
+		polling      = 50; /* ms */
+		break;
 	}
 	if (NULL == ir_codes) {
 		printk("%s: Oops: IR config error [card=%d]\n",
@@ -646,7 +652,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
 		 pci_name(dev->pci));
 
-	ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
+	err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
+	if (err < 0)
+		goto err_out_free;
+
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
 	input_dev->id.bustype = BUS_PCI;
@@ -677,6 +686,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 	saa7134_ir_stop(dev);
 	dev->remote = NULL;
  err_out_free:
+	ir_input_free(input_dev);
 	input_free_device(input_dev);
 	kfree(ir);
 	return err;
@@ -688,6 +698,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
 		return;
 
 	saa7134_ir_stop(dev);
+	ir_input_free(dev->remote->dev);
 	input_unregister_device(dev->remote->dev);
 	kfree(dev->remote);
 	dev->remote = NULL;
@@ -695,10 +706,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
 
 void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
 {
-	const unsigned short addr_list[] = {
-		0x7a, 0x47, 0x71, 0x2d,
-		I2C_CLIENT_END
-	};
+	struct i2c_board_info info;
 
 	struct i2c_msg msg_msi = {
 		.addr = 0x50,
@@ -714,9 +722,9 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
 		return;
 	}
 
-	memset(&dev->info, 0, sizeof(dev->info));
+	memset(&info, 0, sizeof(struct i2c_board_info));
 	memset(&dev->init_data, 0, sizeof(dev->init_data));
-	strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
+	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
 
 	switch (dev->board) {
 	case SAA7134_BOARD_PINNACLE_PCTV_110i:
@@ -725,23 +733,24 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
 		if (pinnacle_remote == 0) {
 			dev->init_data.get_key = get_key_pinnacle_color;
 			dev->init_data.ir_codes = &ir_codes_pinnacle_color_table;
-			dev->info.addr = 0x47;
+			info.addr = 0x47;
 		} else {
 			dev->init_data.get_key = get_key_pinnacle_grey;
 			dev->init_data.ir_codes = &ir_codes_pinnacle_grey_table;
-			dev->info.addr = 0x47;
+			info.addr = 0x47;
 		}
 		break;
 	case SAA7134_BOARD_UPMOST_PURPLE_TV:
 		dev->init_data.name = "Purple TV";
 		dev->init_data.get_key = get_key_purpletv;
 		dev->init_data.ir_codes = &ir_codes_purpletv_table;
+		info.addr = 0x7a;
 		break;
 	case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
 		dev->init_data.name = "MSI TV@nywhere Plus";
 		dev->init_data.get_key = get_key_msi_tvanywhere_plus;
 		dev->init_data.ir_codes = &ir_codes_msi_tvanywhere_plus_table;
-		dev->info.addr = 0x30;
+		info.addr = 0x30;
 		/* MSI TV@nywhere Plus controller doesn't seem to
 		   respond to probes unless we read something from
 		   an existing device. Weird...
@@ -755,6 +764,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
 		dev->init_data.name = "HVR 1110";
 		dev->init_data.get_key = get_key_hvr1110;
 		dev->init_data.ir_codes = &ir_codes_hauppauge_new_table;
+		info.addr = 0x71;
 		break;
 	case SAA7134_BOARD_BEHOLD_607FM_MK3:
 	case SAA7134_BOARD_BEHOLD_607FM_MK5:
@@ -772,23 +782,20 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
 		dev->init_data.name = "BeholdTV";
 		dev->init_data.get_key = get_key_beholdm6xx;
 		dev->init_data.ir_codes = &ir_codes_behold_table;
+		info.addr = 0x2d;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
-		dev->info.addr = 0x40;
+		info.addr = 0x40;
 		break;
-	}
-
-	if (dev->init_data.name)
-		dev->info.platform_data = &dev->init_data;
-	/* No need to probe if address is known */
-	if (dev->info.addr) {
-		i2c_new_device(&dev->i2c_adap, &dev->info);
+	default:
+		dprintk("No I2C IR support for board %x\n", dev->board);
 		return;
 	}
 
-	/* Address not known, fallback to probing */
-	i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
+	if (dev->init_data.name)
+		info.platform_data = &dev->init_data;
+	i2c_new_device(&dev->i2c_adap, &info);
 }
 
 static int saa7134_rc5_irq(struct saa7134_dev *dev)
@@ -936,7 +943,7 @@ static void nec_task(unsigned long data)
 		dprintk("scancode = 0x%02x (code = 0x%02x, notcode= 0x%02x)\n",
 			 ir->code, ircode, not_code);
 
-		ir_input_keydown(ir->dev, &ir->ir, ir->code, ir->code);
+		ir_input_keydown(ir->dev, &ir->ir, ir->code);
 	} else
 		dprintk("Repeat last key\n");
 
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index da26f476a302..35f8daa3a359 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1499,7 +1499,7 @@ static int video_release(struct file *file)
 	saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0);
 	saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
 
-	saa_call_all(dev, tuner, s_standby);
+	saa_call_all(dev, core, s_power, 0);
 	if (fh->radio)
 		saa_call_all(dev, core, ioctl, RDS_CMD_CLOSE, &cmd);
 
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index f8697d46ff5f..53b7e0b8a2fb 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -297,6 +297,8 @@ struct saa7134_format {
 #define SAA7134_BOARD_BEHOLD_X7             171
 #define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172
 #define SAA7134_BOARD_ZOLID_HYBRID_PCI		173
+#define SAA7134_BOARD_ASUS_EUROPA_HYBRID	174
+#define SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S 175
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -592,7 +594,6 @@ struct saa7134_dev {
 	unsigned int               insuspend;
 
 	/* I2C keyboard data */
-	struct i2c_board_info      info;
 	struct IR_i2c_init_data    init_data;
 
 	/* SAA7134_MPEG_* */
diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c
index 6a2d847d6a88..cf099c59b38e 100644
--- a/drivers/media/video/saa7164/saa7164-dvb.c
+++ b/drivers/media/video/saa7164/saa7164-dvb.c
@@ -68,6 +68,7 @@ static struct tda18271_config hauppauge_hvr22x0s_tuner_config = {
 	.std_map	= &hauppauge_tda18271_std_map,
 	.gate		= TDA18271_GATE_ANALOG,
 	.role		= TDA18271_SLAVE,
+	.output_opt     = TDA18271_OUTPUT_LT_OFF,
 	.rf_cal_on_startup = 1
 };
 
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
index b15c40908e84..6818df571168 100644
--- a/drivers/media/video/saa717x.c
+++ b/drivers/media/video/saa717x.c
@@ -1115,7 +1115,7 @@ static int saa717x_s_video_routing(struct v4l2_subdev *sd,
 	v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", input);
 	/* inputs from 0-9 are available*/
 	/* saa717x have mode0-mode9 but mode5 is reserved. */
-	if (input < 0 || input > 9 || input == 5)
+	if (input > 9 || input == 5)
 		return -EINVAL;
 
 	if (decoder->input != input) {
@@ -1312,7 +1312,7 @@ static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 		"MONO", "STEREO", "LANG1", "LANG2/SAP"
 	};
 
-	audio_mode = V4L2_TUNER_MODE_STEREO;
+	audio_mode = TUNER_AUDIO_STEREO;
 
 	switch (vt->audmode) {
 		case V4L2_TUNER_MODE_MONO:
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 9c8b7c7b89ee..a4f3472d4db8 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -153,6 +153,40 @@ static u32 ceu_read(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs)
 	return ioread32(priv->base + reg_offs);
 }
 
+static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
+{
+	int i, success = 0;
+	struct soc_camera_device *icd = pcdev->icd;
+
+	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
+
+	/* wait CSTSR.CPTON bit */
+	for (i = 0; i < 1000; i++) {
+		if (!(ceu_read(pcdev, CSTSR) & 1)) {
+			success++;
+			break;
+		}
+		udelay(1);
+	}
+
+	/* wait CAPSR.CPKIL bit */
+	for (i = 0; i < 1000; i++) {
+		if (!(ceu_read(pcdev, CAPSR) & (1 << 16))) {
+			success++;
+			break;
+		}
+		udelay(1);
+	}
+
+
+	if (2 != success) {
+		dev_warn(&icd->dev, "soft reset time out\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
 /*
  *  Videobuf operations
  */
@@ -202,26 +236,45 @@ static void free_buffer(struct videobuf_queue *vq,
 #define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */
 #define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */
 #define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */
+#define CEU_CEIER_VBP   (1 << 20) /* vbp error */
 #define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */
+#define CEU_CEIER_MASK (CEU_CEIER_CPEIE | CEU_CEIER_VBP)
 
 
-static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
+/*
+ * return value doesn't reflex the success/failure to queue the new buffer,
+ * but rather the status of the previous buffer.
+ */
+static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
 {
 	struct soc_camera_device *icd = pcdev->icd;
 	dma_addr_t phys_addr_top, phys_addr_bottom;
+	u32 status;
+	int ret = 0;
 
 	/* The hardware is _very_ picky about this sequence. Especially
 	 * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge
 	 * several not-so-well documented interrupt sources in CETCR.
 	 */
-	ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_CPEIE);
-	ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & CEU_CETCR_MAGIC);
-	ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_CPEIE);
+	ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK);
+	status = ceu_read(pcdev, CETCR);
+	ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC);
+	ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
 	ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP);
 	ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW);
 
+	/*
+	 * When a VBP interrupt occurs, a capture end interrupt does not occur
+	 * and the image of that frame is not captured correctly. So, soft reset
+	 * is needed here.
+	 */
+	if (status & CEU_CEIER_VBP) {
+		sh_mobile_ceu_soft_reset(pcdev);
+		ret = -EIO;
+	}
+
 	if (!pcdev->active)
-		return;
+		return ret;
 
 	phys_addr_top = videobuf_to_dma_contig(pcdev->active);
 	ceu_write(pcdev, CDAYR, phys_addr_top);
@@ -247,6 +300,8 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
 
 	pcdev->active->state = VIDEOBUF_ACTIVE;
 	ceu_write(pcdev, CAPSR, 0x1); /* start capture */
+
+	return ret;
 }
 
 static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
@@ -319,6 +374,11 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
 	list_add_tail(&vb->queue, &pcdev->capture);
 
 	if (!pcdev->active) {
+		/*
+		 * Because there were no active buffer at this moment,
+		 * we are not interested in the return value of
+		 * sh_mobile_ceu_capture here.
+		 */
 		pcdev->active = vb;
 		sh_mobile_ceu_capture(pcdev);
 	}
@@ -379,9 +439,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
 	else
 		pcdev->active = NULL;
 
-	sh_mobile_ceu_capture(pcdev);
-
-	vb->state = VIDEOBUF_DONE;
+	vb->state = (sh_mobile_ceu_capture(pcdev) < 0) ?
+		VIDEOBUF_ERROR : VIDEOBUF_DONE;
 	do_gettimeofday(&vb->ts);
 	vb->field_count++;
 	wake_up(&vb->done);
@@ -407,13 +466,9 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 
 	pm_runtime_get_sync(ici->v4l2_dev.dev);
 
-	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
-	while (ceu_read(pcdev, CSTSR) & 1)
-		msleep(1);
-
 	pcdev->icd = icd;
 
-	return 0;
+	return sh_mobile_ceu_soft_reset(pcdev);
 }
 
 /* Called with .video_lock held */
@@ -427,7 +482,7 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 
 	/* disable capture, disable interrupts */
 	ceu_write(pcdev, CEIER, 0);
-	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
+	sh_mobile_ceu_soft_reset(pcdev);
 
 	/* make sure active buffer is canceled */
 	spin_lock_irqsave(&pcdev->lock, flags);
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index aba92e2313d8..5b3eaa16afd2 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -320,6 +320,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 	unsigned char buffer[4];
+	int tune_now = 1;
 
 	if (type == UNSET || type == TUNER_ABSENT) {
 		tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
@@ -328,7 +329,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
 
 	t->type = type;
 	/* prevent invalid config values */
-	t->config = ((new_config >= 0) && (new_config < 256)) ? new_config : 0;
+	t->config = new_config < 256 ? new_config : 0;
 	if (tuner_callback != NULL) {
 		tuner_dbg("defining GPIO callback\n");
 		t->fe.callback = tuner_callback;
@@ -404,6 +405,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
 		};
 		if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
 			goto attach_failed;
+		tune_now = 0;
 		break;
 	}
 	case TUNER_TDA9887:
@@ -419,6 +421,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
 		if (!dvb_attach(xc5000_attach,
 				&t->fe, t->i2c->adapter, &xc5000_cfg))
 			goto attach_failed;
+		tune_now = 0;
 		break;
 	}
 	case TUNER_NXP_TDA18271:
@@ -430,6 +433,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
 		if (!dvb_attach(tda18271_attach, &t->fe, t->i2c->addr,
 				t->i2c->adapter, &cfg))
 			goto attach_failed;
+		tune_now = 0;
 		break;
 	}
 	default:
@@ -458,12 +462,13 @@ static void set_type(struct i2c_client *c, unsigned int type,
 	if (t->mode_mask == T_UNINITIALIZED)
 		t->mode_mask = new_mode_mask;
 
-	/* xc2028/3028 and xc5000 requires a firmware to be set-up later
+	/* Some tuners require more initialization setup before use,
+	   such as firmware download or device calibration.
 	   trying to set a frequency here will just fail
 	   FIXME: better to move set_freq to the tuner code. This is needed
 	   on analog tuners for PLL to properly work
 	 */
-	if (t->type != TUNER_XC2028 && t->type != TUNER_XC5000)
+	if (tune_now)
 		set_freq(c, (V4L2_TUNER_RADIO == t->mode) ?
 			    t->radio_freq : t->tv_freq);
 
@@ -752,14 +757,17 @@ static int tuner_s_radio(struct v4l2_subdev *sd)
 	return 0;
 }
 
-static int tuner_s_standby(struct v4l2_subdev *sd)
+static int tuner_s_power(struct v4l2_subdev *sd, int on)
 {
 	struct tuner *t = to_tuner(sd);
 	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
+	if (on)
+		return 0;
+
 	tuner_dbg("Putting tuner to sleep\n");
 
-	if (check_mode(t, "s_standby") == -EINVAL)
+	if (check_mode(t, "s_power") == -EINVAL)
 		return 0;
 	t->mode = T_STANDBY;
 	if (analog_ops->standby)
@@ -961,6 +969,7 @@ static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
 static const struct v4l2_subdev_core_ops tuner_core_ops = {
 	.log_status = tuner_log_status,
 	.s_std = tuner_s_std,
+	.s_power = tuner_s_power,
 };
 
 static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
@@ -971,7 +980,6 @@ static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
 	.g_frequency = tuner_g_frequency,
 	.s_type_addr = tuner_s_type_addr,
 	.s_config = tuner_s_config,
-	.s_standby = tuner_s_standby,
 };
 
 static const struct v4l2_subdev_ops tuner_ops = {
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 0869bafc2b56..800fc1b111ef 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -1919,7 +1919,7 @@ static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = {
 	.s_radio = tvaudio_s_radio,
 	.s_frequency = tvaudio_s_frequency,
 	.s_tuner = tvaudio_s_tuner,
-	.s_tuner = tvaudio_g_tuner,
+	.g_tuner = tvaudio_g_tuner,
 };
 
 static const struct v4l2_subdev_audio_ops tvaudio_audio_ops = {
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
index 244372627df2..26b4e718cd6d 100644
--- a/drivers/media/video/tvp514x.c
+++ b/drivers/media/video/tvp514x.c
@@ -272,7 +272,7 @@ static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
 read_again:
 
 	err = i2c_smbus_read_byte_data(client, reg);
-	if (err == -1) {
+	if (err < 0) {
 		if (retry <= I2C_RETRY_COUNT) {
 			v4l2_warn(sd, "Read: retry ... %d\n", retry);
 			retry++;
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index 31d57f2d09e1..a0addcb04295 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -225,7 +225,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
 	int error;
 
 	usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
-	strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
+	strlcat(cam->input_physname, "/input0", sizeof(cam->input_physname));
 
 	cam->input = input_dev = input_allocate_device();
 	if (!input_dev) {
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index 803d3e4e29a2..c4d1b96b5cee 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -89,7 +89,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
 	int error;
 
 	usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
-	strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
+	strlcat(cam->input_physname, "/input0", sizeof(cam->input_physname));
 
 	cam->input = input_dev = input_allocate_device();
 	if (!input_dev) {
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index a2a50d608a3f..c07b0ac452ab 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -601,7 +601,7 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
 {
 	struct usb_usbvision *usbvision = video_drvdata(file);
 
-	if ((input >= usbvision->video_inputs) || (input < 0) )
+	if (input >= usbvision->video_inputs)
 		return -EINVAL;
 
 	mutex_lock(&usbvision->lock);
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 1b89735e62fd..0469d7a876a8 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -742,17 +742,7 @@ struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
 	v4l2_id &= V4L2_CTRL_ID_MASK;
 
 	/* Find the control. */
-	__uvc_find_control(chain->processing, v4l2_id, mapping, &ctrl, next);
-	if (ctrl && !next)
-		return ctrl;
-
-	list_for_each_entry(entity, &chain->iterms, chain) {
-		__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
-		if (ctrl && !next)
-			return ctrl;
-	}
-
-	list_for_each_entry(entity, &chain->extensions, chain) {
+	list_for_each_entry(entity, &chain->entities, chain) {
 		__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
 		if (ctrl && !next)
 			return ctrl;
@@ -826,6 +816,13 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 		ret = 0;
 		goto out;
 
+	case V4L2_CTRL_TYPE_BUTTON:
+		v4l2_ctrl->minimum = 0;
+		v4l2_ctrl->maximum = 0;
+		v4l2_ctrl->step = 0;
+		ret = 0;
+		goto out;
+
 	default:
 		break;
 	}
@@ -944,17 +941,7 @@ int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
 	int ret = 0;
 
 	/* Find the control. */
-	ret = uvc_ctrl_commit_entity(chain->dev, chain->processing, rollback);
-	if (ret < 0)
-		goto done;
-
-	list_for_each_entry(entity, &chain->iterms, chain) {
-		ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
-		if (ret < 0)
-			goto done;
-	}
-
-	list_for_each_entry(entity, &chain->extensions, chain) {
+	list_for_each_entry(entity, &chain->entities, chain) {
 		ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
 		if (ret < 0)
 			goto done;
@@ -1068,8 +1055,9 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
 	int ret;
 
 	/* Find the extension unit. */
-	list_for_each_entry(entity, &chain->extensions, chain) {
-		if (entity->id == xctrl->unit)
+	list_for_each_entry(entity, &chain->entities, chain) {
+		if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
+		    entity->id == xctrl->unit)
 			break;
 	}
 
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 8756be569154..c31bc50113bc 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -46,6 +46,7 @@
 unsigned int uvc_no_drop_param;
 static unsigned int uvc_quirks_param;
 unsigned int uvc_trace_param;
+unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
 
 /* ------------------------------------------------------------------------
  * Video formats
@@ -248,29 +249,9 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
 		entity = list_entry(&dev->entities, struct uvc_entity, list);
 
 	list_for_each_entry_continue(entity, &dev->entities, list) {
-		switch (UVC_ENTITY_TYPE(entity)) {
-		case UVC_TT_STREAMING:
-			if (entity->output.bSourceID == id)
-				return entity;
-			break;
-
-		case UVC_VC_PROCESSING_UNIT:
-			if (entity->processing.bSourceID == id)
+		for (i = 0; i < entity->bNrInPins; ++i)
+			if (entity->baSourceID[i] == id)
 				return entity;
-			break;
-
-		case UVC_VC_SELECTOR_UNIT:
-			for (i = 0; i < entity->selector.bNrInPins; ++i)
-				if (entity->selector.baSourceID[i] == id)
-					return entity;
-			break;
-
-		case UVC_VC_EXTENSION_UNIT:
-			for (i = 0; i < entity->extension.bNrInPins; ++i)
-				if (entity->extension.baSourceID[i] == id)
-					return entity;
-			break;
-		}
 	}
 
 	return NULL;
@@ -426,7 +407,8 @@ static int uvc_parse_format(struct uvc_device *dev,
 	/* Parse the frame descriptors. Only uncompressed, MJPEG and frame
 	 * based formats have frame descriptors.
 	 */
-	while (buflen > 2 && buffer[2] == ftype) {
+	while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
+	       buffer[2] == ftype) {
 		frame = &format->frame[format->nframes];
 		if (ftype != UVC_VS_FRAME_FRAME_BASED)
 			n = buflen > 25 ? buffer[25] : 0;
@@ -503,12 +485,14 @@ static int uvc_parse_format(struct uvc_device *dev,
 		buffer += buffer[0];
 	}
 
-	if (buflen > 2 && buffer[2] == UVC_VS_STILL_IMAGE_FRAME) {
+	if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
+	    buffer[2] == UVC_VS_STILL_IMAGE_FRAME) {
 		buflen -= buffer[0];
 		buffer += buffer[0];
 	}
 
-	if (buflen > 2 && buffer[2] == UVC_VS_COLORFORMAT) {
+	if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
+	    buffer[2] == UVC_VS_COLORFORMAT) {
 		if (buflen < 6) {
 			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
 			       "interface %d COLORFORMAT error\n",
@@ -749,6 +733,11 @@ static int uvc_parse_streaming(struct uvc_device *dev,
 		buffer += buffer[0];
 	}
 
+	if (buflen)
+		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+			"%d has %u bytes of trailing descriptor garbage.\n",
+			dev->udev->devnum, alts->desc.bInterfaceNumber, buflen);
+
 	/* Parse the alternate settings to find the maximum bandwidth. */
 	for (i = 0; i < intf->num_altsetting; ++i) {
 		struct usb_host_endpoint *ep;
@@ -776,6 +765,28 @@ error:
 	return ret;
 }
 
+static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
+		unsigned int num_pads, unsigned int extra_size)
+{
+	struct uvc_entity *entity;
+	unsigned int num_inputs;
+	unsigned int size;
+
+	num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
+	size = sizeof(*entity) + extra_size + num_inputs;
+	entity = kzalloc(size, GFP_KERNEL);
+	if (entity == NULL)
+		return NULL;
+
+	entity->id = id;
+	entity->type = type;
+
+	entity->bNrInPins = num_inputs;
+	entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size;
+
+	return entity;
+}
+
 /* Parse vendor-specific extensions. */
 static int uvc_parse_vendor_control(struct uvc_device *dev,
 	const unsigned char *buffer, int buflen)
@@ -827,21 +838,18 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
 			break;
 		}
 
-		unit = kzalloc(sizeof *unit + p + 2*n, GFP_KERNEL);
+		unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3],
+					p + 1, 2*n);
 		if (unit == NULL)
 			return -ENOMEM;
 
-		unit->id = buffer[3];
-		unit->type = UVC_VC_EXTENSION_UNIT;
 		memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
 		unit->extension.bNumControls = buffer[20];
-		unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]);
-		unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
-		memcpy(unit->extension.baSourceID, &buffer[22], p);
+		memcpy(unit->baSourceID, &buffer[22], p);
 		unit->extension.bControlSize = buffer[22+p];
-		unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
-		unit->extension.bmControlsType = (__u8 *)unit + sizeof *unit
-					       + p + n;
+		unit->extension.bmControls = (__u8 *)unit + sizeof(*unit);
+		unit->extension.bmControlsType = (__u8 *)unit + sizeof(*unit)
+					       + n;
 		memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
 
 		if (buffer[24+p+2*n] != 0)
@@ -938,13 +946,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
 			return -EINVAL;
 		}
 
-		term = kzalloc(sizeof *term + n + p, GFP_KERNEL);
+		term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],
+					1, n + p);
 		if (term == NULL)
 			return -ENOMEM;
 
-		term->id = buffer[3];
-		term->type = type | UVC_TERM_INPUT;
-
 		if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
 			term->camera.bControlSize = n;
 			term->camera.bmControls = (__u8 *)term + sizeof *term;
@@ -999,13 +1005,12 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
 			return 0;
 		}
 
-		term = kzalloc(sizeof *term, GFP_KERNEL);
+		term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3],
+					1, 0);
 		if (term == NULL)
 			return -ENOMEM;
 
-		term->id = buffer[3];
-		term->type = type | UVC_TERM_OUTPUT;
-		term->output.bSourceID = buffer[7];
+		memcpy(term->baSourceID, &buffer[7], 1);
 
 		if (buffer[8] != 0)
 			usb_string(udev, buffer[8], term->name,
@@ -1026,15 +1031,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
 			return -EINVAL;
 		}
 
-		unit = kzalloc(sizeof *unit + p, GFP_KERNEL);
+		unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0);
 		if (unit == NULL)
 			return -ENOMEM;
 
-		unit->id = buffer[3];
-		unit->type = buffer[2];
-		unit->selector.bNrInPins = buffer[4];
-		unit->selector.baSourceID = (__u8 *)unit + sizeof *unit;
-		memcpy(unit->selector.baSourceID, &buffer[5], p);
+		memcpy(unit->baSourceID, &buffer[5], p);
 
 		if (buffer[5+p] != 0)
 			usb_string(udev, buffer[5+p], unit->name,
@@ -1056,13 +1057,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
 			return -EINVAL;
 		}
 
-		unit = kzalloc(sizeof *unit + n, GFP_KERNEL);
+		unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n);
 		if (unit == NULL)
 			return -ENOMEM;
 
-		unit->id = buffer[3];
-		unit->type = buffer[2];
-		unit->processing.bSourceID = buffer[4];
+		memcpy(unit->baSourceID, &buffer[4], 1);
 		unit->processing.wMaxMultiplier =
 			get_unaligned_le16(&buffer[5]);
 		unit->processing.bControlSize = buffer[7];
@@ -1091,19 +1090,15 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
 			return -EINVAL;
 		}
 
-		unit = kzalloc(sizeof *unit + p + n, GFP_KERNEL);
+		unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n);
 		if (unit == NULL)
 			return -ENOMEM;
 
-		unit->id = buffer[3];
-		unit->type = buffer[2];
 		memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
 		unit->extension.bNumControls = buffer[20];
-		unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]);
-		unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
-		memcpy(unit->extension.baSourceID, &buffer[22], p);
+		memcpy(unit->baSourceID, &buffer[22], p);
 		unit->extension.bControlSize = buffer[22+p];
-		unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
+		unit->extension.bmControls = (__u8 *)unit + sizeof *unit;
 		memcpy(unit->extension.bmControls, &buffer[23+p], n);
 
 		if (buffer[23+p+n] != 0)
@@ -1209,13 +1204,12 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
 		if (uvc_trace_param & UVC_TRACE_PROBE)
 			printk(" <- XU %d", entity->id);
 
-		if (entity->extension.bNrInPins != 1) {
+		if (entity->bNrInPins != 1) {
 			uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "
 				"than 1 input pin.\n", entity->id);
 			return -1;
 		}
 
-		list_add_tail(&entity->chain, &chain->extensions);
 		break;
 
 	case UVC_VC_PROCESSING_UNIT:
@@ -1236,7 +1230,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
 			printk(" <- SU %d", entity->id);
 
 		/* Single-input selector units are ignored. */
-		if (entity->selector.bNrInPins == 1)
+		if (entity->bNrInPins == 1)
 			break;
 
 		if (chain->selector != NULL) {
@@ -1254,20 +1248,17 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
 		if (uvc_trace_param & UVC_TRACE_PROBE)
 			printk(" <- IT %d\n", entity->id);
 
-		list_add_tail(&entity->chain, &chain->iterms);
 		break;
 
 	case UVC_TT_STREAMING:
-		if (uvc_trace_param & UVC_TRACE_PROBE)
-			printk(" <- IT %d\n", entity->id);
-
-		if (!UVC_ENTITY_IS_ITERM(entity)) {
-			uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
-				"terminal %u.\n", entity->id);
-			return -1;
+		if (UVC_ENTITY_IS_ITERM(entity)) {
+			if (uvc_trace_param & UVC_TRACE_PROBE)
+				printk(" <- IT %d\n", entity->id);
+		} else {
+			if (uvc_trace_param & UVC_TRACE_PROBE)
+				printk(" OT %d", entity->id);
 		}
 
-		list_add_tail(&entity->chain, &chain->iterms);
 		break;
 
 	default:
@@ -1276,6 +1267,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
 		return -1;
 	}
 
+	list_add_tail(&entity->chain, &chain->entities);
 	return 0;
 }
 
@@ -1299,14 +1291,14 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain,
 
 		switch (UVC_ENTITY_TYPE(forward)) {
 		case UVC_VC_EXTENSION_UNIT:
-			if (forward->extension.bNrInPins != 1) {
+			if (forward->bNrInPins != 1) {
 				uvc_trace(UVC_TRACE_DESCR, "Extension unit %d "
 					  "has more than 1 input pin.\n",
 					  entity->id);
 				return -EINVAL;
 			}
 
-			list_add_tail(&forward->chain, &chain->extensions);
+			list_add_tail(&forward->chain, &chain->entities);
 			if (uvc_trace_param & UVC_TRACE_PROBE) {
 				if (!found)
 					printk(" (->");
@@ -1326,7 +1318,7 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain,
 				return -EINVAL;
 			}
 
-			list_add_tail(&forward->chain, &chain->oterms);
+			list_add_tail(&forward->chain, &chain->entities);
 			if (uvc_trace_param & UVC_TRACE_PROBE) {
 				if (!found)
 					printk(" (->");
@@ -1344,24 +1336,22 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain,
 }
 
 static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
-	struct uvc_entity *entity)
+	struct uvc_entity **_entity)
 {
+	struct uvc_entity *entity = *_entity;
 	struct uvc_entity *term;
-	int id = -1, i;
+	int id = -EINVAL, i;
 
 	switch (UVC_ENTITY_TYPE(entity)) {
 	case UVC_VC_EXTENSION_UNIT:
-		id = entity->extension.baSourceID[0];
-		break;
-
 	case UVC_VC_PROCESSING_UNIT:
-		id = entity->processing.bSourceID;
+		id = entity->baSourceID[0];
 		break;
 
 	case UVC_VC_SELECTOR_UNIT:
 		/* Single-input selector units are ignored. */
-		if (entity->selector.bNrInPins == 1) {
-			id = entity->selector.baSourceID[0];
+		if (entity->bNrInPins == 1) {
+			id = entity->baSourceID[0];
 			break;
 		}
 
@@ -1369,8 +1359,8 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
 			printk(" <- IT");
 
 		chain->selector = entity;
-		for (i = 0; i < entity->selector.bNrInPins; ++i) {
-			id = entity->selector.baSourceID[i];
+		for (i = 0; i < entity->bNrInPins; ++i) {
+			id = entity->baSourceID[i];
 			term = uvc_entity_by_id(chain->dev, id);
 			if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
 				uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
@@ -1382,7 +1372,7 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
 			if (uvc_trace_param & UVC_TRACE_PROBE)
 				printk(" %d", term->id);
 
-			list_add_tail(&term->chain, &chain->iterms);
+			list_add_tail(&term->chain, &chain->entities);
 			uvc_scan_chain_forward(chain, term, entity);
 		}
 
@@ -1391,34 +1381,49 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
 
 		id = 0;
 		break;
+
+	case UVC_ITT_VENDOR_SPECIFIC:
+	case UVC_ITT_CAMERA:
+	case UVC_ITT_MEDIA_TRANSPORT_INPUT:
+	case UVC_OTT_VENDOR_SPECIFIC:
+	case UVC_OTT_DISPLAY:
+	case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
+	case UVC_TT_STREAMING:
+		id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0;
+		break;
+	}
+
+	if (id <= 0) {
+		*_entity = NULL;
+		return id;
 	}
 
-	return id;
+	entity = uvc_entity_by_id(chain->dev, id);
+	if (entity == NULL) {
+		uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+			"unknown entity %d.\n", id);
+		return -EINVAL;
+	}
+
+	*_entity = entity;
+	return 0;
 }
 
 static int uvc_scan_chain(struct uvc_video_chain *chain,
-			  struct uvc_entity *oterm)
+			  struct uvc_entity *term)
 {
 	struct uvc_entity *entity, *prev;
-	int id;
 
-	entity = oterm;
-	list_add_tail(&entity->chain, &chain->oterms);
-	uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
+	uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:");
 
-	id = entity->output.bSourceID;
-	while (id != 0) {
-		prev = entity;
-		entity = uvc_entity_by_id(chain->dev, id);
-		if (entity == NULL) {
-			uvc_trace(UVC_TRACE_DESCR, "Found reference to "
-				"unknown entity %d.\n", id);
-			return -EINVAL;
-		}
+	entity = term;
+	prev = NULL;
 
+	while (entity != NULL) {
+		/* Entity must not be part of an existing chain */
 		if (entity->chain.next || entity->chain.prev) {
 			uvc_trace(UVC_TRACE_DESCR, "Found reference to "
-				"entity %d already in chain.\n", id);
+				"entity %d already in chain.\n", entity->id);
 			return -EINVAL;
 		}
 
@@ -1430,34 +1435,34 @@ static int uvc_scan_chain(struct uvc_video_chain *chain,
 		if (uvc_scan_chain_forward(chain, entity, prev) < 0)
 			return -EINVAL;
 
-		/* Stop when a terminal is found. */
-		if (UVC_ENTITY_IS_TERM(entity))
-			break;
-
 		/* Backward scan */
-		id = uvc_scan_chain_backward(chain, entity);
-		if (id < 0)
-			return id;
+		prev = entity;
+		if (uvc_scan_chain_backward(chain, &entity) < 0)
+			return -EINVAL;
 	}
 
 	return 0;
 }
 
-static unsigned int uvc_print_terms(struct list_head *terms, char *buffer)
+static unsigned int uvc_print_terms(struct list_head *terms, u16 dir,
+		char *buffer)
 {
 	struct uvc_entity *term;
 	unsigned int nterms = 0;
 	char *p = buffer;
 
 	list_for_each_entry(term, terms, chain) {
-		p += sprintf(p, "%u", term->id);
-		if (term->chain.next != terms) {
+		if (!UVC_ENTITY_IS_TERM(term) ||
+		    UVC_TERM_DIRECTION(term) != dir)
+			continue;
+
+		if (nterms)
 			p += sprintf(p, ",");
-			if (++nterms >= 4) {
-				p += sprintf(p, "...");
-				break;
-			}
+		if (++nterms >= 4) {
+			p += sprintf(p, "...");
+			break;
 		}
+		p += sprintf(p, "%u", term->id);
 	}
 
 	return p - buffer;
@@ -1468,9 +1473,9 @@ static const char *uvc_print_chain(struct uvc_video_chain *chain)
 	static char buffer[43];
 	char *p = buffer;
 
-	p += uvc_print_terms(&chain->iterms, p);
+	p += uvc_print_terms(&chain->entities, UVC_TERM_INPUT, p);
 	p += sprintf(p, " -> ");
-	uvc_print_terms(&chain->oterms, p);
+	uvc_print_terms(&chain->entities, UVC_TERM_OUTPUT, p);
 
 	return buffer;
 }
@@ -1501,9 +1506,7 @@ static int uvc_scan_device(struct uvc_device *dev)
 		if (chain == NULL)
 			return -ENOMEM;
 
-		INIT_LIST_HEAD(&chain->iterms);
-		INIT_LIST_HEAD(&chain->oterms);
-		INIT_LIST_HEAD(&chain->extensions);
+		INIT_LIST_HEAD(&chain->entities);
 		mutex_init(&chain->ctrl_mutex);
 		chain->dev = dev;
 
@@ -1531,22 +1534,92 @@ static int uvc_scan_device(struct uvc_device *dev)
  */
 
 /*
+ * Delete the UVC device.
+ *
+ * Called by the kernel when the last reference to the uvc_device structure
+ * is released.
+ *
+ * As this function is called after or during disconnect(), all URBs have
+ * already been canceled by the USB core. There is no need to kill the
+ * interrupt URB manually.
+ */
+static void uvc_delete(struct uvc_device *dev)
+{
+	struct list_head *p, *n;
+
+	usb_put_intf(dev->intf);
+	usb_put_dev(dev->udev);
+
+	uvc_status_cleanup(dev);
+	uvc_ctrl_cleanup_device(dev);
+
+	list_for_each_safe(p, n, &dev->chains) {
+		struct uvc_video_chain *chain;
+		chain = list_entry(p, struct uvc_video_chain, list);
+		kfree(chain);
+	}
+
+	list_for_each_safe(p, n, &dev->entities) {
+		struct uvc_entity *entity;
+		entity = list_entry(p, struct uvc_entity, list);
+		kfree(entity);
+	}
+
+	list_for_each_safe(p, n, &dev->streams) {
+		struct uvc_streaming *streaming;
+		streaming = list_entry(p, struct uvc_streaming, list);
+		usb_driver_release_interface(&uvc_driver.driver,
+			streaming->intf);
+		usb_put_intf(streaming->intf);
+		kfree(streaming->format);
+		kfree(streaming->header.bmaControls);
+		kfree(streaming);
+	}
+
+	kfree(dev);
+}
+
+static void uvc_release(struct video_device *vdev)
+{
+	struct uvc_streaming *stream = video_get_drvdata(vdev);
+	struct uvc_device *dev = stream->dev;
+
+	video_device_release(vdev);
+
+	/* Decrement the registered streams count and delete the device when it
+	 * reaches zero.
+	 */
+	if (atomic_dec_and_test(&dev->nstreams))
+		uvc_delete(dev);
+}
+
+/*
  * Unregister the video devices.
  */
 static void uvc_unregister_video(struct uvc_device *dev)
 {
 	struct uvc_streaming *stream;
 
+	/* Unregistering all video devices might result in uvc_delete() being
+	 * called from inside the loop if there's no open file handle. To avoid
+	 * that, increment the stream count before iterating over the streams
+	 * and decrement it when done.
+	 */
+	atomic_inc(&dev->nstreams);
+
 	list_for_each_entry(stream, &dev->streams, list) {
 		if (stream->vdev == NULL)
 			continue;
 
-		if (stream->vdev->minor == -1)
-			video_device_release(stream->vdev);
-		else
-			video_unregister_device(stream->vdev);
+		video_unregister_device(stream->vdev);
 		stream->vdev = NULL;
 	}
+
+	/* Decrement the stream count and call uvc_delete explicitly if there
+	 * are no stream left.
+	 */
+	if (atomic_dec_and_test(&dev->nstreams))
+		uvc_delete(dev);
 }
 
 static int uvc_register_video(struct uvc_device *dev,
@@ -1580,7 +1653,7 @@ static int uvc_register_video(struct uvc_device *dev,
 	vdev->parent = &dev->intf->dev;
 	vdev->minor = -1;
 	vdev->fops = &uvc_fops;
-	vdev->release = video_device_release;
+	vdev->release = uvc_release;
 	strlcpy(vdev->name, dev->name, sizeof vdev->name);
 
 	/* Set the driver data before calling video_register_device, otherwise
@@ -1598,6 +1671,7 @@ static int uvc_register_video(struct uvc_device *dev,
 		return ret;
 	}
 
+	atomic_inc(&dev->nstreams);
 	return 0;
 }
 
@@ -1605,13 +1679,13 @@ static int uvc_register_video(struct uvc_device *dev,
  * Register all video devices in all chains.
  */
 static int uvc_register_terms(struct uvc_device *dev,
-	struct uvc_video_chain *chain, struct list_head *terms)
+	struct uvc_video_chain *chain)
 {
 	struct uvc_streaming *stream;
 	struct uvc_entity *term;
 	int ret;
 
-	list_for_each_entry(term, terms, chain) {
+	list_for_each_entry(term, &chain->entities, chain) {
 		if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
 			continue;
 
@@ -1637,11 +1711,7 @@ static int uvc_register_chains(struct uvc_device *dev)
 	int ret;
 
 	list_for_each_entry(chain, &dev->chains, list) {
-		ret = uvc_register_terms(dev, chain, &chain->iterms);
-		if (ret < 0)
-			return ret;
-
-		ret = uvc_register_terms(dev, chain, &chain->oterms);
+		ret = uvc_register_terms(dev, chain);
 		if (ret < 0)
 			return ret;
 	}
@@ -1653,61 +1723,6 @@ static int uvc_register_chains(struct uvc_device *dev)
  * USB probe, disconnect, suspend and resume
  */
 
-/*
- * Delete the UVC device.
- *
- * Called by the kernel when the last reference to the uvc_device structure
- * is released.
- *
- * Unregistering the video devices is done here because every opened instance
- * must be closed before the device can be unregistered. An alternative would
- * have been to use another reference count for uvc_v4l2_open/uvc_release, and
- * unregister the video devices on disconnect when that reference count drops
- * to zero.
- *
- * As this function is called after or during disconnect(), all URBs have
- * already been canceled by the USB core. There is no need to kill the
- * interrupt URB manually.
- */
-void uvc_delete(struct kref *kref)
-{
-	struct uvc_device *dev = container_of(kref, struct uvc_device, kref);
-	struct list_head *p, *n;
-
-	/* Unregister the video devices. */
-	uvc_unregister_video(dev);
-	usb_put_intf(dev->intf);
-	usb_put_dev(dev->udev);
-
-	uvc_status_cleanup(dev);
-	uvc_ctrl_cleanup_device(dev);
-
-	list_for_each_safe(p, n, &dev->chains) {
-		struct uvc_video_chain *chain;
-		chain = list_entry(p, struct uvc_video_chain, list);
-		kfree(chain);
-	}
-
-	list_for_each_safe(p, n, &dev->entities) {
-		struct uvc_entity *entity;
-		entity = list_entry(p, struct uvc_entity, list);
-		kfree(entity);
-	}
-
-	list_for_each_safe(p, n, &dev->streams) {
-		struct uvc_streaming *streaming;
-		streaming = list_entry(p, struct uvc_streaming, list);
-		usb_driver_release_interface(&uvc_driver.driver,
-			streaming->intf);
-		usb_put_intf(streaming->intf);
-		kfree(streaming->format);
-		kfree(streaming->header.bmaControls);
-		kfree(streaming);
-	}
-
-	kfree(dev);
-}
-
 static int uvc_probe(struct usb_interface *intf,
 		     const struct usb_device_id *id)
 {
@@ -1730,7 +1745,7 @@ static int uvc_probe(struct usb_interface *intf,
 	INIT_LIST_HEAD(&dev->entities);
 	INIT_LIST_HEAD(&dev->chains);
 	INIT_LIST_HEAD(&dev->streams);
-	kref_init(&dev->kref);
+	atomic_set(&dev->nstreams, 0);
 	atomic_set(&dev->users, 0);
 
 	dev->udev = usb_get_dev(udev);
@@ -1792,7 +1807,7 @@ static int uvc_probe(struct usb_interface *intf,
 	return 0;
 
 error:
-	kref_put(&dev->kref, uvc_delete);
+	uvc_unregister_video(dev);
 	return -ENODEV;
 }
 
@@ -1809,21 +1824,9 @@ static void uvc_disconnect(struct usb_interface *intf)
 	    UVC_SC_VIDEOSTREAMING)
 		return;
 
-	/* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide
-	 * lock is needed to prevent uvc_disconnect from releasing its
-	 * reference to the uvc_device instance after uvc_v4l2_open() received
-	 * the pointer to the device (video_devdata) but before it got the
-	 * chance to increase the reference count (kref_get).
-	 *
-	 * Note that the reference can't be released with the lock held,
-	 * otherwise a AB-BA deadlock can occur with videodev_lock that
-	 * videodev acquires in videodev_open() and video_unregister_device().
-	 */
-	mutex_lock(&uvc_driver.open_mutex);
 	dev->state |= UVC_DEV_DISCONNECTED;
-	mutex_unlock(&uvc_driver.open_mutex);
 
-	kref_put(&dev->kref, uvc_delete);
+	uvc_unregister_video(dev);
 }
 
 static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
@@ -1899,6 +1902,15 @@ static int uvc_reset_resume(struct usb_interface *intf)
  * though they are compliant.
  */
 static struct usb_device_id uvc_ids[] = {
+	/* Genius eFace 2025 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x0458,
+	  .idProduct		= 0x706e,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
 	/* Microsoft Lifecam NX-6000 */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2123,6 +2135,15 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_STATUS_INTERVAL },
+	/* MSI StarCam 370i */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x1b3b,
+	  .idProduct		= 0x2951,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
 	/* SiGma Micro USB Web Camera */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2159,7 +2180,6 @@ static int __init uvc_init(void)
 
 	INIT_LIST_HEAD(&uvc_driver.devices);
 	INIT_LIST_HEAD(&uvc_driver.controls);
-	mutex_init(&uvc_driver.open_mutex);
 	mutex_init(&uvc_driver.ctrl_mutex);
 
 	uvc_ctrl_init();
@@ -2184,6 +2204,8 @@ module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(quirks, "Forced device quirks");
 module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(trace, "Trace level bitmask");
+module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index a2bdd806efab..23239a4adefe 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -364,37 +364,30 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
  * unprivileged state. Only a single instance can be in a privileged state at
  * a given time. Trying to perform an operation that requires privileges will
  * automatically acquire the required privileges if possible, or return -EBUSY
- * otherwise. Privileges are dismissed when closing the instance.
+ * otherwise. Privileges are dismissed when closing the instance or when
+ * freeing the video buffers using VIDIOC_REQBUFS.
  *
  * Operations that require privileges are:
  *
  * - VIDIOC_S_INPUT
  * - VIDIOC_S_PARM
  * - VIDIOC_S_FMT
- * - VIDIOC_TRY_FMT
  * - VIDIOC_REQBUFS
  */
 static int uvc_acquire_privileges(struct uvc_fh *handle)
 {
-	int ret = 0;
-
 	/* Always succeed if the handle is already privileged. */
 	if (handle->state == UVC_HANDLE_ACTIVE)
 		return 0;
 
 	/* Check if the device already has a privileged handle. */
-	mutex_lock(&uvc_driver.open_mutex);
 	if (atomic_inc_return(&handle->stream->active) != 1) {
 		atomic_dec(&handle->stream->active);
-		ret = -EBUSY;
-		goto done;
+		return -EBUSY;
 	}
 
 	handle->state = UVC_HANDLE_ACTIVE;
-
-done:
-	mutex_unlock(&uvc_driver.open_mutex);
-	return ret;
+	return 0;
 }
 
 static void uvc_dismiss_privileges(struct uvc_fh *handle)
@@ -421,24 +414,20 @@ static int uvc_v4l2_open(struct file *file)
 	int ret = 0;
 
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
-	mutex_lock(&uvc_driver.open_mutex);
 	stream = video_drvdata(file);
 
-	if (stream->dev->state & UVC_DEV_DISCONNECTED) {
-		ret = -ENODEV;
-		goto done;
-	}
+	if (stream->dev->state & UVC_DEV_DISCONNECTED)
+		return -ENODEV;
 
 	ret = usb_autopm_get_interface(stream->dev->intf);
 	if (ret < 0)
-		goto done;
+		return ret;
 
 	/* Create the device handle. */
 	handle = kzalloc(sizeof *handle, GFP_KERNEL);
 	if (handle == NULL) {
 		usb_autopm_put_interface(stream->dev->intf);
-		ret = -ENOMEM;
-		goto done;
+		return -ENOMEM;
 	}
 
 	if (atomic_inc_return(&stream->dev->users) == 1) {
@@ -447,7 +436,7 @@ static int uvc_v4l2_open(struct file *file)
 			usb_autopm_put_interface(stream->dev->intf);
 			atomic_dec(&stream->dev->users);
 			kfree(handle);
-			goto done;
+			return ret;
 		}
 	}
 
@@ -456,11 +445,7 @@ static int uvc_v4l2_open(struct file *file)
 	handle->state = UVC_HANDLE_PASSIVE;
 	file->private_data = handle;
 
-	kref_get(&stream->dev->kref);
-
-done:
-	mutex_unlock(&uvc_driver.open_mutex);
-	return ret;
+	return 0;
 }
 
 static int uvc_v4l2_release(struct file *file)
@@ -490,7 +475,6 @@ static int uvc_v4l2_release(struct file *file)
 		uvc_status_stop(stream->dev);
 
 	usb_autopm_put_interface(stream->dev->intf);
-	kref_put(&stream->dev->kref, uvc_delete);
 	return 0;
 }
 
@@ -636,12 +620,16 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 		    (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
 			if (index != 0)
 				return -EINVAL;
-			iterm = list_first_entry(&chain->iterms,
-					struct uvc_entity, chain);
+			list_for_each_entry(iterm, &chain->entities, chain) {
+				if (UVC_ENTITY_IS_ITERM(iterm))
+					break;
+			}
 			pin = iterm->id;
-		} else if (pin < selector->selector.bNrInPins) {
-			pin = selector->selector.baSourceID[index];
-			list_for_each_entry(iterm, chain->iterms.next, chain) {
+		} else if (pin < selector->bNrInPins) {
+			pin = selector->baSourceID[index];
+			list_for_each_entry(iterm, &chain->entities, chain) {
+				if (!UVC_ENTITY_IS_ITERM(iterm))
+					continue;
 				if (iterm->id == pin)
 					break;
 			}
@@ -692,7 +680,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 			break;
 		}
 
-		if (input == 0 || input > chain->selector->selector.bNrInPins)
+		if (input == 0 || input > chain->selector->bNrInPins)
 			return -EINVAL;
 
 		return uvc_query_ctrl(chain->dev, UVC_SET_CUR,
@@ -731,9 +719,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	{
 		struct uvc_streaming_control probe;
 
-		if ((ret = uvc_acquire_privileges(handle)) < 0)
-			return ret;
-
 		return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL);
 	}
 
@@ -888,6 +873,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 		if (ret < 0)
 			return ret;
 
+		if (ret == 0)
+			uvc_dismiss_privileges(handle);
+
 		rb->count = ret;
 		ret = 0;
 		break;
@@ -1051,7 +1039,7 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
 		    size_t count, loff_t *ppos)
 {
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n");
-	return -ENODEV;
+	return -EINVAL;
 }
 
 /*
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index a6e41d12b221..05139a4f14f6 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -135,7 +135,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream,
 
 	ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum,
 		probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
-		size, UVC_CTRL_STREAMING_TIMEOUT);
+		size, uvc_timeout_param);
 
 	if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) {
 		/* Some cameras, mostly based on Bison Electronics chipsets,
@@ -239,7 +239,7 @@ static int uvc_set_video_ctrl(struct uvc_streaming *stream,
 
 	ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum,
 		probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
-		size, UVC_CTRL_STREAMING_TIMEOUT);
+		size, uvc_timeout_param);
 	if (ret != size) {
 		uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
 			"%d (exp. %u).\n", probe ? "probe" : "commit",
@@ -770,8 +770,9 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
 	/* Retry allocations until one succeed. */
 	for (; npackets > 1; npackets /= 2) {
 		for (i = 0; i < UVC_URBS; ++i) {
+			stream->urb_size = psize * npackets;
 			stream->urb_buffer[i] = usb_buffer_alloc(
-				stream->dev->udev, psize * npackets,
+				stream->dev->udev, stream->urb_size,
 				gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
 			if (!stream->urb_buffer[i]) {
 				uvc_free_urb_buffers(stream);
@@ -780,11 +781,15 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
 		}
 
 		if (i == UVC_URBS) {
-			stream->urb_size = psize * npackets;
+			uvc_trace(UVC_TRACE_VIDEO, "Allocated %u URB buffers "
+				"of %ux%u bytes each.\n", UVC_URBS, npackets,
+				psize);
 			return npackets;
 		}
 	}
 
+	uvc_trace(UVC_TRACE_VIDEO, "Failed to allocate URB buffers (%u bytes "
+		"per packet).\n", psize);
 	return 0;
 }
 
@@ -935,10 +940,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
 		bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
 
 		if (bandwidth == 0) {
-			uvc_printk(KERN_WARNING, "device %s requested null "
-				"bandwidth, defaulting to lowest.\n",
-				stream->dev->name);
+			uvc_trace(UVC_TRACE_VIDEO, "Device requested null "
+				"bandwidth, defaulting to lowest.\n");
 			bandwidth = 1;
+		} else {
+			uvc_trace(UVC_TRACE_VIDEO, "Device requested %u "
+				"B/frame bandwidth.\n", bandwidth);
 		}
 
 		for (i = 0; i < intf->num_altsetting; ++i) {
@@ -955,8 +962,11 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
 				break;
 		}
 
-		if (i >= intf->num_altsetting)
+		if (i >= intf->num_altsetting) {
+			uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
+				"for requested bandwidth.\n");
 			return -EIO;
+		}
 
 		ret = usb_set_interface(stream->dev->udev, intfnum, i);
 		if (ret < 0)
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index e7958aa454ce..7ec9a04ced50 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -75,6 +75,7 @@ struct uvc_xu_control {
 
 #define UVC_TERM_INPUT			0x0000
 #define UVC_TERM_OUTPUT			0x8000
+#define UVC_TERM_DIRECTION(term)	((term)->type & 0x8000)
 
 #define UVC_ENTITY_TYPE(entity)		((entity)->type & 0x7fff)
 #define UVC_ENTITY_IS_UNIT(entity)	(((entity)->type & 0xff00) == 0)
@@ -148,7 +149,7 @@ struct uvc_xu_control {
 #define UVC_MAX_STATUS_SIZE	16
 
 #define UVC_CTRL_CONTROL_TIMEOUT	300
-#define UVC_CTRL_STREAMING_TIMEOUT	1000
+#define UVC_CTRL_STREAMING_TIMEOUT	3000
 
 /* Devices quirks */
 #define UVC_QUIRK_STATUS_INTERVAL	0x00000001
@@ -292,11 +293,9 @@ struct uvc_entity {
 		} media;
 
 		struct {
-			__u8  bSourceID;
 		} output;
 
 		struct {
-			__u8  bSourceID;
 			__u16 wMaxMultiplier;
 			__u8  bControlSize;
 			__u8  *bmControls;
@@ -304,21 +303,20 @@ struct uvc_entity {
 		} processing;
 
 		struct {
-			__u8  bNrInPins;
-			__u8  *baSourceID;
 		} selector;
 
 		struct {
 			__u8  guidExtensionCode[16];
 			__u8  bNumControls;
-			__u8  bNrInPins;
-			__u8  *baSourceID;
 			__u8  bControlSize;
 			__u8  *bmControls;
 			__u8  *bmControlsType;
 		} extension;
 	};
 
+	__u8 bNrInPins;
+	__u8 *baSourceID;
+
 	unsigned int ncontrols;
 	struct uvc_control *controls;
 };
@@ -408,11 +406,9 @@ struct uvc_video_chain {
 	struct uvc_device *dev;
 	struct list_head list;
 
-	struct list_head iterms;		/* Input terminals */
-	struct list_head oterms;		/* Output terminals */
+	struct list_head entities;		/* All entities */
 	struct uvc_entity *processing;		/* Processing unit */
 	struct uvc_entity *selector;		/* Selector unit */
-	struct list_head extensions;		/* Extension units */
 
 	struct mutex ctrl_mutex;
 };
@@ -475,7 +471,6 @@ struct uvc_device {
 	char name[32];
 
 	enum uvc_device_state state;
-	struct kref kref;
 	struct list_head list;
 	atomic_t users;
 
@@ -488,6 +483,7 @@ struct uvc_device {
 
 	/* Video Streaming interfaces */
 	struct list_head streams;
+	atomic_t nstreams;
 
 	/* Status Interrupt Endpoint */
 	struct usb_host_endpoint *int_ep;
@@ -511,8 +507,6 @@ struct uvc_fh {
 struct uvc_driver {
 	struct usb_driver driver;
 
-	struct mutex open_mutex;	/* protects from open/disconnect race */
-
 	struct list_head devices;	/* struct uvc_device list */
 	struct list_head controls;	/* struct uvc_control_info list */
 	struct mutex ctrl_mutex;	/* protects controls and devices
@@ -533,12 +527,14 @@ struct uvc_driver {
 #define UVC_TRACE_FRAME		(1 << 7)
 #define UVC_TRACE_SUSPEND	(1 << 8)
 #define UVC_TRACE_STATUS	(1 << 9)
+#define UVC_TRACE_VIDEO		(1 << 10)
 
 #define UVC_WARN_MINMAX		0
 #define UVC_WARN_PROBE_DEF	1
 
 extern unsigned int uvc_no_drop_param;
 extern unsigned int uvc_trace_param;
+extern unsigned int uvc_timeout_param;
 
 #define uvc_trace(flag, msg...) \
 	do { \
@@ -571,7 +567,6 @@ extern unsigned int uvc_trace_param;
 
 /* Core driver */
 extern struct uvc_driver uvc_driver;
-extern void uvc_delete(struct kref *kref);
 
 /* Video buffers queue management. */
 extern void uvc_queue_init(struct uvc_video_queue *queue,
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index f5a93ae3cdf9..e8e5affbabce 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -431,6 +431,8 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_CHROMA_AGC:		return "Chroma AGC";
 	case V4L2_CID_COLOR_KILLER:		return "Color Killer";
 	case V4L2_CID_COLORFX:			return "Color Effects";
+	case V4L2_CID_ROTATE:			return "Rotate";
+	case V4L2_CID_BG_COLOR:			return "Background color";
 
 	/* MPEG controls */
 	case V4L2_CID_MPEG_CLASS: 		return "MPEG Encoder Controls";
@@ -587,6 +589,13 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
 		qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 		min = max = step = def = 0;
 		break;
+	case V4L2_CID_BG_COLOR:
+		qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+		step = 1;
+		min = 0;
+		/* Max is calculated as RGB888 that is 2^24 */
+		max = 0xFFFFFF;
+		break;
 	default:
 		qctrl->type = V4L2_CTRL_TYPE_INTEGER;
 		break;
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index 8e93c6f25c83..bb0a1c8de414 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -110,7 +110,7 @@ EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
 
 
 void videobuf_queue_core_init(struct videobuf_queue *q,
-			 struct videobuf_queue_ops *ops,
+			 const struct videobuf_queue_ops *ops,
 			 struct device *dev,
 			 spinlock_t *irqlock,
 			 enum v4l2_buf_type type,
@@ -360,7 +360,7 @@ int __videobuf_mmap_setup(struct videobuf_queue *q,
 		q->bufs[i]->bsize  = bsize;
 		switch (memory) {
 		case V4L2_MEMORY_MMAP:
-			q->bufs[i]->boff  = bsize * i;
+			q->bufs[i]->boff = PAGE_ALIGN(bsize) * i;
 			break;
 		case V4L2_MEMORY_USERPTR:
 		case V4L2_MEMORY_OVERLAY:
@@ -430,9 +430,9 @@ int videobuf_reqbufs(struct videobuf_queue *q,
 		count = VIDEO_MAX_FRAME;
 	size = 0;
 	q->ops->buf_setup(q, &count, &size);
-	size = PAGE_ALIGN(size);
-	dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
-		count, size, (count*size)>>PAGE_SHIFT);
+	dprintk(1, "reqbufs: bufs=%d, size=0x%x [%u pages total]\n",
+		count, size,
+		(unsigned int)((count*PAGE_ALIGN(size))>>PAGE_SHIFT) );
 
 	retval = __videobuf_mmap_setup(q, count, size, req->memory);
 	if (retval < 0) {
@@ -1099,7 +1099,7 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
 	mbuf->size   = 0;
 	for (i = 0; i < mbuf->frames; i++) {
 		mbuf->offsets[i]  = q->bufs[i]->boff;
-		mbuf->size       += q->bufs[i]->bsize;
+		mbuf->size       += PAGE_ALIGN(q->bufs[i]->bsize);
 	}
 
 	return 0;
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index c3065c4bcba9..d25f28461da1 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -429,7 +429,7 @@ static struct videobuf_qtype_ops qops = {
 };
 
 void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
-				    struct videobuf_queue_ops *ops,
+				    const struct videobuf_queue_ops *ops,
 				    struct device *dev,
 				    spinlock_t *irqlock,
 				    enum v4l2_buf_type type,
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 032ebae0134a..fa78555b118b 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -588,7 +588,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 			retval = -EBUSY;
 			goto done;
 		}
-		size += q->bufs[last]->bsize;
+		size += PAGE_ALIGN(q->bufs[last]->bsize);
 		if (size == (vma->vm_end - vma->vm_start))
 			break;
 	}
@@ -610,7 +610,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 			continue;
 		q->bufs[i]->map   = map;
 		q->bufs[i]->baddr = vma->vm_start + size;
-		size += q->bufs[i]->bsize;
+		size += PAGE_ALIGN(q->bufs[i]->bsize);
 	}
 
 	map->count    = 1;
@@ -702,7 +702,7 @@ void *videobuf_sg_alloc(size_t size)
 }
 
 void videobuf_queue_sg_init(struct videobuf_queue* q,
-			 struct videobuf_queue_ops *ops,
+			 const struct videobuf_queue_ops *ops,
 			 struct device *dev,
 			 spinlock_t *irqlock,
 			 enum v4l2_buf_type type,
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index 0e7dcba8e4ae..a56cf0d3a6d6 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -139,7 +139,9 @@ static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
 			  struct device *device,
 			  char *adapter_name,
 			  short *adapter_nr,
-			  int mfe_shared)
+			  int mfe_shared,
+			  int (*fe_ioctl_override)(struct dvb_frontend *,
+					unsigned int, void *, unsigned int))
 {
 	int result;
 
@@ -154,6 +156,7 @@ static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
 	}
 	fe->adapter.priv = adapter_priv;
 	fe->adapter.mfe_shared = mfe_shared;
+	fe->adapter.fe_ioctl_override = fe_ioctl_override;
 
 	return result;
 }
@@ -253,7 +256,9 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
 			  void *adapter_priv,
 			  struct device *device,
 			  short *adapter_nr,
-			  int mfe_shared)
+			  int mfe_shared,
+			  int (*fe_ioctl_override)(struct dvb_frontend *,
+					unsigned int, void *, unsigned int))
 {
 	struct list_head *list, *q;
 	struct videobuf_dvb_frontend *fe;
@@ -267,7 +272,7 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
 
 	/* Bring up the adapter */
 	res = videobuf_dvb_register_adapter(f, module, adapter_priv, device,
-		fe->dvb.name, adapter_nr, mfe_shared);
+		fe->dvb.name, adapter_nr, mfe_shared, fe_ioctl_override);
 	if (res < 0) {
 		printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res);
 		return res;
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 35f3900c5633..d6e6a28fb6b8 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -391,8 +391,8 @@ static struct videobuf_qtype_ops qops = {
 };
 
 void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
-			 struct videobuf_queue_ops *ops,
-			 void *dev,
+			 const struct videobuf_queue_ops *ops,
+			 struct device *dev,
 			 spinlock_t *irqlock,
 			 enum v4l2_buf_type type,
 			 enum v4l2_field field,
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 97e0ce28ff18..33205d7537d8 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -391,7 +391,7 @@ static int vpx3220_s_routing(struct v4l2_subdev *sd,
 		{0x0e, 1}
 	};
 
-	if (input < 0 || input > 2)
+	if (input > 2)
 		return -EINVAL;
 
 	v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[input]);
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 47137deafcfd..e9f72ca458f1 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -2764,7 +2764,7 @@ static int zoran_enum_input(struct file *file, void *__fh,
 	struct zoran_fh *fh = __fh;
 	struct zoran *zr = fh->zr;
 
-	if (inp->index < 0 || inp->index >= zr->card.inputs)
+	if (inp->index >= zr->card.inputs)
 		return -EINVAL;
 	else {
 		int id = inp->index;
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index 9aae011d92ab..2ef110b5221b 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -115,6 +115,7 @@ static struct usb_device_id device_table[] = {
 	{USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 },
 	{USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 },
 	{USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD2 },
+	{USB_DEVICE(0x06d6, 0x003d), .driver_info = METHOD0 },
 	{}			/* Terminating entry */
 };