Procházet zdrojové kódy

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: (116 commits)
  V4L/DVB (13698): pms: replace asm/uaccess.h to linux/uaccess.h
  V4L/DVB (13690): radio/si470x: #include <sched.h>
  V4L/DVB (13688): au8522: modify the attributes of local filter coefficients
  V4L/DVB (13687): cx231xx: use NULL when pointer is needed
  V4L/DVB: Davinci VPFE Capture: remove unused #include <linux/version.h>
  V4L/DVB (13685): Correct code taking the size of a pointer
  V4L/DVB (13684): Fix some cut-and-paste noise in dib0090.h
  V4L/DVB (13683): sanio-ms: clean up init, exit and id_table
  V4L/DVB (13682): dib8000: make some constant static
  V4L/DVB: lgs8gxx: Use shifts rather than multiply/divide when possible
  V4L/DVB (13680b): DocBook/media: create links for included sources
  V4L/DVB (13680a): DocBook/media: copy images after building HTML
  V4L/DVB (13678): Add support for yet another DvbWorld, TeVii and Prof USB devices
  V4L/DVB (13676): configurable IRQ mode on NetUP Dual DVB-S2 CI; IRQ from CAM processing (CI interface works faster)
  V4L/DVB (13674): stv090x: Add DiSEqC envelope mode
  V4L/DVB (13673): lnbp21: Implement 22 kHz tone control
  V4L/DVB (13671): sh_mobile_ceu_camera: Remove frame size page alignment
  V4L/DVB (13670): soc-camera: Add mt9t112 camera driver
  V4L/DVB (13669): tw9910: Add sync polarity support
  V4L/DVB (13668): tw9910: remove cropping
  ...
Linus Torvalds před 15 roky
rodič
revize
6a5df38f5f
100 změnil soubory, kde provedl 5409 přidání a 1561 odebrání
  1. 15 6
      Documentation/DocBook/Makefile
  2. 18 0
      Documentation/DocBook/media-entities.tmpl
  3. 4 0
      Documentation/DocBook/media-indices.tmpl
  4. 35 0
      Documentation/DocBook/v4l/common.xml
  5. 12 4
      Documentation/DocBook/v4l/compat.xml
  6. 24 2
      Documentation/DocBook/v4l/v4l2.xml
  7. 114 2
      Documentation/DocBook/v4l/videodev2.h.xml
  8. 238 0
      Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml
  9. 35 1
      Documentation/DocBook/v4l/vidioc-enuminput.xml
  10. 35 1
      Documentation/DocBook/v4l/vidioc-enumoutput.xml
  11. 111 0
      Documentation/DocBook/v4l/vidioc-g-dv-preset.xml
  12. 224 0
      Documentation/DocBook/v4l/vidioc-g-dv-timings.xml
  13. 6 0
      Documentation/DocBook/v4l/vidioc-g-std.xml
  14. 85 0
      Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
  15. 6 0
      Documentation/DocBook/v4l/vidioc-querystd.xml
  16. 24 10
      Documentation/video4linux/gspca.txt
  17. 157 0
      Documentation/video4linux/sh_mobile_ceu_camera.txt
  18. 14 2
      Documentation/video4linux/v4l2-framework.txt
  19. 23 18
      arch/sh/boards/mach-ap325rxa/setup.c
  20. 11 2
      arch/sh/boards/mach-kfr2r09/setup.c
  21. 18 14
      arch/sh/boards/mach-migor/setup.c
  22. 9 0
      drivers/media/IR/Kconfig
  23. 5 0
      drivers/media/IR/Makefile
  24. 1 19
      drivers/media/IR/ir-functions.c
  25. 149 70
      drivers/media/IR/ir-keymaps.c
  26. 73 17
      drivers/media/IR/ir-keytable.c
  27. 1 0
      drivers/media/Kconfig
  28. 1 1
      drivers/media/Makefile
  29. 0 2
      drivers/media/common/Makefile
  30. 10 50
      drivers/media/common/saa7146_fops.c
  31. 4 10
      drivers/media/dvb/dm1105/dm1105.c
  32. 6 2
      drivers/media/dvb/dvb-usb/Kconfig
  33. 15 11
      drivers/media/dvb/dvb-usb/dib0700.h
  34. 94 7
      drivers/media/dvb/dvb-usb/dib0700_core.c
  35. 503 222
      drivers/media/dvb/dvb-usb/dib0700_devices.c
  36. 13 2
      drivers/media/dvb/dvb-usb/dibusb-common.c
  37. 3 0
      drivers/media/dvb/dvb-usb/dvb-usb-ids.h
  38. 309 147
      drivers/media/dvb/dvb-usb/dw2102.c
  39. 6 4
      drivers/media/dvb/dvb-usb/friio-fe.c
  40. 2 2
      drivers/media/dvb/dvb-usb/gp8psk-fe.c
  41. 9 0
      drivers/media/dvb/frontends/Kconfig
  42. 1 0
      drivers/media/dvb/frontends/Makefile
  43. 2 2
      drivers/media/dvb/frontends/au8522_decoder.c
  44. 349 325
      drivers/media/dvb/frontends/dib0070.c
  45. 3 1
      drivers/media/dvb/frontends/dib0070.h
  46. 1522 0
      drivers/media/dvb/frontends/dib0090.c
  47. 108 0
      drivers/media/dvb/frontends/dib0090.h
  48. 89 48
      drivers/media/dvb/frontends/dib8000.c
  49. 27 5
      drivers/media/dvb/frontends/dib8000.h
  50. 12 3
      drivers/media/dvb/frontends/dibx000_common.c
  51. 69 2
      drivers/media/dvb/frontends/dibx000_common.h
  52. 2 2
      drivers/media/dvb/frontends/lgs8gxx.c
  53. 27 1
      drivers/media/dvb/frontends/lnbp21.c
  54. 13 0
      drivers/media/dvb/frontends/stv0900_core.c
  55. 4 3
      drivers/media/dvb/frontends/stv090x.c
  56. 2 0
      drivers/media/dvb/frontends/stv090x.h
  57. 2 2
      drivers/media/dvb/siano/smsdvb.c
  58. 4 4
      drivers/media/dvb/siano/smssdio.c
  59. 14 4
      drivers/media/dvb/siano/smsusb.c
  60. 16 36
      drivers/media/dvb/ttpci/budget-ci.c
  61. 2 5
      drivers/media/radio/Kconfig
  62. 4 0
      drivers/media/radio/radio-aimslab.c
  63. 4 0
      drivers/media/radio/radio-aztech.c
  64. 4 0
      drivers/media/radio/radio-gemtek-pci.c
  65. 4 0
      drivers/media/radio/radio-maestro.c
  66. 4 0
      drivers/media/radio/radio-maxiradio.c
  67. 4 0
      drivers/media/radio/radio-mr800.c
  68. 4 0
      drivers/media/radio/radio-rtrack2.c
  69. 58 24
      drivers/media/radio/radio-sf16fmi.c
  70. 4 0
      drivers/media/radio/radio-sf16fmr2.c
  71. 5 7
      drivers/media/radio/radio-tea5764.c
  72. 4 0
      drivers/media/radio/radio-terratec.c
  73. 4 0
      drivers/media/radio/radio-trust.c
  74. 4 0
      drivers/media/radio/radio-typhoon.c
  75. 4 0
      drivers/media/radio/radio-zoltrix.c
  76. 98 0
      drivers/media/radio/si470x/radio-si470x-common.c
  77. 196 23
      drivers/media/radio/si470x/radio-si470x-i2c.c
  78. 2 95
      drivers/media/radio/si470x/radio-si470x-usb.c
  79. 4 1
      drivers/media/radio/si470x/radio-si470x.h
  80. 6 4
      drivers/media/video/Kconfig
  81. 2 1
      drivers/media/video/Makefile
  82. 2 3
      drivers/media/video/arv.c
  83. 8 28
      drivers/media/video/au0828/au0828-video.c
  84. 0 1
      drivers/media/video/au0828/au0828.h
  85. 17 24
      drivers/media/video/bt8xx/bttv-driver.c
  86. 2 2
      drivers/media/video/bt8xx/bttv-i2c.c
  87. 3 6
      drivers/media/video/bt8xx/bttv-input.c
  88. 2 2
      drivers/media/video/c-qcam.c
  89. 0 1
      drivers/media/video/cafe_ccic.c
  90. 107 114
      drivers/media/video/cpia.c
  91. 14 20
      drivers/media/video/cpia2/cpia2_v4l.c
  92. 2 2
      drivers/media/video/cx18/cx18-fileops.c
  93. 10 10
      drivers/media/video/cx18/cx18-streams.c
  94. 12 11
      drivers/media/video/cx231xx/cx231xx-cards.c
  95. 0 26
      drivers/media/video/cx231xx/cx231xx-core.c
  96. 3 7
      drivers/media/video/cx231xx/cx231xx-input.c
  97. 33 25
      drivers/media/video/cx231xx/cx231xx-video.c
  98. 0 2
      drivers/media/video/cx231xx/cx231xx.h
  99. 78 29
      drivers/media/video/cx23885/cimax2.c
  100. 7 22
      drivers/media/video/cx23885/cx23885-417.c

+ 15 - 6
Documentation/DocBook/Makefile

@@ -32,10 +32,10 @@ PS_METHOD	= $(prefer-db2x)
 
 ###
 # The targets that may be used.
-PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs media
+PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs xmldoclinks
 
 BOOKS := $(addprefix $(obj)/,$(DOCBOOKS))
-xmldocs: $(BOOKS)
+xmldocs: $(BOOKS) xmldoclinks
 sgmldocs: xmldocs
 
 PS := $(patsubst %.xml, %.ps, $(BOOKS))
@@ -45,15 +45,24 @@ PDF := $(patsubst %.xml, %.pdf, $(BOOKS))
 pdfdocs: $(PDF)
 
 HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
-htmldocs: media $(HTML)
+htmldocs: $(HTML)
 	$(call build_main_index)
+	$(call build_images)
 
 MAN := $(patsubst %.xml, %.9, $(BOOKS))
 mandocs: $(MAN)
 
-media:
-	mkdir -p $(srctree)/Documentation/DocBook/media/
-	cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(srctree)/Documentation/DocBook/media/
+build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \
+	       cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(objtree)/Documentation/DocBook/media/
+
+xmldoclinks:
+ifneq ($(objtree),$(srctree))
+	for dep in dvb media-entities.tmpl media-indices.tmpl v4l; do \
+		rm -f $(objtree)/Documentation/DocBook/$$dep \
+		&& ln -s $(srctree)/Documentation/DocBook/$$dep $(objtree)/Documentation/DocBook/ \
+		|| exit; \
+	done
+endif
 
 installmandocs: mandocs
 	mkdir -p /usr/local/man/man9/

+ 18 - 0
Documentation/DocBook/media-entities.tmpl

@@ -23,6 +23,7 @@
 <!ENTITY VIDIOC-ENUMINPUT "<link linkend='vidioc-enuminput'><constant>VIDIOC_ENUMINPUT</constant></link>">
 <!ENTITY VIDIOC-ENUMOUTPUT "<link linkend='vidioc-enumoutput'><constant>VIDIOC_ENUMOUTPUT</constant></link>">
 <!ENTITY VIDIOC-ENUMSTD "<link linkend='vidioc-enumstd'><constant>VIDIOC_ENUMSTD</constant></link>">
+<!ENTITY VIDIOC-ENUM-DV-PRESETS "<link linkend='vidioc-enum-dv-presets'><constant>VIDIOC_ENUM_DV_PRESETS</constant></link>">
 <!ENTITY VIDIOC-ENUM-FMT "<link linkend='vidioc-enum-fmt'><constant>VIDIOC_ENUM_FMT</constant></link>">
 <!ENTITY VIDIOC-ENUM-FRAMEINTERVALS "<link linkend='vidioc-enum-frameintervals'><constant>VIDIOC_ENUM_FRAMEINTERVALS</constant></link>">
 <!ENTITY VIDIOC-ENUM-FRAMESIZES "<link linkend='vidioc-enum-framesizes'><constant>VIDIOC_ENUM_FRAMESIZES</constant></link>">
@@ -30,6 +31,8 @@
 <!ENTITY VIDIOC-G-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_G_AUDOUT</constant></link>">
 <!ENTITY VIDIOC-G-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_G_CROP</constant></link>">
 <!ENTITY VIDIOC-G-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_G_CTRL</constant></link>">
+<!ENTITY VIDIOC-G-DV-PRESET "<link linkend='vidioc-g-dv-preset'><constant>VIDIOC_G_DV_PRESET</constant></link>">
+<!ENTITY VIDIOC-G-DV-TIMINGS "<link linkend='vidioc-g-dv-timings'><constant>VIDIOC_G_DV_TIMINGS</constant></link>">
 <!ENTITY VIDIOC-G-ENC-INDEX "<link linkend='vidioc-g-enc-index'><constant>VIDIOC_G_ENC_INDEX</constant></link>">
 <!ENTITY VIDIOC-G-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_G_EXT_CTRLS</constant></link>">
 <!ENTITY VIDIOC-G-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_G_FBUF</constant></link>">
@@ -53,6 +56,7 @@
 <!ENTITY VIDIOC-QUERYCTRL "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYCTRL</constant></link>">
 <!ENTITY VIDIOC-QUERYMENU "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYMENU</constant></link>">
 <!ENTITY VIDIOC-QUERYSTD "<link linkend='vidioc-querystd'><constant>VIDIOC_QUERYSTD</constant></link>">
+<!ENTITY VIDIOC-QUERY-DV-PRESET "<link linkend='vidioc-query-dv-preset'><constant>VIDIOC_QUERY_DV_PRESET</constant></link>">
 <!ENTITY VIDIOC-REQBUFS "<link linkend='vidioc-reqbufs'><constant>VIDIOC_REQBUFS</constant></link>">
 <!ENTITY VIDIOC-STREAMOFF "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMOFF</constant></link>">
 <!ENTITY VIDIOC-STREAMON "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMON</constant></link>">
@@ -60,6 +64,8 @@
 <!ENTITY VIDIOC-S-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_S_AUDOUT</constant></link>">
 <!ENTITY VIDIOC-S-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_S_CROP</constant></link>">
 <!ENTITY VIDIOC-S-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_S_CTRL</constant></link>">
+<!ENTITY VIDIOC-S-DV-PRESET "<link linkend='vidioc-g-dv-preset'><constant>VIDIOC_S_DV_PRESET</constant></link>">
+<!ENTITY VIDIOC-S-DV-TIMINGS "<link linkend='vidioc-g-dv-timings'><constant>VIDIOC_S_DV_TIMINGS</constant></link>">
 <!ENTITY VIDIOC-S-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_S_EXT_CTRLS</constant></link>">
 <!ENTITY VIDIOC-S-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_S_FBUF</constant></link>">
 <!ENTITY VIDIOC-S-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_S_FMT</constant></link>">
@@ -118,6 +124,7 @@
 <!-- Structures -->
 <!ENTITY v4l2-audio "struct&nbsp;<link linkend='v4l2-audio'>v4l2_audio</link>">
 <!ENTITY v4l2-audioout "struct&nbsp;<link linkend='v4l2-audioout'>v4l2_audioout</link>">
+<!ENTITY v4l2-bt-timings "struct&nbsp;<link linkend='v4l2-bt-timings'>v4l2_bt_timings</link>">
 <!ENTITY v4l2-buffer "struct&nbsp;<link linkend='v4l2-buffer'>v4l2_buffer</link>">
 <!ENTITY v4l2-capability "struct&nbsp;<link linkend='v4l2-capability'>v4l2_capability</link>">
 <!ENTITY v4l2-captureparm "struct&nbsp;<link linkend='v4l2-captureparm'>v4l2_captureparm</link>">
@@ -128,6 +135,9 @@
 <!ENTITY v4l2-dbg-chip-ident "struct&nbsp;<link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link>">
 <!ENTITY v4l2-dbg-match "struct&nbsp;<link linkend='v4l2-dbg-match'>v4l2_dbg_match</link>">
 <!ENTITY v4l2-dbg-register "struct&nbsp;<link linkend='v4l2-dbg-register'>v4l2_dbg_register</link>">
+<!ENTITY v4l2-dv-enum-preset "struct&nbsp;<link linkend='v4l2-dv-enum-preset'>v4l2_dv_enum_preset</link>">
+<!ENTITY v4l2-dv-preset "struct&nbsp;<link linkend='v4l2-dv-preset'>v4l2_dv_preset</link>">
+<!ENTITY v4l2-dv-timings "struct&nbsp;<link linkend='v4l2-dv-timings'>v4l2_dv_timings</link>">
 <!ENTITY v4l2-enc-idx "struct&nbsp;<link linkend='v4l2-enc-idx'>v4l2_enc_idx</link>">
 <!ENTITY v4l2-enc-idx-entry "struct&nbsp;<link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link>">
 <!ENTITY v4l2-encoder-cmd "struct&nbsp;<link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link>">
@@ -243,6 +253,10 @@
 <!ENTITY sub-enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml">
 <!ENTITY sub-enuminput SYSTEM "v4l/vidioc-enuminput.xml">
 <!ENTITY sub-enumoutput SYSTEM "v4l/vidioc-enumoutput.xml">
+<!ENTITY sub-enum-dv-presets SYSTEM "v4l/vidioc-enum-dv-presets.xml">
+<!ENTITY sub-g-dv-preset SYSTEM "v4l/vidioc-g-dv-preset.xml">
+<!ENTITY sub-query-dv-preset SYSTEM "v4l/vidioc-query-dv-preset.xml">
+<!ENTITY sub-g-dv-timings SYSTEM "v4l/vidioc-g-dv-timings.xml">
 <!ENTITY sub-enumstd SYSTEM "v4l/vidioc-enumstd.xml">
 <!ENTITY sub-g-audio SYSTEM "v4l/vidioc-g-audio.xml">
 <!ENTITY sub-g-audioout SYSTEM "v4l/vidioc-g-audioout.xml">
@@ -333,6 +347,10 @@
 <!ENTITY enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml">
 <!ENTITY enuminput SYSTEM "v4l/vidioc-enuminput.xml">
 <!ENTITY enumoutput SYSTEM "v4l/vidioc-enumoutput.xml">
+<!ENTITY enum-dv-presets SYSTEM "v4l/vidioc-enum-dv-presets.xml">
+<!ENTITY g-dv-preset SYSTEM "v4l/vidioc-g-dv-preset.xml">
+<!ENTITY query-dv-preset SYSTEM "v4l/vidioc-query-dv-preset.xml">
+<!ENTITY g-dv-timings SYSTEM "v4l/vidioc-g-dv-timings.xml">
 <!ENTITY enumstd SYSTEM "v4l/vidioc-enumstd.xml">
 <!ENTITY g-audio SYSTEM "v4l/vidioc-g-audio.xml">
 <!ENTITY g-audioout SYSTEM "v4l/vidioc-g-audioout.xml">

+ 4 - 0
Documentation/DocBook/media-indices.tmpl

@@ -36,6 +36,7 @@
 <indexentry><primaryie>enum&nbsp;<link linkend='v4l2-preemphasis'>v4l2_preemphasis</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-audio'>v4l2_audio</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-audioout'>v4l2_audioout</link></primaryie></indexentry>
+<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-bt-timings'>v4l2_bt_timings</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-buffer'>v4l2_buffer</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-capability'>v4l2_capability</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-captureparm'>v4l2_captureparm</link></primaryie></indexentry>
@@ -46,6 +47,9 @@
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dbg-match'>v4l2_dbg_match</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dbg-register'>v4l2_dbg_register</link></primaryie></indexentry>
+<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dv-enum-preset'>v4l2_dv_enum_preset</link></primaryie></indexentry>
+<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dv-preset'>v4l2_dv_preset</link></primaryie></indexentry>
+<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dv-timings'>v4l2_dv_timings</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-enc-idx'>v4l2_enc_idx</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link></primaryie></indexentry>
 <indexentry><primaryie>struct&nbsp;<link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link></primaryie></indexentry>

+ 35 - 0
Documentation/DocBook/v4l/common.xml

@@ -716,6 +716,41 @@ if (-1 == ioctl (fd, &VIDIOC-S-STD;, &amp;std_id)) {
 }
       </programlisting>
     </example>
+  <section id="dv-timings">
+	<title>Digital Video (DV) Timings</title>
+	<para>
+	The video standards discussed so far has been dealing with Analog TV and the
+corresponding video timings. Today there are many more different hardware interfaces
+such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry
+video signals and there is a need to extend the API to select the video timings
+for these interfaces. Since it is not possible to extend the &v4l2-std-id; due to
+the limited bits available, a new set of IOCTLs is added to set/get video timings at
+the input and output: </para><itemizedlist>
+	<listitem>
+	<para>DV Presets: Digital Video (DV) presets. These are IDs representing a
+video timing at the input/output. Presets are pre-defined timings implemented
+by the hardware according to video standards. A __u32 data type is used to represent
+a preset unlike the bit mask that is used in &v4l2-std-id; allowing future extensions
+to support as many different presets as needed.</para>
+	</listitem>
+	<listitem>
+	<para>Custom DV Timings: This will allow applications to define more detailed
+custom video timings for the interface. This includes parameters such as width, height,
+polarities, frontporch, backporch etc.
+	</para>
+	</listitem>
+	</itemizedlist>
+	<para>To enumerate and query the attributes of DV presets supported by a device,
+applications use the &VIDIOC-ENUM-DV-PRESETS; ioctl. To get the current DV preset,
+applications use the &VIDIOC-G-DV-PRESET; ioctl and to set a preset they use the
+&VIDIOC-S-DV-PRESET; ioctl.</para>
+	<para>To set custom DV timings for the device, applications use the
+&VIDIOC-S-DV-TIMINGS; ioctl and to get current custom DV timings they use the
+&VIDIOC-G-DV-TIMINGS; ioctl.</para>
+	<para>Applications can make use of the <xref linkend="input-capabilities" /> and
+<xref linkend="output-capabilities"/> flags to decide what ioctls are available to set the
+video timings for the device.</para>
+	</section>
   </section>
 
   &sub-controls;

+ 12 - 4
Documentation/DocBook/v4l/compat.xml

@@ -2291,8 +2291,8 @@ was renamed to <structname id="v4l2-chip-ident-old">v4l2_chip_ident_old</structn
 	<listitem>
 	  <para>New control <constant>V4L2_CID_COLORFX</constant> was added.</para>
 	</listitem>
-       </orderedlist>
-     </section>
+      </orderedlist>
+    </section>
     <section>
       <title>V4L2 in Linux 2.6.32</title>
       <orderedlist>
@@ -2322,8 +2322,16 @@ more information.</para>
 	<listitem>
 	  <para>Added Remote Controller chapter, describing the default Remote Controller mapping for media devices.</para>
 	</listitem>
-       </orderedlist>
-     </section>
+      </orderedlist>
+    </section>
+    <section>
+      <title>V4L2 in Linux 2.6.33</title>
+      <orderedlist>
+	<listitem>
+	  <para>Added support for Digital Video timings in order to support HDTV receivers and transmitters.</para>
+	</listitem>
+      </orderedlist>
+    </section>
    </section>
 
    <section id="other">

+ 24 - 2
Documentation/DocBook/v4l/v4l2.xml

@@ -74,6 +74,17 @@ Remote Controller chapter.</contrib>
 	  </address>
 	</affiliation>
       </author>
+
+      <author>
+	<firstname>Muralidharan</firstname>
+	<surname>Karicheri</surname>
+	<contrib>Documented the Digital Video timings API.</contrib>
+	<affiliation>
+	  <address>
+	    <email>m-karicheri2@ti.com</email>
+	  </address>
+	</affiliation>
+      </author>
     </authorgroup>
 
     <copyright>
@@ -89,7 +100,7 @@ Remote Controller chapter.</contrib>
       <year>2008</year>
       <year>2009</year>
       <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
-Rubli, Andy Walls, Mauro Carvalho Chehab</holder>
+Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab</holder>
     </copyright>
     <legalnotice>
     <para>Except when explicitly stated as GPL, programming examples within
@@ -102,6 +113,13 @@ structs, ioctls) must be noted in more detail in the history chapter
 (compat.sgml), along with the possible impact on existing drivers and
 applications. -->
 
+      <revision>
+	<revnumber>2.6.33</revnumber>
+	<date>2009-12-03</date>
+	<authorinitials>mk</authorinitials>
+	<revremark>Added documentation for the Digital Video timings API.</revremark>
+      </revision>
+
       <revision>
 	<revnumber>2.6.32</revnumber>
 	<date>2009-08-31</date>
@@ -355,7 +373,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 2.6.32</subtitle>
+ <subtitle>Revision 2.6.33</subtitle>
 
   <chapter id="common">
     &sub-common;
@@ -411,6 +429,7 @@ and discussions on the V4L mailing list.</revremark>
     &sub-encoder-cmd;
     &sub-enumaudio;
     &sub-enumaudioout;
+    &sub-enum-dv-presets;
     &sub-enum-fmt;
     &sub-enum-framesizes;
     &sub-enum-frameintervals;
@@ -421,6 +440,8 @@ and discussions on the V4L mailing list.</revremark>
     &sub-g-audioout;
     &sub-g-crop;
     &sub-g-ctrl;
+    &sub-g-dv-preset;
+    &sub-g-dv-timings;
     &sub-g-enc-index;
     &sub-g-ext-ctrls;
     &sub-g-fbuf;
@@ -441,6 +462,7 @@ and discussions on the V4L mailing list.</revremark>
     &sub-querybuf;
     &sub-querycap;
     &sub-queryctrl;
+    &sub-query-dv-preset;
     &sub-querystd;
     &sub-reqbufs;
     &sub-s-hw-freq-seek;

+ 114 - 2
Documentation/DocBook/v4l/videodev2.h.xml

@@ -733,6 +733,99 @@ struct <link linkend="v4l2-standard">v4l2_standard</link> {
         __u32                reserved[4];
 };
 
+/*
+ *      V I D E O       T I M I N G S   D V     P R E S E T
+ */
+struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link> {
+        __u32   preset;
+        __u32   reserved[4];
+};
+
+/*
+ *      D V     P R E S E T S   E N U M E R A T I O N
+ */
+struct <link linkend="v4l2-dv-enum-preset">v4l2_dv_enum_preset</link> {
+        __u32   index;
+        __u32   preset;
+        __u8    name[32]; /* Name of the preset timing */
+        __u32   width;
+        __u32   height;
+        __u32   reserved[4];
+};
+
+/*
+ *      D V     P R E S E T     V A L U E S
+ */
+#define         V4L2_DV_INVALID         0
+#define         V4L2_DV_480P59_94       1 /* BT.1362 */
+#define         V4L2_DV_576P50          2 /* BT.1362 */
+#define         V4L2_DV_720P24          3 /* SMPTE 296M */
+#define         V4L2_DV_720P25          4 /* SMPTE 296M */
+#define         V4L2_DV_720P30          5 /* SMPTE 296M */
+#define         V4L2_DV_720P50          6 /* SMPTE 296M */
+#define         V4L2_DV_720P59_94       7 /* SMPTE 274M */
+#define         V4L2_DV_720P60          8 /* SMPTE 274M/296M */
+#define         V4L2_DV_1080I29_97      9 /* BT.1120/ SMPTE 274M */
+#define         V4L2_DV_1080I30         10 /* BT.1120/ SMPTE 274M */
+#define         V4L2_DV_1080I25         11 /* BT.1120 */
+#define         V4L2_DV_1080I50         12 /* SMPTE 296M */
+#define         V4L2_DV_1080I60         13 /* SMPTE 296M */
+#define         V4L2_DV_1080P24         14 /* SMPTE 296M */
+#define         V4L2_DV_1080P25         15 /* SMPTE 296M */
+#define         V4L2_DV_1080P30         16 /* SMPTE 296M */
+#define         V4L2_DV_1080P50         17 /* BT.1120 */
+#define         V4L2_DV_1080P60         18 /* BT.1120 */
+
+/*
+ *      D V     B T     T I M I N G S
+ */
+
+/* BT.656/BT.1120 timing data */
+struct <link linkend="v4l2-bt-timings">v4l2_bt_timings</link> {
+        __u32   width;          /* width in pixels */
+        __u32   height;         /* height in lines */
+        __u32   interlaced;     /* Interlaced or progressive */
+        __u32   polarities;     /* Positive or negative polarity */
+        __u64   pixelclock;     /* Pixel clock in HZ. Ex. 74.25MHz-&gt;74250000 */
+        __u32   hfrontporch;    /* Horizpontal front porch in pixels */
+        __u32   hsync;          /* Horizontal Sync length in pixels */
+        __u32   hbackporch;     /* Horizontal back porch in pixels */
+        __u32   vfrontporch;    /* Vertical front porch in pixels */
+        __u32   vsync;          /* Vertical Sync length in lines */
+        __u32   vbackporch;     /* Vertical back porch in lines */
+        __u32   il_vfrontporch; /* Vertical front porch for bottom field of
+                                 * interlaced field formats
+                                 */
+        __u32   il_vsync;       /* Vertical sync length for bottom field of
+                                 * interlaced field formats
+                                 */
+        __u32   il_vbackporch;  /* Vertical back porch for bottom field of
+                                 * interlaced field formats
+                                 */
+        __u32   reserved[16];
+} __attribute__ ((packed));
+
+/* Interlaced or progressive format */
+#define V4L2_DV_PROGRESSIVE     0
+#define V4L2_DV_INTERLACED      1
+
+/* Polarities. If bit is not set, it is assumed to be negative polarity */
+#define V4L2_DV_VSYNC_POS_POL   0x00000001
+#define V4L2_DV_HSYNC_POS_POL   0x00000002
+
+
+/* DV timings */
+struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link> {
+        __u32 type;
+        union {
+                struct <link linkend="v4l2-bt-timings">v4l2_bt_timings</link>  bt;
+                __u32   reserved[32];
+        };
+} __attribute__ ((packed));
+
+/* Values for the type field */
+#define V4L2_DV_BT_656_1120     0       /* BT.656/1120 timing type */
+
 /*
  *      V I D E O   I N P U T S
  */
@@ -744,7 +837,8 @@ struct <link linkend="v4l2-input">v4l2_input</link> {
         __u32        tuner;             /*  Associated tuner */
         v4l2_std_id  std;
         __u32        status;
-        __u32        reserved[4];
+        __u32        capabilities;
+        __u32        reserved[3];
 };
 
 /*  Values for the 'type' field */
@@ -775,6 +869,11 @@ struct <link linkend="v4l2-input">v4l2_input</link> {
 #define V4L2_IN_ST_NO_ACCESS   0x02000000  /* Conditional access denied */
 #define V4L2_IN_ST_VTR         0x04000000  /* VTR time constant */
 
+/* capabilities flags */
+#define V4L2_IN_CAP_PRESETS             0x00000001 /* Supports S_DV_PRESET */
+#define V4L2_IN_CAP_CUSTOM_TIMINGS      0x00000002 /* Supports S_DV_TIMINGS */
+#define V4L2_IN_CAP_STD                 0x00000004 /* Supports S_STD */
+
 /*
  *      V I D E O   O U T P U T S
  */
@@ -785,13 +884,19 @@ struct <link linkend="v4l2-output">v4l2_output</link> {
         __u32        audioset;          /*  Associated audios (bitfield) */
         __u32        modulator;         /*  Associated modulator */
         v4l2_std_id  std;
-        __u32        reserved[4];
+        __u32        capabilities;
+        __u32        reserved[3];
 };
 /*  Values for the 'type' field */
 #define V4L2_OUTPUT_TYPE_MODULATOR              1
 #define V4L2_OUTPUT_TYPE_ANALOG                 2
 #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY       3
 
+/* capabilities flags */
+#define V4L2_OUT_CAP_PRESETS            0x00000001 /* Supports S_DV_PRESET */
+#define V4L2_OUT_CAP_CUSTOM_TIMINGS     0x00000002 /* Supports S_DV_TIMINGS */
+#define V4L2_OUT_CAP_STD                0x00000004 /* Supports S_STD */
+
 /*
  *      C O N T R O L S
  */
@@ -1626,6 +1731,13 @@ struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link> {
 #endif
 
 #define VIDIOC_S_HW_FREQ_SEEK    _IOW('V', 82, struct <link linkend="v4l2-hw-freq-seek">v4l2_hw_freq_seek</link>)
+#define VIDIOC_ENUM_DV_PRESETS  _IOWR('V', 83, struct <link linkend="v4l2-dv-enum-preset">v4l2_dv_enum_preset</link>)
+#define VIDIOC_S_DV_PRESET      _IOWR('V', 84, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
+#define VIDIOC_G_DV_PRESET      _IOWR('V', 85, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
+#define VIDIOC_QUERY_DV_PRESET  _IOR('V',  86, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
+#define VIDIOC_S_DV_TIMINGS     _IOWR('V', 87, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
+#define VIDIOC_G_DV_TIMINGS     _IOWR('V', 88, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 

+ 238 - 0
Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml

@@ -0,0 +1,238 @@
+<refentry id="vidioc-enum-dv-presets">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUM_DV_PRESETS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUM_DV_PRESETS</refname>
+    <refpurpose>Enumerate supported Digital Video presets</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_dv_enum_preset *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_ENUM_DV_PRESETS</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of a DV preset, applications initialize the
+<structfield>index</structfield> field and zero the reserved array of &v4l2-dv-enum-preset;
+and call the <constant>VIDIOC_ENUM_DV_PRESETS</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all DV Presets supported,
+applications shall begin at index zero, incrementing by one until the
+driver returns <errorcode>EINVAL</errorcode>. Drivers may enumerate a
+different set of DV presets after switching the video input or
+output.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-dv-enum-preset">
+      <title>struct <structname>v4l2_dv_enum_presets</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>index</structfield></entry>
+	    <entry>Number of the DV preset, set by the
+application.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>preset</structfield></entry>
+	    <entry>This field identifies one of the DV preset values listed in <xref linkend="v4l2-dv-presets-vals"/>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>name</structfield>[24]</entry>
+	    <entry>Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is
+intended for the user.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>width</structfield></entry>
+	    <entry>Width of the active video in pixels for the DV preset.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>height</structfield></entry>
+	    <entry>Height of the active video in lines for the DV preset.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[4]</entry>
+	    <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-dv-presets-vals">
+      <title>struct <structname>DV Presets</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>Preset</entry>
+	    <entry>Preset value</entry>
+	    <entry>Description</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_INVALID</entry>
+	    <entry>0</entry>
+	    <entry>Invalid preset value.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_480P59_94</entry>
+	    <entry>1</entry>
+	    <entry>720x480 progressive video at 59.94 fps as per BT.1362.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_576P50</entry>
+	    <entry>2</entry>
+	    <entry>720x576 progressive video at 50 fps as per BT.1362.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_720P24</entry>
+	    <entry>3</entry>
+	    <entry>1280x720 progressive video at 24 fps as per SMPTE 296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_720P25</entry>
+	    <entry>4</entry>
+	    <entry>1280x720 progressive video at 25 fps as per SMPTE 296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_720P30</entry>
+	    <entry>5</entry>
+	    <entry>1280x720 progressive video at 30 fps as per SMPTE 296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_720P50</entry>
+	    <entry>6</entry>
+	    <entry>1280x720 progressive video at 50 fps as per SMPTE 296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_720P59_94</entry>
+	    <entry>7</entry>
+	    <entry>1280x720 progressive video at 59.94 fps as per SMPTE 274M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_720P60</entry>
+	    <entry>8</entry>
+	    <entry>1280x720 progressive video at 60 fps as per SMPTE 274M/296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080I29_97</entry>
+	    <entry>9</entry>
+	    <entry>1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080I30</entry>
+	    <entry>10</entry>
+	    <entry>1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080I25</entry>
+	    <entry>11</entry>
+	    <entry>1920x1080 interlaced video at 25 fps as per BT.1120.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080I50</entry>
+	    <entry>12</entry>
+	    <entry>1920x1080 interlaced video at 50 fps as per SMPTE 296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080I60</entry>
+	    <entry>13</entry>
+	    <entry>1920x1080 interlaced video at 60 fps as per SMPTE 296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080P24</entry>
+	    <entry>14</entry>
+	    <entry>1920x1080 progressive video at 24 fps as per SMPTE 296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080P25</entry>
+	    <entry>15</entry>
+	    <entry>1920x1080 progressive video at 25 fps as per SMPTE 296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080P30</entry>
+	    <entry>16</entry>
+	    <entry>1920x1080 progressive video at 30 fps as per SMPTE 296M.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080P50</entry>
+	    <entry>17</entry>
+	    <entry>1920x1080 progressive video at 50 fps as per BT.1120.</entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_1080P60</entry>
+	    <entry>18</entry>
+	    <entry>1920x1080 progressive video at 60 fps as per BT.1120.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>The &v4l2-dv-enum-preset; <structfield>index</structfield>
+is out of bounds.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->

+ 35 - 1
Documentation/DocBook/v4l/vidioc-enuminput.xml

@@ -124,7 +124,13 @@ current input.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>reserved</structfield>[4]</entry>
+	    <entry><structfield>capabilities</structfield></entry>
+	    <entry>This field provides capabilities for the
+input. See <xref linkend="input-capabilities" /> for flags.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[3]</entry>
 	    <entry>Reserved for future extensions. Drivers must set
 the array to zero.</entry>
 	  </row>
@@ -261,6 +267,34 @@ flag is set Macrovision has been detected.</entry>
 	</tbody>
       </tgroup>
     </table>
+
+    <!-- Capability flags based on video timings RFC by Muralidharan
+Karicheri, titled RFC (v1.2): V4L - Support for video timings at the
+input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
+	-->
+    <table frame="none" pgwide="1" id="input-capabilities">
+      <title>Input capabilities</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_IN_CAP_PRESETS</constant></entry>
+	    <entry>0x00000001</entry>
+	    <entry>This input supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry>
+	    <entry>0x00000002</entry>
+	    <entry>This input supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_IN_CAP_STD</constant></entry>
+	    <entry>0x00000004</entry>
+	    <entry>This input supports setting the TV standard by using VIDIOC_S_STD.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
   </refsect1>
 
   <refsect1>

+ 35 - 1
Documentation/DocBook/v4l/vidioc-enumoutput.xml

@@ -114,7 +114,13 @@ details on video standards and how to switch see <xref
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>reserved</structfield>[4]</entry>
+	    <entry><structfield>capabilities</structfield></entry>
+	    <entry>This field provides capabilities for the
+output. See <xref linkend="output-capabilities" /> for flags.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[3]</entry>
 	    <entry>Reserved for future extensions. Drivers must set
 the array to zero.</entry>
 	  </row>
@@ -147,6 +153,34 @@ CVBS, S-Video, RGB.</entry>
       </tgroup>
     </table>
 
+    <!-- Capabilities flags based on video timings RFC by Muralidharan
+Karicheri, titled RFC (v1.2): V4L - Support for video timings at the
+input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
+	-->
+    <table frame="none" pgwide="1" id="output-capabilities">
+      <title>Output capabilities</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_OUT_CAP_PRESETS</constant></entry>
+	    <entry>0x00000001</entry>
+	    <entry>This output supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry>
+	    <entry>0x00000002</entry>
+	    <entry>This output supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_OUT_CAP_STD</constant></entry>
+	    <entry>0x00000004</entry>
+	    <entry>This output supports setting the TV standard by using VIDIOC_S_STD.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
   </refsect1>
   <refsect1>
     &return-value;

+ 111 - 0
Documentation/DocBook/v4l/vidioc-g-dv-preset.xml

@@ -0,0 +1,111 @@
+<refentry id="vidioc-g-dv-preset">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_DV_PRESET</refname>
+    <refname>VIDIOC_S_DV_PRESET</refname>
+    <refpurpose>Query or select the DV preset of the current input or output</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>&v4l2-dv-preset;
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+    <para>To query and select the current DV preset, applications
+use the <constant>VIDIOC_G_DV_PRESET</constant> and <constant>VIDIOC_S_DV_PRESET</constant>
+ioctls which take a pointer to a &v4l2-dv-preset; type as argument.
+Applications must zero the reserved array in &v4l2-dv-preset;.
+<constant>VIDIOC_G_DV_PRESET</constant> returns a dv preset in the field
+<structfield>preset</structfield> of &v4l2-dv-preset;.</para>
+
+    <para><constant>VIDIOC_S_DV_PRESET</constant> accepts a pointer to a &v4l2-dv-preset;
+that has the preset value to be set. Applications must zero the reserved array in &v4l2-dv-preset;.
+If the preset is not supported, it returns an &EINVAL; </para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>This ioctl is not supported, or the
+<constant>VIDIOC_S_DV_PRESET</constant>,<constant>VIDIOC_S_DV_PRESET</constant> parameter was unsuitable.</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
+	<listitem>
+	  <para>The device is busy and therefore can not change the preset.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+
+    <table pgwide="1" frame="none" id="v4l2-dv-preset">
+      <title>struct <structname>v4l2_dv_preset</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>preset</structfield></entry>
+	    <entry>Preset value to represent the digital video timings</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved[4]</structfield></entry>
+	    <entry>Reserved fields for future use</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->

+ 224 - 0
Documentation/DocBook/v4l/vidioc-g-dv-timings.xml

@@ -0,0 +1,224 @@
+<refentry id="vidioc-g-dv-timings">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_DV_TIMINGS</refname>
+    <refname>VIDIOC_S_DV_TIMINGS</refname>
+    <refpurpose>Get or set custom DV timings for input or output</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>&v4l2-dv-timings;
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+    <para>To set custom DV timings for the input or output, applications use the
+<constant>VIDIOC_S_DV_TIMINGS</constant> ioctl and to get the current custom timings,
+applications use the <constant>VIDIOC_G_DV_TIMINGS</constant> ioctl. The detailed timing
+information is filled in using the structure &v4l2-dv-timings;. These ioctls take
+a pointer to the &v4l2-dv-timings; structure as argument. If the ioctl is not supported
+or the timing values are not correct, the driver returns &EINVAL;.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>This ioctl is not supported, or the
+<constant>VIDIOC_S_DV_TIMINGS</constant> parameter was unsuitable.</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
+	<listitem>
+	  <para>The device is busy and therefore can not change the timings.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+
+    <table pgwide="1" frame="none" id="v4l2-bt-timings">
+      <title>struct <structname>v4l2_bt_timings</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>width</structfield></entry>
+	    <entry>Width of the active video in pixels</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>height</structfield></entry>
+	    <entry>Height of the active video in lines</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>interlaced</structfield></entry>
+	    <entry>Progressive (0) or interlaced (1)</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>polarities</structfield></entry>
+	    <entry>This is a bit mask that defines polarities of sync signals.
+bit 0 (V4L2_DV_VSYNC_POS_POL) is for vertical sync polarity and bit 1 (V4L2_DV_HSYNC_POS_POL) is for horizontal sync polarity. If the bit is set
+(1) it is positive polarity and if is cleared (0), it is negative polarity.</entry>
+	  </row>
+	  <row>
+	    <entry>__u64</entry>
+	    <entry><structfield>pixelclock</structfield></entry>
+	    <entry>Pixel clock in Hz. Ex. 74.25MHz->74250000</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>hfrontporch</structfield></entry>
+	    <entry>Horizontal front porch in pixels</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>hsync</structfield></entry>
+	    <entry>Horizontal sync length in pixels</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>hbackporch</structfield></entry>
+	    <entry>Horizontal back porch in pixels</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>vfrontporch</structfield></entry>
+	    <entry>Vertical front porch in lines</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>vsync</structfield></entry>
+	    <entry>Vertical sync length in lines</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>vbackporch</structfield></entry>
+	    <entry>Vertical back porch in lines</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>il_vfrontporch</structfield></entry>
+	    <entry>Vertical front porch in lines for bottom field of interlaced field formats</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>il_vsync</structfield></entry>
+	    <entry>Vertical sync length in lines for bottom field of interlaced field formats</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>il_vbackporch</structfield></entry>
+	    <entry>Vertical back porch in lines for bottom field of interlaced field formats</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-dv-timings">
+      <title>struct <structname>v4l2_dv_timings</structname></title>
+      <tgroup cols="4">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>type</structfield></entry>
+	    <entry></entry>
+	    <entry>Type of DV timings as listed in <xref linkend="dv-timing-types"/>.</entry>
+	  </row>
+	  <row>
+	    <entry>union</entry>
+	    <entry><structfield></structfield></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>&v4l2-bt-timings;</entry>
+	    <entry><structfield>bt</structfield></entry>
+	    <entry>Timings defined by BT.656/1120 specifications</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[32]</entry>
+	    <entry></entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="dv-timing-types">
+      <title>DV Timing types</title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>Timing type</entry>
+	    <entry>value</entry>
+	    <entry>Description</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry></entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry>V4L2_DV_BT_656_1120</entry>
+	    <entry>0</entry>
+	    <entry>BT.656/1120 timings</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->

+ 6 - 0
Documentation/DocBook/v4l/vidioc-g-std.xml

@@ -86,6 +86,12 @@ standards.</para>
 <constant>VIDIOC_S_STD</constant> parameter was unsuitable.</para>
 	</listitem>
       </varlistentry>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
+	<listitem>
+	  <para>The device is busy and therefore can not change the standard</para>
+	</listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>

+ 85 - 0
Documentation/DocBook/v4l/vidioc-query-dv-preset.xml

@@ -0,0 +1,85 @@
+<refentry id="vidioc-query-dv-preset">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_QUERY_DV_PRESET</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_QUERY_DV_PRESET</refname>
+    <refpurpose>Sense the DV preset received by the current
+input</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>&v4l2-dv-preset; *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+	<varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_QUERY_DV_PRESET</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The hardware may be able to detect the current DV preset
+automatically, similar to sensing the video standard. To do so, applications
+call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a
+&v4l2-dv-preset; type. Once the hardware detects a preset, that preset is
+returned in the preset field of &v4l2-dv-preset;. When detection is not
+possible or fails, the value V4L2_DV_INVALID is returned.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>This ioctl is not supported.</para>
+	</listitem>
+    </varlistentry>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
+	<listitem>
+	  <para>The device is busy and therefore can not sense the preset</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->

+ 6 - 0
Documentation/DocBook/v4l/vidioc-querystd.xml

@@ -70,6 +70,12 @@ current video input or output.</para>
 	  <para>This ioctl is not supported.</para>
 	</listitem>
       </varlistentry>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
+	<listitem>
+	  <para>The device is busy and therefore can not detect the standard</para>
+	</listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>

+ 24 - 10
Documentation/video4linux/gspca.txt

@@ -12,6 +12,7 @@ m5602		0402:5602	ALi Video Camera Controller
 spca501		040a:0002	Kodak DVC-325
 spca500		040a:0300	Kodak EZ200
 zc3xx		041e:041e	Creative WebCam Live!
+ov519		041e:4003	Video Blaster WebCam Go Plus
 spca500		041e:400a	Creative PC-CAM 300
 sunplus		041e:400b	Creative PC-CAM 600
 sunplus		041e:4012	PC-Cam350
@@ -168,10 +169,14 @@ sunplus		055f:c650	Mustek MDC5500Z
 zc3xx		055f:d003	Mustek WCam300A
 zc3xx		055f:d004	Mustek WCam300 AN
 conex		0572:0041	Creative Notebook cx11646
+ov519		05a9:0511	Video Blaster WebCam 3/WebCam Plus, D-Link USB Digital Video Camera
+ov519		05a9:0518	Creative WebCam
 ov519		05a9:0519	OV519 Microphone
 ov519		05a9:0530	OmniVision
+ov519		05a9:2800	OmniVision SuperCAM
 ov519		05a9:4519	Webcam Classic
 ov519		05a9:8519	OmniVision
+ov519		05a9:a511	D-Link USB Digital Video Camera
 ov519		05a9:a518	D-Link DSB-C310 Webcam
 sunplus		05da:1018	Digital Dream Enigma 1.3
 stk014		05e1:0893	Syntek DV4000
@@ -187,7 +192,7 @@ ov534		06f8:3002	Hercules Blog Webcam
 ov534		06f8:3003	Hercules Dualpix HD Weblog
 sonixj		06f8:3004	Hercules Classic Silver
 sonixj		06f8:3008	Hercules Deluxe Optical Glass
-pac7311		06f8:3009	Hercules Classic Link
+pac7302		06f8:3009	Hercules Classic Link
 spca508		0733:0110	ViewQuest VQ110
 spca501		0733:0401	Intel Create and Share
 spca501		0733:0402	ViewQuest M318B
@@ -199,6 +204,7 @@ sunplus		0733:2221	Mercury Digital Pro 3.1p
 sunplus		0733:3261	Concord 3045 spca536a
 sunplus		0733:3281	Cyberpix S550V
 spca506		0734:043b	3DeMon USB Capture aka
+ov519		0813:0002	Dual Mode USB Camera Plus
 spca500		084d:0003	D-Link DSC-350
 spca500		08ca:0103	Aiptek PocketDV
 sunplus		08ca:0104	Aiptek PocketDVII 1.3
@@ -236,15 +242,15 @@ pac7311		093a:2603	Philips SPC 500 NC
 pac7311		093a:2608	Trust WB-3300p
 pac7311		093a:260e	Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
 pac7311		093a:260f	SnakeCam
-pac7311		093a:2620	Apollo AC-905
-pac7311		093a:2621	PAC731x
-pac7311		093a:2622	Genius Eye 312
-pac7311		093a:2624	PAC7302
-pac7311		093a:2626	Labtec 2200
-pac7311		093a:2628	Genius iLook 300
-pac7311		093a:2629	Genious iSlim 300
-pac7311		093a:262a	Webcam 300k
-pac7311		093a:262c	Philips SPC 230 NC
+pac7302		093a:2620	Apollo AC-905
+pac7302		093a:2621	PAC731x
+pac7302		093a:2622	Genius Eye 312
+pac7302		093a:2624	PAC7302
+pac7302		093a:2626	Labtec 2200
+pac7302		093a:2628	Genius iLook 300
+pac7302		093a:2629	Genious iSlim 300
+pac7302		093a:262a	Webcam 300k
+pac7302		093a:262c	Philips SPC 230 NC
 jeilinj		0979:0280	Sakar 57379
 zc3xx		0ac8:0302	Z-star Vimicro zc0302
 vc032x		0ac8:0321	Vimicro generic vc0321
@@ -259,6 +265,7 @@ vc032x		0ac8:c002	Sony embedded vimicro
 vc032x		0ac8:c301	Samsung Q1 Ultra Premium
 spca508		0af9:0010	Hama USB Sightcam 100
 spca508		0af9:0011	Hama USB Sightcam 100
+ov519		0b62:0059	iBOT2 Webcam
 sonixb		0c45:6001	Genius VideoCAM NB
 sonixb		0c45:6005	Microdia Sweex Mini Webcam
 sonixb		0c45:6007	Sonix sn9c101 + Tas5110D
@@ -318,8 +325,10 @@ sn9c20x		0c45:62b3	PC Camera (SN9C202 + OV9655)
 sn9c20x		0c45:62bb	PC Camera (SN9C202 + OV7660)
 sn9c20x		0c45:62bc	PC Camera (SN9C202 + HV7131R)
 sunplus		0d64:0303	Sunplus FashionCam DXG
+ov519		0e96:c001	TRUST 380 USB2 SPACEC@M
 etoms		102c:6151	Qcam Sangha CIF
 etoms		102c:6251	Qcam xxxxxx VGA
+ov519		1046:9967	W9967CF/W9968CF WebCam IC, Video Blaster WebCam Go
 zc3xx		10fd:0128	Typhoon Webshot II USB 300k 0x0128
 spca561		10fd:7e50	FlyCam Usb 100
 zc3xx		10fd:8050	Typhoon Webshot II USB 300k
@@ -332,7 +341,12 @@ spca501		1776:501c	Arowana 300K CMOS Camera
 t613		17a1:0128	TASCORP JPEG Webcam, NGS Cyclops
 vc032x		17ef:4802	Lenovo Vc0323+MI1310_SOC
 pac207		2001:f115	D-Link DSB-C120
+sq905c		2770:9050	sq905c
+sq905c		2770:905c	DualCamera
+sq905		2770:9120	Argus Digital Camera DC1512
+sq905c		2770:913d	sq905c
 spca500		2899:012c	Toptro Industrial
+ov519		8020:ef04	ov519
 spca508		8086:0110	Intel Easy PC Camera
 spca500		8086:0630	Intel Pocket PC Camera
 spca506		99fa:8988	Grandtec V.cap

+ 157 - 0
Documentation/video4linux/sh_mobile_ceu_camera.txt

@@ -0,0 +1,157 @@
+	Cropping and Scaling algorithm, used in the sh_mobile_ceu_camera driver
+	=======================================================================
+
+Terminology
+-----------
+
+sensor scales: horizontal and vertical scales, configured by the sensor driver
+host scales: -"- host driver
+combined scales: sensor_scale * host_scale
+
+
+Generic scaling / cropping scheme
+---------------------------------
+
+-1--
+|
+-2-- -\
+|      --\
+|         --\
++-5-- -\     -- -3--
+|       ---\
+|           --- -4-- -\
+|                      -\
+|                        - -6--
+|
+|                        - -6'-
+|                      -/
+|           --- -4'- -/
+|       ---/
++-5'- -/
+|            -- -3'-
+|         --/
+|      --/
+-2'- -/
+|
+|
+-1'-
+
+Produced by user requests:
+
+S_CROP(left / top = (5) - (1), width / height = (5') - (5))
+S_FMT(width / height = (6') - (6))
+
+Here:
+
+(1) to (1') - whole max width or height
+(1) to (2)  - sensor cropped left or top
+(2) to (2') - sensor cropped width or height
+(3) to (3') - sensor scale
+(3) to (4)  - CEU cropped left or top
+(4) to (4') - CEU cropped width or height
+(5) to (5') - reverse sensor scale applied to CEU cropped width or height
+(2) to (5)  - reverse sensor scale applied to CEU cropped left or top
+(6) to (6') - CEU scale - user window
+
+
+S_FMT
+-----
+
+Do not touch input rectangle - it is already optimal.
+
+1. Calculate current sensor scales:
+
+	scale_s = ((3') - (3)) / ((2') - (2))
+
+2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at
+current sensor scales onto input window - this is user S_CROP:
+
+	width_u = (5') - (5) = ((4') - (4)) * scale_s
+
+3. Calculate new combined scales from "effective" input window to requested user
+window:
+
+	scale_comb = width_u / ((6') - (6))
+
+4. Calculate sensor output window by applying combined scales to real input
+window:
+
+	width_s_out = ((2') - (2)) / scale_comb
+
+5. Apply iterative sensor S_FMT for sensor output window.
+
+	subdev->video_ops->s_fmt(.width = width_s_out)
+
+6. Retrieve sensor output window (g_fmt)
+
+7. Calculate new sensor scales:
+
+	scale_s_new = ((3')_new - (3)_new) / ((2') - (2))
+
+8. Calculate new CEU crop - apply sensor scales to previously calculated
+"effective" crop:
+
+	width_ceu = (4')_new - (4)_new = width_u / scale_s_new
+	left_ceu = (4)_new - (3)_new = ((5) - (2)) / scale_s_new
+
+9. Use CEU cropping to crop to the new window:
+
+	ceu_crop(.width = width_ceu, .left = left_ceu)
+
+10. Use CEU scaling to scale to the requested user window:
+
+	scale_ceu = width_ceu / width
+
+
+S_CROP
+------
+
+If old scale applied to new crop is invalid produce nearest new scale possible
+
+1. Calculate current combined scales.
+
+	scale_comb = (((4') - (4)) / ((6') - (6))) * (((2') - (2)) / ((3') - (3)))
+
+2. Apply iterative sensor S_CROP for new input window.
+
+3. If old combined scales applied to new crop produce an impossible user window,
+adjust scales to produce nearest possible window.
+
+	width_u_out = ((5') - (5)) / scale_comb
+
+	if (width_u_out > max)
+		scale_comb = ((5') - (5)) / max;
+	else if (width_u_out < min)
+		scale_comb = ((5') - (5)) / min;
+
+4. Issue G_CROP to retrieve actual input window.
+
+5. Using actual input window and calculated combined scales calculate sensor
+target output window.
+
+	width_s_out = ((3') - (3)) = ((2') - (2)) / scale_comb
+
+6. Apply iterative S_FMT for new sensor target output window.
+
+7. Issue G_FMT to retrieve the actual sensor output window.
+
+8. Calculate sensor scales.
+
+	scale_s = ((3') - (3)) / ((2') - (2))
+
+9. Calculate sensor output subwindow to be cropped on CEU by applying sensor
+scales to the requested window.
+
+	width_ceu = ((5') - (5)) / scale_s
+
+10. Use CEU cropping for above calculated window.
+
+11. Calculate CEU scales from sensor scales from results of (10) and user window
+from (3)
+
+	scale_ceu = calc_scale(((5') - (5)), &width_u_out)
+
+12. Apply CEU scales.
+
+--
+Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>

+ 14 - 2
Documentation/video4linux/v4l2-framework.txt

@@ -561,6 +561,8 @@ video_device helper functions
 
 There are a few useful helper functions:
 
+- file/video_device private data
+
 You can set/get driver private data in the video_device struct using:
 
 void *video_get_drvdata(struct video_device *vdev);
@@ -575,8 +577,7 @@ struct video_device *video_devdata(struct file *file);
 
 returns the video_device belonging to the file struct.
 
-The final helper function combines video_get_drvdata with
-video_devdata:
+The video_drvdata function combines video_get_drvdata with video_devdata:
 
 void *video_drvdata(struct file *file);
 
@@ -584,6 +585,17 @@ You can go from a video_device struct to the v4l2_device struct using:
 
 struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
 
+- Device node name
+
+The video_device node kernel name can be retrieved using
+
+const char *video_device_node_name(struct video_device *vdev);
+
+The name is used as a hint by userspace tools such as udev. The function
+should be used where possible instead of accessing the video_device::num and
+video_device::minor fields.
+
+
 video buffer helper functions
 -----------------------------
 

+ 23 - 18
arch/sh/boards/mach-ap325rxa/setup.c

@@ -316,20 +316,23 @@ static struct soc_camera_platform_info camera_info = {
 	.format_name = "UYVY",
 	.format_depth = 16,
 	.format = {
-		.pixelformat = V4L2_PIX_FMT_UYVY,
+		.code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
 		.colorspace = V4L2_COLORSPACE_SMPTE170M,
+		.field = V4L2_FIELD_NONE,
 		.width = 640,
 		.height = 480,
 	},
 	.bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
 	SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8,
 	.set_capture = camera_set_capture,
-	.link = {
-		.bus_id		= 0,
-		.add_device	= ap325rxa_camera_add,
-		.del_device	= ap325rxa_camera_del,
-		.module_name	= "soc_camera_platform",
-	},
+};
+
+struct soc_camera_link camera_link = {
+	.bus_id		= 0,
+	.add_device	= ap325rxa_camera_add,
+	.del_device	= ap325rxa_camera_del,
+	.module_name	= "soc_camera_platform",
+	.priv		= &camera_info,
 };
 
 static void dummy_release(struct device *dev)
@@ -347,7 +350,7 @@ static struct platform_device camera_device = {
 static int ap325rxa_camera_add(struct soc_camera_link *icl,
 			       struct device *dev)
 {
-	if (icl != &camera_info.link || camera_probe() <= 0)
+	if (icl != &camera_link || camera_probe() <= 0)
 		return -ENODEV;
 
 	camera_info.dev = dev;
@@ -357,7 +360,7 @@ static int ap325rxa_camera_add(struct soc_camera_link *icl,
 
 static void ap325rxa_camera_del(struct soc_camera_link *icl)
 {
-	if (icl != &camera_info.link)
+	if (icl != &camera_link)
 		return;
 
 	platform_device_unregister(&camera_device);
@@ -470,13 +473,15 @@ static struct ov772x_camera_info ov7725_info = {
 	.buswidth	= SOCAM_DATAWIDTH_8,
 	.flags		= OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP,
 	.edgectrl	= OV772X_AUTO_EDGECTRL(0xf, 0),
-	.link = {
-		.bus_id		= 0,
-		.power		= ov7725_power,
-		.board_info	= &ap325rxa_i2c_camera[0],
-		.i2c_adapter_id	= 0,
-		.module_name	= "ov772x",
-	},
+};
+
+static struct soc_camera_link ov7725_link = {
+	.bus_id		= 0,
+	.power		= ov7725_power,
+	.board_info	= &ap325rxa_i2c_camera[0],
+	.i2c_adapter_id	= 0,
+	.module_name	= "ov772x",
+	.priv		= &ov7725_info,
 };
 
 static struct platform_device ap325rxa_camera[] = {
@@ -484,13 +489,13 @@ static struct platform_device ap325rxa_camera[] = {
 		.name	= "soc-camera-pdrv",
 		.id	= 0,
 		.dev	= {
-			.platform_data = &ov7725_info.link,
+			.platform_data = &ov7725_link,
 		},
 	}, {
 		.name	= "soc-camera-pdrv",
 		.id	= 1,
 		.dev	= {
-			.platform_data = &camera_info.link,
+			.platform_data = &camera_link,
 		},
 	},
 };

+ 11 - 2
arch/sh/boards/mach-kfr2r09/setup.c

@@ -19,6 +19,7 @@
 #include <linux/input/sh_keysc.h>
 #include <linux/i2c.h>
 #include <linux/usb/r8a66597.h>
+#include <media/rj54n1cb0c.h>
 #include <media/soc_camera.h>
 #include <media/sh_mobile_ceu.h>
 #include <video/sh_mobile_lcdc.h>
@@ -255,6 +256,9 @@ static struct i2c_board_info kfr2r09_i2c_camera = {
 
 static struct clk *camera_clk;
 
+/* set VIO_CKO clock to 25MHz */
+#define CEU_MCLK_FREQ 25000000
+
 #define DRVCRB 0xA405018C
 static int camera_power(struct device *dev, int mode)
 {
@@ -267,8 +271,7 @@ static int camera_power(struct device *dev, int mode)
 		if (IS_ERR(camera_clk))
 			return PTR_ERR(camera_clk);
 
-		/* set VIO_CKO clock to 25MHz */
-		rate = clk_round_rate(camera_clk, 25000000);
+		rate = clk_round_rate(camera_clk, CEU_MCLK_FREQ);
 		ret = clk_set_rate(camera_clk, rate);
 		if (ret < 0)
 			goto eclkrate;
@@ -318,11 +321,17 @@ eclkrate:
 	return ret;
 }
 
+static struct rj54n1_pdata rj54n1_priv = {
+	.mclk_freq	= CEU_MCLK_FREQ,
+	.ioctl_high	= false,
+};
+
 static struct soc_camera_link rj54n1_link = {
 	.power		= camera_power,
 	.board_info	= &kfr2r09_i2c_camera,
 	.i2c_adapter_id	= 1,
 	.module_name	= "rj54n1cb0c",
+	.priv		= &rj54n1_priv,
 };
 
 static struct platform_device kfr2r09_camera = {

+ 18 - 14
arch/sh/boards/mach-migor/setup.c

@@ -432,23 +432,27 @@ static struct i2c_board_info migor_i2c_camera[] = {
 
 static struct ov772x_camera_info ov7725_info = {
 	.buswidth	= SOCAM_DATAWIDTH_8,
-	.link = {
-		.power		= ov7725_power,
-		.board_info	= &migor_i2c_camera[0],
-		.i2c_adapter_id	= 0,
-		.module_name	= "ov772x",
-	},
+};
+
+static struct soc_camera_link ov7725_link = {
+	.power		= ov7725_power,
+	.board_info	= &migor_i2c_camera[0],
+	.i2c_adapter_id	= 0,
+	.module_name	= "ov772x",
+	.priv		= &ov7725_info,
 };
 
 static struct tw9910_video_info tw9910_info = {
 	.buswidth	= SOCAM_DATAWIDTH_8,
 	.mpout		= TW9910_MPO_FIELD,
-	.link = {
-		.power		= tw9910_power,
-		.board_info	= &migor_i2c_camera[1],
-		.i2c_adapter_id	= 0,
-		.module_name	= "tw9910",
-	}
+};
+
+static struct soc_camera_link tw9910_link = {
+	.power		= tw9910_power,
+	.board_info	= &migor_i2c_camera[1],
+	.i2c_adapter_id	= 0,
+	.module_name	= "tw9910",
+	.priv		= &tw9910_info,
 };
 
 static struct platform_device migor_camera[] = {
@@ -456,13 +460,13 @@ static struct platform_device migor_camera[] = {
 		.name	= "soc-camera-pdrv",
 		.id	= 0,
 		.dev	= {
-			.platform_data = &ov7725_info.link,
+			.platform_data = &ov7725_link,
 		},
 	}, {
 		.name	= "soc-camera-pdrv",
 		.id	= 1,
 		.dev	= {
-			.platform_data = &tw9910_info.link,
+			.platform_data = &tw9910_link,
 		},
 	},
 };

+ 9 - 0
drivers/media/IR/Kconfig

@@ -0,0 +1,9 @@
+config IR_CORE
+	tristate
+	depends on INPUT
+	default INPUT
+
+config VIDEO_IR
+	tristate
+	depends on IR_CORE
+	default IR_CORE

+ 5 - 0
drivers/media/IR/Makefile

@@ -0,0 +1,5 @@
+ir-common-objs  := ir-functions.o ir-keymaps.o
+ir-core-objs	:= ir-keytable.o
+
+obj-$(CONFIG_IR_CORE) += ir-core.o
+obj-$(CONFIG_VIDEO_IR) += ir-common.o

+ 1 - 19
drivers/media/common/ir-functions.c → drivers/media/IR/ir-functions.c

@@ -34,9 +34,6 @@ static int repeat = 1;
 module_param(repeat, int, 0444);
 MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
 
-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)
@@ -55,25 +52,10 @@ static void ir_input_key_event(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 ir_type)
 {
 	ir->ir_type = ir_type;
 
-	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;
-
-	IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n",
-		ir->keytable.size,
-		ir->keytable.size * sizeof(ir->keytable.scan));
-
-	ir_copy_table(&ir->keytable, ir_codes);
-	ir_set_keycode_table(dev, &ir->keytable);
-
-	clear_bit(0, dev->keybit);
-	set_bit(EV_KEY, dev->evbit);
 	if (repeat)
 		set_bit(EV_REP, dev->evbit);
 

+ 149 - 70
drivers/media/common/ir-keymaps.c → drivers/media/IR/ir-keymaps.c

@@ -1847,76 +1847,6 @@ 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 },
@@ -3314,3 +3244,152 @@ struct ir_scancode_table ir_codes_gadmei_rm008z_table = {
 };
 EXPORT_SYMBOL_GPL(ir_codes_gadmei_rm008z_table);
 
+/*************************************************************
+ *		COMPLETE SCANCODE TABLES
+ * Instead of just a partial scancode, the tables bellow
+ * contains the complete scancode and the receiver protocol
+ *************************************************************/
+
+/*
+ * 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),
+	.ir_type = IR_TYPE_RC5,
+};
+EXPORT_SYMBOL_GPL(ir_codes_rc5_hauppauge_new_table);
+
+/* Terratec Cinergy Hybrid T USB XS FM
+   Mauro Carvalho Chehab <mchehab@redhat.com>
+ */
+static struct ir_scancode ir_codes_nec_terratec_cinergy_xs[] = {
+	{ 0x1441, KEY_HOME},
+	{ 0x1401, KEY_POWER2},
+
+	{ 0x1442, KEY_MENU},		/* DVD menu */
+	{ 0x1443, KEY_SUBTITLE},
+	{ 0x1444, KEY_TEXT},		/* Teletext */
+	{ 0x1445, KEY_DELETE},
+
+	{ 0x1402, KEY_1},
+	{ 0x1403, KEY_2},
+	{ 0x1404, KEY_3},
+	{ 0x1405, KEY_4},
+	{ 0x1406, KEY_5},
+	{ 0x1407, KEY_6},
+	{ 0x1408, KEY_7},
+	{ 0x1409, KEY_8},
+	{ 0x140a, KEY_9},
+	{ 0x140c, KEY_0},
+
+	{ 0x140b, KEY_TUNER},		/* AV */
+	{ 0x140d, KEY_MODE},		/* A.B */
+
+	{ 0x1446, KEY_TV},
+	{ 0x1447, KEY_DVD},
+	{ 0x1449, KEY_VIDEO},
+	{ 0x144a, KEY_RADIO},		/* Music */
+	{ 0x144b, KEY_CAMERA},		/* PIC */
+
+	{ 0x1410, KEY_UP},
+	{ 0x1411, KEY_LEFT},
+	{ 0x1412, KEY_OK},
+	{ 0x1413, KEY_RIGHT},
+	{ 0x1414, KEY_DOWN},
+
+	{ 0x140f, KEY_EPG},
+	{ 0x1416, KEY_INFO},
+	{ 0x144d, KEY_BACKSPACE},
+
+	{ 0x141c, KEY_VOLUMEUP},
+	{ 0x141e, KEY_VOLUMEDOWN},
+
+	{ 0x144c, KEY_PLAY},
+	{ 0x141d, KEY_MUTE},
+
+	{ 0x141b, KEY_CHANNELUP},
+	{ 0x141f, KEY_CHANNELDOWN},
+
+	{ 0x1417, KEY_RED},
+	{ 0x1418, KEY_GREEN},
+	{ 0x1419, KEY_YELLOW},
+	{ 0x141a, KEY_BLUE},
+
+	{ 0x1458, KEY_RECORD},
+	{ 0x1448, KEY_STOP},
+	{ 0x1440, KEY_PAUSE},
+
+	{ 0x1454, KEY_LAST},
+	{ 0x144e, KEY_REWIND},
+	{ 0x144f, KEY_FASTFORWARD},
+	{ 0x145c, KEY_NEXT},
+};
+struct ir_scancode_table ir_codes_nec_terratec_cinergy_xs_table = {
+	.scan = ir_codes_nec_terratec_cinergy_xs,
+	.size = ARRAY_SIZE(ir_codes_nec_terratec_cinergy_xs),
+	.ir_type = IR_TYPE_NEC,
+};
+EXPORT_SYMBOL_GPL(ir_codes_nec_terratec_cinergy_xs_table);
+

+ 73 - 17
drivers/media/common/ir-keytable.c → drivers/media/IR/ir-keytable.c

@@ -1,10 +1,19 @@
 /* ir-register.c - handle IR scancode->keycode tables
  *
  * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.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 version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
  */
 
-#include <linux/usb/input.h>
 
+#include <linux/usb/input.h>
 #include <media/ir-common.h>
 
 #define IR_TAB_MIN_SIZE	32
@@ -72,6 +81,7 @@ int ir_roundup_tablesize(int n_elems)
 
 	return n_elems;
 }
+EXPORT_SYMBOL_GPL(ir_roundup_tablesize);
 
 /**
  * ir_copy_table() - copies a keytable, discarding the unused entries
@@ -100,6 +110,7 @@ int ir_copy_table(struct ir_scancode_table *destin,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(ir_copy_table);
 
 /**
  * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table
@@ -114,7 +125,8 @@ static int ir_getkeycode(struct input_dev *dev,
 			 int scancode, int *keycode)
 {
 	int elem;
-	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
+	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
 
 	elem = ir_seek_table(rc_tab, scancode);
 	if (elem >= 0) {
@@ -136,7 +148,6 @@ static int ir_getkeycode(struct input_dev *dev,
 	return 0;
 }
 
-
 /**
  * ir_is_resize_needed() - Check if the table needs rezise
  * @table:		keycode table that may need to resize
@@ -286,7 +297,8 @@ 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_input_dev *ir_dev = input_get_drvdata(dev);
+	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
 	struct ir_scancode *keymap = rc_tab->scan;
 	unsigned long flags;
 
@@ -360,7 +372,8 @@ static int ir_setkeycode(struct input_dev *dev,
  */
 u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
 {
-	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
+	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
 	struct ir_scancode *keymap = rc_tab->scan;
 	int elem;
 
@@ -378,9 +391,10 @@ u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
 	/* Reports userspace that an unknown keycode were got */
 	return KEY_RESERVED;
 }
+EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
 
 /**
- * ir_set_keycode_table() - sets the IR keycode table and add the handlers
+ * ir_input_register() - 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
@@ -389,17 +403,34 @@ u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
  * 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)
+int ir_input_register(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);
+	struct ir_input_dev *ir_dev;
+	struct ir_scancode  *keymap    = rc_tab->scan;
+	int i, rc;
 
 	if (rc_tab->scan == NULL || !rc_tab->size)
 		return -EINVAL;
 
+	ir_dev = kzalloc(sizeof(*ir_dev), GFP_KERNEL);
+	if (!ir_dev)
+		return -ENOMEM;
+
+	spin_lock_init(&rc_tab->lock);
+
+	ir_dev->rc_tab.size = ir_roundup_tablesize(rc_tab->size);
+	ir_dev->rc_tab.scan = kzalloc(ir_dev->rc_tab.size *
+				    sizeof(struct ir_scancode), GFP_KERNEL);
+	if (!ir_dev->rc_tab.scan)
+		return -ENOMEM;
+
+	IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n",
+		ir_dev->rc_tab.size,
+		ir_dev->rc_tab.size * sizeof(ir_dev->rc_tab.scan));
+
+	ir_copy_table(&ir_dev->rc_tab, rc_tab);
+
 	/* 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++) {
@@ -407,23 +438,48 @@ int ir_set_keycode_table(struct input_dev *input_dev,
 			i, keymap[i].keycode);
 		set_bit(keymap[i].keycode, input_dev->keybit);
 	}
+	clear_bit(0, input_dev->keybit);
+
+	set_bit(EV_KEY, input_dev->evbit);
 
 	input_dev->getkeycode = ir_getkeycode;
 	input_dev->setkeycode = ir_setkeycode;
-	input_set_drvdata(input_dev, rc_tab);
+	input_set_drvdata(input_dev, ir_dev);
 
-	return 0;
+	rc = input_register_device(input_dev);
+	if (rc < 0) {
+		kfree(rc_tab->scan);
+		kfree(ir_dev);
+		input_set_drvdata(input_dev, NULL);
+	}
+
+	return rc;
 }
+EXPORT_SYMBOL_GPL(ir_input_register);
 
-void ir_input_free(struct input_dev *dev)
+void ir_input_unregister(struct input_dev *dev)
 {
-	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
+	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+	struct ir_scancode_table *rc_tab;
+
+	if (!ir_dev)
+		return;
 
 	IR_dprintk(1, "Freed keycode table\n");
 
+	rc_tab = &ir_dev->rc_tab;
 	rc_tab->size = 0;
 	kfree(rc_tab->scan);
 	rc_tab->scan = NULL;
+
+	kfree(ir_dev);
+	input_unregister_device(dev);
 }
-EXPORT_SYMBOL_GPL(ir_input_free);
+EXPORT_SYMBOL_GPL(ir_input_unregister);
+
+int ir_core_debug;    /* ir_debug level (0,1,2) */
+EXPORT_SYMBOL_GPL(ir_core_debug);
+module_param_named(debug, ir_core_debug, int, 0644);
 
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");

+ 1 - 0
drivers/media/Kconfig

@@ -99,6 +99,7 @@ config VIDEO_MEDIA
 comment "Multimedia drivers"
 
 source "drivers/media/common/Kconfig"
+source "drivers/media/IR/Kconfig"
 
 #
 # Tuner drivers for DVB and V4L

+ 1 - 1
drivers/media/Makefile

@@ -2,7 +2,7 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y += common/ video/
+obj-y += common/ IR/ video/
 
 obj-$(CONFIG_VIDEO_DEV) += radio/
 obj-$(CONFIG_DVB_CORE)  += dvb/

+ 0 - 2
drivers/media/common/Makefile

@@ -1,8 +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-keytable.o
 
 obj-y += tuners/
 obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
 obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
-obj-$(CONFIG_VIDEO_IR) += ir-common.o

+ 10 - 50
drivers/media/common/saa7146_fops.c

@@ -1,7 +1,5 @@
 #include <media/saa7146_vv.h>
 
-#define BOARD_CAN_DO_VBI(dev)   (dev->revision != 0 && dev->vv_data->vbi_minor != -1)
-
 /****************************************************************************/
 /* resource management functions, shamelessly stolen from saa7134 driver */
 
@@ -194,43 +192,24 @@ void saa7146_buffer_timeout(unsigned long data)
 
 static int fops_open(struct file *file)
 {
-	unsigned int minor = video_devdata(file)->minor;
-	struct saa7146_dev *h = NULL, *dev = NULL;
-	struct list_head *list;
+	struct video_device *vdev = video_devdata(file);
+	struct saa7146_dev *dev = video_drvdata(file);
 	struct saa7146_fh *fh = NULL;
 	int result = 0;
 
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	enum v4l2_buf_type type;
 
-	DEB_EE(("file:%p, minor:%d\n", file, minor));
+	DEB_EE(("file:%p, dev:%s\n", file, video_device_node_name(vdev)));
 
 	if (mutex_lock_interruptible(&saa7146_devices_lock))
 		return -ERESTARTSYS;
 
-	list_for_each(list,&saa7146_devices) {
-		h = list_entry(list, struct saa7146_dev, item);
-		if( NULL == h->vv_data ) {
-			DEB_D(("device %p has not registered video devices.\n",h));
-			continue;
-		}
-		DEB_D(("trying: %p @ major %d,%d\n",h,h->vv_data->video_minor,h->vv_data->vbi_minor));
-
-		if (h->vv_data->video_minor == minor) {
-			dev = h;
-		}
-		if (h->vv_data->vbi_minor == minor) {
-			type = V4L2_BUF_TYPE_VBI_CAPTURE;
-			dev = h;
-		}
-	}
-	if (NULL == dev) {
-		DEB_S(("no such video device.\n"));
-		result = -ENODEV;
-		goto out;
-	}
-
 	DEB_D(("using: %p\n",dev));
 
+	type = vdev->vfl_type == VFL_TYPE_GRABBER
+	     ? V4L2_BUF_TYPE_VIDEO_CAPTURE
+	     : V4L2_BUF_TYPE_VBI_CAPTURE;
+
 	/* check if an extension is registered */
 	if( NULL == dev->ext ) {
 		DEB_S(("no extension registered for this device.\n"));
@@ -474,9 +453,6 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
 	   configuration data) */
 	dev->ext_vv_data = ext_vv;
 
-	vv->video_minor = -1;
-	vv->vbi_minor = -1;
-
 	vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle);
 	if( NULL == vv->d_clipping.cpu_addr ) {
 		ERR(("out of memory. aborting.\n"));
@@ -515,7 +491,6 @@ EXPORT_SYMBOL_GPL(saa7146_vv_release);
 int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 			    char *name, int type)
 {
-	struct saa7146_vv *vv = dev->vv_data;
 	struct video_device *vfd;
 	int err;
 	int i;
@@ -543,15 +518,8 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 		return err;
 	}
 
-	if( VFL_TYPE_GRABBER == type ) {
-		vv->video_minor = vfd->minor;
-		INFO(("%s: registered device video%d [v4l2]\n",
-			dev->name, vfd->num));
-	} else {
-		vv->vbi_minor = vfd->minor;
-		INFO(("%s: registered device vbi%d [v4l2]\n",
-			dev->name, vfd->num));
-	}
+	INFO(("%s: registered device %s [v4l2]\n",
+		dev->name, video_device_node_name(vfd)));
 
 	*vid = vfd;
 	return 0;
@@ -560,16 +528,8 @@ EXPORT_SYMBOL_GPL(saa7146_register_device);
 
 int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
 {
-	struct saa7146_vv *vv = dev->vv_data;
-
 	DEB_EE(("dev:%p\n",dev));
 
-	if ((*vid)->vfl_type == VFL_TYPE_GRABBER) {
-		vv->video_minor = -1;
-	} else {
-		vv->vbi_minor = -1;
-	}
-
 	video_unregister_device(*vid);
 	*vid = NULL;
 

+ 4 - 10
drivers/media/dvb/dm1105/dm1105.c

@@ -589,7 +589,7 @@ 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));
 
-	err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes);
+	err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type);
 	if (err < 0) {
 		input_free_device(input_dev);
 		return err;
@@ -611,20 +611,14 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
 
 	INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
 
-	err = input_register_device(input_dev);
-	if (err) {
-		ir_input_free(input_dev);
-		input_free_device(input_dev);
-		return err;
-	}
+	err = ir_input_register(input_dev, ir_codes);
 
-	return 0;
+	return err;
 }
 
 void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
 {
-	ir_input_free(dm1105->ir.input_dev);
-	input_unregister_device(dm1105->ir.input_dev);
+	ir_input_unregister(dm1105->ir.input_dev);
 }
 
 static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)

+ 6 - 2
drivers/media/dvb/dvb-usb/Kconfig

@@ -265,9 +265,13 @@ config DVB_USB_DW2102
 	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
 	select DVB_MT312 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10039 if !DVB_FE_CUSTOMISE
+	select DVB_DS3000 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	select DVB_STV6110 if !DVB_FE_CUSTOMISE
+	select DVB_STV0900 if !DVB_FE_CUSTOMISE
 	help
-	  Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
-	  and the TeVii S650, S630.
+	  Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0
+	  receivers.
 
 config DVB_USB_CINERGY_T2
 	tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"

+ 15 - 11
drivers/media/dvb/dvb-usb/dib0700.h

@@ -20,20 +20,22 @@ extern int dvb_usb_dib0700_debug;
 #define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args)
 #define deb_data(args...)   dprintk(dvb_usb_dib0700_debug,0x08,args)
 
-#define REQUEST_I2C_READ     0x2
-#define REQUEST_I2C_WRITE    0x3
-#define REQUEST_POLL_RC      0x4 /* deprecated in firmware v1.20 */
-#define REQUEST_JUMPRAM      0x8
-#define REQUEST_SET_CLOCK    0xB
-#define REQUEST_SET_GPIO     0xC
-#define REQUEST_ENABLE_VIDEO 0xF
+#define REQUEST_SET_USB_XFER_LEN    0x0 /* valid only for firmware version */
+					/* higher than 1.21 */
+#define REQUEST_I2C_READ            0x2
+#define REQUEST_I2C_WRITE           0x3
+#define REQUEST_POLL_RC             0x4 /* deprecated in firmware v1.20 */
+#define REQUEST_JUMPRAM             0x8
+#define REQUEST_SET_CLOCK           0xB
+#define REQUEST_SET_GPIO            0xC
+#define REQUEST_ENABLE_VIDEO        0xF
 	// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
 	// 2 Byte: MPEG2 mode:  4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
 	// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines)    4LSB(     "                "           )
-#define REQUEST_SET_RC       0x11
-#define REQUEST_NEW_I2C_READ 0x12
-#define REQUEST_NEW_I2C_WRITE 0x13
-#define REQUEST_GET_VERSION  0x15
+#define REQUEST_SET_RC              0x11
+#define REQUEST_NEW_I2C_READ        0x12
+#define REQUEST_NEW_I2C_WRITE       0x13
+#define REQUEST_GET_VERSION         0x15
 
 struct dib0700_state {
 	u8 channel_state;
@@ -44,6 +46,8 @@ struct dib0700_state {
 	u8 is_dib7000pc;
 	u8 fw_use_new_i2c_api;
 	u8 disable_streaming_master_mode;
+    u32 fw_version;
+    u32 nb_packet_buffer_size;
 };
 
 extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,

+ 94 - 7
drivers/media/dvb/dvb-usb/dib0700_core.c

@@ -17,6 +17,14 @@ int dvb_usb_dib0700_ir_proto = 1;
 module_param(dvb_usb_dib0700_ir_proto, int, 0644);
 MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
 
+static int nb_packet_buffer_size = 21;
+module_param(nb_packet_buffer_size, int, 0644);
+MODULE_PARM_DESC(nb_packet_buffer_size,
+	"Set the dib0700 driver data buffer size. This parameter "
+	"corresponds to the number of TS packets. The actual size of "
+	"the data buffer corresponds to this parameter "
+	"multiplied by 188 (default: 21)");
+
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 
@@ -28,10 +36,14 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
 				  REQUEST_GET_VERSION,
 				  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
 				  b, sizeof(b), USB_CTRL_GET_TIMEOUT);
-	*hwversion  = (b[0] << 24)  | (b[1] << 16)  | (b[2] << 8)  | b[3];
-	*romversion = (b[4] << 24)  | (b[5] << 16)  | (b[6] << 8)  | b[7];
-	*ramversion = (b[8] << 24)  | (b[9] << 16)  | (b[10] << 8) | b[11];
-	*fwtype     = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15];
+	if (hwversion != NULL)
+		*hwversion  = (b[0] << 24)  | (b[1] << 16)  | (b[2] << 8)  | b[3];
+	if (romversion != NULL)
+		*romversion = (b[4] << 24)  | (b[5] << 16)  | (b[6] << 8)  | b[7];
+	if (ramversion != NULL)
+		*ramversion = (b[8] << 24)  | (b[9] << 16)  | (b[10] << 8) | b[11];
+	if (fwtype != NULL)
+		*fwtype     = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15];
 	return ret;
 }
 
@@ -97,6 +109,27 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
 	return dib0700_ctrl_wr(d,buf,3);
 }
 
+static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
+{
+    struct dib0700_state *st = d->priv;
+    u8 b[3];
+    int ret;
+
+    if (st->fw_version >= 0x10201) {
+	b[0] = REQUEST_SET_USB_XFER_LEN;
+	b[1] = (nb_ts_packets >> 8)&0xff;
+	b[2] = nb_ts_packets & 0xff;
+
+	deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+
+	ret = dib0700_ctrl_wr(d, b, 3);
+    } else {
+	deb_info("this firmware does not allow to change the USB xfer len\n");
+	ret = -EIO;
+    }
+    return ret;
+}
+
 /*
  * I2C master xfer function (supported in 1.20 firmware)
  */
@@ -328,7 +361,9 @@ static int dib0700_jumpram(struct usb_device *udev, u32 address)
 int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
 {
 	struct hexline hx;
-	int pos = 0, ret, act_len;
+	int pos = 0, ret, act_len, i, adap_num;
+	u8 b[16];
+	u32 fw_version;
 
 	u8 buf[260];
 
@@ -364,6 +399,34 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
 	} else
 		ret = -EIO;
 
+	/* the number of ts packet has to be at least 1 */
+	if (nb_packet_buffer_size < 1)
+		nb_packet_buffer_size = 1;
+
+	/* get the fimware version */
+	usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				  REQUEST_GET_VERSION,
+				  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+				  b, sizeof(b), USB_CTRL_GET_TIMEOUT);
+	fw_version = (b[8] << 24)  | (b[9] << 16)  | (b[10] << 8) | b[11];
+
+	/* set the buffer size - DVB-USB is allocating URB buffers
+	 * only after the firwmare download was successful */
+	for (i = 0; i < dib0700_device_count; i++) {
+		for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
+				adap_num++) {
+			if (fw_version >= 0x10201)
+				dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
+			else {
+				/* for fw version older than 1.20.1,
+				 * the buffersize has to be n times 512 */
+				dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
+				if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512)
+					dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512;
+			}
+		}
+	}
+
 	return ret;
 }
 
@@ -371,6 +434,18 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	struct dib0700_state *st = adap->dev->priv;
 	u8 b[4];
+	int ret;
+
+	if ((onoff != 0) && (st->fw_version >= 0x10201)) {
+		/* for firmware later than 1.20.1,
+		 * the USB xfer length can be set  */
+		ret = dib0700_set_usb_xfer_len(adap->dev,
+			st->nb_packet_buffer_size);
+		if (ret < 0) {
+			deb_info("can not set the USB xfer len\n");
+			return ret;
+		}
+	}
 
 	b[0] = REQUEST_ENABLE_VIDEO;
 	b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
@@ -415,9 +490,21 @@ static int dib0700_probe(struct usb_interface *intf,
 
 	for (i = 0; i < dib0700_device_count; i++)
 		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE,
-					&dev, adapter_nr) == 0)
-		{
+		    &dev, adapter_nr) == 0) {
+			struct dib0700_state *st = dev->priv;
+			u32 hwversion, romversion, fw_version, fwtype;
+
+			dib0700_get_version(dev, &hwversion, &romversion,
+				&fw_version, &fwtype);
+
+			deb_info("Firmware version: %x, %d, 0x%x, %d\n",
+				hwversion, romversion, fw_version, fwtype);
+
+			st->fw_version = fw_version;
+			st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
+
 			dib0700_rc_setup(dev);
+
 			return 0;
 		}
 

+ 503 - 222
drivers/media/dvb/dvb-usb/dib0700_devices.c

@@ -18,6 +18,7 @@
 #include "xc5000.h"
 #include "s5h1411.h"
 #include "dib0070.h"
+#include "dib0090.h"
 #include "lgdt3305.h"
 #include "mxl5007t.h"
 
@@ -130,93 +131,95 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
 /* MT226x */
 static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
 	{
-		BAND_UHF, // band_caps
+		BAND_UHF,
 
 		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
 		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
-
-		1130,  // inv_gain
-		21,  // time_stabiliz
-
-		0,  // alpha_level
-		118,  // thlock
-
-		0,     // wbd_inv
-		3530,  // wbd_ref
-		1,     // wbd_sel
-		0,     // wbd_alpha
-
-		65535,  // agc1_max
-		33770,  // agc1_min
-		65535,  // agc2_max
-		23592,  // agc2_min
-
-		0,    // agc1_pt1
-		62,   // agc1_pt2
-		255,  // agc1_pt3
-		64,   // agc1_slope1
-		64,   // agc1_slope2
-		132,  // agc2_pt1
-		192,  // agc2_pt2
-		80,   // agc2_slope1
-		80,   // agc2_slope2
-
-		17,  // alpha_mant
-		27,  // alpha_exp
-		23,  // beta_mant
-		51,  // beta_exp
-
-		1,  // perform_agc_softsplit
+		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8)
+	    | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+		1130,
+		21,
+
+		0,
+		118,
+
+		0,
+		3530,
+		1,
+		0,
+
+		65535,
+		33770,
+		65535,
+		23592,
+
+		0,
+		62,
+		255,
+		64,
+		64,
+		132,
+		192,
+		80,
+		80,
+
+		17,
+		27,
+		23,
+		51,
+
+		1,
 	}, {
-		BAND_VHF | BAND_LBAND, // band_caps
+		BAND_VHF | BAND_LBAND,
 
 		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
 		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
-
-		2372, // inv_gain
-		21,   // time_stabiliz
-
-		0,    // alpha_level
-		118,  // thlock
-
-		0,    // wbd_inv
-		3530, // wbd_ref
-		1,     // wbd_sel
-		0,    // wbd_alpha
-
-		65535, // agc1_max
-		0,     // agc1_min
-		65535, // agc2_max
-		23592, // agc2_min
-
-		0,    // agc1_pt1
-		128,  // agc1_pt2
-		128,  // agc1_pt3
-		128,  // agc1_slope1
-		0,    // agc1_slope2
-		128,  // agc2_pt1
-		253,  // agc2_pt2
-		81,   // agc2_slope1
-		0,    // agc2_slope2
-
-		17,  // alpha_mant
-		27,  // alpha_exp
-		23,  // beta_mant
-		51,  // beta_exp
-
-		1,  // perform_agc_softsplit
+		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8)
+	    | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+
+		2372,
+		21,
+
+		0,
+		118,
+
+		0,
+		3530,
+		1,
+		0,
+
+		65535,
+		0,
+		65535,
+		23592,
+
+		0,
+		128,
+		128,
+		128,
+		0,
+		128,
+		253,
+		81,
+		0,
+
+		17,
+		27,
+		23,
+		51,
+
+		1,
 	}
 };
 
 static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
-	60000, 30000, // internal, sampling
-	1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
-	0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
-	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
-	0, // ifreq
-	20452225, // timf
+	60000, 30000,
+	1, 8, 3, 1, 0,
+	0, 0, 1, 1, 2,
+	(3 << 14) | (1 << 12) | (524 << 0),
+	0,
+	20452225,
 };
 
 static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
@@ -605,17 +608,17 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
 		}
 		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;
-		}
+	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.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];
+	poll_reply.data       = buf[4];
+	poll_reply.not_data   = buf[5];
 
 		break;
 	}
@@ -632,7 +635,7 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
 	/* 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 & 0xff) &&
-		    rc5_data(&keymap[i]) == poll_reply.data) {
+			rc5_data(&keymap[i]) == poll_reply.data) {
 			*event = keymap[i].event;
 			found = 1;
 			break;
@@ -641,8 +644,8 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
 
 	if (found == 0) {
 		err("Unknown remote controller key: %04x %02x %02x",
-		    poll_reply.system,
-		    poll_reply.data, poll_reply.not_data);
+			poll_reply.system,
+			poll_reply.data, poll_reply.not_data);
 		d->last_event = 0;
 		return 0;
 	}
@@ -933,47 +936,48 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
 static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
-	BAND_UHF | BAND_VHF,       // band_caps
+	BAND_UHF | BAND_VHF,
 
 	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
 	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
-
-	712,  // inv_gain
-	41,  // time_stabiliz
-
-	0,  // alpha_level
-	118,  // thlock
-
-	0,     // wbd_inv
-	4095,  // wbd_ref
-	0,     // wbd_sel
-	0,     // wbd_alpha
-
-	42598,  // agc1_max
-	17694,  // agc1_min
-	45875,  // agc2_max
-	2621,  // agc2_min
-	0,  // agc1_pt1
-	76,  // agc1_pt2
-	139,  // agc1_pt3
-	52,  // agc1_slope1
-	59,  // agc1_slope2
-	107,  // agc2_pt1
-	172,  // agc2_pt2
-	57,  // agc2_slope1
-	70,  // agc2_slope2
-
-	21,  // alpha_mant
-	25,  // alpha_exp
-	28,  // beta_mant
-	48,  // beta_exp
-
-	1,  // perform_agc_softsplit
-	{  0,     // split_min
-	   107,   // split_max
-	   51800, // global_split_min
-	   24700  // global_split_max
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+
+	712,
+	41,
+
+	0,
+	118,
+
+	0,
+	4095,
+	0,
+	0,
+
+	42598,
+	17694,
+	45875,
+	2621,
+	0,
+	76,
+	139,
+	52,
+	59,
+	107,
+	172,
+	57,
+	70,
+
+	21,
+	25,
+	28,
+	48,
+
+	1,
+	{  0,
+	   107,
+	   51800,
+	   24700
 	},
 };
 
@@ -982,54 +986,55 @@ static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
 
 	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
 	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
 
-	712, // inv_gain
-	41,  // time_stabiliz
+	712,
+	41,
 
-	0,   // alpha_level
-	118, // thlock
+	0,
+	118,
 
-	0,    // wbd_inv
-	4095, // wbd_ref
-	0,    // wbd_sel
-	0,    // wbd_alpha
+	0,
+	4095,
+	0,
+	0,
 
-	42598, // agc1_max
-	16384, // agc1_min
-	42598, // agc2_max
-	    0, // agc2_min
+	42598,
+	16384,
+	42598,
+	    0,
 
-	  0,   // agc1_pt1
-	137,   // agc1_pt2
-	255,   // agc1_pt3
+	  0,
+	137,
+	255,
 
-	  0,   // agc1_slope1
-	255,   // agc1_slope2
+	  0,
+	255,
 
-	0,     // agc2_pt1
-	0,     // agc2_pt2
+	0,
+	0,
 
-	 0,    // agc2_slope1
-	41,    // agc2_slope2
+	 0,
+	41,
 
-	15, // alpha_mant
-	25, // alpha_exp
+	15,
+	25,
 
-	28, // beta_mant
-	48, // beta_exp
+	28,
+	48,
 
-	0, // perform_agc_softsplit
+	0,
 };
 
 static struct dibx000_bandwidth_config stk7700p_pll_config = {
-	60000, 30000, // internal, sampling
-	1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
-	0, 0, 1, 1, 0, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
-	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
-	60258167, // ifreq
-	20452225, // timf
-	30000000, // xtal
+	60000, 30000,
+	1, 8, 3, 1, 0,
+	0, 0, 1, 1, 0,
+	(3 << 14) | (1 << 12) | (524 << 0),
+	60258167,
+	20452225,
+	30000000,
 };
 
 static struct dib7000m_config stk7700p_dib7000m_config = {
@@ -1115,41 +1120,42 @@ static struct dibx000_agc_config dib7070_agc_config = {
 	BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
 	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
 	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
-
-	600, // inv_gain
-	10,  // time_stabiliz
-
-	0,  // alpha_level
-	118,  // thlock
-
-	0,     // wbd_inv
-	3530,  // wbd_ref
-	1,     // wbd_sel
-	5,     // wbd_alpha
-
-	65535,  // agc1_max
-		0,  // agc1_min
-
-	65535,  // agc2_max
-	0,      // agc2_min
-
-	0,      // agc1_pt1
-	40,     // agc1_pt2
-	183,    // agc1_pt3
-	206,    // agc1_slope1
-	255,    // agc1_slope2
-	72,     // agc2_pt1
-	152,    // agc2_pt2
-	88,     // agc2_slope1
-	90,     // agc2_slope2
-
-	17,  // alpha_mant
-	27,  // alpha_exp
-	23,  // beta_mant
-	51,  // beta_exp
-
-	0,  // perform_agc_softsplit
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+	600,
+	10,
+
+	0,
+	118,
+
+	0,
+	3530,
+	1,
+	5,
+
+	65535,
+		0,
+
+	65535,
+	0,
+
+	0,
+	40,
+	183,
+	206,
+	255,
+	72,
+	152,
+	88,
+	90,
+
+	17,
+	27,
+	23,
+	51,
+
+	0,
 };
 
 static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
@@ -1276,13 +1282,13 @@ static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int 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
-	0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
-	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
-	(0 << 25) | 0, // ifreq = 0.000000 MHz
-	20452225, // timf
-	12000000, // xtal_hz
+	60000, 15000,
+	1, 20, 3, 1, 0,
+	0, 0, 1, 1, 2,
+	(3 << 14) | (1 << 12) | (524 << 0),
+	(0 << 25) | 0,
+	20452225,
+	12000000,
 };
 
 static struct dib7000p_config dib7070p_dib7000p_config = {
@@ -1476,12 +1482,12 @@ static struct dib8000_config dib807x_dib8000_config[2] = {
 	}
 };
 
-static int dib807x_tuner_reset(struct dvb_frontend *fe, int onoff)
+static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff)
 {
 	return dib8000_set_gpio(fe, 5, 0, !onoff);
 }
 
-static int dib807x_tuner_sleep(struct dvb_frontend *fe, int onoff)
+static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff)
 {
 	return dib8000_set_gpio(fe, 0, 0, onoff);
 }
@@ -1494,8 +1500,8 @@ static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = {
 static struct dib0070_config dib807x_dib0070_config[2] = {
 	{
 		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
-		.reset = dib807x_tuner_reset,
-		.sleep = dib807x_tuner_sleep,
+		.reset = dib80xx_tuner_reset,
+		.sleep = dib80xx_tuner_sleep,
 		.clock_khz = 12000,
 		.clock_pad_drive = 4,
 		.vga_filter = 1,
@@ -1508,8 +1514,8 @@ static struct dib0070_config dib807x_dib0070_config[2] = {
 		.freq_offset_khz_vhf = -100,
 	}, {
 		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
-		.reset = dib807x_tuner_reset,
-		.sleep = dib807x_tuner_sleep,
+		.reset = dib80xx_tuner_reset,
+		.sleep = dib80xx_tuner_sleep,
 		.clock_khz = 12000,
 		.clock_pad_drive = 2,
 		.vga_filter = 1,
@@ -1566,12 +1572,14 @@ 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)
+static int stk80xx_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)
+static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter,
+	int onoff)
 {
     return dib8000_pid_filter_ctrl(adapter->fe, onoff);
 }
@@ -1624,7 +1632,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
 	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
 	/* initialize IC 0 */
-	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x80);
+	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80);
 
 	adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
 			      &dib807x_dib8000_config[0]);
@@ -1635,7 +1643,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
 static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
 {
 	/* initialize IC 1 */
-	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x82);
+	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82);
 
 	adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82,
 			      &dib807x_dib8000_config[1]);
@@ -1643,6 +1651,245 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
 	return adap->fe == NULL ? -ENODEV : 0;
 }
 
+/* STK8096GP */
+struct dibx000_agc_config dib8090_agc_config[2] = {
+    {
+	BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
+     * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+     * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+	787,
+	10,
+
+	0,
+	118,
+
+	0,
+	3530,
+	1,
+	5,
+
+	65535,
+	0,
+
+	65535,
+	0,
+
+	0,
+	32,
+	114,
+	143,
+	144,
+	114,
+	227,
+	116,
+	117,
+
+	28,
+	26,
+	31,
+	51,
+
+	0,
+    },
+    {
+	BAND_CBAND,
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
+     * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+     * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+	787,
+	10,
+
+	0,
+	118,
+
+	0,
+	3530,
+	1,
+	5,
+
+	0,
+	0,
+
+	65535,
+	0,
+
+	0,
+	32,
+	114,
+	143,
+	144,
+	114,
+	227,
+	116,
+	117,
+
+	28,
+	26,
+	31,
+	51,
+
+	0,
+    }
+};
+
+static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = {
+    54000, 13500,
+    1, 18, 3, 1, 0,
+    0, 0, 1, 1, 2,
+    (3 << 14) | (1 << 12) | (599 << 0),
+    (0 << 25) | 0,
+    20199727,
+    12000000,
+};
+
+static int dib8090_get_adc_power(struct dvb_frontend *fe)
+{
+    return dib8000_get_adc_power(fe, 1);
+}
+
+static struct dib8000_config dib809x_dib8000_config = {
+    .output_mpeg2_in_188_bytes = 1,
+
+    .agc_config_count = 2,
+    .agc = dib8090_agc_config,
+    .agc_control = dib0090_dcc_freq,
+    .pll = &dib8090_pll_config_12mhz,
+    .tuner_is_baseband = 1,
+
+    .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+    .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+    .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+    .hostbus_diversity = 1,
+    .div_cfg = 0x31,
+    .output_mode = OUTMODE_MPEG2_FIFO,
+    .drives = 0x2d98,
+    .diversity_delay = 144,
+    .refclksel = 3,
+};
+
+static struct dib0090_config dib809x_dib0090_config = {
+    .io.pll_bypass = 1,
+    .io.pll_range = 1,
+    .io.pll_prediv = 1,
+    .io.pll_loopdiv = 20,
+    .io.adc_clock_ratio = 8,
+    .io.pll_int_loop_filt = 0,
+    .io.clock_khz = 12000,
+    .reset = dib80xx_tuner_reset,
+    .sleep = dib80xx_tuner_sleep,
+    .clkouttobamse = 1,
+    .analog_output = 1,
+    .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS,
+    .wbd_vhf_offset = 100,
+    .wbd_cband_offset = 450,
+    .use_pwm_agc = 1,
+    .clkoutdrive = 1,
+    .get_adc_power = dib8090_get_adc_power,
+	.freq_offset_khz_uhf = 0,
+	.freq_offset_khz_vhf = -143,
+};
+
+static int dib8096_set_param_override(struct dvb_frontend *fe,
+		struct dvb_frontend_parameters *fep)
+{
+    struct dvb_usb_adapter *adap = fe->dvb->priv;
+    struct dib0700_adapter_state *state = adap->priv;
+    u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+    u16 offset;
+    int ret = 0;
+    enum frontend_tune_state tune_state = CT_SHUTDOWN;
+    u16 ltgain, rf_gain_limit;
+
+    ret = state->set_param_save(fe, fep);
+    if (ret < 0)
+	return ret;
+
+    switch (band) {
+    case BAND_VHF:
+	    offset = 100;
+	    break;
+    case BAND_UHF:
+	    offset = 550;
+	    break;
+    default:
+	    offset = 0;
+	    break;
+    }
+    offset += (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2;
+    dib8000_set_wbd_ref(fe, offset);
+
+
+    if (band == BAND_CBAND) {
+	deb_info("tuning in CBAND - soft-AGC startup\n");
+	/* TODO specific wbd target for dib0090 - needed for startup ? */
+	dib0090_set_tune_state(fe, CT_AGC_START);
+	do {
+		ret = dib0090_gain_control(fe);
+		msleep(ret);
+		tune_state = dib0090_get_tune_state(fe);
+		if (tune_state == CT_AGC_STEP_0)
+			dib8000_set_gpio(fe, 6, 0, 1);
+		else if (tune_state == CT_AGC_STEP_1) {
+			dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, &ltgain);
+			if (rf_gain_limit == 0)
+				dib8000_set_gpio(fe, 6, 0, 0);
+		}
+	} while (tune_state < CT_AGC_STOP);
+	dib0090_pwm_gain_reset(fe);
+	dib8000_pwm_agc_reset(fe);
+	dib8000_set_tune_state(fe, CT_DEMOD_START);
+    } else {
+	deb_info("not tuning in CBAND - standard AGC startup\n");
+	dib0090_pwm_gain_reset(fe);
+    }
+
+    return 0;
+}
+
+static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
+{
+    struct dib0700_adapter_state *st = adap->priv;
+    struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+    if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+	return -ENODEV;
+
+    st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+    adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override;
+    return 0;
+}
+
+static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80);
+
+	adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config);
+
+	return adap->fe == NULL ?  -ENODEV : 0;
+}
 
 /* STK7070PD */
 static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
@@ -1929,14 +2176,17 @@ struct usb_device_id dib0700_usb_id_table[] = {
 	{ USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_STK7700D) },
 /* 55 */{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_STK7700D_2) },
 	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73A) },
-	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73ESE) },
-	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV282E) },
+	{ USB_DEVICE(USB_VID_PCTV,	USB_PID_PINNACLE_PCTV73ESE) },
+	{ USB_DEVICE(USB_VID_PCTV,	USB_PID_PINNACLE_PCTV282E) },
 	{ USB_DEVICE(USB_VID_DIBCOM,	USB_PID_DIBCOM_STK7770P) },
 /* 60 */{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS_2) },
 	{ 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) },
+/* 65 */{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73ESE) },
+	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV282E) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK8096GP) },
 	{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -2238,11 +2488,11 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ NULL },
 			},
 			{   "Pinnacle PCTV 73e SE",
-				{ &dib0700_usb_id_table[57], NULL },
+				{ &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL },
 				{ NULL },
 			},
 			{   "Pinnacle PCTV 282e",
-				{ &dib0700_usb_id_table[58], NULL },
+				{ &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL },
 				{ NULL },
 			},
 		},
@@ -2471,8 +2721,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{
 				.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,
+				.pid_filter = stk80xx_pid_filter,
+				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
 				.frontend_attach  = stk807x_frontend_attach,
 				.tuner_attach     = dib807x_tuner_attach,
 
@@ -2510,8 +2760,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{
 				.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,
+				.pid_filter = stk80xx_pid_filter,
+				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
 				.frontend_attach  = stk807xpvr_frontend_attach0,
 				.tuner_attach     = dib807x_tuner_attach,
 
@@ -2523,8 +2773,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{
 				.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,
+				.pid_filter = stk80xx_pid_filter,
+				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
 				.frontend_attach  = stk807xpvr_frontend_attach1,
 				.tuner_attach     = dib807x_tuner_attach,
 
@@ -2543,6 +2793,37 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			},
 		},
 
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = dib0700_rc_keys,
+		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_query         = dib0700_rc_query
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+					DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter = stk80xx_pid_filter,
+				.pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+				.frontend_attach  = stk809x_frontend_attach,
+				.tuner_attach     = dib809x_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+				.size_of_priv =
+					sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "DiBcom STK8096GP reference design",
+				{ &dib0700_usb_id_table[67], NULL },
+				{ NULL },
+			},
+		},
+
 		.rc_interval      = DEFAULT_RC_INTERVAL,
 		.rc_key_map       = dib0700_rc_keys,
 		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),

+ 13 - 2
drivers/media/dvb/dvb-usb/dibusb-common.c

@@ -142,8 +142,13 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
 		} else if ((msg[i].flags & I2C_M_RD) == 0) {
 			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
 				break;
-		} else
-			break;
+		} else if (msg[i].addr != 0x50) {
+			/* 0x50 is the address of the eeprom - we need to protect it
+			 * from dibusb's bad i2c implementation: reads without
+			 * writing the offset before are forbidden */
+			if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0)
+				break;
+		}
 	}
 
 	mutex_unlock(&d->i2c_mutex);
@@ -243,6 +248,12 @@ static struct dib3000mc_config mod3000p_dib3000p_config = {
 
 int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
 {
+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
+			adap->dev->udev->descriptor.idProduct ==
+			USB_PID_LITEON_DVB_T_WARM) {
+		msleep(1000);
+	}
+
 	if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS,  &mod3000p_dib3000p_config)) != NULL ||
 		(adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) {
 		if (adap->priv != NULL) {

+ 3 - 0
drivers/media/dvb/dvb-usb/dvb-usb-ids.h

@@ -47,6 +47,7 @@
 #define USB_VID_MSI_2				0x1462
 #define USB_VID_OPERA1				0x695c
 #define USB_VID_PINNACLE			0x2304
+#define USB_VID_PCTV				0x2013
 #define USB_VID_PIXELVIEW			0x1554
 #define USB_VID_TECHNOTREND			0x0b48
 #define USB_VID_TERRATEC			0x0ccd
@@ -101,6 +102,7 @@
 #define USB_PID_DIBCOM_STK7070PD			0x1ebe
 #define USB_PID_DIBCOM_STK807XP				0x1f90
 #define USB_PID_DIBCOM_STK807XPVR			0x1f98
+#define USB_PID_DIBCOM_STK8096GP                        0x1fa0
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
 #define USB_PID_DIBCOM_STK7770P				0x1e80
 #define USB_PID_DPOSH_M9206_COLD			0x9206
@@ -211,6 +213,7 @@
 #define USB_PID_PINNACLE_PCTV801E_SE			0x023b
 #define USB_PID_PINNACLE_PCTV73A			0x0243
 #define USB_PID_PINNACLE_PCTV73ESE			0x0245
+#define USB_PID_PINNACLE_PCTV74E			0x0246
 #define USB_PID_PINNACLE_PCTV282E			0x0248
 #define USB_PID_PIXELVIEW_SBTVD				0x5010
 #define USB_PID_PCTV_200E				0x020e

+ 309 - 147
drivers/media/dvb/dvb-usb/dw2102.c

@@ -20,6 +20,11 @@
 #include "tda1002x.h"
 #include "mt312.h"
 #include "zl10039.h"
+#include "ds3000.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "stb6100.h"
+#include "stb6100_proc.h"
 
 #ifndef USB_PID_DW2102
 #define USB_PID_DW2102 0x2102
@@ -37,12 +42,20 @@
 #define USB_PID_CINERGY_S 0x0064
 #endif
 
+#ifndef USB_PID_TEVII_S630
+#define USB_PID_TEVII_S630 0xd630
+#endif
+
 #ifndef USB_PID_TEVII_S650
 #define USB_PID_TEVII_S650 0xd650
 #endif
 
-#ifndef USB_PID_TEVII_S630
-#define USB_PID_TEVII_S630 0xd630
+#ifndef USB_PID_TEVII_S660
+#define USB_PID_TEVII_S660 0xd660
+#endif
+
+#ifndef USB_PID_PROF_1100
+#define USB_PID_PROF_1100 0xb012
 #endif
 
 #define DW210X_READ_MSG 0
@@ -55,6 +68,10 @@
 #define DW2102_VOLTAGE_CTRL (0x1800)
 #define DW2102_RC_QUERY (0x1a00)
 
+#define	err_str "did not find the firmware file. (%s) " \
+		"Please see linux/Documentation/dvb/ for more details " \
+		"on firmware-problems."
+
 struct dvb_usb_rc_keys_table {
 	struct dvb_usb_rc_key *rc_keys;
 	int rc_keys_size;
@@ -71,6 +88,12 @@ static int ir_keymap;
 module_param_named(keymap, ir_keymap, int, 0644);
 MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs  ...");
 
+/* demod probe */
+static int demod_probe = 1;
+module_param_named(demod, demod_probe, int, 0644);
+MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 "
+			"4=stv0903+stb6100(or-able)).");
+
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
@@ -183,7 +206,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
 	switch (num) {
 	case 2:
 		/* read si2109 register by number */
-		buf6[0] = 0xd0;
+		buf6[0] = msg[0].addr << 1;
 		buf6[1] = msg[0].len;
 		buf6[2] = msg[0].buf[0];
 		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
@@ -198,7 +221,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
 		switch (msg[0].addr) {
 		case 0x68:
 			/* write to si2109 register */
-			buf6[0] = 0xd0;
+			buf6[0] = msg[0].addr << 1;
 			buf6[1] = msg[0].len;
 			memcpy(buf6 + 2, msg[0].buf, msg[0].len);
 			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
@@ -239,7 +262,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
 		/* read */
 		/* first write first register number */
 		u8 ibuf[msg[1].len + 2], obuf[3];
-		obuf[0] = 0xd0;
+		obuf[0] = msg[0].addr << 1;
 		obuf[1] = msg[0].len;
 		obuf[2] = msg[0].buf[0];
 		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
@@ -256,7 +279,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
 		case 0x68: {
 			/* write to register */
 			u8 obuf[msg[0].len + 2];
-			obuf[0] = 0xd0;
+			obuf[0] = msg[0].addr << 1;
 			obuf[1] = msg[0].len;
 			memcpy(obuf + 2, msg[0].buf, msg[0].len);
 			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
@@ -266,7 +289,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
 		case 0x61: {
 			/* write to tuner */
 			u8 obuf[msg[0].len + 2];
-			obuf[0] = 0xc2;
+			obuf[0] = msg[0].addr << 1;
 			obuf[1] = msg[0].len;
 			memcpy(obuf + 2, msg[0].buf, msg[0].len);
 			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
@@ -301,78 +324,78 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int ret = 0;
-	int len, i;
+	int len, i, j;
 
 	if (!d)
 		return -ENODEV;
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
-	switch (num) {
-	case 2: {
-		/* read */
-		/* first write first register number */
-		u8 ibuf[msg[1].len + 2], obuf[3];
-		obuf[0] = 0xaa;
-		obuf[1] = msg[0].len;
-		obuf[2] = msg[0].buf[0];
-		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
-				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
-		/* second read registers */
-		ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0,
-				ibuf, msg[1].len + 2, DW210X_READ_MSG);
-		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
-
-		break;
-	}
-	case 1:
-		switch (msg[0].addr) {
-		case 0x55: {
-			if (msg[0].buf[0] == 0xf7) {
-				/* firmware */
-				/* Write in small blocks */
-				u8 obuf[19];
-				obuf[0] = 0xaa;
-				obuf[1] = 0x11;
-				obuf[2] = 0xf7;
-				len = msg[0].len - 1;
-				i = 1;
-				do {
-					memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len));
-					ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
-						obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG);
-					i += 16;
-					len -= 16;
-				} while (len > 0);
-			} else {
-				/* write to register */
-				u8 obuf[msg[0].len + 2];
-				obuf[0] = 0xaa;
-				obuf[1] = msg[0].len;
-				memcpy(obuf + 2, msg[0].buf, msg[0].len);
-				ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
-						obuf, msg[0].len + 2, DW210X_WRITE_MSG);
-			}
-			break;
-		}
+	for (j = 0; j < num; j++) {
+		switch (msg[j].addr) {
 		case(DW2102_RC_QUERY): {
 			u8 ibuf[2];
 			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
 					ibuf, 2, DW210X_READ_MSG);
-			memcpy(msg[0].buf, ibuf , 2);
+			memcpy(msg[j].buf, ibuf , 2);
 			break;
 		}
 		case(DW2102_VOLTAGE_CTRL): {
 			u8 obuf[2];
 			obuf[0] = 0x30;
-			obuf[1] = msg[0].buf[0];
+			obuf[1] = msg[j].buf[0];
 			ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
 					obuf, 2, DW210X_WRITE_MSG);
 			break;
 		}
+		/*case 0x55: cx24116
+		case 0x6a: stv0903
+		case 0x68: ds3000, stv0903
+		case 0x60: ts2020, stv6110, stb6100 */
+		default: {
+			if (msg[j].flags == I2C_M_RD) {
+				/* read registers */
+				u8  ibuf[msg[j].len + 2];
+				ret = dw210x_op_rw(d->udev, 0xc3,
+						(msg[j].addr << 1) + 1, 0,
+						ibuf, msg[j].len + 2,
+						DW210X_READ_MSG);
+				memcpy(msg[j].buf, ibuf + 2, msg[j].len);
+			mdelay(10);
+			} else if (((msg[j].buf[0] == 0xb0) &&
+						(msg[j].addr == 0x68)) ||
+						((msg[j].buf[0] == 0xf7) &&
+						(msg[j].addr == 0x55))) {
+				/* write firmware */
+				u8 obuf[19];
+				obuf[0] = msg[j].addr << 1;
+				obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len);
+				obuf[2] = msg[j].buf[0];
+				len = msg[j].len - 1;
+				i = 1;
+				do {
+					memcpy(obuf + 3, msg[j].buf + i,
+							(len > 16 ? 16 : len));
+					ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+						obuf, (len > 16 ? 16 : len) + 3,
+						DW210X_WRITE_MSG);
+					i += 16;
+					len -= 16;
+				} while (len > 0);
+			} else {
+				/* write registers */
+				u8 obuf[msg[j].len + 2];
+				obuf[0] = msg[j].addr << 1;
+				obuf[1] = msg[j].len;
+				memcpy(obuf + 2, msg[j].buf, msg[j].len);
+				ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+						obuf, msg[j].len + 2,
+						DW210X_WRITE_MSG);
+			}
+			break;
+		}
 		}
 
-		break;
 	}
 
 	mutex_unlock(&d->i2c_mutex);
@@ -442,63 +465,85 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 	return num;
 }
 
-static int s630_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 								int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int ret = 0;
+	int len, i, j;
 
 	if (!d)
 		return -ENODEV;
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
-	switch (num) {
-	case 2: { /* read */
-		u8 ibuf[msg[1].len], obuf[3];
-		obuf[0] = msg[1].len;
-		obuf[1] = (msg[0].addr << 1);
-		obuf[2] = msg[0].buf[0];
-
-		ret = dw210x_op_rw(d->udev, 0x90, 0, 0,
-					obuf, 3, DW210X_WRITE_MSG);
-		msleep(5);
-		ret = dw210x_op_rw(d->udev, 0x91, 0, 0,
-					ibuf, msg[1].len, DW210X_READ_MSG);
-		memcpy(msg[1].buf, ibuf, msg[1].len);
-		break;
-	}
-	case 1:
-		switch (msg[0].addr) {
-		case 0x60:
-		case 0x0e: {
-			/* write to zl10313, zl10039 register, */
-			u8 obuf[msg[0].len + 2];
-			obuf[0] = msg[0].len + 1;
-			obuf[1] = (msg[0].addr << 1);
-			memcpy(obuf + 2, msg[0].buf, msg[0].len);
-			ret = dw210x_op_rw(d->udev, 0x80, 0, 0,
-					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
-			break;
-		}
+	for (j = 0; j < num; j++) {
+		switch (msg[j].addr) {
 		case (DW2102_RC_QUERY): {
 			u8 ibuf[4];
 			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
 					ibuf, 4, DW210X_READ_MSG);
-			msg[0].buf[0] = ibuf[3];
+			memcpy(msg[j].buf, ibuf + 1, 2);
 			break;
 		}
 		case (DW2102_VOLTAGE_CTRL): {
 			u8 obuf[2];
-			obuf[0] = 0x03;
-			obuf[1] = msg[0].buf[0];
+			obuf[0] = 3;
+			obuf[1] = msg[j].buf[0];
 			ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
 					obuf, 2, DW210X_WRITE_MSG);
 			break;
 		}
+		/*case 0x55: cx24116
+		case 0x6a: stv0903
+		case 0x68: ds3000, stv0903
+		case 0x60: ts2020, stv6110, stb6100
+		case 0xa0: eeprom */
+		default: {
+			if (msg[j].flags == I2C_M_RD) {
+				/* read registers */
+				u8 ibuf[msg[j].len];
+				ret = dw210x_op_rw(d->udev, 0x91, 0, 0,
+						ibuf, msg[j].len,
+						DW210X_READ_MSG);
+				memcpy(msg[j].buf, ibuf, msg[j].len);
+				break;
+			} else if ((msg[j].buf[0] == 0xb0) &&
+						(msg[j].addr == 0x68)) {
+				/* write firmware */
+				u8 obuf[19];
+				obuf[0] = (msg[j].len > 16 ?
+						18 : msg[j].len + 1);
+				obuf[1] = msg[j].addr << 1;
+				obuf[2] = msg[j].buf[0];
+				len = msg[j].len - 1;
+				i = 1;
+				do {
+					memcpy(obuf + 3, msg[j].buf + i,
+							(len > 16 ? 16 : len));
+					ret = dw210x_op_rw(d->udev, 0x80, 0, 0,
+						obuf, (len > 16 ? 16 : len) + 3,
+						DW210X_WRITE_MSG);
+					i += 16;
+					len -= 16;
+				} while (len > 0);
+			} else {
+				/* write registers */
+				u8 obuf[msg[j].len + 2];
+				obuf[0] = msg[j].len + 1;
+				obuf[1] = (msg[j].addr << 1);
+				memcpy(obuf + 2, msg[j].buf, msg[j].len);
+				ret = dw210x_op_rw(d->udev,
+						(num > 1 ? 0x90 : 0x80), 0, 0,
+						obuf, msg[j].len + 2,
+						DW210X_WRITE_MSG);
+				break;
+			}
+			break;
+		}
 		}
 
-		break;
+		msleep(3);
 	}
 
 	mutex_unlock(&d->i2c_mutex);
@@ -535,8 +580,8 @@ static struct i2c_algorithm dw3101_i2c_algo = {
 	.functionality = dw210x_i2c_func,
 };
 
-static struct i2c_algorithm s630_i2c_algo = {
-	.master_xfer = s630_i2c_transfer,
+static struct i2c_algorithm s6x0_i2c_algo = {
+	.master_xfer = s6x0_i2c_transfer,
 	.functionality = dw210x_i2c_func,
 };
 
@@ -564,25 +609,34 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 	return 0;
 };
 
-static int s630_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 {
 	int i, ret;
-	u8 buf[3], eeprom[256], eepromline[16];
+	u8 ibuf[] = { 0 }, obuf[] = { 0 };
+	u8 eeprom[256], eepromline[16];
+	struct i2c_msg msg[] = {
+		{
+			.addr = 0xa0 >> 1,
+			.flags = 0,
+			.buf = obuf,
+			.len = 1,
+		}, {
+			.addr = 0xa0 >> 1,
+			.flags = I2C_M_RD,
+			.buf = ibuf,
+			.len = 1,
+		}
+	};
 
 	for (i = 0; i < 256; i++) {
-		buf[0] = 1;
-		buf[1] = 0xa0;
-		buf[2] = i;
-		ret = dw210x_op_rw(d->udev, 0x90, 0, 0,
-					buf, 3, DW210X_WRITE_MSG);
-		ret = dw210x_op_rw(d->udev, 0x91, 0, 0,
-					buf, 1, DW210X_READ_MSG);
-		if (ret < 0) {
+		obuf[0] = i;
+		ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2);
+		if (ret != 2) {
 			err("read eeprom failed.");
 			return -1;
 		} else {
-			eepromline[i % 16] = buf[0];
-			eeprom[i] = buf[0];
+			eepromline[i % 16] = ibuf[0];
+			eeprom[i] = ibuf[0];
 		}
 
 		if ((i % 16) == 15) {
@@ -644,19 +698,104 @@ static struct mt312_config zl313_config = {
 	.demod_address = 0x0e,
 };
 
+static struct ds3000_config dw2104_ds3000_config = {
+	.demod_address = 0x68,
+};
+
+static struct stv0900_config dw2104a_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,
+};
+
+static struct stb6100_config dw2104a_stb6100_config = {
+	.tuner_address = 0x60,
+	.refclock = 27000000,
+};
+
+static struct stv0900_config dw2104_stv0900_config = {
+	.demod_address = 0x68,
+	.demod_mode = 0,
+	.xtal = 8000000,
+	.clkmode = 3,
+	.diseqc_mode = 2,
+	.tun1_maddress = 0,
+	.tun1_adc = 1,/* 1 Vpp */
+	.path1_mode = 3,
+};
+
+static struct stv6110_config dw2104_stv6110_config = {
+	.i2c_address = 0x60,
+	.mclk = 16000000,
+	.clk_div = 1,
+};
+
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
-	if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
-			&d->dev->i2c_adap)) != NULL) {
+	struct dvb_tuner_ops *tuner_ops = NULL;
+
+	if (demod_probe & 4) {
+		d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
+				&d->dev->i2c_adap, 0);
+		if (d->fe != NULL) {
+			if (dvb_attach(stb6100_attach, d->fe,
+					&dw2104a_stb6100_config,
+					&d->dev->i2c_adap)) {
+				tuner_ops = &d->fe->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;
+				d->fe->ops.set_voltage = dw210x_set_voltage;
+				info("Attached STV0900+STB6100!\n");
+				return 0;
+			}
+		}
+	}
+
+	if (demod_probe & 2) {
+		d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
+				&d->dev->i2c_adap, 0);
+		if (d->fe != NULL) {
+			if (dvb_attach(stv6110_attach, d->fe,
+					&dw2104_stv6110_config,
+					&d->dev->i2c_adap)) {
+				d->fe->ops.set_voltage = dw210x_set_voltage;
+				info("Attached STV0900+STV6110A!\n");
+				return 0;
+			}
+		}
+	}
+
+	if (demod_probe & 1) {
+		d->fe = dvb_attach(cx24116_attach, &dw2104_config,
+				&d->dev->i2c_adap);
+		if (d->fe != NULL) {
+			d->fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached cx24116!\n");
+			return 0;
+		}
+	}
+
+	d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
+			&d->dev->i2c_adap);
+	if (d->fe != NULL) {
 		d->fe->ops.set_voltage = dw210x_set_voltage;
-		info("Attached cx24116!\n");
+		info("Attached DS3000!\n");
 		return 0;
 	}
+
 	return -EIO;
 }
 
 static struct dvb_usb_device_properties dw2102_properties;
 static struct dvb_usb_device_properties dw2104_properties;
+static struct dvb_usb_device_properties s6x0_properties;
 
 static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 {
@@ -670,14 +809,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 			return 0;
 		}
 	}
+
 	if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
-		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
 		d->fe = dvb_attach(stv0288_attach, &earda_config,
 					&d->dev->i2c_adap);
 		if (d->fe != NULL) {
-			d->fe->ops.set_voltage = dw210x_set_voltage;
-			info("Attached stv0288!\n");
-			return 0;
+			if (dvb_attach(stb6000_attach, d->fe, 0x61,
+					&d->dev->i2c_adap)) {
+				d->fe->ops.set_voltage = dw210x_set_voltage;
+				info("Attached stv0288!\n");
+				return 0;
+			}
 		}
 	}
 
@@ -705,15 +847,38 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
 	return -EIO;
 }
 
-static int s630_frontend_attach(struct dvb_usb_adapter *d)
+static int s6x0_frontend_attach(struct dvb_usb_adapter *d)
 {
 	d->fe = dvb_attach(mt312_attach, &zl313_config,
-				&d->dev->i2c_adap);
+			&d->dev->i2c_adap);
+	if (d->fe != NULL) {
+		if (dvb_attach(zl10039_attach, d->fe, 0x60,
+				&d->dev->i2c_adap)) {
+			d->fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached zl100313+zl10039!\n");
+			return 0;
+		}
+	}
+
+	d->fe = dvb_attach(stv0288_attach, &earda_config,
+			&d->dev->i2c_adap);
+	if (d->fe != NULL) {
+		if (dvb_attach(stb6000_attach, d->fe, 0x61,
+				&d->dev->i2c_adap)) {
+			d->fe->ops.set_voltage = dw210x_set_voltage;
+			info("Attached stv0288+stb6000!\n");
+			return 0;
+		}
+	}
+
+	d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
+			&d->dev->i2c_adap);
 	if (d->fe != NULL) {
 		d->fe->ops.set_voltage = dw210x_set_voltage;
-		info("Attached zl10313!\n");
+		info("Attached ds3000+ds2020!\n");
 		return 0;
 	}
+
 	return -EIO;
 }
 
@@ -724,14 +889,6 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 	return 0;
 }
 
-static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(stb6000_attach, adap->fe, 0x61,
-		&adap->dev->i2c_adap);
-
-	return 0;
-}
-
 static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
 {
 	dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -740,14 +897,6 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
 	return 0;
 }
 
-static int s630_zl10039_tuner_attach(struct dvb_usb_adapter *adap)
-{
-	dvb_attach(zl10039_attach, adap->fe, 0x60,
-		&adap->dev->i2c_adap);
-
-	return 0;
-}
-
 static struct dvb_usb_rc_key dw210x_rc_keys[] = {
 	{ 0xf80a, KEY_Q },		/*power*/
 	{ 0xf80c, KEY_M },		/*mute*/
@@ -922,6 +1071,8 @@ static struct usb_device_id dw2102_table[] = {
 	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
 	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
 	{USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
+	{USB_DEVICE(0x3011, USB_PID_PROF_1100)},
+	{USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
 	{ }
 };
 
@@ -935,15 +1086,13 @@ static int dw2102_load_firmware(struct usb_device *dev,
 	u8 reset;
 	u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
 	const struct firmware *fw;
-	const char *filename = "dvb-usb-dw2101.fw";
+	const char *fw_2101 = "dvb-usb-dw2101.fw";
 
 	switch (dev->descriptor.idProduct) {
 	case 0x2101:
-		ret = request_firmware(&fw, filename, &dev->dev);
+		ret = request_firmware(&fw, fw_2101, &dev->dev);
 		if (ret != 0) {
-			err("did not find the firmware file. (%s) "
-			"Please see linux/Documentation/dvb/ for more details "
-			"on firmware-problems.", filename);
+			err(err_str, fw_2101);
 			return ret;
 		}
 		break;
@@ -983,6 +1132,11 @@ static int dw2102_load_firmware(struct usb_device *dev,
 		}
 		/* init registers */
 		switch (dev->descriptor.idProduct) {
+		case USB_PID_PROF_1100:
+			s6x0_properties.rc_key_map = tbs_rc_keys;
+			s6x0_properties.rc_key_map_size =
+					ARRAY_SIZE(tbs_rc_keys);
+			break;
 		case USB_PID_TEVII_S650:
 			dw2104_properties.rc_key_map = tevii_rc_keys;
 			dw2104_properties.rc_key_map_size =
@@ -1021,7 +1175,6 @@ static int dw2102_load_firmware(struct usb_device *dev,
 						DW210X_READ_MSG);
 				if (reset16[2] == 0x11) {
 					dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
-					dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach;
 					break;
 				}
 			}
@@ -1184,13 +1337,13 @@ static struct dvb_usb_device_properties dw3101_properties = {
 	}
 };
 
-static struct dvb_usb_device_properties s630_properties = {
+static struct dvb_usb_device_properties s6x0_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 	.usb_ctrl = DEVICE_SPECIFIC,
 	.firmware = "dvb-usb-s630.fw",
 	.no_reconnect = 1,
 
-	.i2c_algo = &s630_i2c_algo,
+	.i2c_algo = &s6x0_i2c_algo,
 	.rc_key_map = tevii_rc_keys,
 	.rc_key_map_size = ARRAY_SIZE(tevii_rc_keys),
 	.rc_interval = 150,
@@ -1199,12 +1352,12 @@ static struct dvb_usb_device_properties s630_properties = {
 	.generic_bulk_ctrl_endpoint = 0x81,
 	.num_adapters = 1,
 	.download_firmware = dw2102_load_firmware,
-	.read_mac_address = s630_read_mac_address,
+	.read_mac_address = s6x0_read_mac_address,
 	.adapter = {
 		{
-			.frontend_attach = s630_frontend_attach,
+			.frontend_attach = s6x0_frontend_attach,
 			.streaming_ctrl = NULL,
-			.tuner_attach = s630_zl10039_tuner_attach,
+			.tuner_attach = NULL,
 			.stream = {
 				.type = USB_BULK,
 				.count = 8,
@@ -1217,12 +1370,20 @@ static struct dvb_usb_device_properties s630_properties = {
 			},
 		}
 	},
-	.num_device_descs = 1,
+	.num_device_descs = 3,
 	.devices = {
 		{"TeVii S630 USB",
 			{&dw2102_table[6], NULL},
 			{NULL},
 		},
+		{"Prof 1100 USB ",
+			{&dw2102_table[7], NULL},
+			{NULL},
+		},
+		{"TeVii S660 USB",
+			{&dw2102_table[8], NULL},
+			{NULL},
+		},
 	}
 };
 
@@ -1235,10 +1396,10 @@ static int dw2102_probe(struct usb_interface *intf,
 			THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &dw3101_properties,
 			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &s630_properties,
-			THIS_MODULE, NULL, adapter_nr)) {
+	    0 == dvb_usb_device_init(intf, &s6x0_properties,
+			THIS_MODULE, NULL, adapter_nr))
 		return 0;
-	}
+
 	return -ENODEV;
 }
 
@@ -1269,6 +1430,7 @@ module_exit(dw2102_module_exit);
 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
 MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
 				" DVB-C 3101 USB2.0,"
-				" TeVii S600, S630, S650 USB2.0 devices");
+				" TeVii S600, S630, S650, S660 USB2.0,"
+				" Prof 1100 USB2.0 devices");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");

+ 6 - 4
drivers/media/dvb/dvb-usb/friio-fe.c

@@ -134,11 +134,13 @@ static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq)
 	deb_fe("%s: freq=%d, step=%d\n", __func__, freq,
 	       state->frontend.ops.info.frequency_stepsize);
 	/* freq -> oscilator frequency conversion. */
-	/* freq: 473,000,000 + n*6,000,000 (no 1/7MHz shift to center freq) */
-	/* add 400[1/7 MHZ] = 57.142857MHz.   57MHz for the IF,  */
-	/*                                   1/7MHz for center freq shift */
+	/* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */
 	f = freq / state->frontend.ops.info.frequency_stepsize;
-	f += 400;
+	/* add 399[1/7 MHZ] = 57MHz for the IF  */
+	f += 399;
+	/* add center frequency shift if necessary */
+	if (f % 7 == 0)
+		f++;
 	pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */
 	pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1;
 	pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F;

+ 2 - 2
drivers/media/dvb/dvb-usb/gp8psk-fe.c

@@ -146,8 +146,8 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
 
 	switch (c->delivery_system) {
 	case SYS_DVBS:
-		/* Only QPSK is supported for DVB-S */
-		if (c->modulation != QPSK) {
+		/* Allow QPSK and 8PSK (even for DVB-S) */
+		if (c->modulation != QPSK && c->modulation != PSK_8) {
 			deb_fe("%s: unsupported modulation selected (%d)\n",
 				__func__, c->modulation);
 			return -EOPNOTSUPP;

+ 9 - 0
drivers/media/dvb/frontends/Kconfig

@@ -526,6 +526,15 @@ config DVB_TUNER_DIB0070
 	  This device is only used inside a SiP called together with a
 	  demodulator for now.
 
+config DVB_TUNER_DIB0090
+	tristate "DiBcom DiB0090 silicon base-band tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner DiB0090 from DiBcom.
+	  This device is only used inside a SiP called together with a
+	  demodulator for now.
+
 comment "SEC control devices for DVB-S"
 	depends on DVB_CORE
 

+ 1 - 0
drivers/media/dvb/frontends/Makefile

@@ -55,6 +55,7 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
 obj-$(CONFIG_DVB_TDA8261) += tda8261.o
 obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
+obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
 obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o

+ 2 - 2
drivers/media/dvb/frontends/au8522_decoder.c

@@ -62,7 +62,7 @@ struct au8522_register_config {
    The values are as follows from left to right
    0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13"
 */
-struct au8522_register_config filter_coef[] = {
+static const struct au8522_register_config filter_coef[] = {
 	{AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} },
 	{AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} },
 	{AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} },
@@ -104,7 +104,7 @@ struct au8522_register_config filter_coef[] = {
    0="SIF" 1="ATVRF/ATVRF13"
    Note: the "ATVRF/ATVRF13" mode has never been tested
 */
-struct au8522_register_config lpfilter_coef[] = {
+static const struct au8522_register_config lpfilter_coef[] = {
 	{0x060b, {0x21, 0x0b} },
 	{0x060c, {0xad, 0xad} },
 	{0x060d, {0x70, 0xf0} },

+ 349 - 325
drivers/media/dvb/frontends/dib0070.c

@@ -49,21 +49,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 #define DIB0070_P1G  0x03
 #define DIB0070S_P1A 0x02
 
-enum frontend_tune_state {
-	CT_TUNER_START = 10,
-	CT_TUNER_STEP_0,
-	CT_TUNER_STEP_1,
-	CT_TUNER_STEP_2,
-	CT_TUNER_STEP_3,
-	CT_TUNER_STEP_4,
-	CT_TUNER_STEP_5,
-	CT_TUNER_STEP_6,
-	CT_TUNER_STEP_7,
-	CT_TUNER_STOP,
-};
-
-#define FE_CALLBACK_TIME_NEVER 0xffffffff
-
 struct dib0070_state {
 	struct i2c_adapter *i2c;
 	struct dvb_frontend *fe;
@@ -71,10 +56,10 @@ struct dib0070_state {
 	u16 wbd_ff_offset;
 	u8 revision;
 
-	enum frontend_tune_state tune_state;
-	u32 current_rf;
+    enum frontend_tune_state tune_state;
+    u32 current_rf;
 
-	/* for the captrim binary search */
+    /* for the captrim binary search */
 	s8 step;
 	u16 adc_diff;
 
@@ -85,7 +70,7 @@ struct dib0070_state {
 	const struct dib0070_tuning *current_tune_table_index;
 	const struct dib0070_lna_match *lna_match;
 
-	u8 wbd_gain_current;
+    u8  wbd_gain_current;
 	u16 wbd_offset_3_3[2];
 };
 
@@ -93,8 +78,8 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
 {
 	u8 b[2];
 	struct i2c_msg msg[2] = {
-		{.addr = state->cfg->i2c_address,.flags = 0,.buf = &reg,.len = 1},
-		{.addr = state->cfg->i2c_address,.flags = I2C_M_RD,.buf = b,.len = 2},
+		{ .addr = state->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b,  .len = 2 },
 	};
 	if (i2c_transfer(state->i2c, msg, 2) != 2) {
 		printk(KERN_WARNING "DiB0070 I2C read failed\n");
@@ -106,7 +91,7 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
 static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
 {
 	u8 b[3] = { reg, val >> 8, val & 0xff };
-	struct i2c_msg msg = {.addr = state->cfg->i2c_address,.flags = 0,.buf = b,.len = 3 };
+	struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
 	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
 		printk(KERN_WARNING "DiB0070 I2C write failed\n");
 		return -EREMOTEIO;
@@ -124,30 +109,30 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
 
 static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
 {
-	struct dib0070_state *state = fe->tuner_priv;
-	u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
-
-	if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 7000)
-		tmp |= (0 << 14);
-	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 6000)
-		tmp |= (1 << 14);
-	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 5000)
-		tmp |= (2 << 14);
-	else
-		tmp |= (3 << 14);
-
-	dib0070_write_reg(state, 0x02, tmp);
-
-	/* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
-	if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
-		u16 value = dib0070_read_reg(state, 0x17);
-
-		dib0070_write_reg(state, 0x17, value & 0xfffc);
-		tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
-		dib0070_write_reg(state, 0x01, tmp | (60 << 9));
-
-		dib0070_write_reg(state, 0x17, value);
-	}
+    struct dib0070_state *state = fe->tuner_priv;
+    u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
+
+    if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
+	tmp |= (0 << 14);
+    else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
+	tmp |= (1 << 14);
+    else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
+	tmp |= (2 << 14);
+    else
+	tmp |= (3 << 14);
+
+    dib0070_write_reg(state, 0x02, tmp);
+
+    /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
+    if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
+	u16 value = dib0070_read_reg(state, 0x17);
+
+	dib0070_write_reg(state, 0x17, value & 0xfffc);
+	tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
+	dib0070_write_reg(state, 0x01, tmp | (60 << 9));
+
+	dib0070_write_reg(state, 0x17, value);
+    }
 	return 0;
 }
 
@@ -160,14 +145,14 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state
 	if (*tune_state == CT_TUNER_STEP_0) {
 
 		dib0070_write_reg(state, 0x0f, 0xed10);
-		dib0070_write_reg(state, 0x17, 0x0034);
+		dib0070_write_reg(state, 0x17,    0x0034);
 
 		dib0070_write_reg(state, 0x18, 0x0032);
 		state->step = state->captrim = state->fcaptrim = 64;
 		state->adc_diff = 3000;
 		ret = 20;
 
-		*tune_state = CT_TUNER_STEP_1;
+	*tune_state = CT_TUNER_STEP_1;
 	} else if (*tune_state == CT_TUNER_STEP_1) {
 		state->step /= 2;
 		dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
@@ -178,7 +163,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state
 
 		adc = dib0070_read_reg(state, 0x19);
 
-		dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc * (u32) 1800 / (u32) 1024);
+		dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
 
 		if (adc >= 400) {
 			adc -= 400;
@@ -193,6 +178,8 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state
 			state->adc_diff = adc;
 			state->fcaptrim = state->captrim;
 
+
+
 		}
 		state->captrim += (step_sign * state->step);
 
@@ -213,7 +200,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state
 static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
 {
 	struct dib0070_state *state = fe->tuner_priv;
-	u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
+    u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
 	dprintk("CTRL_LO5: 0x%x", lo5);
 	return dib0070_write_reg(state, 0x15, lo5);
 }
@@ -227,99 +214,99 @@ void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
 		dib0070_write_reg(state, 0x1a, 0x0000);
 	} else {
 		dib0070_write_reg(state, 0x1b, 0x4112);
-		if (state->cfg->vga_filter != 0) {
-			dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
-			dprintk("vga filter register is set to %x", state->cfg->vga_filter);
-		} else
-			dib0070_write_reg(state, 0x1a, 0x0009);
+	if (state->cfg->vga_filter != 0) {
+		dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
+		dprintk("vga filter register is set to %x", state->cfg->vga_filter);
+	} else
+		dib0070_write_reg(state, 0x1a, 0x0009);
 	}
 }
 
 EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
 struct dib0070_tuning {
-	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
-	u8 switch_trim;
-	u8 vco_band;
-	u8 hfdiv;
-	u8 vco_multi;
-	u8 presc;
-	u8 wbdmux;
-	u16 tuner_enable;
+    u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
+    u8 switch_trim;
+    u8 vco_band;
+    u8 hfdiv;
+    u8 vco_multi;
+    u8 presc;
+    u8 wbdmux;
+    u16 tuner_enable;
 };
 
 struct dib0070_lna_match {
-	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
-	u8 lna_band;
+    u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
+    u8 lna_band;
 };
 
 static const struct dib0070_tuning dib0070s_tuning_table[] = {
-	{570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800},	/* UHF */
-	{700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800},
-	{863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800},
-	{1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400},	/* LBAND */
-	{1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400},
-	{2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400},
-	{0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000},	/* SBAND */
+    {     570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
+    {     700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
+    {     863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
+    {    1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
+    {    1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
+    {    2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
+    { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
 };
 
 static const struct dib0070_tuning dib0070_tuning_table[] = {
-	{115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000},	/* FM below 92MHz cannot be tuned */
-	{179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000},	/* VHF */
-	{189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000},
-	{250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000},
-	{569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800},	/* UHF */
-	{699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800},
-	{863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800},
-	{0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400},	/* LBAND or everything higher than UHF */
+    {     115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
+    {     179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
+    {     189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
+    {     250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
+    {     569999, 2, 1, 5,  6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
+    {     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
+    {     863999, 2, 1, 1,  4, 2, 2, 0x4000 | 0x0800 },
+    { 0xffffffff, 0, 1, 0,  2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
 };
 
 static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
-	{180000, 0},		/* VHF */
-	{188000, 1},
-	{196400, 2},
-	{250000, 3},
-	{550000, 0},		/* UHF */
-	{590000, 1},
-	{666000, 3},
-	{864000, 5},
-	{1500000, 0},		/* LBAND or everything higher than UHF */
-	{1600000, 1},
-	{2000000, 3},
-	{0xffffffff, 7},
+    {     180000, 0 }, /* VHF */
+    {     188000, 1 },
+    {     196400, 2 },
+    {     250000, 3 },
+    {     550000, 0 }, /* UHF */
+    {     590000, 1 },
+    {     666000, 3 },
+    {     864000, 5 },
+    {    1500000, 0 }, /* LBAND or everything higher than UHF */
+    {    1600000, 1 },
+    {    2000000, 3 },
+    { 0xffffffff, 7 },
 };
 
 static const struct dib0070_lna_match dib0070_lna[] = {
-	{180000, 0},		/* VHF */
-	{188000, 1},
-	{196400, 2},
-	{250000, 3},
-	{550000, 2},		/* UHF */
-	{650000, 3},
-	{750000, 5},
-	{850000, 6},
-	{864000, 7},
-	{1500000, 0},		/* LBAND or everything higher than UHF */
-	{1600000, 1},
-	{2000000, 3},
-	{0xffffffff, 7},
+    {     180000, 0 }, /* VHF */
+    {     188000, 1 },
+    {     196400, 2 },
+    {     250000, 3 },
+    {     550000, 2 }, /* UHF */
+    {     650000, 3 },
+    {     750000, 5 },
+    {     850000, 6 },
+    {     864000, 7 },
+    {    1500000, 0 }, /* LBAND or everything higher than UHF */
+    {    1600000, 1 },
+    {    2000000, 3 },
+    { 0xffffffff, 7 },
 };
 
-#define LPF	100		// define for the loop filter 100kHz by default 16-07-06
+#define LPF	100
 static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
 {
-	struct dib0070_state *state = fe->tuner_priv;
+    struct dib0070_state *state = fe->tuner_priv;
 
-	const struct dib0070_tuning *tune;
-	const struct dib0070_lna_match *lna_match;
+    const struct dib0070_tuning *tune;
+    const struct dib0070_lna_match *lna_match;
 
-	enum frontend_tune_state *tune_state = &state->tune_state;
-	int ret = 10;		/* 1ms is the default delay most of the time */
+    enum frontend_tune_state *tune_state = &state->tune_state;
+    int ret = 10; /* 1ms is the default delay most of the time */
 
-	u8 band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000);
-	u32 freq = fe->dtv_property_cache.frequency / 1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
+    u8  band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
+    u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
 
 #ifdef CONFIG_SYS_ISDBT
-	if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
+    if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
 		if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
 		     && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
 		    || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
@@ -328,172 +315,180 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par
 			&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
 			freq += 850;
 #endif
+    if (state->current_rf != freq) {
+
+	switch (state->revision) {
+	case DIB0070S_P1A:
+	    tune = dib0070s_tuning_table;
+	    lna_match = dib0070_lna;
+	    break;
+	default:
+	    tune = dib0070_tuning_table;
+	    if (state->cfg->flip_chip)
+		lna_match = dib0070_lna_flip_chip;
+	    else
+		lna_match = dib0070_lna;
+	    break;
+	}
+	while (freq > tune->max_freq) /* find the right one */
+	    tune++;
+	while (freq > lna_match->max_freq) /* find the right one */
+	    lna_match++;
+
+	state->current_tune_table_index = tune;
+	state->lna_match = lna_match;
+    }
+
+    if (*tune_state == CT_TUNER_START) {
+	dprintk("Tuning for Band: %hd (%d kHz)", band, freq);
 	if (state->current_rf != freq) {
+		u8 REFDIV;
+		u32 FBDiv, Rest, FREF, VCOF_kHz;
+		u8 Den;
+
+		state->current_rf = freq;
+		state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
+
+
+		dib0070_write_reg(state, 0x17, 0x30);
+
+
+		VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
+
+		switch (band) {
+		case BAND_VHF:
+			REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
+			break;
+		case BAND_FM:
+			REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
+			break;
+		default:
+			REFDIV = (u8) (state->cfg->clock_khz  / 10000);
+			break;
+		}
+		FREF = state->cfg->clock_khz / REFDIV;
+
+
 
 		switch (state->revision) {
 		case DIB0070S_P1A:
-			tune = dib0070s_tuning_table;
-			lna_match = dib0070_lna;
+			FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
+			Rest  = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
 			break;
+
+		case DIB0070_P1G:
+		case DIB0070_P1F:
 		default:
-			tune = dib0070_tuning_table;
-			if (state->cfg->flip_chip)
-				lna_match = dib0070_lna_flip_chip;
-			else
-				lna_match = dib0070_lna;
+			FBDiv = (freq / (FREF / 2));
+			Rest  = 2 * freq - FBDiv * FREF;
 			break;
 		}
-		while (freq > tune->max_freq)	/* find the right one */
-			tune++;
-		while (freq > lna_match->max_freq)	/* find the right one */
-			lna_match++;
 
-		state->current_tune_table_index = tune;
-		state->lna_match = lna_match;
-	}
+		if (Rest < LPF)
+			Rest = 0;
+		else if (Rest < 2 * LPF)
+			Rest = 2 * LPF;
+		else if (Rest > (FREF - LPF)) {
+			Rest = 0;
+			FBDiv += 1;
+		} else if (Rest > (FREF - 2 * LPF))
+			Rest = FREF - 2 * LPF;
+		Rest = (Rest * 6528) / (FREF / 10);
+
+		Den = 1;
+		if (Rest > 0) {
+			state->lo4 |= (1 << 14) | (1 << 12);
+			Den = 255;
+		}
+
 
-	if (*tune_state == CT_TUNER_START) {
-		dprintk("Tuning for Band: %hd (%d kHz)", band, freq);
-		if (state->current_rf != freq) {
-			u8 REFDIV;
-			u32 FBDiv, Rest, FREF, VCOF_kHz;
-			u8 Den;
-
-			state->current_rf = freq;
-			state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
-
-			dib0070_write_reg(state, 0x17, 0x30);
-
-			VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
-
-			switch (band) {
-			case BAND_VHF:
-				REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
-				break;
-			case BAND_FM:
-				REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
-				break;
-			default:
-				REFDIV = (u8) (state->cfg->clock_khz / 10000);
-				break;
-			}
-			FREF = state->cfg->clock_khz / REFDIV;
-
-			switch (state->revision) {
-			case DIB0070S_P1A:
-				FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
-				Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
-				break;
-
-			case DIB0070_P1G:
-			case DIB0070_P1F:
-			default:
-				FBDiv = (freq / (FREF / 2));
-				Rest = 2 * freq - FBDiv * FREF;
-				break;
-			}
-
-			if (Rest < LPF)
-				Rest = 0;
-			else if (Rest < 2 * LPF)
-				Rest = 2 * LPF;
-			else if (Rest > (FREF - LPF)) {
-				Rest = 0;
-				FBDiv += 1;
-			} else if (Rest > (FREF - 2 * LPF))
-				Rest = FREF - 2 * LPF;
-			Rest = (Rest * 6528) / (FREF / 10);
-
-			Den = 1;
-			if (Rest > 0) {
-				state->lo4 |= (1 << 14) | (1 << 12);
-				Den = 255;
-			}
-
-			dib0070_write_reg(state, 0x11, (u16) FBDiv);
-			dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
-			dib0070_write_reg(state, 0x13, (u16) Rest);
-
-			if (state->revision == DIB0070S_P1A) {
-
-				if (band == BAND_SBAND) {
-					dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
-					dib0070_write_reg(state, 0x1d, 0xFFFF);
-				} else
-					dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
-			}
-
-			dib0070_write_reg(state, 0x20,
-					  0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
-
-			dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF);
-			dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest);
-			dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
-			dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv);
-			dprintk("VCO = %hd", state->current_tune_table_index->vco_band);
-			dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq);
-
-			*tune_state = CT_TUNER_STEP_0;
-		} else {	/* we are already tuned to this frequency - the configuration is correct  */
-			ret = 50;	/* wakeup time */
-			*tune_state = CT_TUNER_STEP_5;
+		dib0070_write_reg(state, 0x11, (u16)FBDiv);
+		dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
+		dib0070_write_reg(state, 0x13, (u16) Rest);
+
+		if (state->revision == DIB0070S_P1A) {
+
+			if (band == BAND_SBAND) {
+				dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
+				dib0070_write_reg(state, 0x1d, 0xFFFF);
+			} else
+				dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
 		}
-	} else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
 
-		ret = dib0070_captrim(state, tune_state);
+		dib0070_write_reg(state, 0x20,
+			0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
 
-	} else if (*tune_state == CT_TUNER_STEP_4) {
-		const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
-		if (tmp != NULL) {
-			while (freq / 1000 > tmp->freq)	/* find the right one */
-				tmp++;
-			dib0070_write_reg(state, 0x0f,
-					  (0 << 15) | (1 << 14) | (3 << 12) | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) | (state->
-																current_tune_table_index->
-																wbdmux << 0));
-			state->wbd_gain_current = tmp->wbd_gain_val;
-		} else {
+		dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF);
+		dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest);
+		dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
+		dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv);
+		dprintk("VCO = %hd", state->current_tune_table_index->vco_band);
+		dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq);
+
+		*tune_state = CT_TUNER_STEP_0;
+	} else { /* we are already tuned to this frequency - the configuration is correct  */
+		ret = 50; /* wakeup time */
+		*tune_state = CT_TUNER_STEP_5;
+	}
+    } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
+
+	ret = dib0070_captrim(state, tune_state);
+
+    } else if (*tune_state == CT_TUNER_STEP_4) {
+	const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
+	if (tmp != NULL) {
+		while (freq/1000 > tmp->freq) /* find the right one */
+			tmp++;
+		dib0070_write_reg(state, 0x0f,
+			(0 << 15) | (1 << 14) | (3 << 12)
+			| (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
+			| (state->current_tune_table_index->wbdmux << 0));
+		state->wbd_gain_current = tmp->wbd_gain_val;
+	} else {
 			dib0070_write_reg(state, 0x0f,
 					  (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index->
 														wbdmux << 0));
-			state->wbd_gain_current = 6;
-		}
+	    state->wbd_gain_current = 6;
+	}
 
-		dib0070_write_reg(state, 0x06, 0x3fff);
+	dib0070_write_reg(state, 0x06, 0x3fff);
 		dib0070_write_reg(state, 0x07,
 				  (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
-		dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
-		dib0070_write_reg(state, 0x0d, 0x0d80);
+	dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
+	dib0070_write_reg(state, 0x0d, 0x0d80);
 
-		dib0070_write_reg(state, 0x18, 0x07ff);
-		dib0070_write_reg(state, 0x17, 0x0033);
 
-		*tune_state = CT_TUNER_STEP_5;
-	} else if (*tune_state == CT_TUNER_STEP_5) {
-		dib0070_set_bandwidth(fe, ch);
-		*tune_state = CT_TUNER_STOP;
-	} else {
-		ret = FE_CALLBACK_TIME_NEVER;	/* tuner finished, time to call again infinite */
-	}
-	return ret;
+	dib0070_write_reg(state, 0x18,   0x07ff);
+	dib0070_write_reg(state, 0x17, 0x0033);
+
+
+	*tune_state = CT_TUNER_STEP_5;
+    } else if (*tune_state == CT_TUNER_STEP_5) {
+	dib0070_set_bandwidth(fe, ch);
+	*tune_state = CT_TUNER_STOP;
+    } else {
+	ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
+    }
+    return ret;
 }
 
+
 static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
 {
-	struct dib0070_state *state = fe->tuner_priv;
-	uint32_t ret;
+    struct dib0070_state *state = fe->tuner_priv;
+    uint32_t ret;
 
-	state->tune_state = CT_TUNER_START;
+    state->tune_state = CT_TUNER_START;
 
-	do {
-		ret = dib0070_tune_digital(fe, p);
-		if (ret != FE_CALLBACK_TIME_NEVER)
-			msleep(ret / 10);
-		else
-			break;
-	} while (state->tune_state != CT_TUNER_STOP);
+    do {
+	ret = dib0070_tune_digital(fe, p);
+	if (ret != FE_CALLBACK_TIME_NEVER)
+		msleep(ret/10);
+	else
+	    break;
+    } while (state->tune_state != CT_TUNER_STOP);
 
-	return 0;
+    return 0;
 }
 
 static int dib0070_wakeup(struct dvb_frontend *fe)
@@ -512,92 +507,113 @@ static int dib0070_sleep(struct dvb_frontend *fe)
 	return 0;
 }
 
-static const u16 dib0070_p1f_defaults[] = {
+u8 dib0070_get_rf_output(struct dvb_frontend *fe)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+	return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
+}
+EXPORT_SYMBOL(dib0070_get_rf_output);
+
+int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+	u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
+	if (no > 3)
+		no = 3;
+	if (no < 1)
+		no = 1;
+	return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
+}
+EXPORT_SYMBOL(dib0070_set_rf_output);
+
+static const u16 dib0070_p1f_defaults[] =
+
+{
 	7, 0x02,
-	0x0008,
-	0x0000,
-	0x0000,
-	0x0000,
-	0x0000,
-	0x0002,
-	0x0100,
+		0x0008,
+		0x0000,
+		0x0000,
+		0x0000,
+		0x0000,
+		0x0002,
+		0x0100,
 
 	3, 0x0d,
-	0x0d80,
-	0x0001,
-	0x0000,
+		0x0d80,
+		0x0001,
+		0x0000,
 
 	4, 0x11,
-	0x0000,
-	0x0103,
-	0x0000,
-	0x0000,
+		0x0000,
+		0x0103,
+		0x0000,
+		0x0000,
 
 	3, 0x16,
-	0x0004 | 0x0040,
-	0x0030,
-	0x07ff,
+		0x0004 | 0x0040,
+		0x0030,
+		0x07ff,
 
 	6, 0x1b,
-	0x4112,
-	0xff00,
-	0xc07f,
-	0x0000,
-	0x0180,
-	0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
+		0x4112,
+		0xff00,
+		0xc07f,
+		0x0000,
+		0x0180,
+		0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
 
 	0,
 };
 
 static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
 {
-	u16 tuner_en = dib0070_read_reg(state, 0x20);
-	u16 offset;
-
-	dib0070_write_reg(state, 0x18, 0x07ff);
-	dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
-	dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
-	msleep(9);
-	offset = dib0070_read_reg(state, 0x19);
-	dib0070_write_reg(state, 0x20, tuner_en);
-	return offset;
+    u16 tuner_en = dib0070_read_reg(state, 0x20);
+    u16 offset;
+
+    dib0070_write_reg(state, 0x18, 0x07ff);
+    dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
+    dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
+    msleep(9);
+    offset = dib0070_read_reg(state, 0x19);
+    dib0070_write_reg(state, 0x20, tuner_en);
+    return offset;
 }
 
 static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
 {
-	u8 gain;
-	for (gain = 6; gain < 8; gain++) {
-		state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
-		dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain - 6]);
-	}
+    u8 gain;
+    for (gain = 6; gain < 8; gain++) {
+	state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
+	dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]);
+    }
 }
 
 u16 dib0070_wbd_offset(struct dvb_frontend *fe)
 {
-	struct dib0070_state *state = fe->tuner_priv;
-	const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
-	u32 freq = fe->dtv_property_cache.frequency / 1000;
-
-	if (tmp != NULL) {
-		while (freq / 1000 > tmp->freq)	/* find the right one */
-			tmp++;
-		state->wbd_gain_current = tmp->wbd_gain_val;
+    struct dib0070_state *state = fe->tuner_priv;
+    const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
+    u32 freq = fe->dtv_property_cache.frequency/1000;
+
+    if (tmp != NULL) {
+	while (freq/1000 > tmp->freq) /* find the right one */
+	    tmp++;
+	state->wbd_gain_current = tmp->wbd_gain_val;
 	} else
-		state->wbd_gain_current = 6;
+	state->wbd_gain_current = 6;
 
-	return state->wbd_offset_3_3[state->wbd_gain_current - 6];
+    return state->wbd_offset_3_3[state->wbd_gain_current - 6];
 }
-
 EXPORT_SYMBOL(dib0070_wbd_offset);
 
 #define pgm_read_word(w) (*w)
 static int dib0070_reset(struct dvb_frontend *fe)
 {
-	struct dib0070_state *state = fe->tuner_priv;
+    struct dib0070_state *state = fe->tuner_priv;
 	u16 l, r, *n;
 
 	HARD_RESET(state);
 
+
 #ifndef FORCE_SBAND_TUNER
 	if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
 		state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
@@ -605,7 +621,7 @@ static int dib0070_reset(struct dvb_frontend *fe)
 #else
 #warning forcing SBAND
 #endif
-	state->revision = DIB0070S_P1A;
+		state->revision = DIB0070S_P1A;
 
 	/* P1F or not */
 	dprintk("Revision: %x", state->revision);
@@ -620,7 +636,7 @@ static int dib0070_reset(struct dvb_frontend *fe)
 	while (l) {
 		r = pgm_read_word(n++);
 		do {
-			dib0070_write_reg(state, (u8) r, pgm_read_word(n++));
+			dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
 			r++;
 		} while (--l);
 		l = pgm_read_word(n++);
@@ -633,6 +649,7 @@ static int dib0070_reset(struct dvb_frontend *fe)
 	else
 		r = 2;
 
+
 	r |= state->cfg->osc_buffer_state << 3;
 
 	dib0070_write_reg(state, 0x10, r);
@@ -643,16 +660,24 @@ static int dib0070_reset(struct dvb_frontend *fe)
 		dib0070_write_reg(state, 0x02, r | (1 << 5));
 	}
 
-	if (state->revision == DIB0070S_P1A)
-		dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
-	else
+    if (state->revision == DIB0070S_P1A)
+	dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
+    else
 		dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter);
 
 	dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
 
-	dib0070_wbd_offset_calibration(state);
+    dib0070_wbd_offset_calibration(state);
 
-	return 0;
+    return 0;
+}
+
+static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+    struct dib0070_state *state = fe->tuner_priv;
+
+    *frequency = 1000 * state->current_rf;
+    return 0;
 }
 
 static int dib0070_release(struct dvb_frontend *fe)
@@ -664,18 +689,18 @@ static int dib0070_release(struct dvb_frontend *fe)
 
 static const struct dvb_tuner_ops dib0070_ops = {
 	.info = {
-		 .name = "DiBcom DiB0070",
-		 .frequency_min = 45000000,
-		 .frequency_max = 860000000,
-		 .frequency_step = 1000,
-		 },
-	.release = dib0070_release,
-
-	.init = dib0070_wakeup,
-	.sleep = dib0070_sleep,
-	.set_params = dib0070_tune,
-
-//      .get_frequency = dib0070_get_frequency,
+		.name           = "DiBcom DiB0070",
+		.frequency_min  =  45000000,
+		.frequency_max  = 860000000,
+		.frequency_step =      1000,
+	},
+	.release       = dib0070_release,
+
+	.init          = dib0070_wakeup,
+	.sleep         = dib0070_sleep,
+	.set_params    = dib0070_tune,
+
+	.get_frequency = dib0070_get_frequency,
 //      .get_bandwidth = dib0070_get_bandwidth
 };
 
@@ -687,7 +712,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
 
 	state->cfg = cfg;
 	state->i2c = i2c;
-	state->fe = fe;
+	state->fe  = fe;
 	fe->tuner_priv = state;
 
 	if (dib0070_reset(fe) != 0)
@@ -699,12 +724,11 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
 	fe->tuner_priv = state;
 	return fe;
 
- free_mem:
+free_mem:
 	kfree(state);
 	fe->tuner_priv = NULL;
 	return NULL;
 }
-
 EXPORT_SYMBOL(dib0070_attach);
 
 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");

+ 3 - 1
drivers/media/dvb/frontends/dib0070.h

@@ -52,6 +52,8 @@ struct dib0070_config {
 extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
 extern u16 dib0070_wbd_offset(struct dvb_frontend *);
 extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open);
+extern u8 dib0070_get_rf_output(struct dvb_frontend *fe);
+extern int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no);
 #else
 static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
 {
@@ -62,7 +64,7 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struc
 static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
+	return 0;
 }
 
 static inline void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)

+ 1522 - 0
drivers/media/dvb/frontends/dib0090.c

@@ -0,0 +1,1522 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, 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.
+ *
+ *
+ * This code is more or less generated from another driver, please
+ * excuse some codingstyle oddities.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib0090.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { \
+	if (debug) { \
+		printk(KERN_DEBUG "DiB0090: "); \
+		printk(args); \
+		printk("\n"); \
+	} \
+} while (0)
+
+#define CONFIG_SYS_ISDBT
+#define CONFIG_BAND_CBAND
+#define CONFIG_BAND_VHF
+#define CONFIG_BAND_UHF
+#define CONFIG_DIB0090_USE_PWM_AGC
+
+#define EN_LNA0      0x8000
+#define EN_LNA1      0x4000
+#define EN_LNA2      0x2000
+#define EN_LNA3      0x1000
+#define EN_MIX0      0x0800
+#define EN_MIX1      0x0400
+#define EN_MIX2      0x0200
+#define EN_MIX3      0x0100
+#define EN_IQADC     0x0040
+#define EN_PLL       0x0020
+#define EN_TX        0x0010
+#define EN_BB        0x0008
+#define EN_LO        0x0004
+#define EN_BIAS      0x0001
+
+#define EN_IQANA     0x0002
+#define EN_DIGCLK    0x0080	/* not in the 0x24 reg, only in 0x1b */
+#define EN_CRYSTAL   0x0002
+
+#define EN_UHF		 0x22E9
+#define EN_VHF		 0x44E9
+#define EN_LBD		 0x11E9
+#define EN_SBD		 0x44E9
+#define EN_CAB		 0x88E9
+
+#define pgm_read_word(w) (*w)
+
+struct dc_calibration;
+
+struct dib0090_tuning {
+	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
+	u8 switch_trim;
+	u8 lna_tune;
+	u8 lna_bias;
+	u16 v2i;
+	u16 mix;
+	u16 load;
+	u16 tuner_enable;
+};
+
+struct dib0090_pll {
+	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
+	u8 vco_band;
+	u8 hfdiv_code;
+	u8 hfdiv;
+	u8 topresc;
+};
+
+struct dib0090_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe;
+	const struct dib0090_config *config;
+
+	u8 current_band;
+	u16 revision;
+	enum frontend_tune_state tune_state;
+	u32 current_rf;
+
+	u16 wbd_offset;
+	s16 wbd_target;		/* in dB */
+
+	s16 rf_gain_limit;	/* take-over-point: where to split between bb and rf gain */
+	s16 current_gain;	/* keeps the currently programmed gain */
+	u8 agc_step;		/* new binary search */
+
+	u16 gain[2];		/* for channel monitoring */
+
+	const u16 *rf_ramp;
+	const u16 *bb_ramp;
+
+	/* for the software AGC ramps */
+	u16 bb_1_def;
+	u16 rf_lt_def;
+	u16 gain_reg[4];
+
+	/* for the captrim/dc-offset search */
+	s8 step;
+	s16 adc_diff;
+	s16 min_adc_diff;
+
+	s8 captrim;
+	s8 fcaptrim;
+
+	const struct dc_calibration *dc;
+	u16 bb6, bb7;
+
+	const struct dib0090_tuning *current_tune_table_index;
+	const struct dib0090_pll *current_pll_table_index;
+
+	u8 tuner_is_tuned;
+	u8 agc_freeze;
+
+	u8 reset;
+};
+
+static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
+{
+	u8 b[2];
+	struct i2c_msg msg[2] = {
+		{.addr = state->config->i2c_address, .flags = 0, .buf = &reg, .len = 1},
+		{.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2},
+	};
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "DiB0090 I2C read failed\n");
+		return 0;
+	}
+	return (b[0] << 8) | b[1];
+}
+
+static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
+{
+	u8 b[3] = { reg & 0xff, val >> 8, val & 0xff };
+	struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 };
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "DiB0090 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+#define HARD_RESET(state) do {  if (cfg->reset) {  if (cfg->sleep) cfg->sleep(fe, 0); msleep(10);  cfg->reset(fe, 1); msleep(10);  cfg->reset(fe, 0); msleep(10);  }  } while (0)
+#define ADC_TARGET -220
+#define GAIN_ALPHA 5
+#define WBD_ALPHA 6
+#define LPF	100
+static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
+{
+	do {
+		dib0090_write_reg(state, r++, *b++);
+	} while (--c);
+}
+
+static u16 dib0090_identify(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	u16 v;
+
+	v = dib0090_read_reg(state, 0x1a);
+
+#ifdef FIRMWARE_FIREFLY
+	/* pll is not locked locked */
+	if (!(v & 0x800))
+		dprintk("FE%d : Identification : pll is not yet locked", fe->id);
+#endif
+
+	/* without PLL lock info */
+	v &= 0x3ff;
+	dprintk("P/V: %04x:", v);
+
+	if ((v >> 8) & 0xf)
+		dprintk("FE%d : Product ID = 0x%x : KROSUS", fe->id, (v >> 8) & 0xf);
+	else
+		return 0xff;
+
+	v &= 0xff;
+	if (((v >> 5) & 0x7) == 0x1)
+		dprintk("FE%d : MP001 : 9090/8096", fe->id);
+	else if (((v >> 5) & 0x7) == 0x4)
+		dprintk("FE%d : MP005 : Single Sband", fe->id);
+	else if (((v >> 5) & 0x7) == 0x6)
+		dprintk("FE%d : MP008 : diversity VHF-UHF-LBAND", fe->id);
+	else if (((v >> 5) & 0x7) == 0x7)
+		dprintk("FE%d : MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND", fe->id);
+	else
+		return 0xff;
+
+	/* revision only */
+	if ((v & 0x1f) == 0x3)
+		dprintk("FE%d : P1-D/E/F detected", fe->id);
+	else if ((v & 0x1f) == 0x1)
+		dprintk("FE%d : P1C detected", fe->id);
+	else if ((v & 0x1f) == 0x0) {
+#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
+		dprintk("FE%d : P1-A/B detected: using previous driver - support will be removed soon", fe->id);
+		dib0090_p1b_register(fe);
+#else
+		dprintk("FE%d : P1-A/B detected: driver is deactivated - not available", fe->id);
+		return 0xff;
+#endif
+	}
+
+	return v;
+}
+
+static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	HARD_RESET(state);
+
+	dib0090_write_reg(state, 0x24, EN_PLL);
+	dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL);	/* PLL, DIG_CLK and CRYSTAL remain */
+
+	/* adcClkOutRatio=8->7, release reset */
+	dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
+	if (cfg->clkoutdrive != 0)
+		dib0090_write_reg(state, 0x23,
+				  (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (cfg->clkoutdrive << 5) | (cfg->
+																	   clkouttobamse
+																	   << 4) | (0
+																		    <<
+																		    2)
+				  | (0));
+	else
+		dib0090_write_reg(state, 0x23,
+				  (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (7 << 5) | (cfg->
+															    clkouttobamse << 4) | (0
+																		   <<
+																		   2)
+				  | (0));
+
+	/* enable pll, de-activate reset, ratio: 2/1 = 60MHz */
+	dib0090_write_reg(state, 0x21,
+			  (cfg->io.pll_bypass << 15) | (1 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv));
+
+}
+
+static int dib0090_wakeup(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	if (state->config->sleep)
+		state->config->sleep(fe, 0);
+	return 0;
+}
+
+static int dib0090_sleep(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	if (state->config->sleep)
+		state->config->sleep(fe, 1);
+	return 0;
+}
+
+extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	if (fast)
+		dib0090_write_reg(state, 0x04, 0);
+	else
+		dib0090_write_reg(state, 0x04, 1);
+}
+EXPORT_SYMBOL(dib0090_dcc_freq);
+
+static const u16 rf_ramp_pwm_cband[] = {
+	0,			/* max RF gain in 10th of dB */
+	0,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
+	0,			/* ramp_max = maximum X used on the ramp */
+	(0 << 10) | 0,		/* 0x2c, LNA 1 = 0dB */
+	(0 << 10) | 0,		/* 0x2d, LNA 1 */
+	(0 << 10) | 0,		/* 0x2e, LNA 2 = 0dB */
+	(0 << 10) | 0,		/* 0x2f, LNA 2 */
+	(0 << 10) | 0,		/* 0x30, LNA 3 = 0dB */
+	(0 << 10) | 0,		/* 0x31, LNA 3 */
+	(0 << 10) | 0,		/* GAIN_4_1, LNA 4 = 0dB */
+	(0 << 10) | 0,		/* GAIN_4_2, LNA 4 */
+};
+
+static const u16 rf_ramp_vhf[] = {
+	412,			/* max RF gain in 10th of dB */
+	132, 307, 127,		/* LNA1,  13.2dB */
+	105, 412, 255,		/* LNA2,  10.5dB */
+	50, 50, 127,		/* LNA3,  5dB */
+	125, 175, 127,		/* LNA4,  12.5dB */
+	0, 0, 127,		/* CBAND, 0dB */
+};
+
+static const u16 rf_ramp_uhf[] = {
+	412,			/* max RF gain in 10th of dB */
+	132, 307, 127,		/* LNA1  : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */
+	105, 412, 255,		/* LNA2  : 10.5 dB */
+	50, 50, 127,		/* LNA3  :  5.0 dB */
+	125, 175, 127,		/* LNA4  : 12.5 dB */
+	0, 0, 127,		/* CBAND :  0.0 dB */
+};
+
+static const u16 rf_ramp_cband[] = {
+	332,			/* max RF gain in 10th of dB */
+	132, 252, 127,		/* LNA1,  dB */
+	80, 332, 255,		/* LNA2,  dB */
+	0, 0, 127,		/* LNA3,  dB */
+	0, 0, 127,		/* LNA4,  dB */
+	120, 120, 127,		/* LT1 CBAND */
+};
+
+static const u16 rf_ramp_pwm_vhf[] = {
+	404,			/* max RF gain in 10th of dB */
+	25,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
+	1011,			/* ramp_max = maximum X used on the ramp */
+	(6 << 10) | 417,	/* 0x2c, LNA 1 = 13.2dB */
+	(0 << 10) | 756,	/* 0x2d, LNA 1 */
+	(16 << 10) | 756,	/* 0x2e, LNA 2 = 10.5dB */
+	(0 << 10) | 1011,	/* 0x2f, LNA 2 */
+	(16 << 10) | 290,	/* 0x30, LNA 3 = 5dB */
+	(0 << 10) | 417,	/* 0x31, LNA 3 */
+	(7 << 10) | 0,		/* GAIN_4_1, LNA 4 = 12.5dB */
+	(0 << 10) | 290,	/* GAIN_4_2, LNA 4 */
+};
+
+static const u16 rf_ramp_pwm_uhf[] = {
+	404,			/* max RF gain in 10th of dB */
+	25,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
+	1011,			/* ramp_max = maximum X used on the ramp */
+	(6 << 10) | 417,	/* 0x2c, LNA 1 = 13.2dB */
+	(0 << 10) | 756,	/* 0x2d, LNA 1 */
+	(16 << 10) | 756,	/* 0x2e, LNA 2 = 10.5dB */
+	(0 << 10) | 1011,	/* 0x2f, LNA 2 */
+	(16 << 10) | 0,		/* 0x30, LNA 3 = 5dB */
+	(0 << 10) | 127,	/* 0x31, LNA 3 */
+	(7 << 10) | 127,	/* GAIN_4_1, LNA 4 = 12.5dB */
+	(0 << 10) | 417,	/* GAIN_4_2, LNA 4 */
+};
+
+static const u16 bb_ramp_boost[] = {
+	550,			/* max BB gain in 10th of dB */
+	260, 260, 26,		/* BB1, 26dB */
+	290, 550, 29,		/* BB2, 29dB */
+};
+
+static const u16 bb_ramp_pwm_normal[] = {
+	500,			/* max RF gain in 10th of dB */
+	8,			/* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
+	400,
+	(2 << 9) | 0,		/* 0x35 = 21dB */
+	(0 << 9) | 168,		/* 0x36 */
+	(2 << 9) | 168,		/* 0x37 = 29dB */
+	(0 << 9) | 400,		/* 0x38 */
+};
+
+struct slope {
+	int16_t range;
+	int16_t slope;
+};
+static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
+{
+	u8 i;
+	u16 rest;
+	u16 ret = 0;
+	for (i = 0; i < num; i++) {
+		if (val > slopes[i].range)
+			rest = slopes[i].range;
+		else
+			rest = val;
+		ret += (rest * slopes[i].slope) / slopes[i].range;
+		val -= rest;
+	}
+	return ret;
+}
+
+static const struct slope dib0090_wbd_slopes[3] = {
+	{66, 120},		/* -64,-52: offset -   65 */
+	{600, 170},		/* -52,-35: 65     -  665 */
+	{170, 250},		/* -45,-10: 665    - 835 */
+};
+
+static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
+{
+	wbd &= 0x3ff;
+	if (wbd < state->wbd_offset)
+		wbd = 0;
+	else
+		wbd -= state->wbd_offset;
+	/* -64dB is the floor */
+	return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
+}
+
+static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
+{
+	u16 offset = 250;
+
+	/* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
+
+	if (state->current_band == BAND_VHF)
+		offset = 650;
+#ifndef FIRMWARE_FIREFLY
+	if (state->current_band == BAND_VHF)
+		offset = state->config->wbd_vhf_offset;
+	if (state->current_band == BAND_CBAND)
+		offset = state->config->wbd_cband_offset;
+#endif
+
+	state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
+	dprintk("wbd-target: %d dB", (u32) state->wbd_target);
+}
+
+static const int gain_reg_addr[4] = {
+	0x08, 0x0a, 0x0f, 0x01
+};
+
+static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
+{
+	u16 rf, bb, ref;
+	u16 i, v, gain_reg[4] = { 0 }, gain;
+	const u16 *g;
+
+	if (top_delta < -511)
+		top_delta = -511;
+	if (top_delta > 511)
+		top_delta = 511;
+
+	if (force) {
+		top_delta *= (1 << WBD_ALPHA);
+		gain_delta *= (1 << GAIN_ALPHA);
+	}
+
+	if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit))	/* overflow */
+		state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
+	else
+		state->rf_gain_limit += top_delta;
+
+	if (state->rf_gain_limit < 0)	/*underflow */
+		state->rf_gain_limit = 0;
+
+	/* use gain as a temporary variable and correct current_gain */
+	gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
+	if (gain_delta >= ((s16) gain - state->current_gain))	/* overflow */
+		state->current_gain = gain;
+	else
+		state->current_gain += gain_delta;
+	/* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
+	if (state->current_gain < 0)
+		state->current_gain = 0;
+
+	/* now split total gain to rf and bb gain */
+	gain = state->current_gain >> GAIN_ALPHA;
+
+	/* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
+	if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
+		rf = state->rf_gain_limit >> WBD_ALPHA;
+		bb = gain - rf;
+		if (bb > state->bb_ramp[0])
+			bb = state->bb_ramp[0];
+	} else {		/* high signal level -> all gains put on RF */
+		rf = gain;
+		bb = 0;
+	}
+
+	state->gain[0] = rf;
+	state->gain[1] = bb;
+
+	/* software ramp */
+	/* Start with RF gains */
+	g = state->rf_ramp + 1;	/* point on RF LNA1 max gain */
+	ref = rf;
+	for (i = 0; i < 7; i++) {	/* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
+		if (g[0] == 0 || ref < (g[1] - g[0]))	/* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */
+			v = 0;	/* force the gain to write for the current amp to be null */
+		else if (ref >= g[1])	/* Gain to set is higher than the high working point of this amp */
+			v = g[2];	/* force this amp to be full gain */
+		else		/* compute the value to set to this amp because we are somewhere in his range */
+			v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
+
+		if (i == 0)	/* LNA 1 reg mapping */
+			gain_reg[0] = v;
+		else if (i == 1)	/* LNA 2 reg mapping */
+			gain_reg[0] |= v << 7;
+		else if (i == 2)	/* LNA 3 reg mapping */
+			gain_reg[1] = v;
+		else if (i == 3)	/* LNA 4 reg mapping */
+			gain_reg[1] |= v << 7;
+		else if (i == 4)	/* CBAND LNA reg mapping */
+			gain_reg[2] = v | state->rf_lt_def;
+		else if (i == 5)	/* BB gain 1 reg mapping */
+			gain_reg[3] = v << 3;
+		else if (i == 6)	/* BB gain 2 reg mapping */
+			gain_reg[3] |= v << 8;
+
+		g += 3;		/* go to next gain bloc */
+
+		/* When RF is finished, start with BB */
+		if (i == 4) {
+			g = state->bb_ramp + 1;	/* point on BB gain 1 max gain */
+			ref = bb;
+		}
+	}
+	gain_reg[3] |= state->bb_1_def;
+	gain_reg[3] |= ((bb % 10) * 100) / 125;
+
+#ifdef DEBUG_AGC
+	dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb,
+		gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
+#endif
+
+	/* Write the amplifier regs */
+	for (i = 0; i < 4; i++) {
+		v = gain_reg[i];
+		if (force || state->gain_reg[i] != v) {
+			state->gain_reg[i] = v;
+			dib0090_write_reg(state, gain_reg_addr[i], v);
+		}
+	}
+}
+
+static void dib0090_set_boost(struct dib0090_state *state, int onoff)
+{
+	state->bb_1_def &= 0xdfff;
+	state->bb_1_def |= onoff << 13;
+}
+
+static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
+{
+	state->rf_ramp = cfg;
+}
+
+static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
+{
+	state->rf_ramp = cfg;
+
+	dib0090_write_reg(state, 0x2a, 0xffff);
+
+	dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
+
+	dib0090_write_regs(state, 0x2c, cfg + 3, 6);
+	dib0090_write_regs(state, 0x3e, cfg + 9, 2);
+}
+
+static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
+{
+	state->bb_ramp = cfg;
+	dib0090_set_boost(state, cfg[0] > 500);	/* we want the boost if the gain is higher that 50dB */
+}
+
+static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
+{
+	state->bb_ramp = cfg;
+
+	dib0090_set_boost(state, cfg[0] > 500);	/* we want the boost if the gain is higher that 50dB */
+
+	dib0090_write_reg(state, 0x33, 0xffff);
+	dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
+	dib0090_write_regs(state, 0x35, cfg + 3, 4);
+}
+
+void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	/* reset the AGC */
+
+	if (state->config->use_pwm_agc) {
+#ifdef CONFIG_BAND_SBAND
+		if (state->current_band == BAND_SBAND) {
+			dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
+			dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
+		} else
+#endif
+#ifdef CONFIG_BAND_CBAND
+		if (state->current_band == BAND_CBAND) {
+			dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
+			dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+		} else
+#endif
+#ifdef CONFIG_BAND_VHF
+		if (state->current_band == BAND_VHF) {
+			dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
+			dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+		} else
+#endif
+		{
+			dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
+			dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+		}
+
+		if (state->rf_ramp[0] != 0)
+			dib0090_write_reg(state, 0x32, (3 << 11));
+		else
+			dib0090_write_reg(state, 0x32, (0 << 11));
+
+		dib0090_write_reg(state, 0x39, (1 << 10));
+	}
+}
+EXPORT_SYMBOL(dib0090_pwm_gain_reset);
+
+int dib0090_gain_control(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	enum frontend_tune_state *tune_state = &state->tune_state;
+	int ret = 10;
+
+	u16 wbd_val = 0;
+	u8 apply_gain_immediatly = 1;
+	s16 wbd_error = 0, adc_error = 0;
+
+	if (*tune_state == CT_AGC_START) {
+		state->agc_freeze = 0;
+		dib0090_write_reg(state, 0x04, 0x0);
+
+#ifdef CONFIG_BAND_SBAND
+		if (state->current_band == BAND_SBAND) {
+			dib0090_set_rframp(state, rf_ramp_sband);
+			dib0090_set_bbramp(state, bb_ramp_boost);
+		} else
+#endif
+#ifdef CONFIG_BAND_VHF
+		if (state->current_band == BAND_VHF) {
+			dib0090_set_rframp(state, rf_ramp_vhf);
+			dib0090_set_bbramp(state, bb_ramp_boost);
+		} else
+#endif
+#ifdef CONFIG_BAND_CBAND
+		if (state->current_band == BAND_CBAND) {
+			dib0090_set_rframp(state, rf_ramp_cband);
+			dib0090_set_bbramp(state, bb_ramp_boost);
+		} else
+#endif
+		{
+			dib0090_set_rframp(state, rf_ramp_uhf);
+			dib0090_set_bbramp(state, bb_ramp_boost);
+		}
+
+		dib0090_write_reg(state, 0x32, 0);
+		dib0090_write_reg(state, 0x39, 0);
+
+		dib0090_wbd_target(state, state->current_rf);
+
+		state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
+		state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
+
+		*tune_state = CT_AGC_STEP_0;
+	} else if (!state->agc_freeze) {
+		s16 wbd;
+
+		int adc;
+		wbd_val = dib0090_read_reg(state, 0x1d);
+
+		/* read and calc the wbd power */
+		wbd = dib0090_wbd_to_db(state, wbd_val);
+		wbd_error = state->wbd_target - wbd;
+
+		if (*tune_state == CT_AGC_STEP_0) {
+			if (wbd_error < 0 && state->rf_gain_limit > 0) {
+#ifdef CONFIG_BAND_CBAND
+				/* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
+				u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
+				if (state->current_band == BAND_CBAND && ltg2) {
+					ltg2 >>= 1;
+					state->rf_lt_def &= ltg2 << 10;	/* reduce in 3 steps from 7 to 0 */
+				}
+#endif
+			} else {
+				state->agc_step = 0;
+				*tune_state = CT_AGC_STEP_1;
+			}
+		} else {
+			/* calc the adc power */
+			adc = state->config->get_adc_power(fe);
+			adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21;	/* included in [0:-700] */
+
+			adc_error = (s16) (((s32) ADC_TARGET) - adc);
+#ifdef CONFIG_STANDARD_DAB
+			if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
+				adc_error += 130;
+#endif
+#ifdef CONFIG_STANDARD_DVBT
+			if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
+			    (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
+				adc_error += 60;
+#endif
+#ifdef CONFIG_SYS_ISDBT
+			if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count >
+											       0)
+											      &&
+											      ((state->fe->dtv_property_cache.layer[0].modulation ==
+												QAM_64)
+											       || (state->fe->dtv_property_cache.layer[0].
+												   modulation == QAM_16)))
+											     ||
+											     ((state->fe->dtv_property_cache.layer[1].segment_count >
+											       0)
+											      &&
+											      ((state->fe->dtv_property_cache.layer[1].modulation ==
+												QAM_64)
+											       || (state->fe->dtv_property_cache.layer[1].
+												   modulation == QAM_16)))
+											     ||
+											     ((state->fe->dtv_property_cache.layer[2].segment_count >
+											       0)
+											      &&
+											      ((state->fe->dtv_property_cache.layer[2].modulation ==
+												QAM_64)
+											       || (state->fe->dtv_property_cache.layer[2].
+												   modulation == QAM_16)))
+			    )
+			    )
+				adc_error += 60;
+#endif
+
+			if (*tune_state == CT_AGC_STEP_1) {	/* quickly go to the correct range of the ADC power */
+				if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
+
+#ifdef CONFIG_STANDARD_DAB
+					if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
+						dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63));	/* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
+						dib0090_write_reg(state, 0x04, 0x0);
+					} else
+#endif
+					{
+						dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
+						dib0090_write_reg(state, 0x04, 0x01);	/*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
+					}
+
+					*tune_state = CT_AGC_STOP;
+				}
+			} else {
+				/* everything higher than or equal to CT_AGC_STOP means tracking */
+				ret = 100;	/* 10ms interval */
+				apply_gain_immediatly = 0;
+			}
+		}
+#ifdef DEBUG_AGC
+		dprintk
+		    ("FE: %d, tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",
+		     (u32) fe->id, (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
+		     (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
+#endif
+	}
+
+	/* apply gain */
+	if (!state->agc_freeze)
+		dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
+	return ret;
+}
+EXPORT_SYMBOL(dib0090_gain_control);
+
+void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	if (rf)
+		*rf = state->gain[0];
+	if (bb)
+		*bb = state->gain[1];
+	if (rf_gain_limit)
+		*rf_gain_limit = state->rf_gain_limit;
+	if (rflt)
+		*rflt = (state->rf_lt_def >> 10) & 0x7;
+}
+EXPORT_SYMBOL(dib0090_get_current_gain);
+
+u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner)
+{
+	struct dib0090_state *st = tuner->tuner_priv;
+	return st->wbd_offset;
+}
+EXPORT_SYMBOL(dib0090_get_wbd_offset);
+
+static const u16 dib0090_defaults[] = {
+
+	25, 0x01,
+	0x0000,
+	0x99a0,
+	0x6008,
+	0x0000,
+	0x8acb,
+	0x0000,
+	0x0405,
+	0x0000,
+	0x0000,
+	0x0000,
+	0xb802,
+	0x0300,
+	0x2d12,
+	0xbac0,
+	0x7c00,
+	0xdbb9,
+	0x0954,
+	0x0743,
+	0x8000,
+	0x0001,
+	0x0040,
+	0x0100,
+	0x0000,
+	0xe910,
+	0x149e,
+
+	1, 0x1c,
+	0xff2d,
+
+	1, 0x39,
+	0x0000,
+
+	1, 0x1b,
+	EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL,
+	2, 0x1e,
+	0x07FF,
+	0x0007,
+
+	1, 0x24,
+	EN_UHF | EN_CRYSTAL,
+
+	2, 0x3c,
+	0x3ff,
+	0x111,
+	0
+};
+
+static int dib0090_reset(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	u16 l, r, *n;
+
+	dib0090_reset_digital(fe, state->config);
+	state->revision = dib0090_identify(fe);
+
+	/* Revision definition */
+	if (state->revision == 0xff)
+		return -EINVAL;
+#ifdef EFUSE
+	else if ((state->revision & 0x1f) >= 3)	/* Update the efuse : Only available for KROSUS > P1C */
+		dib0090_set_EFUSE(state);
+#endif
+
+#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
+	if (!(state->revision & 0x1))	/* it is P1B - reset is already done */
+		return 0;
+#endif
+
+	/* Upload the default values */
+	n = (u16 *) dib0090_defaults;
+	l = pgm_read_word(n++);
+	while (l) {
+		r = pgm_read_word(n++);
+		do {
+			/* DEBUG_TUNER */
+			/* dprintk("%d, %d, %d", l, r, pgm_read_word(n)); */
+			dib0090_write_reg(state, r, pgm_read_word(n++));
+			r++;
+		} while (--l);
+		l = pgm_read_word(n++);
+	}
+
+	/* Congigure in function of the crystal */
+	if (state->config->io.clock_khz >= 24000)
+		l = 1;
+	else
+		l = 2;
+	dib0090_write_reg(state, 0x14, l);
+	dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
+
+	state->reset = 3;	/* enable iq-offset-calibration and wbd-calibration when tuning next time */
+
+	return 0;
+}
+
+#define steps(u) (((u) > 15) ? ((u)-16) : (u))
+#define INTERN_WAIT 10
+static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+	int ret = INTERN_WAIT * 10;
+
+	switch (*tune_state) {
+	case CT_TUNER_STEP_2:
+		/* Turns to positive */
+		dib0090_write_reg(state, 0x1f, 0x7);
+		*tune_state = CT_TUNER_STEP_3;
+		break;
+
+	case CT_TUNER_STEP_3:
+		state->adc_diff = dib0090_read_reg(state, 0x1d);
+
+		/* Turns to negative */
+		dib0090_write_reg(state, 0x1f, 0x4);
+		*tune_state = CT_TUNER_STEP_4;
+		break;
+
+	case CT_TUNER_STEP_4:
+		state->adc_diff -= dib0090_read_reg(state, 0x1d);
+		*tune_state = CT_TUNER_STEP_5;
+		ret = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+struct dc_calibration {
+	uint8_t addr;
+	uint8_t offset;
+	uint8_t pga:1;
+	uint16_t bb1;
+	uint8_t i:1;
+};
+
+static const struct dc_calibration dc_table[] = {
+	/* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
+	{0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
+	{0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
+	/* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
+	{0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
+	{0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
+	{0},
+};
+
+static void dib0090_set_trim(struct dib0090_state *state)
+{
+	u16 *val;
+
+	if (state->dc->addr == 0x07)
+		val = &state->bb7;
+	else
+		val = &state->bb6;
+
+	*val &= ~(0x1f << state->dc->offset);
+	*val |= state->step << state->dc->offset;
+
+	dib0090_write_reg(state, state->dc->addr, *val);
+}
+
+static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+	int ret = 0;
+
+	switch (*tune_state) {
+
+	case CT_TUNER_START:
+		/* init */
+		dprintk("Internal DC calibration");
+
+		/* the LNA is off */
+		dib0090_write_reg(state, 0x24, 0x02ed);
+
+		/* force vcm2 = 0.8V */
+		state->bb6 = 0;
+		state->bb7 = 0x040d;
+
+		state->dc = dc_table;
+
+		*tune_state = CT_TUNER_STEP_0;
+
+		/* fall through */
+
+	case CT_TUNER_STEP_0:
+		dib0090_write_reg(state, 0x01, state->dc->bb1);
+		dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
+
+		state->step = 0;
+
+		state->min_adc_diff = 1023;
+
+		*tune_state = CT_TUNER_STEP_1;
+		ret = 50;
+		break;
+
+	case CT_TUNER_STEP_1:
+		dib0090_set_trim(state);
+
+		*tune_state = CT_TUNER_STEP_2;
+		break;
+
+	case CT_TUNER_STEP_2:
+	case CT_TUNER_STEP_3:
+	case CT_TUNER_STEP_4:
+		ret = dib0090_get_offset(state, tune_state);
+		break;
+
+	case CT_TUNER_STEP_5:	/* found an offset */
+		dprintk("FE%d: IQC read=%d, current=%x", state->fe->id, (u32) state->adc_diff, state->step);
+
+		/* first turn for this frequency */
+		if (state->step == 0) {
+			if (state->dc->pga && state->adc_diff < 0)
+				state->step = 0x10;
+			if (state->dc->pga == 0 && state->adc_diff > 0)
+				state->step = 0x10;
+		}
+
+		state->adc_diff = ABS(state->adc_diff);
+
+		if (state->adc_diff < state->min_adc_diff && steps(state->step) < 15) {	/* stop search when the delta to 0 is increasing */
+			state->step++;
+			state->min_adc_diff = state->adc_diff;
+			*tune_state = CT_TUNER_STEP_1;
+		} else {
+
+			/* the minimum was what we have seen in the step before */
+			state->step--;
+			dib0090_set_trim(state);
+
+			dprintk("FE%d: BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->fe->id, state->dc->addr, state->adc_diff,
+				state->step);
+
+			state->dc++;
+			if (state->dc->addr == 0)	/* done */
+				*tune_state = CT_TUNER_STEP_6;
+			else
+				*tune_state = CT_TUNER_STEP_0;
+
+		}
+		break;
+
+	case CT_TUNER_STEP_6:
+		dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
+		dib0090_write_reg(state, 0x1f, 0x7);
+		*tune_state = CT_TUNER_START;	/* reset done -> real tuning can now begin */
+		state->reset &= ~0x1;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+	switch (*tune_state) {
+	case CT_TUNER_START:
+		/* WBD-mode=log, Bias=2, Gain=6, Testmode=1, en=1, WBDMUX=1 */
+		dib0090_write_reg(state, 0x10, 0xdb09 | (1 << 10));
+		dib0090_write_reg(state, 0x24, EN_UHF & 0x0fff);
+
+		*tune_state = CT_TUNER_STEP_0;
+		return 90;	/* wait for the WBDMUX to switch and for the ADC to sample */
+	case CT_TUNER_STEP_0:
+		state->wbd_offset = dib0090_read_reg(state, 0x1d);
+		dprintk("WBD calibration offset = %d", state->wbd_offset);
+
+		*tune_state = CT_TUNER_START;	/* reset done -> real tuning can now begin */
+		state->reset &= ~0x2;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static void dib0090_set_bandwidth(struct dib0090_state *state)
+{
+	u16 tmp;
+
+	if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
+		tmp = (3 << 14);
+	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
+		tmp = (2 << 14);
+	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
+		tmp = (1 << 14);
+	else
+		tmp = (0 << 14);
+
+	state->bb_1_def &= 0x3fff;
+	state->bb_1_def |= tmp;
+
+	dib0090_write_reg(state, 0x01, state->bb_1_def);	/* be sure that we have the right bb-filter */
+}
+
+static const struct dib0090_pll dib0090_pll_table[] = {
+#ifdef CONFIG_BAND_CBAND
+	{56000, 0, 9, 48, 6},
+	{70000, 1, 9, 48, 6},
+	{87000, 0, 8, 32, 4},
+	{105000, 1, 8, 32, 4},
+	{115000, 0, 7, 24, 6},
+	{140000, 1, 7, 24, 6},
+	{170000, 0, 6, 16, 4},
+#endif
+#ifdef CONFIG_BAND_VHF
+	{200000, 1, 6, 16, 4},
+	{230000, 0, 5, 12, 6},
+	{280000, 1, 5, 12, 6},
+	{340000, 0, 4, 8, 4},
+	{380000, 1, 4, 8, 4},
+	{450000, 0, 3, 6, 6},
+#endif
+#ifdef CONFIG_BAND_UHF
+	{580000, 1, 3, 6, 6},
+	{700000, 0, 2, 4, 4},
+	{860000, 1, 2, 4, 4},
+#endif
+#ifdef CONFIG_BAND_LBAND
+	{1800000, 1, 0, 2, 4},
+#endif
+#ifdef CONFIG_BAND_SBAND
+	{2900000, 0, 14, 1, 4},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
+
+#ifdef CONFIG_BAND_CBAND
+	{184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
+	{227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
+	{380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
+#endif
+#ifdef CONFIG_BAND_UHF
+	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+#endif
+#ifdef CONFIG_BAND_LBAND
+	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+#endif
+#ifdef CONFIG_BAND_SBAND
+	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
+	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_tuning_table[] = {
+
+#ifdef CONFIG_BAND_CBAND
+	{170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
+#endif
+#ifdef CONFIG_BAND_VHF
+	{184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+	{227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+	{380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+#endif
+#ifdef CONFIG_BAND_UHF
+	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+#endif
+#ifdef CONFIG_BAND_LBAND
+	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+#endif
+#ifdef CONFIG_BAND_SBAND
+	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
+	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
+#endif
+};
+
+#define WBD     0x781		/* 1 1 1 1 0000 0 0 1 */
+static int dib0090_tune(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	const struct dib0090_tuning *tune = state->current_tune_table_index;
+	const struct dib0090_pll *pll = state->current_pll_table_index;
+	enum frontend_tune_state *tune_state = &state->tune_state;
+
+	u32 rf;
+	u16 lo4 = 0xe900, lo5, lo6, Den;
+	u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
+	u16 tmp, adc;
+	int8_t step_sign;
+	int ret = 10;		/* 1ms is the default delay most of the time */
+	u8 c, i;
+
+	state->current_band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000);
+	rf = fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
+							BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->freq_offset_khz_vhf);
+	/* in any case we first need to do a reset if needed */
+	if (state->reset & 0x1)
+		return dib0090_dc_offset_calibration(state, tune_state);
+	else if (state->reset & 0x2)
+		return dib0090_wbd_calibration(state, tune_state);
+
+    /************************* VCO ***************************/
+	/* Default values for FG                                 */
+	/* from these are needed :                               */
+	/* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv             */
+
+#ifdef CONFIG_SYS_ISDBT
+	if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
+		rf += 850;
+#endif
+
+	if (state->current_rf != rf) {
+		state->tuner_is_tuned = 0;
+
+		tune = dib0090_tuning_table;
+
+		tmp = (state->revision >> 5) & 0x7;
+		if (tmp == 0x4 || tmp == 0x7) {
+			/* CBAND tuner version for VHF */
+			if (state->current_band == BAND_FM || state->current_band == BAND_VHF) {
+				/* Force CBAND */
+				state->current_band = BAND_CBAND;
+				tune = dib0090_tuning_table_fm_vhf_on_cband;
+			}
+		}
+
+		pll = dib0090_pll_table;
+		/* Look for the interval */
+		while (rf > tune->max_freq)
+			tune++;
+		while (rf > pll->max_freq)
+			pll++;
+		state->current_tune_table_index = tune;
+		state->current_pll_table_index = pll;
+	}
+
+	if (*tune_state == CT_TUNER_START) {
+
+		if (state->tuner_is_tuned == 0)
+			state->current_rf = 0;
+
+		if (state->current_rf != rf) {
+
+			dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
+
+			/* external loop filter, otherwise:
+			 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
+			 * lo6 = 0x0e34 */
+			if (pll->vco_band)
+				lo5 = 0x049e;
+			else if (state->config->analog_output)
+				lo5 = 0x041d;
+			else
+				lo5 = 0x041c;
+
+			lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7);	/* bit 15 is the split to the slave, we do not do it here */
+
+			if (!state->config->io.pll_int_loop_filt)
+				lo6 = 0xff28;
+			else
+				lo6 = (state->config->io.pll_int_loop_filt << 3);
+
+			VCOF_kHz = (pll->hfdiv * rf) * 2;
+
+			FREF = state->config->io.clock_khz;
+
+			FBDiv = (VCOF_kHz / pll->topresc / FREF);
+			Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
+
+			if (Rest < LPF)
+				Rest = 0;
+			else if (Rest < 2 * LPF)
+				Rest = 2 * LPF;
+			else if (Rest > (FREF - LPF)) {
+				Rest = 0;
+				FBDiv += 1;
+			} else if (Rest > (FREF - 2 * LPF))
+				Rest = FREF - 2 * LPF;
+			Rest = (Rest * 6528) / (FREF / 10);
+
+			Den = 1;
+
+			dprintk(" *****  ******* Rest value = %d", Rest);
+
+			if (Rest > 0) {
+				if (state->config->analog_output)
+					lo6 |= (1 << 2) | 2;
+				else
+					lo6 |= (1 << 2) | 1;
+				Den = 255;
+			}
+#ifdef CONFIG_BAND_SBAND
+			if (state->current_band == BAND_SBAND)
+				lo6 &= 0xfffb;
+#endif
+
+			dib0090_write_reg(state, 0x15, (u16) FBDiv);
+
+			dib0090_write_reg(state, 0x16, (Den << 8) | 1);
+
+			dib0090_write_reg(state, 0x17, (u16) Rest);
+
+			dib0090_write_reg(state, 0x19, lo5);
+
+			dib0090_write_reg(state, 0x1c, lo6);
+
+			lo6 = tune->tuner_enable;
+			if (state->config->analog_output)
+				lo6 = (lo6 & 0xff9f) | 0x2;
+
+			dib0090_write_reg(state, 0x24, lo6 | EN_LO
+#ifdef CONFIG_DIB0090_USE_PWM_AGC
+					  | state->config->use_pwm_agc * EN_CRYSTAL
+#endif
+			    );
+
+			state->current_rf = rf;
+
+			/* prepare a complete captrim */
+			state->step = state->captrim = state->fcaptrim = 64;
+
+		} else {	/* we are already tuned to this frequency - the configuration is correct  */
+
+			/* do a minimal captrim even if the frequency has not changed */
+			state->step = 4;
+			state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
+		}
+		state->adc_diff = 3000;
+
+		dib0090_write_reg(state, 0x10, 0x2B1);
+
+		dib0090_write_reg(state, 0x1e, 0x0032);
+
+		ret = 20;
+		*tune_state = CT_TUNER_STEP_1;
+	} else if (*tune_state == CT_TUNER_STEP_0) {
+		/* nothing */
+	} else if (*tune_state == CT_TUNER_STEP_1) {
+		state->step /= 2;
+		dib0090_write_reg(state, 0x18, lo4 | state->captrim);
+		*tune_state = CT_TUNER_STEP_2;
+	} else if (*tune_state == CT_TUNER_STEP_2) {
+
+		adc = dib0090_read_reg(state, 0x1d);
+		dprintk("FE %d CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) fe->id, (u32) state->captrim, (u32) adc,
+			(u32) (adc) * (u32) 1800 / (u32) 1024);
+
+		if (adc >= 400) {
+			adc -= 400;
+			step_sign = -1;
+		} else {
+			adc = 400 - adc;
+			step_sign = 1;
+		}
+
+		if (adc < state->adc_diff) {
+			dprintk("FE %d CAPTRIM=%d is closer to target (%d/%d)", (u32) fe->id, (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
+			state->adc_diff = adc;
+			state->fcaptrim = state->captrim;
+
+		}
+
+		state->captrim += step_sign * state->step;
+		if (state->step >= 1)
+			*tune_state = CT_TUNER_STEP_1;
+		else
+			*tune_state = CT_TUNER_STEP_3;
+
+		ret = 15;
+	} else if (*tune_state == CT_TUNER_STEP_3) {
+		/*write the final cptrim config */
+		dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
+
+#ifdef CONFIG_TUNER_DIB0090_CAPTRIM_MEMORY
+		state->memory[state->memory_index].cap = state->fcaptrim;
+#endif
+
+		*tune_state = CT_TUNER_STEP_4;
+	} else if (*tune_state == CT_TUNER_STEP_4) {
+		dib0090_write_reg(state, 0x1e, 0x07ff);
+
+		dprintk("FE %d Final Captrim: %d", (u32) fe->id, (u32) state->fcaptrim);
+		dprintk("FE %d HFDIV code: %d", (u32) fe->id, (u32) pll->hfdiv_code);
+		dprintk("FE %d VCO = %d", (u32) fe->id, (u32) pll->vco_band);
+		dprintk("FE %d VCOF in kHz: %d ((%d*%d) << 1))", (u32) fe->id, (u32) ((pll->hfdiv * rf) * 2), (u32) pll->hfdiv, (u32) rf);
+		dprintk("FE %d REFDIV: %d, FREF: %d", (u32) fe->id, (u32) 1, (u32) state->config->io.clock_khz);
+		dprintk("FE %d FBDIV: %d, Rest: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
+		dprintk("FE %d Num: %d, Den: %d, SD: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x17),
+			(u32) (dib0090_read_reg(state, 0x16) >> 8), (u32) dib0090_read_reg(state, 0x1c) & 0x3);
+
+		c = 4;
+		i = 3;
+#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
+		if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) {
+			c = 2;
+			i = 2;
+		}
+#endif
+		dib0090_write_reg(state, 0x10, (c << 13) | (i << 11) | (WBD
+#ifdef CONFIG_DIB0090_USE_PWM_AGC
+									| (state->config->use_pwm_agc << 1)
+#endif
+				  ));
+		dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | (tune->lna_bias << 0));
+		dib0090_write_reg(state, 0x0c, tune->v2i);
+		dib0090_write_reg(state, 0x0d, tune->mix);
+		dib0090_write_reg(state, 0x0e, tune->load);
+
+		*tune_state = CT_TUNER_STEP_5;
+	} else if (*tune_state == CT_TUNER_STEP_5) {
+
+		/* initialize the lt gain register */
+		state->rf_lt_def = 0x7c00;
+		dib0090_write_reg(state, 0x0f, state->rf_lt_def);
+
+		dib0090_set_bandwidth(state);
+		state->tuner_is_tuned = 1;
+		*tune_state = CT_TUNER_STOP;
+	} else
+		ret = FE_CALLBACK_TIME_NEVER;
+	return ret;
+}
+
+static int dib0090_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	return state->tune_state;
+}
+EXPORT_SYMBOL(dib0090_get_tune_state);
+
+int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	state->tune_state = tune_state;
+	return 0;
+}
+EXPORT_SYMBOL(dib0090_set_tune_state);
+
+static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+
+	*frequency = 1000 * state->current_rf;
+	return 0;
+}
+
+static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+	struct dib0090_state *state = fe->tuner_priv;
+	uint32_t ret;
+
+	state->tune_state = CT_TUNER_START;
+
+	do {
+		ret = dib0090_tune(fe);
+		if (ret != FE_CALLBACK_TIME_NEVER)
+			msleep(ret / 10);
+		else
+			break;
+	} while (state->tune_state != CT_TUNER_STOP);
+
+	return 0;
+}
+
+static const struct dvb_tuner_ops dib0090_ops = {
+	.info = {
+		 .name = "DiBcom DiB0090",
+		 .frequency_min = 45000000,
+		 .frequency_max = 860000000,
+		 .frequency_step = 1000,
+		 },
+	.release = dib0090_release,
+
+	.init = dib0090_wakeup,
+	.sleep = dib0090_sleep,
+	.set_params = dib0090_set_params,
+	.get_frequency = dib0090_get_frequency,
+};
+
+struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
+{
+	struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
+	if (st == NULL)
+		return NULL;
+
+	st->config = config;
+	st->i2c = i2c;
+	st->fe = fe;
+	fe->tuner_priv = st;
+
+	if (dib0090_reset(fe) != 0)
+		goto free_mem;
+
+	printk(KERN_INFO "DiB0090: successfully identified\n");
+	memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
+
+	return fe;
+ free_mem:
+	kfree(st);
+	fe->tuner_priv = NULL;
+	return NULL;
+}
+EXPORT_SYMBOL(dib0090_register);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
+MODULE_LICENSE("GPL");

+ 108 - 0
drivers/media/dvb/frontends/dib0090.h

@@ -0,0 +1,108 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ */
+#ifndef DIB0090_H
+#define DIB0090_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+#define DEFAULT_DIB0090_I2C_ADDRESS 0x60
+
+struct dib0090_io_config {
+	u32 clock_khz;
+
+	u8 pll_bypass:1;
+	u8 pll_range:1;
+	u8 pll_prediv:6;
+	u8 pll_loopdiv:6;
+
+	u8 adc_clock_ratio;	/* valid is 8, 7 ,6 */
+	u16 pll_int_loop_filt;
+};
+
+struct dib0090_config {
+	struct dib0090_io_config io;
+	int (*reset) (struct dvb_frontend *, int);
+	int (*sleep) (struct dvb_frontend *, int);
+
+	/*  offset in kHz */
+	int freq_offset_khz_uhf;
+	int freq_offset_khz_vhf;
+
+	int (*get_adc_power) (struct dvb_frontend *);
+
+	u8 clkouttobamse:1;	/* activate or deactivate clock output */
+	u8 analog_output;
+
+	u8 i2c_address;
+	/* add drives and other things if necessary */
+	u16 wbd_vhf_offset;
+	u16 wbd_cband_offset;
+	u8 use_pwm_agc;
+	u8 clkoutdrive;
+};
+
+#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
+extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast);
+extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe);
+extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner);
+extern int dib0090_gain_control(struct dvb_frontend *fe);
+extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe);
+extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
+extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt);
+#else
+static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return 0;
+}
+
+static inline int dib0090_gain_control(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return CT_DONE;
+}
+
+static inline int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+
+static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+#endif
+
+#endif

+ 89 - 48
drivers/media/dvb/frontends/dib8000.c

@@ -28,18 +28,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 
 #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
 
-enum frontend_tune_state {
-	CT_AGC_START = 20,
-	CT_AGC_STEP_0,
-	CT_AGC_STEP_1,
-	CT_AGC_STEP_2,
-	CT_AGC_STEP_3,
-	CT_AGC_STEP_4,
-	CT_AGC_STOP,
-
-	CT_DEMOD_START = 30,
-};
-
 #define FE_STATUS_TUNE_FAILED 0
 
 struct i2c_device {
@@ -133,104 +121,104 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
 	return dib8000_i2c_write16(&state->i2c, reg, val);
 }
 
-const int16_t coeff_2k_sb_1seg_dqpsk[8] = {
+static const int16_t coeff_2k_sb_1seg_dqpsk[8] = {
 	(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
 	    (920 << 5) | 0x09
 };
 
-const int16_t coeff_2k_sb_1seg[8] = {
+static const int16_t coeff_2k_sb_1seg[8] = {
 	(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
 };
 
-const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
+static const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
 	(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
 	    (-931 << 5) | 0x0f
 };
 
-const int16_t coeff_2k_sb_3seg_0dqpsk[8] = {
+static const int16_t coeff_2k_sb_3seg_0dqpsk[8] = {
 	(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
 	    (982 << 5) | 0x0c
 };
 
-const int16_t coeff_2k_sb_3seg_1dqpsk[8] = {
+static const int16_t coeff_2k_sb_3seg_1dqpsk[8] = {
 	(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
 	    (-720 << 5) | 0x0d
 };
 
-const int16_t coeff_2k_sb_3seg[8] = {
+static const int16_t coeff_2k_sb_3seg[8] = {
 	(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
 	    (-610 << 5) | 0x0a
 };
 
-const int16_t coeff_4k_sb_1seg_dqpsk[8] = {
+static const int16_t coeff_4k_sb_1seg_dqpsk[8] = {
 	(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
 	    (-922 << 5) | 0x0d
 };
 
-const int16_t coeff_4k_sb_1seg[8] = {
+static const int16_t coeff_4k_sb_1seg[8] = {
 	(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
 	    (-655 << 5) | 0x0a
 };
 
-const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
+static const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
 	(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
 	    (-958 << 5) | 0x13
 };
 
-const int16_t coeff_4k_sb_3seg_0dqpsk[8] = {
+static const int16_t coeff_4k_sb_3seg_0dqpsk[8] = {
 	(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
 	    (-568 << 5) | 0x0f
 };
 
-const int16_t coeff_4k_sb_3seg_1dqpsk[8] = {
+static const int16_t coeff_4k_sb_3seg_1dqpsk[8] = {
 	(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
 	    (-848 << 5) | 0x13
 };
 
-const int16_t coeff_4k_sb_3seg[8] = {
+static const int16_t coeff_4k_sb_3seg[8] = {
 	(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
 	    (-869 << 5) | 0x13
 };
 
-const int16_t coeff_8k_sb_1seg_dqpsk[8] = {
+static const int16_t coeff_8k_sb_1seg_dqpsk[8] = {
 	(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
 	    (-598 << 5) | 0x10
 };
 
-const int16_t coeff_8k_sb_1seg[8] = {
+static const int16_t coeff_8k_sb_1seg[8] = {
 	(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
 	    (585 << 5) | 0x0f
 };
 
-const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
+static const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
 	(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
 	    (0 << 5) | 0x14
 };
 
-const int16_t coeff_8k_sb_3seg_0dqpsk[8] = {
+static const int16_t coeff_8k_sb_3seg_0dqpsk[8] = {
 	(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
 	    (-877 << 5) | 0x15
 };
 
-const int16_t coeff_8k_sb_3seg_1dqpsk[8] = {
+static const int16_t coeff_8k_sb_3seg_1dqpsk[8] = {
 	(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
 	    (-921 << 5) | 0x14
 };
 
-const int16_t coeff_8k_sb_3seg[8] = {
+static const int16_t coeff_8k_sb_3seg[8] = {
 	(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
 	    (690 << 5) | 0x14
 };
 
-const int16_t ana_fe_coeff_3seg[24] = {
+static const int16_t ana_fe_coeff_3seg[24] = {
 	81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
 };
 
-const int16_t ana_fe_coeff_1seg[24] = {
+static const int16_t ana_fe_coeff_1seg[24] = {
 	249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
 };
 
-const int16_t ana_fe_coeff_13seg[24] = {
+static const int16_t ana_fe_coeff_13seg[24] = {
 	396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
 };
 
@@ -852,6 +840,14 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
 	return 0;
 }
 
+void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	dib8000_set_adc_state(state, DIBX000_ADC_ON);
+	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
+}
+EXPORT_SYMBOL(dib8000_pwm_agc_reset);
+
 static int dib8000_agc_soft_split(struct dib8000_state *state)
 {
 	u16 agc, split_offset;
@@ -939,6 +935,32 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
 
 }
 
+static const int32_t lut_1000ln_mant[] =
+{
+	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
+};
+
+int32_t dib8000_get_adc_power(struct dvb_frontend *fe, uint8_t mode)
+{
+    struct dib8000_state *state = fe->demodulator_priv;
+    uint32_t ix = 0, tmp_val = 0, exp = 0, mant = 0;
+    int32_t val;
+
+    val = dib8000_read32(state, 384);
+    /* mode = 1 : ln_agcpower calc using mant-exp conversion and mantis look up table */
+    if (mode) {
+	tmp_val = val;
+	while (tmp_val >>= 1)
+		exp++;
+	mant = (val * 1000 / (1<<exp));
+	ix = (uint8_t)((mant-1000)/100); /* index of the LUT */
+	val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908); /* 1000 * ln(adcpower_real) ; 693 = 1000ln(2) ; 6908 = 1000*ln(1000) ; 20 comes from adc_real = adc_pow_int / 2**20 */
+	val = (val*256)/1000;
+    }
+    return val;
+}
+EXPORT_SYMBOL(dib8000_get_adc_power);
+
 static void dib8000_update_timf(struct dib8000_state *state)
 {
 	u32 timf = state->timf = dib8000_read32(state, 435);
@@ -1401,10 +1423,9 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
 			}
 			break;
 		}
-	}
-	if (state->fe.dtv_property_cache.isdbt_sb_mode == 1)
 		for (i = 0; i < 8; i++)
 			dib8000_write_word(state, 343 + i, ncoeff[i]);
+	}
 
 	// P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
 	dib8000_write_word(state, 351,
@@ -1854,6 +1875,24 @@ static int dib8000_sleep(struct dvb_frontend *fe)
 	}
 }
 
+enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	return state->tune_state;
+}
+EXPORT_SYMBOL(dib8000_get_tune_state);
+
+int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+	struct dib8000_state *state = fe->demodulator_priv;
+	state->tune_state = tune_state;
+	return 0;
+}
+EXPORT_SYMBOL(dib8000_set_tune_state);
+
+
+
+
 static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
@@ -2043,29 +2082,31 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
 
 	*stat = 0;
 
-	if ((lock >> 14) & 1)	// AGC
+	if ((lock >> 13) & 1)
 		*stat |= FE_HAS_SIGNAL;
 
-	if ((lock >> 8) & 1)	// Equal
+	if ((lock >> 8) & 1) /* Equal */
 		*stat |= FE_HAS_CARRIER;
 
-	if ((lock >> 3) & 1)	// TMCC_SYNC
+	if (((lock >> 1) & 0xf) == 0xf) /* TMCC_SYNC */
 		*stat |= FE_HAS_SYNC;
 
-	if ((lock >> 5) & 7)	// FEC MPEG
+	if (((lock >> 12) & 1) && ((lock >> 5) & 7)) /* FEC MPEG */
 		*stat |= FE_HAS_LOCK;
 
-	lock = dib8000_read_word(state, 554);	// Viterbi Layer A
-	if (lock & 0x01)
-		*stat |= FE_HAS_VITERBI;
+	if ((lock >> 12) & 1) {
+		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
+		if (lock & 0x01)
+			*stat |= FE_HAS_VITERBI;
 
-	lock = dib8000_read_word(state, 555);	// Viterbi Layer B
-	if (lock & 0x01)
-		*stat |= FE_HAS_VITERBI;
+		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
+		if (lock & 0x01)
+			*stat |= FE_HAS_VITERBI;
 
-	lock = dib8000_read_word(state, 556);	// Viterbi Layer C
-	if (lock & 0x01)
-		*stat |= FE_HAS_VITERBI;
+		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
+		if (lock & 0x01)
+			*stat |= FE_HAS_VITERBI;
+	}
 
 	return 0;
 }

+ 27 - 5
drivers/media/dvb/frontends/dib8000.h

@@ -46,6 +46,10 @@ 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);
+extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
+extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe);
+extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe);
+extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode);
 #else
 static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
 {
@@ -59,35 +63,53 @@ static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe
 	return NULL;
 }
 
-int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
+static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return -ENODEV;
 }
 
-int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return -ENODEV;
 }
 
-int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+static inline 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)
+static inline 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)
+static inline 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;
 }
+static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+    return CT_SHUTDOWN,
+}
+static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
 #endif
 
 #endif

+ 12 - 3
drivers/media/dvb/frontends/dibx000_common.c

@@ -6,7 +6,7 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); } } while (0)
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0)
 
 static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
 {
@@ -25,7 +25,7 @@ static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst,
 					enum dibx000_i2c_interface intf)
 {
 	if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) {
-		dprintk("selecting interface: %d\n", intf);
+		dprintk("selecting interface: %d", intf);
 		mst->selected_interface = intf;
 		return dibx000_write_word(mst, mst->base_reg + 4, intf);
 	}
@@ -171,9 +171,18 @@ void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
 {
 	i2c_del_adapter(&mst->gated_tuner_i2c_adap);
 }
-
 EXPORT_SYMBOL(dibx000_exit_i2c_master);
 
+
+u32 systime()
+{
+    struct timespec t;
+
+    t = current_kernel_time();
+    return (t.tv_sec * 10000) + (t.tv_nsec / 100000);
+}
+EXPORT_SYMBOL(systime);
+
 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
 MODULE_DESCRIPTION("Common function the DiBcom demodulator family");
 MODULE_LICENSE("GPL");

+ 69 - 2
drivers/media/dvb/frontends/dibx000_common.h

@@ -36,13 +36,17 @@ extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master
 extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
 extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst);
 
+extern u32 systime(void);
+
 #define BAND_LBAND 0x01
 #define BAND_UHF   0x02
 #define BAND_VHF   0x04
 #define BAND_SBAND 0x08
-#define BAND_FM	   0x10
+#define BAND_FM    0x10
+#define BAND_CBAND 0x20
 
-#define BAND_OF_FREQUENCY(freq_kHz) ( (freq_kHz) <= 115000 ? BAND_FM : \
+#define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \
+									(freq_kHz) <= 115000 ? BAND_FM : \
 									(freq_kHz) <= 250000 ? BAND_VHF : \
 									(freq_kHz) <= 863000 ? BAND_UHF : \
 									(freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND )
@@ -149,4 +153,67 @@ enum dibx000_adc_states {
 #define OUTMODE_MPEG2_FIFO          5
 #define OUTMODE_ANALOG_ADC          6
 
+enum frontend_tune_state {
+    CT_TUNER_START = 10,
+    CT_TUNER_STEP_0,
+    CT_TUNER_STEP_1,
+    CT_TUNER_STEP_2,
+    CT_TUNER_STEP_3,
+    CT_TUNER_STEP_4,
+    CT_TUNER_STEP_5,
+    CT_TUNER_STEP_6,
+    CT_TUNER_STEP_7,
+    CT_TUNER_STOP,
+
+    CT_AGC_START = 20,
+    CT_AGC_STEP_0,
+    CT_AGC_STEP_1,
+    CT_AGC_STEP_2,
+    CT_AGC_STEP_3,
+    CT_AGC_STEP_4,
+    CT_AGC_STOP,
+
+	CT_DEMOD_START = 30,
+    CT_DEMOD_STEP_1,
+    CT_DEMOD_STEP_2,
+    CT_DEMOD_STEP_3,
+    CT_DEMOD_STEP_4,
+    CT_DEMOD_STEP_5,
+    CT_DEMOD_STEP_6,
+    CT_DEMOD_STEP_7,
+    CT_DEMOD_STEP_8,
+    CT_DEMOD_STEP_9,
+    CT_DEMOD_STEP_10,
+    CT_DEMOD_SEARCH_NEXT = 41,
+    CT_DEMOD_STEP_LOCKED,
+    CT_DEMOD_STOP,
+
+    CT_DONE = 100,
+    CT_SHUTDOWN,
+
+};
+
+struct dvb_frontend_parametersContext {
+#define CHANNEL_STATUS_PARAMETERS_UNKNOWN   0x01
+#define CHANNEL_STATUS_PARAMETERS_SET       0x02
+    u8 status;
+    u32 tune_time_estimation[2];
+    s32 tps_available;
+    u16 tps[9];
+};
+
+#define FE_STATUS_TUNE_FAILED          0
+#define FE_STATUS_TUNE_TIMED_OUT      -1
+#define FE_STATUS_TUNE_TIME_TOO_SHORT -2
+#define FE_STATUS_TUNE_PENDING        -3
+#define FE_STATUS_STD_SUCCESS         -4
+#define FE_STATUS_FFT_SUCCESS         -5
+#define FE_STATUS_DEMOD_SUCCESS       -6
+#define FE_STATUS_LOCKED              -7
+#define FE_STATUS_DATA_LOCKED         -8
+
+#define FE_CALLBACK_TIME_NEVER 0xffffffff
+
+#define ABS(x) ((x < 0) ? (-x) : (x))
+
 #endif

+ 2 - 2
drivers/media/dvb/frontends/lgs8gxx.c

@@ -199,7 +199,7 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
 
 	val = freq;
 	if (freq != 0) {
-		val *= (u64)1 << 32;
+		val <<= 32;
 		if (if_clk != 0)
 			do_div(val, if_clk);
 		v32 = val & 0xFFFFFFFF;
@@ -246,7 +246,7 @@ static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
 
 	val = v32;
 	val *= priv->config->if_clk_freq;
-	val /= (u64)1 << 32;
+	val >>= 32;
 	dprintk("AFC = %u kHz\n", (u32)val);
 	return 0;
 }

+ 27 - 1
drivers/media/dvb/frontends/lnbp21.c

@@ -1,7 +1,7 @@
 /*
  * lnbp21.c - driver for lnb supply and control ic lnbp21
  *
- * Copyright (C) 2006 Oliver Endriss
+ * Copyright (C) 2006, 2009 Oliver Endriss <o.endriss@gmx.de>
  * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
  *
  * This program is free software; you can redistribute it and/or
@@ -91,6 +91,31 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
 	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
 }
 
+static int lnbp21_set_tone(struct dvb_frontend *fe,
+				fe_sec_tone_mode_t tone)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = lnbp21->i2c_addr, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	switch (tone) {
+	case SEC_TONE_OFF:
+		lnbp21->config &= ~LNBP21_TEN;
+		break;
+	case SEC_TONE_ON:
+		lnbp21->config |= LNBP21_TEN;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
 static void lnbp21_release(struct dvb_frontend *fe)
 {
 	/* LNBP power off */
@@ -133,6 +158,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
 	/* override frontend ops */
 	fe->ops.set_voltage = lnbp21_set_voltage;
 	fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+	fe->ops.set_tone = lnbp21_set_tone;
 	printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
 
 	return fe;

+ 13 - 0
drivers/media/dvb/frontends/stv0900_core.c

@@ -1451,6 +1451,8 @@ static int stv0900_status(struct stv0900_internal *intp,
 {
 	enum fe_stv0900_search_state demod_state;
 	int locked = FALSE;
+	u8 tsbitrate0_val, tsbitrate1_val;
+	s32 bitrate;
 
 	demod_state = stv0900_get_bits(intp, HEADER_MODE);
 	switch (demod_state) {
@@ -1473,6 +1475,17 @@ static int stv0900_status(struct stv0900_internal *intp,
 
 	dprintk("%s: locked = %d\n", __func__, locked);
 
+	if (stvdebug) {
+		/* Print TS bitrate */
+		tsbitrate0_val = stv0900_read_reg(intp, TSBITRATE0);
+		tsbitrate1_val = stv0900_read_reg(intp, TSBITRATE1);
+		/* Formula Bit rate = Mclk * px_tsfifo_bitrate / 16384 */
+		bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000)
+			* (tsbitrate1_val << 8 | tsbitrate0_val);
+		bitrate /= 16384;
+		dprintk("TS bitrate = %d Mbit/sec \n", bitrate);
+	};
+
 	return locked;
 }
 

+ 4 - 3
drivers/media/dvb/frontends/stv090x.c

@@ -3597,7 +3597,8 @@ static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma
 
 	reg = STV090x_READ_DEMOD(state, DISTXCTL);
 
-	STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 2);
+	STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD,
+		(state->config->diseqc_envelope_mode) ? 4 : 2);
 	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
 	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
 		goto err;
@@ -3649,10 +3650,10 @@ static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t
 	reg = STV090x_READ_DEMOD(state, DISTXCTL);
 
 	if (burst == SEC_MINI_A) {
-		mode = 3;
+		mode = (state->config->diseqc_envelope_mode) ? 5 : 3;
 		value = 0x00;
 	} else {
-		mode = 2;
+		mode = (state->config->diseqc_envelope_mode) ? 4 : 2;
 		value = 0xFF;
 	}
 

+ 2 - 0
drivers/media/dvb/frontends/stv090x.h

@@ -75,6 +75,8 @@ struct stv090x_config {
 
 	enum stv090x_i2crpt	repeater_level;
 
+	bool diseqc_envelope_mode;
+
 	int (*tuner_init) (struct dvb_frontend *fe);
 	int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
 	int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);

+ 2 - 2
drivers/media/dvb/siano/smsdvb.c

@@ -662,7 +662,7 @@ adapter_error:
 	return rc;
 }
 
-int smsdvb_module_init(void)
+static int __init smsdvb_module_init(void)
 {
 	int rc;
 
@@ -676,7 +676,7 @@ int smsdvb_module_init(void)
 	return rc;
 }
 
-void smsdvb_module_exit(void)
+static void __exit smsdvb_module_exit(void)
 {
 	smscore_unregister_hotplug(smsdvb_hotplug);
 

+ 4 - 4
drivers/media/dvb/siano/smssdio.c

@@ -48,7 +48,7 @@
 #define SMSSDIO_INT		0x04
 #define SMSSDIO_BLOCK_SIZE	128
 
-static const struct sdio_device_id smssdio_ids[] = {
+static const struct sdio_device_id smssdio_ids[] __devinitconst = {
 	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
 	 .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
 	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
@@ -222,7 +222,7 @@ static void smssdio_interrupt(struct sdio_func *func)
 	smscore_onresponse(smsdev->coredev, cb);
 }
 
-static int smssdio_probe(struct sdio_func *func,
+static int __devinit smssdio_probe(struct sdio_func *func,
 			 const struct sdio_device_id *id)
 {
 	int ret;
@@ -338,7 +338,7 @@ static struct sdio_driver smssdio_driver = {
 /* Module functions                                                */
 /*******************************************************************/
 
-int smssdio_module_init(void)
+static int __init smssdio_module_init(void)
 {
 	int ret = 0;
 
@@ -350,7 +350,7 @@ int smssdio_module_init(void)
 	return ret;
 }
 
-void smssdio_module_exit(void)
+static void __exit smssdio_module_exit(void)
 {
 	sdio_unregister_driver(&smssdio_driver);
 }

+ 14 - 4
drivers/media/dvb/siano/smsusb.c

@@ -390,7 +390,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
 	return rc;
 }
 
-static int smsusb_probe(struct usb_interface *intf,
+static int __devinit smsusb_probe(struct usb_interface *intf,
 			const struct usb_device_id *id)
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
@@ -484,7 +484,7 @@ static int smsusb_resume(struct usb_interface *intf)
 	return 0;
 }
 
-struct usb_device_id smsusb_id_table[] = {
+static const struct usb_device_id smsusb_id_table[] __devinitconst = {
 	{ USB_DEVICE(0x187f, 0x0010),
 		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
 	{ USB_DEVICE(0x187f, 0x0100),
@@ -533,8 +533,18 @@ struct usb_device_id smsusb_id_table[] = {
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ USB_DEVICE(0x2040, 0xb910),
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0xb980),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0xb990),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ USB_DEVICE(0x2040, 0xc000),
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0xc010),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0xc080),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0xc090),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ } /* Terminating entry */
 	};
 
@@ -550,7 +560,7 @@ static struct usb_driver smsusb_driver = {
 	.resume			= smsusb_resume,
 };
 
-int smsusb_module_init(void)
+static int __init smsusb_module_init(void)
 {
 	int rc = usb_register(&smsusb_driver);
 	if (rc)
@@ -561,7 +571,7 @@ int smsusb_module_init(void)
 	return rc;
 }
 
-void smsusb_module_exit(void)
+static void __exit smsusb_module_exit(void)
 {
 	/* Regular USB Cleanup */
 	usb_deregister(&smsusb_driver);

+ 16 - 36
drivers/media/dvb/ttpci/budget-ci.c

@@ -190,12 +190,13 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	struct input_dev *input_dev = budget_ci->ir.dev;
 	int error;
+	struct ir_scancode_table *ir_codes;
+
 
 	budget_ci->ir.dev = input_dev = input_allocate_device();
 	if (!input_dev) {
 		printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
-		error = -ENOMEM;
-		goto out1;
+		return -ENOMEM;
 	}
 
 	snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
@@ -217,6 +218,11 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 	}
 	input_dev->dev.parent = &saa->pci->dev;
 
+	if (rc5_device < 0)
+		budget_ci->ir.rc5_device = IR_DEVICE_ANY;
+	else
+		budget_ci->ir.rc5_device = rc5_device;
+
 	/* Select keymap and address */
 	switch (budget_ci->budget.dev->pci->subsystem_device) {
 	case 0x100c:
@@ -224,53 +230,34 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 	case 0x1011:
 	case 0x1012:
 		/* The hauppauge keymap is a superset of these remotes */
-		error = ir_input_init(input_dev, &budget_ci->ir.state,
-			      IR_TYPE_RC5, &ir_codes_hauppauge_new_table);
-		if (error < 0)
-			goto out2;
+		ir_codes = &ir_codes_hauppauge_new_table;
 
 		if (rc5_device < 0)
 			budget_ci->ir.rc5_device = 0x1f;
-		else
-			budget_ci->ir.rc5_device = rc5_device;
 		break;
 	case 0x1010:
 	case 0x1017:
 	case 0x101a:
 		/* for the Technotrend 1500 bundled remote */
-		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;
-		else
-			budget_ci->ir.rc5_device = rc5_device;
+		ir_codes = &ir_codes_tt_1500_table;
 		break;
 	default:
 		/* unknown remote */
-		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;
-		else
-			budget_ci->ir.rc5_device = rc5_device;
+		ir_codes = &ir_codes_budget_ci_old_table;
 		break;
 	}
 
+	ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5);
+
 	/* initialise the key-up timeout handler */
 	init_timer(&budget_ci->ir.timer_keyup);
 	budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
 	budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
 	budget_ci->ir.last_raw = 0xffff; /* An impossible value */
-	error = input_register_device(input_dev);
+	error = ir_input_register(input_dev, ir_codes);
 	if (error) {
 		printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
-		goto out2;
+		return error;
 	}
 
 	/* note: these must be after input_register_device */
@@ -284,12 +271,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 	saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
 
 	return 0;
-
-out2:
-	ir_input_free(input_dev);
-	input_free_device(input_dev);
-out1:
-	return error;
 }
 
 static void msp430_ir_deinit(struct budget_ci *budget_ci)
@@ -304,8 +285,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);
+	ir_input_unregister(dev);
 }
 
 static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)

+ 2 - 5
drivers/media/radio/Kconfig

@@ -215,13 +215,10 @@ config RADIO_MIROPCM20
 	  module will be called radio-miropcm20.
 
 config RADIO_SF16FMI
-	tristate "SF16FMI Radio"
+	tristate "SF16-FMI/SF16-FMP Radio"
 	depends on ISA && VIDEO_V4L2
 	---help---
-	  Choose Y here if you have one of these FM radio cards.  If you
-	  compile the driver into the kernel and your card is not PnP one, you
-	  have to add "sf16fm=<io>" to the kernel command line (I/O address is
-	  0x284 or 0x384).
+	  Choose Y here if you have one of these FM radio cards.
 
 	  In order to control your radio card, you will need to use programs
 	  that are compatible with the Video For Linux API.  Information on

+ 4 - 0
drivers/media/radio/radio-aimslab.c

@@ -268,6 +268,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct rtrack *rt = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	rt_setfreq(rt, f->frequency);
 	return 0;
 }
@@ -277,6 +279,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct rtrack *rt = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = rt->curfreq;
 	return 0;

+ 4 - 0
drivers/media/radio/radio-aztech.c

@@ -254,6 +254,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct aztech *az = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	az_setfreq(az, f->frequency);
 	return 0;
 }
@@ -263,6 +265,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct aztech *az = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = az->curfreq;
 	return 0;

+ 4 - 0
drivers/media/radio/radio-gemtek-pci.c

@@ -240,6 +240,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct gemtek_pci *card = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	if (f->frequency < GEMTEK_PCI_RANGE_LOW ||
 	    f->frequency > GEMTEK_PCI_RANGE_HIGH)
 		return -EINVAL;
@@ -253,6 +255,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct gemtek_pci *card = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = card->current_frequency;
 	return 0;

+ 4 - 0
drivers/media/radio/radio-maestro.c

@@ -200,6 +200,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct maestro *dev = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
 		return -EINVAL;
 	mutex_lock(&dev->lock);
@@ -213,6 +215,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct maestro *dev = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	mutex_lock(&dev->lock);
 	f->frequency = BITS2FREQ(radio_bits_get(dev));

+ 4 - 0
drivers/media/radio/radio-maxiradio.c

@@ -262,6 +262,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct maxiradio *dev = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
 		dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
 					f->frequency / 16000,
@@ -285,6 +287,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct maxiradio *dev = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = dev->freq;
 

+ 4 - 0
drivers/media/radio/radio-mr800.c

@@ -374,6 +374,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct amradio_device *radio = file->private_data;
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	return amradio_setfreq(radio, f->frequency);
 }
 
@@ -383,6 +385,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct amradio_device *radio = file->private_data;
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = radio->curfreq;
 

+ 4 - 0
drivers/media/radio/radio-rtrack2.c

@@ -167,6 +167,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct rtrack2 *rt = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	rt_setfreq(rt, f->frequency);
 	return 0;
 }
@@ -176,6 +178,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct rtrack2 *rt = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = rt->curfreq;
 	return 0;

+ 58 - 24
drivers/media/radio/radio-sf16fmi.c

@@ -1,4 +1,4 @@
-/* SF16FMI radio driver for Linux radio support
+/* SF16-FMI and SF16-FMP radio driver for Linux radio support
  * heavily based on rtrack driver...
  * (c) 1997 M. Kirkwood
  * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
@@ -11,7 +11,7 @@
  *
  *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
  *  No volume control - only mute/unmute - you have to use line volume
- *  control on SB-part of SF16FMI
+ *  control on SB-part of SF16-FMI/SF16-FMP
  *
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
@@ -30,14 +30,14 @@
 #include <media/v4l2-ioctl.h>
 
 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
-MODULE_DESCRIPTION("A driver for the SF16MI radio.");
+MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio.");
 MODULE_LICENSE("GPL");
 
 static int io = -1;
 static int radio_nr = -1;
 
 module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
+MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)");
 module_param(radio_nr, int, 0);
 
 #define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
@@ -47,13 +47,14 @@ struct fmi
 	struct v4l2_device v4l2_dev;
 	struct video_device vdev;
 	int io;
-	int curvol; /* 1 or 0 */
+	bool mute;
 	unsigned long curfreq; /* freq in kHz */
 	struct mutex lock;
 };
 
 static struct fmi fmi_card;
 static struct pnp_dev *dev;
+bool pnp_attached;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
 /* It is only useful to give freq in interval of 800 (=0.05Mhz),
@@ -105,7 +106,7 @@ static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq)
 	outbits(8, 0xC0, fmi->io);
 	msleep(143);		/* was schedule_timeout(HZ/7) */
 	mutex_unlock(&fmi->lock);
-	if (fmi->curvol)
+	if (!fmi->mute)
 		fmi_unmute(fmi);
 	return 0;
 }
@@ -116,7 +117,7 @@ static inline int fmi_getsigstr(struct fmi *fmi)
 	int res;
 
 	mutex_lock(&fmi->lock);
-	val = fmi->curvol ? 0x08 : 0x00;	/* unmute/mute */
+	val = fmi->mute ? 0x00 : 0x08;	/* mute/unmute */
 	outb(val, fmi->io);
 	outb(val | 0x10, fmi->io);
 	msleep(143); 		/* was schedule_timeout(HZ/7) */
@@ -168,6 +169,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct fmi *fmi = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	if (f->frequency < RSF16_MINFREQ ||
 			f->frequency > RSF16_MAXFREQ)
 		return -EINVAL;
@@ -182,6 +185,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct fmi *fmi = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = fmi->curfreq;
 	return 0;
@@ -204,7 +209,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = fmi->curvol;
+		ctrl->value = fmi->mute;
 		return 0;
 	}
 	return -EINVAL;
@@ -221,7 +226,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 			fmi_mute(fmi);
 		else
 			fmi_unmute(fmi);
-		fmi->curvol = ctrl->value;
+		fmi->mute = ctrl->value;
 		return 0;
 	}
 	return -EINVAL;
@@ -316,26 +321,54 @@ static int __init fmi_init(void)
 {
 	struct fmi *fmi = &fmi_card;
 	struct v4l2_device *v4l2_dev = &fmi->v4l2_dev;
-	int res;
+	int res, i;
+	int probe_ports[] = { 0, 0x284, 0x384 };
+
+	if (io < 0) {
+		for (i = 0; i < ARRAY_SIZE(probe_ports); i++) {
+			io = probe_ports[i];
+			if (io == 0) {
+				io = isapnp_fmi_probe();
+				if (io < 0)
+					continue;
+				pnp_attached = 1;
+			}
+			if (!request_region(io, 2, "radio-sf16fmi")) {
+				if (pnp_attached)
+					pnp_device_detach(dev);
+				io = -1;
+				continue;
+			}
+			if (pnp_attached ||
+			    ((inb(io) & 0xf9) == 0xf9 && (inb(io) & 0x4) == 0))
+				break;
+			release_region(io, 2);
+			io = -1;
+		}
+	} else {
+		if (!request_region(io, 2, "radio-sf16fmi")) {
+			printk(KERN_ERR "radio-sf16fmi: port %#x already in use\n", io);
+			return -EBUSY;
+		}
+		if (inb(io) == 0xff) {
+			printk(KERN_ERR "radio-sf16fmi: card not present at %#x\n", io);
+			release_region(io, 2);
+			return -ENODEV;
+		}
+	}
+	if (io < 0) {
+		printk(KERN_ERR "radio-sf16fmi: no cards found\n");
+		return -ENODEV;
+	}
 
-	if (io < 0)
-		io = isapnp_fmi_probe();
 	strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name));
 	fmi->io = io;
-	if (fmi->io < 0) {
-		v4l2_err(v4l2_dev, "No PnP card found.\n");
-		return fmi->io;
-	}
-	if (!request_region(io, 2, "radio-sf16fmi")) {
-		v4l2_err(v4l2_dev, "port 0x%x already in use\n", fmi->io);
-		pnp_device_detach(dev);
-		return -EBUSY;
-	}
 
 	res = v4l2_device_register(NULL, v4l2_dev);
 	if (res < 0) {
 		release_region(fmi->io, 2);
-		pnp_device_detach(dev);
+		if (pnp_attached)
+			pnp_device_detach(dev);
 		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
 		return res;
 	}
@@ -352,7 +385,8 @@ static int __init fmi_init(void)
 	if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
 		v4l2_device_unregister(v4l2_dev);
 		release_region(fmi->io, 2);
-		pnp_device_detach(dev);
+		if (pnp_attached)
+			pnp_device_detach(dev);
 		return -EINVAL;
 	}
 
@@ -369,7 +403,7 @@ static void __exit fmi_exit(void)
 	video_unregister_device(&fmi->vdev);
 	v4l2_device_unregister(&fmi->v4l2_dev);
 	release_region(fmi->io, 2);
-	if (dev)
+	if (dev && pnp_attached)
 		pnp_device_detach(dev);
 }
 

+ 4 - 0
drivers/media/radio/radio-sf16fmr2.c

@@ -251,6 +251,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct fmr2 *fmr2 = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	if (f->frequency < RSF16_MINFREQ ||
 			f->frequency > RSF16_MAXFREQ)
 		return -EINVAL;
@@ -272,6 +274,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct fmr2 *fmr2 = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = fmr2->curfreq;
 	return 0;

+ 5 - 7
drivers/media/radio/radio-tea5764.c

@@ -314,7 +314,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 	if (v->index > 0)
 		return -EINVAL;
 
-	memset(v, 0, sizeof(v));
+	memset(v, 0, sizeof(*v));
 	strcpy(v->name, "FM");
 	v->type = V4L2_TUNER_RADIO;
 	tea5764_i2c_read(radio);
@@ -349,7 +349,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct tea5764_device *radio = video_drvdata(file);
 
-	if (f->tuner != 0)
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
 		return -EINVAL;
 	if (f->frequency == 0) {
 		/* We special case this as a power down control. */
@@ -370,8 +370,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 	struct tea5764_device *radio = video_drvdata(file);
 	struct tea5764_regs *r = &radio->regs;
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	tea5764_i2c_read(radio);
-	memset(f, 0, sizeof(f));
+	memset(f, 0, sizeof(*f));
 	f->type = V4L2_TUNER_RADIO;
 	if (r->tnctrl & TEA5764_TNCTRL_PUPD0)
 		f->frequency = (tea5764_get_freq(radio) * 2) / 125;
@@ -458,12 +460,8 @@ static int vidioc_s_audio(struct file *file, void *priv,
 static int tea5764_open(struct file *file)
 {
 	/* Currently we support only one device */
-	int minor = video_devdata(file)->minor;
 	struct tea5764_device *radio = video_drvdata(file);
 
-	if (radio->videodev->minor != minor)
-		return -ENODEV;
-
 	mutex_lock(&radio->mutex);
 	/* Only exclusive access */
 	if (radio->users) {

+ 4 - 0
drivers/media/radio/radio-terratec.c

@@ -240,6 +240,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct terratec *tt = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	tt_setfreq(tt, f->frequency);
 	return 0;
 }
@@ -249,6 +251,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct terratec *tt = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = tt->curfreq;
 	return 0;

+ 4 - 0
drivers/media/radio/radio-trust.c

@@ -239,6 +239,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct trust *tr = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	tr_setfreq(tr, f->frequency);
 	return 0;
 }
@@ -248,6 +250,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct trust *tr = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = tr->curfreq;
 	return 0;

+ 4 - 0
drivers/media/radio/radio-typhoon.c

@@ -207,6 +207,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct typhoon *dev = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = dev->curfreq;
 	return 0;
@@ -217,6 +219,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct typhoon *dev = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	dev->curfreq = f->frequency;
 	typhoon_setfreq(dev, dev->curfreq);
 	return 0;

+ 4 - 0
drivers/media/radio/radio-zoltrix.c

@@ -266,6 +266,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 	struct zoltrix *zol = video_drvdata(file);
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
 	if (zol_setfreq(zol, f->frequency) != 0)
 		return -EINVAL;
 	return 0;
@@ -276,6 +278,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 	struct zoltrix *zol = video_drvdata(file);
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = zol->curfreq;
 	return 0;

+ 98 - 0
drivers/media/radio/si470x/radio-si470x-common.c

@@ -425,6 +425,104 @@ int si470x_rds_on(struct si470x_device *radio)
 
 
 
+/**************************************************************************
+ * File Operations Interface
+ **************************************************************************/
+
+/*
+ * si470x_fops_read - read RDS data
+ */
+static ssize_t si470x_fops_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct si470x_device *radio = video_drvdata(file);
+	int retval = 0;
+	unsigned int block_count = 0;
+
+	/* switch on rds reception */
+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+		si470x_rds_on(radio);
+
+	/* block if no new data available */
+	while (radio->wr_index == radio->rd_index) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EWOULDBLOCK;
+			goto done;
+		}
+		if (wait_event_interruptible(radio->read_queue,
+			radio->wr_index != radio->rd_index) < 0) {
+			retval = -EINTR;
+			goto done;
+		}
+	}
+
+	/* calculate block count from byte count */
+	count /= 3;
+
+	/* copy RDS block out of internal buffer and to user buffer */
+	mutex_lock(&radio->lock);
+	while (block_count < count) {
+		if (radio->rd_index == radio->wr_index)
+			break;
+
+		/* always transfer rds complete blocks */
+		if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
+			/* retval = -EFAULT; */
+			break;
+
+		/* increment and wrap read pointer */
+		radio->rd_index += 3;
+		if (radio->rd_index >= radio->buf_size)
+			radio->rd_index = 0;
+
+		/* increment counters */
+		block_count++;
+		buf += 3;
+		retval += 3;
+	}
+	mutex_unlock(&radio->lock);
+
+done:
+	return retval;
+}
+
+
+/*
+ * si470x_fops_poll - poll RDS data
+ */
+static unsigned int si470x_fops_poll(struct file *file,
+		struct poll_table_struct *pts)
+{
+	struct si470x_device *radio = video_drvdata(file);
+	int retval = 0;
+
+	/* switch on rds reception */
+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+		si470x_rds_on(radio);
+
+	poll_wait(file, &radio->read_queue, pts);
+
+	if (radio->rd_index != radio->wr_index)
+		retval = POLLIN | POLLRDNORM;
+
+	return retval;
+}
+
+
+/*
+ * si470x_fops - file operations interface
+ */
+static const struct v4l2_file_operations si470x_fops = {
+	.owner			= THIS_MODULE,
+	.read			= si470x_fops_read,
+	.poll			= si470x_fops_poll,
+	.ioctl			= video_ioctl2,
+	.open			= si470x_fops_open,
+	.release		= si470x_fops_release,
+};
+
+
+
 /**************************************************************************
  * Video4Linux Interface
  **************************************************************************/

+ 196 - 23
drivers/media/radio/si470x/radio-si470x-i2c.c

@@ -22,22 +22,17 @@
  */
 
 
-/*
- * ToDo:
- * - RDS support
- */
-
-
 /* driver definitions */
 #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>";
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 0)
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1)
 #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
 #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.0"
+#define DRIVER_VERSION "1.0.1"
 
 /* kernel includes */
 #include <linux/i2c.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 
 #include "radio-si470x.h"
 
@@ -62,6 +57,20 @@ static int radio_nr = -1;
 module_param(radio_nr, int, 0444);
 MODULE_PARM_DESC(radio_nr, "Radio Nr");
 
+/* RDS buffer blocks */
+static unsigned int rds_buf = 100;
+module_param(rds_buf, uint, 0444);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
+
+/* RDS maximum block errors */
+static unsigned short max_rds_errors = 1;
+/* 0 means   0  errors requiring correction */
+/* 1 means 1-2  errors requiring correction (used by original USBRadio.exe) */
+/* 2 means 3-5  errors requiring correction */
+/* 3 means   6+ errors or errors in checkword, correction not possible */
+module_param(max_rds_errors, ushort, 0644);
+MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
+
 
 
 /**************************************************************************
@@ -173,7 +182,7 @@ int si470x_disconnect_check(struct si470x_device *radio)
 /*
  * si470x_fops_open - file open
  */
-static int si470x_fops_open(struct file *file)
+int si470x_fops_open(struct file *file)
 {
 	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
@@ -181,12 +190,21 @@ static int si470x_fops_open(struct file *file)
 	mutex_lock(&radio->lock);
 	radio->users++;
 
-	if (radio->users == 1)
+	if (radio->users == 1) {
 		/* start radio */
 		retval = si470x_start(radio);
+		if (retval < 0)
+			goto done;
+
+		/* enable RDS interrupt */
+		radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN;
+		radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2;
+		radio->registers[SYSCONFIG1] |= 0x1 << 2;
+		retval = si470x_set_register(radio, SYSCONFIG1);
+	}
 
+done:
 	mutex_unlock(&radio->lock);
-
 	return retval;
 }
 
@@ -194,7 +212,7 @@ static int si470x_fops_open(struct file *file)
 /*
  * si470x_fops_release - file release
  */
-static int si470x_fops_release(struct file *file)
+int si470x_fops_release(struct file *file)
 {
 	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
@@ -215,17 +233,6 @@ static int si470x_fops_release(struct file *file)
 }
 
 
-/*
- * si470x_fops - file operations interface
- */
-const struct v4l2_file_operations si470x_fops = {
-	.owner		= THIS_MODULE,
-	.ioctl		= video_ioctl2,
-	.open		= si470x_fops_open,
-	.release	= si470x_fops_release,
-};
-
-
 
 /**************************************************************************
  * Video4Linux Interface
@@ -252,6 +259,105 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
  * I2C Interface
  **************************************************************************/
 
+/*
+ * si470x_i2c_interrupt_work - rds processing function
+ */
+static void si470x_i2c_interrupt_work(struct work_struct *work)
+{
+	struct si470x_device *radio = container_of(work,
+			struct si470x_device, radio_work);
+	unsigned char regnr;
+	unsigned char blocknum;
+	unsigned short bler; /* rds block errors */
+	unsigned short rds;
+	unsigned char tmpbuf[3];
+	int retval = 0;
+
+	/* safety checks */
+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+		return;
+
+	/* Update RDS registers */
+	for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) {
+		retval = si470x_get_register(radio, STATUSRSSI + regnr);
+		if (retval < 0)
+			return;
+	}
+
+	/* get rds blocks */
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0)
+		/* No RDS group ready, better luck next time */
+		return;
+
+	for (blocknum = 0; blocknum < 4; blocknum++) {
+		switch (blocknum) {
+		default:
+			bler = (radio->registers[STATUSRSSI] &
+					STATUSRSSI_BLERA) >> 9;
+			rds = radio->registers[RDSA];
+			break;
+		case 1:
+			bler = (radio->registers[READCHAN] &
+					READCHAN_BLERB) >> 14;
+			rds = radio->registers[RDSB];
+			break;
+		case 2:
+			bler = (radio->registers[READCHAN] &
+					READCHAN_BLERC) >> 12;
+			rds = radio->registers[RDSC];
+			break;
+		case 3:
+			bler = (radio->registers[READCHAN] &
+					READCHAN_BLERD) >> 10;
+			rds = radio->registers[RDSD];
+			break;
+		};
+
+		/* Fill the V4L2 RDS buffer */
+		put_unaligned_le16(rds, &tmpbuf);
+		tmpbuf[2] = blocknum;		/* offset name */
+		tmpbuf[2] |= blocknum << 3;	/* received offset */
+		if (bler > max_rds_errors)
+			tmpbuf[2] |= 0x80;	/* uncorrectable errors */
+		else if (bler > 0)
+			tmpbuf[2] |= 0x40;	/* corrected error(s) */
+
+		/* copy RDS block to internal buffer */
+		memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
+		radio->wr_index += 3;
+
+		/* wrap write pointer */
+		if (radio->wr_index >= radio->buf_size)
+			radio->wr_index = 0;
+
+		/* check for overflow */
+		if (radio->wr_index == radio->rd_index) {
+			/* increment and wrap read pointer */
+			radio->rd_index += 3;
+			if (radio->rd_index >= radio->buf_size)
+				radio->rd_index = 0;
+		}
+	}
+
+	if (radio->wr_index != radio->rd_index)
+		wake_up_interruptible(&radio->read_queue);
+}
+
+
+/*
+ * si470x_i2c_interrupt - interrupt handler
+ */
+static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id)
+{
+	struct si470x_device *radio = dev_id;
+
+	if (!work_pending(&radio->radio_work))
+		schedule_work(&radio->radio_work);
+
+	return IRQ_HANDLED;
+}
+
+
 /*
  * si470x_i2c_probe - probe for the device
  */
@@ -268,6 +374,8 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
 		retval = -ENOMEM;
 		goto err_initial;
 	}
+
+	INIT_WORK(&radio->radio_work, si470x_i2c_interrupt_work);
 	radio->users = 0;
 	radio->client = client;
 	mutex_init(&radio->lock);
@@ -319,6 +427,26 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
 	/* set initial frequency */
 	si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
 
+	/* rds buffer allocation */
+	radio->buf_size = rds_buf * 3;
+	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
+	if (!radio->buffer) {
+		retval = -EIO;
+		goto err_video;
+	}
+
+	/* rds buffer configuration */
+	radio->wr_index = 0;
+	radio->rd_index = 0;
+	init_waitqueue_head(&radio->read_queue);
+
+	retval = request_irq(client->irq, si470x_i2c_interrupt,
+			IRQF_TRIGGER_FALLING, DRIVER_NAME, radio);
+	if (retval) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_rds;
+	}
+
 	/* register video device */
 	retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
 			radio_nr);
@@ -330,6 +458,9 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
 
 	return 0;
 err_all:
+	free_irq(client->irq, radio);
+err_rds:
+	kfree(radio->buffer);
 err_video:
 	video_device_release(radio->videodev);
 err_radio:
@@ -346,6 +477,8 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
 {
 	struct si470x_device *radio = i2c_get_clientdata(client);
 
+	free_irq(client->irq, radio);
+	cancel_work_sync(&radio->radio_work);
 	video_unregister_device(radio->videodev);
 	kfree(radio);
 	i2c_set_clientdata(client, NULL);
@@ -354,6 +487,44 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
 }
 
 
+#ifdef CONFIG_PM
+/*
+ * si470x_i2c_suspend - suspend the device
+ */
+static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct si470x_device *radio = i2c_get_clientdata(client);
+
+	/* power down */
+	radio->registers[POWERCFG] |= POWERCFG_DISABLE;
+	if (si470x_set_register(radio, POWERCFG) < 0)
+		return -EIO;
+
+	return 0;
+}
+
+
+/*
+ * si470x_i2c_resume - resume the device
+ */
+static int si470x_i2c_resume(struct i2c_client *client)
+{
+	struct si470x_device *radio = i2c_get_clientdata(client);
+
+	/* power up : need 110ms */
+	radio->registers[POWERCFG] |= POWERCFG_ENABLE;
+	if (si470x_set_register(radio, POWERCFG) < 0)
+		return -EIO;
+	msleep(110);
+
+	return 0;
+}
+#else
+#define si470x_i2c_suspend	NULL
+#define si470x_i2c_resume	NULL
+#endif
+
+
 /*
  * si470x_i2c_driver - i2c driver interface
  */
@@ -364,6 +535,8 @@ static struct i2c_driver si470x_i2c_driver = {
 	},
 	.probe			= si470x_i2c_probe,
 	.remove			= __devexit_p(si470x_i2c_remove),
+	.suspend		= si470x_i2c_suspend,
+	.resume			= si470x_i2c_resume,
 	.id_table		= si470x_i2c_id,
 };
 

+ 2 - 95
drivers/media/radio/si470x/radio-si470x-usb.c

@@ -508,90 +508,10 @@ resubmit:
  * File Operations Interface
  **************************************************************************/
 
-/*
- * si470x_fops_read - read RDS data
- */
-static ssize_t si470x_fops_read(struct file *file, char __user *buf,
-		size_t count, loff_t *ppos)
-{
-	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
-	unsigned int block_count = 0;
-
-	/* switch on rds reception */
-	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
-		si470x_rds_on(radio);
-
-	/* block if no new data available */
-	while (radio->wr_index == radio->rd_index) {
-		if (file->f_flags & O_NONBLOCK) {
-			retval = -EWOULDBLOCK;
-			goto done;
-		}
-		if (wait_event_interruptible(radio->read_queue,
-			radio->wr_index != radio->rd_index) < 0) {
-			retval = -EINTR;
-			goto done;
-		}
-	}
-
-	/* calculate block count from byte count */
-	count /= 3;
-
-	/* copy RDS block out of internal buffer and to user buffer */
-	mutex_lock(&radio->lock);
-	while (block_count < count) {
-		if (radio->rd_index == radio->wr_index)
-			break;
-
-		/* always transfer rds complete blocks */
-		if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
-			/* retval = -EFAULT; */
-			break;
-
-		/* increment and wrap read pointer */
-		radio->rd_index += 3;
-		if (radio->rd_index >= radio->buf_size)
-			radio->rd_index = 0;
-
-		/* increment counters */
-		block_count++;
-		buf += 3;
-		retval += 3;
-	}
-	mutex_unlock(&radio->lock);
-
-done:
-	return retval;
-}
-
-
-/*
- * si470x_fops_poll - poll RDS data
- */
-static unsigned int si470x_fops_poll(struct file *file,
-		struct poll_table_struct *pts)
-{
-	struct si470x_device *radio = video_drvdata(file);
-	int retval = 0;
-
-	/* switch on rds reception */
-	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
-		si470x_rds_on(radio);
-
-	poll_wait(file, &radio->read_queue, pts);
-
-	if (radio->rd_index != radio->wr_index)
-		retval = POLLIN | POLLRDNORM;
-
-	return retval;
-}
-
-
 /*
  * si470x_fops_open - file open
  */
-static int si470x_fops_open(struct file *file)
+int si470x_fops_open(struct file *file)
 {
 	struct si470x_device *radio = video_drvdata(file);
 	int retval;
@@ -645,7 +565,7 @@ done:
 /*
  * si470x_fops_release - file release
  */
-static int si470x_fops_release(struct file *file)
+int si470x_fops_release(struct file *file)
 {
 	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
@@ -688,19 +608,6 @@ done:
 }
 
 
-/*
- * si470x_fops - file operations interface
- */
-const struct v4l2_file_operations si470x_fops = {
-	.owner		= THIS_MODULE,
-	.read		= si470x_fops_read,
-	.poll		= si470x_fops_poll,
-	.ioctl		= video_ioctl2,
-	.open		= si470x_fops_open,
-	.release	= si470x_fops_release,
-};
-
-
 
 /**************************************************************************
  * Video4Linux Interface

+ 4 - 1
drivers/media/radio/si470x/radio-si470x.h

@@ -29,6 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/input.h>
@@ -181,6 +182,7 @@ struct si470x_device {
 
 #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
 	struct i2c_client *client;
+	struct work_struct radio_work;
 #endif
 };
 
@@ -212,7 +214,6 @@ struct si470x_device {
 /**************************************************************************
  * Common Functions
  **************************************************************************/
-extern const struct v4l2_file_operations si470x_fops;
 extern struct video_device si470x_viddev_template;
 int si470x_get_register(struct si470x_device *radio, int regnr);
 int si470x_set_register(struct si470x_device *radio, int regnr);
@@ -221,5 +222,7 @@ int si470x_set_freq(struct si470x_device *radio, unsigned int freq);
 int si470x_start(struct si470x_device *radio);
 int si470x_stop(struct si470x_device *radio);
 int si470x_rds_on(struct si470x_device *radio);
+int si470x_fops_open(struct file *file);
+int si470x_fops_release(struct file *file);
 int si470x_vidioc_querycap(struct file *file, void *priv,
 		struct v4l2_capability *capability);

+ 6 - 4
drivers/media/video/Kconfig

@@ -37,10 +37,6 @@ config VIDEO_BTCX
 	depends on PCI
 	tristate
 
-config VIDEO_IR
-	tristate
-	depends on INPUT
-
 config VIDEO_TVEEPROM
 	tristate
 	depends on I2C
@@ -840,6 +836,12 @@ config SOC_CAMERA_MT9T031
 	help
 	  This driver supports MT9T031 cameras from Micron.
 
+config SOC_CAMERA_MT9T112
+	tristate "mt9t112 support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This driver supports MT9T112 cameras from Aptina.
+
 config SOC_CAMERA_MT9V022
 	tristate "mt9v022 support"
 	depends on SOC_CAMERA && I2C

+ 2 - 1
drivers/media/video/Makefile

@@ -75,6 +75,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
 obj-$(CONFIG_SOC_CAMERA_MT9T031)	+= mt9t031.o
+obj-$(CONFIG_SOC_CAMERA_MT9T112)	+= mt9t112.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
 obj-$(CONFIG_SOC_CAMERA_OV772X)		+= ov772x.o
 obj-$(CONFIG_SOC_CAMERA_OV9640)		+= ov9640.o
@@ -149,7 +150,7 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 obj-$(CONFIG_VIDEO_OMAP2)		+= omap2cam.o
-obj-$(CONFIG_SOC_CAMERA)		+= soc_camera.o
+obj-$(CONFIG_SOC_CAMERA)		+= soc_camera.o soc_mediabus.o
 obj-$(CONFIG_SOC_CAMERA_PLATFORM)	+= soc_camera_platform.o
 # soc-camera host drivers have to be linked after camera drivers
 obj-$(CONFIG_VIDEO_MX1)			+= mx1_camera.o

+ 2 - 3
drivers/media/video/arv.c

@@ -767,7 +767,6 @@ static struct video_device ar_template = {
 	.name		= "Colour AR VGA",
 	.fops		= &ar_fops,
 	.release	= ar_release,
-	.minor		= -1,
 };
 
 #define ALIGN4(x)	((((int)(x)) & 0x3) == 0)
@@ -860,8 +859,8 @@ static int __init ar_init(void)
 		goto out_dev;
 	}
 
-	printk("video%d: Found M64278 VGA (IRQ %d, Freq %dMHz).\n",
-		ar->vdev->num, M32R_IRQ_INT3, freq);
+	printk("%s: Found M64278 VGA (IRQ %d, Freq %dMHz).\n",
+		video_device_node_name(ar->vdev), M32R_IRQ_INT3, freq);
 
 	return 0;
 

+ 8 - 28
drivers/media/video/au0828/au0828-video.c

@@ -40,7 +40,6 @@
 #include "au0828.h"
 #include "au0828-reg.h"
 
-static LIST_HEAD(au0828_devlist);
 static DEFINE_MUTEX(au0828_sysfs_lock);
 
 #define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1)
@@ -693,10 +692,8 @@ void au0828_analog_unregister(struct au0828_dev *dev)
 	dprintk(1, "au0828_release_resources called\n");
 	mutex_lock(&au0828_sysfs_lock);
 
-	if (dev->vdev) {
-		list_del(&dev->au0828list);
+	if (dev->vdev)
 		video_unregister_device(dev->vdev);
-	}
 	if (dev->vbi_dev)
 		video_unregister_device(dev->vbi_dev);
 
@@ -737,29 +734,15 @@ static void res_free(struct au0828_fh *fh)
 
 static int au0828_v4l2_open(struct file *filp)
 {
-	int minor = video_devdata(filp)->minor;
 	int ret = 0;
-	struct au0828_dev *h, *dev = NULL;
+	struct au0828_dev *dev = video_drvdata(filp);
 	struct au0828_fh *fh;
-	int type = 0;
-	struct list_head *list;
-
-	list_for_each(list, &au0828_devlist) {
-		h = list_entry(list, struct au0828_dev, au0828list);
-		if (h->vdev->minor == minor) {
-			dev = h;
-			type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		}
+	int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
 #ifdef VBI_IS_WORKING
-		if (h->vbi_dev->minor == minor) {
-			dev = h;
-			type = V4L2_BUF_TYPE_VBI_CAPTURE;
-		}
+	if (video_devdata(filp)->vfl_type == VFL_TYPE_GRABBER)
+		type = V4L2_BUF_TYPE_VBI_CAPTURE;
 #endif
-	}
-
-	if (NULL == dev)
-		return -ENODEV;
 
 	fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
 	if (NULL == fh) {
@@ -1587,7 +1570,6 @@ static const struct video_device au0828_video_template = {
 	.fops                       = &au0828_v4l_fops,
 	.release                    = video_device_release,
 	.ioctl_ops 		    = &video_ioctl_ops,
-	.minor                      = -1,
 	.tvnorms                    = V4L2_STD_NTSC_M,
 	.current_norm               = V4L2_STD_NTSC_M,
 };
@@ -1676,25 +1658,23 @@ int au0828_analog_register(struct au0828_dev *dev,
 	strcpy(dev->vbi_dev->name, "au0828a vbi");
 #endif
 
-	list_add_tail(&dev->au0828list, &au0828_devlist);
-
 	/* Register the v4l2 device */
+	video_set_drvdata(dev->vdev, dev);
 	retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
 	if (retval != 0) {
 		dprintk(1, "unable to register video device (error = %d).\n",
 			retval);
-		list_del(&dev->au0828list);
 		video_device_release(dev->vdev);
 		return -ENODEV;
 	}
 
 #ifdef VBI_IS_WORKING
 	/* Register the vbi device */
+	video_set_drvdata(dev->vbi_dev, dev);
 	retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
 	if (retval != 0) {
 		dprintk(1, "unable to register vbi device (error = %d).\n",
 			retval);
-		list_del(&dev->au0828list);
 		video_device_release(dev->vbi_dev);
 		video_device_release(dev->vdev);
 		return -ENODEV;

+ 0 - 1
drivers/media/video/au0828/au0828.h

@@ -192,7 +192,6 @@ struct au0828_dev {
 	struct au0828_dvb		dvb;
 
 	/* Analog */
-	struct list_head au0828list;
 	struct v4l2_device v4l2_dev;
 	int users;
 	unsigned int stream_on:1;	/* Locks streams */

+ 17 - 24
drivers/media/video/bt8xx/bttv-driver.c

@@ -3206,24 +3206,24 @@ err:
 
 static int bttv_open(struct file *file)
 {
-	int minor = video_devdata(file)->minor;
+	struct video_device *vdev = video_devdata(file);
 	struct bttv *btv = video_drvdata(file);
 	struct bttv_fh *fh;
 	enum v4l2_buf_type type = 0;
 
-	dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
+	dprintk(KERN_DEBUG "bttv: open dev=%s\n", video_device_node_name(vdev));
 
-	lock_kernel();
-	if (btv->video_dev->minor == minor) {
+	if (vdev->vfl_type == VFL_TYPE_GRABBER) {
 		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	} else if (btv->vbi_dev->minor == minor) {
+	} else if (vdev->vfl_type == VFL_TYPE_VBI) {
 		type = V4L2_BUF_TYPE_VBI_CAPTURE;
 	} else {
 		WARN_ON(1);
-		unlock_kernel();
 		return -ENODEV;
 	}
 
+	lock_kernel();
+
 	dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
 		btv->c.nr,v4l2_type_names[type]);
 
@@ -3397,7 +3397,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
 
 static struct video_device bttv_video_template = {
 	.fops         = &bttv_fops,
-	.minor        = -1,
 	.ioctl_ops    = &bttv_ioctl_ops,
 	.tvnorms      = BTTV_NORMS,
 	.current_norm = V4L2_STD_PAL,
@@ -3408,18 +3407,13 @@ static struct video_device bttv_video_template = {
 
 static int radio_open(struct file *file)
 {
-	int minor = video_devdata(file)->minor;
+	struct video_device *vdev = video_devdata(file);
 	struct bttv *btv = video_drvdata(file);
 	struct bttv_fh *fh;
 
-	dprintk("bttv: open minor=%d\n",minor);
+	dprintk("bttv: open dev=%s\n", video_device_node_name(vdev));
 
 	lock_kernel();
-	WARN_ON(btv->radio_dev && btv->radio_dev->minor != minor);
-	if (!btv->radio_dev || btv->radio_dev->minor != minor) {
-		unlock_kernel();
-		return -ENODEV;
-	}
 
 	dprintk("bttv%d: open called (radio)\n",btv->c.nr);
 
@@ -3640,7 +3634,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
 
 static struct video_device radio_template = {
 	.fops      = &radio_fops,
-	.minor     = -1,
 	.ioctl_ops = &radio_ioctl_ops,
 };
 
@@ -4208,21 +4201,21 @@ static struct video_device *vdev_init(struct bttv *btv,
 static void bttv_unregister_video(struct bttv *btv)
 {
 	if (btv->video_dev) {
-		if (-1 != btv->video_dev->minor)
+		if (video_is_registered(btv->video_dev))
 			video_unregister_device(btv->video_dev);
 		else
 			video_device_release(btv->video_dev);
 		btv->video_dev = NULL;
 	}
 	if (btv->vbi_dev) {
-		if (-1 != btv->vbi_dev->minor)
+		if (video_is_registered(btv->vbi_dev))
 			video_unregister_device(btv->vbi_dev);
 		else
 			video_device_release(btv->vbi_dev);
 		btv->vbi_dev = NULL;
 	}
 	if (btv->radio_dev) {
-		if (-1 != btv->radio_dev->minor)
+		if (video_is_registered(btv->radio_dev))
 			video_unregister_device(btv->radio_dev);
 		else
 			video_device_release(btv->radio_dev);
@@ -4244,8 +4237,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
 	if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER,
 				  video_nr[btv->c.nr]) < 0)
 		goto err;
-	printk(KERN_INFO "bttv%d: registered device video%d\n",
-	       btv->c.nr, btv->video_dev->num);
+	printk(KERN_INFO "bttv%d: registered device %s\n",
+	       btv->c.nr, video_device_node_name(btv->video_dev));
 	if (device_create_file(&btv->video_dev->dev,
 				     &dev_attr_card)<0) {
 		printk(KERN_ERR "bttv%d: device_create_file 'card' "
@@ -4261,8 +4254,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
 	if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI,
 				  vbi_nr[btv->c.nr]) < 0)
 		goto err;
-	printk(KERN_INFO "bttv%d: registered device vbi%d\n",
-	       btv->c.nr, btv->vbi_dev->num);
+	printk(KERN_INFO "bttv%d: registered device %s\n",
+	       btv->c.nr, video_device_node_name(btv->vbi_dev));
 
 	if (!btv->has_radio)
 		return 0;
@@ -4273,8 +4266,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
 	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,
 				  radio_nr[btv->c.nr]) < 0)
 		goto err;
-	printk(KERN_INFO "bttv%d: registered device radio%d\n",
-	       btv->c.nr, btv->radio_dev->num);
+	printk(KERN_INFO "bttv%d: registered device %s\n",
+	       btv->c.nr, video_device_node_name(btv->radio_dev));
 
 	/* all done */
 	return 0;

+ 2 - 2
drivers/media/video/bt8xx/bttv-i2c.c

@@ -40,7 +40,7 @@ static int i2c_debug;
 static int i2c_hw;
 static int i2c_scan;
 module_param(i2c_debug, int, 0644);
-MODULE_PARM_DESC(i2c_hw,"configure i2c debug level");
+MODULE_PARM_DESC(i2c_debug, "configure i2c debug level");
 module_param(i2c_hw,    int, 0444);
 MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, "
 			"instead of software bitbang");
@@ -400,7 +400,7 @@ int __devinit init_bttv_i2c(struct bttv *btv)
 		   That's why we probe 0x1a (~0x34) first. CB
 		*/
 		const unsigned short addr_list[] = {
-			0x1a, 0x18, 0x4b, 0x64, 0x30,
+			0x1a, 0x18, 0x4b, 0x64, 0x30, 0x71,
 			I2C_CLIENT_END
 		};
 

+ 3 - 6
drivers/media/video/bt8xx/bttv-input.c

@@ -368,7 +368,7 @@ int bttv_input_init(struct bttv *btv)
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
 		 pci_name(btv->c.pci));
 
-	err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
+	err = ir_input_init(input_dev, &ir->ir, ir_type);
 	if (err < 0)
 		goto err_out_free;
 
@@ -389,7 +389,7 @@ int bttv_input_init(struct bttv *btv)
 	bttv_ir_start(btv, ir);
 
 	/* all done */
-	err = input_register_device(btv->remote->dev);
+	err = ir_input_register(btv->remote->dev, ir_codes);
 	if (err)
 		goto err_out_stop;
 
@@ -403,8 +403,6 @@ 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;
 }
@@ -415,8 +413,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);
+	ir_input_unregister(btv->remote->dev);
 	kfree(btv->remote);
 	btv->remote = NULL;
 }

+ 2 - 2
drivers/media/video/c-qcam.c

@@ -809,8 +809,8 @@ static int init_cqcam(struct parport *port)
 		return -ENODEV;
 	}
 
-	printk(KERN_INFO "video%d: Colour QuickCam found on %s\n",
-	       qcam->vdev.num, qcam->pport->name);
+	printk(KERN_INFO "%s: Colour QuickCam found on %s\n",
+	       video_device_node_name(&qcam->vdev), qcam->pport->name);
 
 	qcams[num_cams++] = qcam;
 

+ 0 - 1
drivers/media/video/cafe_ccic.c

@@ -1723,7 +1723,6 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
 
 static struct video_device cafe_v4l_template = {
 	.name = "cafe",
-	.minor = -1, /* Get one dynamically */
 	.tvnorms = V4L2_STD_NTSC_M,
 	.current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
 

+ 107 - 114
drivers/media/video/cpia.c

@@ -32,6 +32,7 @@
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/ctype.h>
@@ -244,72 +245,67 @@ static void rvfree(void *mem, unsigned long size)
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry *cpia_proc_root=NULL;
 
-static int cpia_read_proc(char *page, char **start, off_t off,
-			  int count, int *eof, void *data)
+static int cpia_proc_show(struct seq_file *m, void *v)
 {
-	char *out = page;
-	int len, tmp;
-	struct cam_data *cam = data;
+	struct cam_data *cam = m->private;
+	int tmp;
 	char tmpstr[29];
 
-	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
-	 *            or we need to get more sophisticated. */
-
-	out += sprintf(out, "read-only\n-----------------------\n");
-	out += sprintf(out, "V4L Driver version:       %d.%d.%d\n",
+	seq_printf(m, "read-only\n-----------------------\n");
+	seq_printf(m, "V4L Driver version:       %d.%d.%d\n",
 		       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
-	out += sprintf(out, "CPIA Version:             %d.%02d (%d.%d)\n",
+	seq_printf(m, "CPIA Version:             %d.%02d (%d.%d)\n",
 		       cam->params.version.firmwareVersion,
 		       cam->params.version.firmwareRevision,
 		       cam->params.version.vcVersion,
 		       cam->params.version.vcRevision);
-	out += sprintf(out, "CPIA PnP-ID:              %04x:%04x:%04x\n",
+	seq_printf(m, "CPIA PnP-ID:              %04x:%04x:%04x\n",
 		       cam->params.pnpID.vendor, cam->params.pnpID.product,
 		       cam->params.pnpID.deviceRevision);
-	out += sprintf(out, "VP-Version:               %d.%d %04x\n",
+	seq_printf(m, "VP-Version:               %d.%d %04x\n",
 		       cam->params.vpVersion.vpVersion,
 		       cam->params.vpVersion.vpRevision,
 		       cam->params.vpVersion.cameraHeadID);
 
-	out += sprintf(out, "system_state:             %#04x\n",
+	seq_printf(m, "system_state:             %#04x\n",
 		       cam->params.status.systemState);
-	out += sprintf(out, "grab_state:               %#04x\n",
+	seq_printf(m, "grab_state:               %#04x\n",
 		       cam->params.status.grabState);
-	out += sprintf(out, "stream_state:             %#04x\n",
+	seq_printf(m, "stream_state:             %#04x\n",
 		       cam->params.status.streamState);
-	out += sprintf(out, "fatal_error:              %#04x\n",
+	seq_printf(m, "fatal_error:              %#04x\n",
 		       cam->params.status.fatalError);
-	out += sprintf(out, "cmd_error:                %#04x\n",
+	seq_printf(m, "cmd_error:                %#04x\n",
 		       cam->params.status.cmdError);
-	out += sprintf(out, "debug_flags:              %#04x\n",
+	seq_printf(m, "debug_flags:              %#04x\n",
 		       cam->params.status.debugFlags);
-	out += sprintf(out, "vp_status:                %#04x\n",
+	seq_printf(m, "vp_status:                %#04x\n",
 		       cam->params.status.vpStatus);
-	out += sprintf(out, "error_code:               %#04x\n",
+	seq_printf(m, "error_code:               %#04x\n",
 		       cam->params.status.errorCode);
 	/* QX3 specific entries */
 	if (cam->params.qx3.qx3_detected) {
-		out += sprintf(out, "button:                   %4d\n",
+		seq_printf(m, "button:                   %4d\n",
 			       cam->params.qx3.button);
-		out += sprintf(out, "cradled:                  %4d\n",
+		seq_printf(m, "cradled:                  %4d\n",
 			       cam->params.qx3.cradled);
 	}
-	out += sprintf(out, "video_size:               %s\n",
+	seq_printf(m, "video_size:               %s\n",
 		       cam->params.format.videoSize == VIDEOSIZE_CIF ?
 		       "CIF " : "QCIF");
-	out += sprintf(out, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
+	seq_printf(m, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
 		       cam->params.roi.colStart*8,
 		       cam->params.roi.rowStart*4,
 		       cam->params.roi.colEnd*8,
 		       cam->params.roi.rowEnd*4);
-	out += sprintf(out, "actual_fps:               %3d\n", cam->fps);
-	out += sprintf(out, "transfer_rate:            %4dkB/s\n",
+	seq_printf(m, "actual_fps:               %3d\n", cam->fps);
+	seq_printf(m, "transfer_rate:            %4dkB/s\n",
 		       cam->transfer_rate);
 
-	out += sprintf(out, "\nread-write\n");
-	out += sprintf(out, "-----------------------  current       min"
+	seq_printf(m, "\nread-write\n");
+	seq_printf(m, "-----------------------  current       min"
 		       "       max   default  comment\n");
-	out += sprintf(out, "brightness:             %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "brightness:             %8d  %8d  %8d  %8d\n",
 		       cam->params.colourParams.brightness, 0, 100, 50);
 	if (cam->params.version.firmwareVersion == 1 &&
 	   cam->params.version.firmwareRevision == 2)
@@ -318,26 +314,26 @@ static int cpia_read_proc(char *page, char **start, off_t off,
 	else
 		tmp = 96;
 
-	out += sprintf(out, "contrast:               %8d  %8d  %8d  %8d"
+	seq_printf(m, "contrast:               %8d  %8d  %8d  %8d"
 		       "  steps of 8\n",
 		       cam->params.colourParams.contrast, 0, tmp, 48);
-	out += sprintf(out, "saturation:             %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "saturation:             %8d  %8d  %8d  %8d\n",
 		       cam->params.colourParams.saturation, 0, 100, 50);
 	tmp = (25000+5000*cam->params.sensorFps.baserate)/
 	      (1<<cam->params.sensorFps.divisor);
-	out += sprintf(out, "sensor_fps:             %4d.%03d  %8d  %8d  %8d\n",
+	seq_printf(m, "sensor_fps:             %4d.%03d  %8d  %8d  %8d\n",
 		       tmp/1000, tmp%1000, 3, 30, 15);
-	out += sprintf(out, "stream_start_line:      %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "stream_start_line:      %8d  %8d  %8d  %8d\n",
 		       2*cam->params.streamStartLine, 0,
 		       cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
 		       cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
-	out += sprintf(out, "sub_sample:             %8s  %8s  %8s  %8s\n",
+	seq_printf(m, "sub_sample:             %8s  %8s  %8s  %8s\n",
 		       cam->params.format.subSample == SUBSAMPLE_420 ?
 		       "420" : "422", "420", "422", "422");
-	out += sprintf(out, "yuv_order:              %8s  %8s  %8s  %8s\n",
+	seq_printf(m, "yuv_order:              %8s  %8s  %8s  %8s\n",
 		       cam->params.format.yuvOrder == YUVORDER_YUYV ?
 		       "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
-	out += sprintf(out, "ecp_timing:             %8s  %8s  %8s  %8s\n",
+	seq_printf(m, "ecp_timing:             %8s  %8s  %8s  %8s\n",
 		       cam->params.ecpTiming ? "slow" : "normal", "slow",
 		       "normal", "normal");
 
@@ -346,13 +342,13 @@ static int cpia_read_proc(char *page, char **start, off_t off,
 	} else {
 		sprintf(tmpstr, "manual");
 	}
-	out += sprintf(out, "color_balance_mode:     %8s  %8s  %8s"
+	seq_printf(m, "color_balance_mode:     %8s  %8s  %8s"
 		       "  %8s\n",  tmpstr, "manual", "auto", "auto");
-	out += sprintf(out, "red_gain:               %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "red_gain:               %8d  %8d  %8d  %8d\n",
 		       cam->params.colourBalance.redGain, 0, 212, 32);
-	out += sprintf(out, "green_gain:             %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "green_gain:             %8d  %8d  %8d  %8d\n",
 		       cam->params.colourBalance.greenGain, 0, 212, 6);
-	out += sprintf(out, "blue_gain:              %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "blue_gain:              %8d  %8d  %8d  %8d\n",
 		       cam->params.colourBalance.blueGain, 0, 212, 92);
 
 	if (cam->params.version.firmwareVersion == 1 &&
@@ -363,10 +359,10 @@ static int cpia_read_proc(char *page, char **start, off_t off,
 		sprintf(tmpstr, "%8d  %8d  %8d", 1, 8, 2);
 
 	if (cam->params.exposure.gainMode == 0)
-		out += sprintf(out, "max_gain:                unknown  %28s"
+		seq_printf(m, "max_gain:                unknown  %28s"
 			       "  powers of 2\n", tmpstr);
 	else
-		out += sprintf(out, "max_gain:               %8d  %28s"
+		seq_printf(m, "max_gain:               %8d  %28s"
 			       "  1,2,4 or 8 \n",
 			       1<<(cam->params.exposure.gainMode-1), tmpstr);
 
@@ -382,12 +378,12 @@ static int cpia_read_proc(char *page, char **start, off_t off,
 		sprintf(tmpstr, "unknown");
 		break;
 	}
-	out += sprintf(out, "exposure_mode:          %8s  %8s  %8s"
+	seq_printf(m, "exposure_mode:          %8s  %8s  %8s"
 		       "  %8s\n",  tmpstr, "manual", "auto", "auto");
-	out += sprintf(out, "centre_weight:          %8s  %8s  %8s  %8s\n",
+	seq_printf(m, "centre_weight:          %8s  %8s  %8s  %8s\n",
 		       (2-cam->params.exposure.centreWeight) ? "on" : "off",
 		       "off", "on", "on");
-	out += sprintf(out, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 possible\n",
+	seq_printf(m, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 possible\n",
 		       1<<cam->params.exposure.gain, 1, 1);
 	if (cam->params.version.firmwareVersion == 1 &&
 	   cam->params.version.firmwareRevision == 2)
@@ -396,7 +392,7 @@ static int cpia_read_proc(char *page, char **start, off_t off,
 	else
 		tmp = 510;
 
-	out += sprintf(out, "fine_exp:               %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "fine_exp:               %8d  %8d  %8d  %8d\n",
 		       cam->params.exposure.fineExp*2, 0, tmp, 0);
 	if (cam->params.version.firmwareVersion == 1 &&
 	   cam->params.version.firmwareRevision == 2)
@@ -405,127 +401,122 @@ static int cpia_read_proc(char *page, char **start, off_t off,
 	else
 		tmp = MAX_EXP;
 
-	out += sprintf(out, "coarse_exp:             %8d  %8d  %8d"
+	seq_printf(m, "coarse_exp:             %8d  %8d  %8d"
 		       "  %8d\n", cam->params.exposure.coarseExpLo+
 		       256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
-	out += sprintf(out, "red_comp:               %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "red_comp:               %8d  %8d  %8d  %8d\n",
 		       cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
-	out += sprintf(out, "green1_comp:            %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "green1_comp:            %8d  %8d  %8d  %8d\n",
 		       cam->params.exposure.green1Comp, COMP_GREEN1, 255,
 		       COMP_GREEN1);
-	out += sprintf(out, "green2_comp:            %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "green2_comp:            %8d  %8d  %8d  %8d\n",
 		       cam->params.exposure.green2Comp, COMP_GREEN2, 255,
 		       COMP_GREEN2);
-	out += sprintf(out, "blue_comp:              %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "blue_comp:              %8d  %8d  %8d  %8d\n",
 		       cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
 
-	out += sprintf(out, "apcor_gain1:            %#8x  %#8x  %#8x  %#8x\n",
+	seq_printf(m, "apcor_gain1:            %#8x  %#8x  %#8x  %#8x\n",
 		       cam->params.apcor.gain1, 0, 0xff, 0x1c);
-	out += sprintf(out, "apcor_gain2:            %#8x  %#8x  %#8x  %#8x\n",
+	seq_printf(m, "apcor_gain2:            %#8x  %#8x  %#8x  %#8x\n",
 		       cam->params.apcor.gain2, 0, 0xff, 0x1a);
-	out += sprintf(out, "apcor_gain4:            %#8x  %#8x  %#8x  %#8x\n",
+	seq_printf(m, "apcor_gain4:            %#8x  %#8x  %#8x  %#8x\n",
 		       cam->params.apcor.gain4, 0, 0xff, 0x2d);
-	out += sprintf(out, "apcor_gain8:            %#8x  %#8x  %#8x  %#8x\n",
+	seq_printf(m, "apcor_gain8:            %#8x  %#8x  %#8x  %#8x\n",
 		       cam->params.apcor.gain8, 0, 0xff, 0x2a);
-	out += sprintf(out, "vl_offset_gain1:        %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "vl_offset_gain1:        %8d  %8d  %8d  %8d\n",
 		       cam->params.vlOffset.gain1, 0, 255, 24);
-	out += sprintf(out, "vl_offset_gain2:        %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "vl_offset_gain2:        %8d  %8d  %8d  %8d\n",
 		       cam->params.vlOffset.gain2, 0, 255, 28);
-	out += sprintf(out, "vl_offset_gain4:        %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "vl_offset_gain4:        %8d  %8d  %8d  %8d\n",
 		       cam->params.vlOffset.gain4, 0, 255, 30);
-	out += sprintf(out, "vl_offset_gain8:        %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "vl_offset_gain8:        %8d  %8d  %8d  %8d\n",
 		       cam->params.vlOffset.gain8, 0, 255, 30);
-	out += sprintf(out, "flicker_control:        %8s  %8s  %8s  %8s\n",
+	seq_printf(m, "flicker_control:        %8s  %8s  %8s  %8s\n",
 		       cam->params.flickerControl.flickerMode ? "on" : "off",
 		       "off", "on", "off");
-	out += sprintf(out, "mains_frequency:        %8d  %8d  %8d  %8d"
+	seq_printf(m, "mains_frequency:        %8d  %8d  %8d  %8d"
 		       " only 50/60\n",
 		       cam->mainsFreq ? 60 : 50, 50, 60, 50);
 	if(cam->params.flickerControl.allowableOverExposure < 0)
-		out += sprintf(out, "allowable_overexposure: %4dauto      auto  %8d      auto\n",
+		seq_printf(m, "allowable_overexposure: %4dauto      auto  %8d      auto\n",
 			       -cam->params.flickerControl.allowableOverExposure,
 			       255);
 	else
-		out += sprintf(out, "allowable_overexposure: %8d      auto  %8d      auto\n",
+		seq_printf(m, "allowable_overexposure: %8d      auto  %8d      auto\n",
 			       cam->params.flickerControl.allowableOverExposure,
 			       255);
-	out += sprintf(out, "compression_mode:       ");
+	seq_printf(m, "compression_mode:       ");
 	switch(cam->params.compression.mode) {
 	case CPIA_COMPRESSION_NONE:
-		out += sprintf(out, "%8s", "none");
+		seq_printf(m, "%8s", "none");
 		break;
 	case CPIA_COMPRESSION_AUTO:
-		out += sprintf(out, "%8s", "auto");
+		seq_printf(m, "%8s", "auto");
 		break;
 	case CPIA_COMPRESSION_MANUAL:
-		out += sprintf(out, "%8s", "manual");
+		seq_printf(m, "%8s", "manual");
 		break;
 	default:
-		out += sprintf(out, "%8s", "unknown");
+		seq_printf(m, "%8s", "unknown");
 		break;
 	}
-	out += sprintf(out, "    none,auto,manual      auto\n");
-	out += sprintf(out, "decimation_enable:      %8s  %8s  %8s  %8s\n",
+	seq_printf(m, "    none,auto,manual      auto\n");
+	seq_printf(m, "decimation_enable:      %8s  %8s  %8s  %8s\n",
 		       cam->params.compression.decimation ==
 		       DECIMATION_ENAB ? "on":"off", "off", "on",
 		       "off");
-	out += sprintf(out, "compression_target:    %9s %9s %9s %9s\n",
+	seq_printf(m, "compression_target:    %9s %9s %9s %9s\n",
 		       cam->params.compressionTarget.frTargeting  ==
 		       CPIA_COMPRESSION_TARGET_FRAMERATE ?
 		       "framerate":"quality",
 		       "framerate", "quality", "quality");
-	out += sprintf(out, "target_framerate:       %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "target_framerate:       %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionTarget.targetFR, 1, 30, 15);
-	out += sprintf(out, "target_quality:         %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "target_quality:         %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionTarget.targetQ, 1, 64, 5);
-	out += sprintf(out, "y_threshold:            %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "y_threshold:            %8d  %8d  %8d  %8d\n",
 		       cam->params.yuvThreshold.yThreshold, 0, 31, 6);
-	out += sprintf(out, "uv_threshold:           %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "uv_threshold:           %8d  %8d  %8d  %8d\n",
 		       cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
-	out += sprintf(out, "hysteresis:             %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "hysteresis:             %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionParams.hysteresis, 0, 255, 3);
-	out += sprintf(out, "threshold_max:          %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "threshold_max:          %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionParams.threshMax, 0, 255, 11);
-	out += sprintf(out, "small_step:             %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "small_step:             %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionParams.smallStep, 0, 255, 1);
-	out += sprintf(out, "large_step:             %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "large_step:             %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionParams.largeStep, 0, 255, 3);
-	out += sprintf(out, "decimation_hysteresis:  %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "decimation_hysteresis:  %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionParams.decimationHysteresis,
 		       0, 255, 2);
-	out += sprintf(out, "fr_diff_step_thresh:    %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "fr_diff_step_thresh:    %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionParams.frDiffStepThresh,
 		       0, 255, 5);
-	out += sprintf(out, "q_diff_step_thresh:     %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "q_diff_step_thresh:     %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionParams.qDiffStepThresh,
 		       0, 255, 3);
-	out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
+	seq_printf(m, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
 		       cam->params.compressionParams.decimationThreshMod,
 		       0, 255, 2);
 	/* QX3 specific entries */
 	if (cam->params.qx3.qx3_detected) {
-		out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n",
+		seq_printf(m, "toplight:               %8s  %8s  %8s  %8s\n",
 			       cam->params.qx3.toplight ? "on" : "off",
 			       "off", "on", "off");
-		out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n",
+		seq_printf(m, "bottomlight:            %8s  %8s  %8s  %8s\n",
 			       cam->params.qx3.bottomlight ? "on" : "off",
 			       "off", "on", "off");
 	}
 
-	len = out - page;
-	len -= off;
-	if (len < count) {
-		*eof = 1;
-		if (len <= 0) return 0;
-	} else
-		len = count;
-
-	*start = page + off;
-	return len;
+	return 0;
 }
 
+static int cpia_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cpia_proc_show, PDE(inode)->data);
+}
 
-static int match(char *checkstr, char **buffer, unsigned long *count,
+static int match(char *checkstr, char **buffer, size_t *count,
 		 int *find_colon, int *err)
 {
 	int ret, colon_found = 1;
@@ -551,7 +542,7 @@ static int match(char *checkstr, char **buffer, unsigned long *count,
 	return ret;
 }
 
-static unsigned long int value(char **buffer, unsigned long *count, int *err)
+static unsigned long int value(char **buffer, size_t *count, int *err)
 {
 	char *p;
 	unsigned long int ret;
@@ -565,10 +556,10 @@ static unsigned long int value(char **buffer, unsigned long *count, int *err)
 	return ret;
 }
 
-static int cpia_write_proc(struct file *file, const char __user *buf,
-			   unsigned long count, void *data)
+static ssize_t cpia_proc_write(struct file *file, const char __user *buf,
+			       size_t count, loff_t *pos)
 {
-	struct cam_data *cam = data;
+	struct cam_data *cam = PDE(file->f_path.dentry->d_inode)->data;
 	struct cam_params new_params;
 	char *page, *buffer;
 	int retval, find_colon;
@@ -582,7 +573,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
 	 * from the comx driver
 	 */
 	if (count > PAGE_SIZE) {
-		printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
+		printk(KERN_ERR "count is %zu > %d!!!\n", count, (int)PAGE_SIZE);
 		return -ENOSPC;
 	}
 
@@ -1340,23 +1331,28 @@ out:
 	return retval;
 }
 
+static const struct file_operations cpia_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= cpia_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+	.write		= cpia_proc_write,
+};
+
 static void create_proc_cpia_cam(struct cam_data *cam)
 {
-	char name[5 + 1 + 10 + 1];
 	struct proc_dir_entry *ent;
 
 	if (!cpia_proc_root || !cam)
 		return;
 
-	snprintf(name, sizeof(name), "video%d", cam->vdev.num);
-
-	ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
+	ent = proc_create_data(video_device_node_name(&cam->vdev),
+			       S_IRUGO|S_IWUSR, cpia_proc_root,
+			       &cpia_proc_fops, cam);
 	if (!ent)
 		return;
 
-	ent->data = cam;
-	ent->read_proc = cpia_read_proc;
-	ent->write_proc = cpia_write_proc;
 	/*
 	   size of the proc entry is 3736 bytes for the standard webcam;
 	   the extra features of the QX3 microscope add 189 bytes.
@@ -1368,13 +1364,10 @@ static void create_proc_cpia_cam(struct cam_data *cam)
 
 static void destroy_proc_cpia_cam(struct cam_data *cam)
 {
-	char name[5 + 1 + 10 + 1];
-
 	if (!cam || !cam->proc_entry)
 		return;
 
-	snprintf(name, sizeof(name), "video%d", cam->vdev.num);
-	remove_proc_entry(name, cpia_proc_root);
+	remove_proc_entry(video_device_node_name(&cam->vdev), cpia_proc_root);
 	cam->proc_entry = NULL;
 }
 
@@ -3999,7 +3992,7 @@ void cpia_unregister_camera(struct cam_data *cam)
 	}
 
 #ifdef CONFIG_PROC_FS
-	DBG("destroying /proc/cpia/video%d\n", cam->vdev.num);
+	DBG("destroying /proc/cpia/%s\n", video_device_node_name(&cam->vdev));
 	destroy_proc_cpia_cam(cam);
 #endif
 	if (!cam->open_count) {

+ 14 - 20
drivers/media/video/cpia2/cpia2_v4l.c

@@ -38,17 +38,12 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/videodev.h>
+#include <linux/stringify.h>
 #include <media/v4l2-ioctl.h>
 
 #include "cpia2.h"
 #include "cpia2dev.h"
 
-
-//#define _CPIA2_DEBUG_
-
-#define MAKE_STRING_1(x)	#x
-#define MAKE_STRING(x)	MAKE_STRING_1(x)
-
 static int video_nr = -1;
 module_param(video_nr, int, 0);
 MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");
@@ -60,26 +55,26 @@ MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)
 static int num_buffers = 3;
 module_param(num_buffers, int, 0);
 MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-"
-		 MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)");
+		 __stringify(VIDEO_MAX_FRAME) ", default 3)");
 
 static int alternate = DEFAULT_ALT;
 module_param(alternate, int, 0);
-MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-"
-		 MAKE_STRING(USBIF_ISO_6) ", default "
-		 MAKE_STRING(DEFAULT_ALT) ")");
+MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-"
+		 __stringify(USBIF_ISO_6) ", default "
+		 __stringify(DEFAULT_ALT) ")");
 
 static int flicker_freq = 60;
 module_param(flicker_freq, int, 0);
-MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or"
-		 MAKE_STRING(60) ", default "
-		 MAKE_STRING(60) ")");
+MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" __stringify(50) "or"
+		 __stringify(60) ", default "
+		 __stringify(60) ")");
 
 static int flicker_mode = NEVER_FLICKER;
 module_param(flicker_mode, int, 0);
 MODULE_PARM_DESC(flicker_mode,
-		 "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or"
-		 MAKE_STRING(ANTI_FLICKER_ON) ", default "
-		 MAKE_STRING(NEVER_FLICKER) ")");
+		 "Flicker supression (" __stringify(NEVER_FLICKER) "or"
+		 __stringify(ANTI_FLICKER_ON) ", default "
+		 __stringify(NEVER_FLICKER) ")");
 
 MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
 MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
@@ -1926,7 +1921,6 @@ static const struct v4l2_file_operations fops_template = {
 static struct video_device cpia2_template = {
 	/* I could not find any place for the old .initialize initializer?? */
 	.name=		"CPiA2 Camera",
-	.minor=		-1,
 	.fops=		&fops_template,
 	.release=	video_device_release,
 };
@@ -1967,9 +1961,9 @@ void cpia2_unregister_camera(struct camera_data *cam)
 	if (!cam->open_count) {
 		video_unregister_device(cam->vdev);
 	} else {
-		LOG("/dev/video%d removed while open, "
-		    "deferring video_unregister_device\n",
-		    cam->vdev->num);
+		LOG("%s removed while open, deferring "
+		    "video_unregister_device\n",
+		    video_device_node_name(cam->vdev));
 	}
 }
 

+ 2 - 2
drivers/media/video/cx18/cx18-fileops.c

@@ -758,8 +758,8 @@ int cx18_v4l2_open(struct file *filp)
 
 	mutex_lock(&cx->serialize_lock);
 	if (cx18_init_on_first_open(cx)) {
-		CX18_ERR("Failed to initialize on minor %d\n",
-			 video_dev->minor);
+		CX18_ERR("Failed to initialize on %s\n",
+			 video_device_node_name(video_dev));
 		mutex_unlock(&cx->serialize_lock);
 		return -ENXIO;
 	}

+ 10 - 10
drivers/media/video/cx18/cx18-streams.c

@@ -219,6 +219,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
 {
 	struct cx18_stream *s = &cx->streams[type];
 	int vfl_type = cx18_stream_info[type].vfl_type;
+	const char *name;
 	int num, ret;
 
 	/* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
@@ -258,31 +259,30 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
 		s->video_dev = NULL;
 		return ret;
 	}
-	num = s->video_dev->num;
+
+	name = video_device_node_name(s->video_dev);
 
 	switch (vfl_type) {
 	case VFL_TYPE_GRABBER:
-		CX18_INFO("Registered device video%d for %s "
-			  "(%d x %d.%02d kB)\n",
-			  num, s->name, cx->stream_buffers[type],
+		CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n",
+			  name, s->name, cx->stream_buffers[type],
 			  cx->stream_buf_size[type] / 1024,
 			  (cx->stream_buf_size[type] * 100 / 1024) % 100);
 		break;
 
 	case VFL_TYPE_RADIO:
-		CX18_INFO("Registered device radio%d for %s\n",
-			num, s->name);
+		CX18_INFO("Registered device %s for %s\n", name, s->name);
 		break;
 
 	case VFL_TYPE_VBI:
 		if (cx->stream_buffers[type])
-			CX18_INFO("Registered device vbi%d for %s "
+			CX18_INFO("Registered device %s for %s "
 				  "(%d x %d bytes)\n",
-				  num, s->name, cx->stream_buffers[type],
+				  name, s->name, cx->stream_buffers[type],
 				  cx->stream_buf_size[type]);
 		else
-			CX18_INFO("Registered device vbi%d for %s\n",
-				num, s->name);
+			CX18_INFO("Registered device %s for %s\n",
+				name, s->name);
 		break;
 	}
 

+ 12 - 11
drivers/media/video/cx231xx/cx231xx-cards.c

@@ -68,19 +68,19 @@ struct cx231xx_board cx231xx_boards[] = {
 				.type = CX231XX_VMUX_TELEVISION,
 				.vmux = CX231XX_VIN_3_1,
 				.amux = CX231XX_AMUX_VIDEO,
-				.gpio = 0,
+				.gpio = NULL,
 			}, {
 				.type = CX231XX_VMUX_COMPOSITE1,
 				.vmux = CX231XX_VIN_2_1,
 				.amux = CX231XX_AMUX_LINE_IN,
-				.gpio = 0,
+				.gpio = NULL,
 			}, {
 				.type = CX231XX_VMUX_SVIDEO,
 				.vmux = CX231XX_VIN_1_1 |
 					(CX231XX_VIN_1_2 << 8) |
 					CX25840_SVIDEO_ON,
 				.amux = CX231XX_AMUX_LINE_IN,
-				.gpio = 0,
+				.gpio = NULL,
 			}
 		},
 	},
@@ -107,19 +107,19 @@ struct cx231xx_board cx231xx_boards[] = {
 				.type = CX231XX_VMUX_TELEVISION,
 				.vmux = CX231XX_VIN_3_1,
 				.amux = CX231XX_AMUX_VIDEO,
-				.gpio = 0,
+				.gpio = NULL,
 			}, {
 				.type = CX231XX_VMUX_COMPOSITE1,
 				.vmux = CX231XX_VIN_2_1,
 				.amux = CX231XX_AMUX_LINE_IN,
-				.gpio = 0,
+				.gpio = NULL,
 			}, {
 				.type = CX231XX_VMUX_SVIDEO,
 				.vmux = CX231XX_VIN_1_1 |
 					(CX231XX_VIN_1_2 << 8) |
 					CX25840_SVIDEO_ON,
 				.amux = CX231XX_AMUX_LINE_IN,
-				.gpio = 0,
+				.gpio = NULL,
 			}
 		},
 	},
@@ -147,19 +147,19 @@ struct cx231xx_board cx231xx_boards[] = {
 				.type = CX231XX_VMUX_TELEVISION,
 				.vmux = CX231XX_VIN_3_1,
 				.amux = CX231XX_AMUX_VIDEO,
-				.gpio = 0,
+				.gpio = NULL,
 			}, {
 				.type = CX231XX_VMUX_COMPOSITE1,
 				.vmux = CX231XX_VIN_2_1,
 				.amux = CX231XX_AMUX_LINE_IN,
-				.gpio = 0,
+				.gpio = NULL,
 			}, {
 				.type = CX231XX_VMUX_SVIDEO,
 				.vmux = CX231XX_VIN_1_1 |
 					(CX231XX_VIN_1_2 << 8) |
 					CX25840_SVIDEO_ON,
 				.amux = CX231XX_AMUX_LINE_IN,
-				.gpio = 0,
+				.gpio = NULL,
 			}
 		},
 	},
@@ -856,8 +856,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
 
 	if (dev->users) {
 		cx231xx_warn
-		    ("device /dev/video%d is open! Deregistration and memory "
-		     "deallocation are deferred on close.\n", dev->vdev->num);
+		    ("device %s is open! Deregistration and memory "
+		     "deallocation are deferred on close.\n",
+		     video_device_node_name(dev->vdev));
 
 		dev->state |= DEV_MISCONFIGURED;
 		cx231xx_uninit_isoc(dev);

+ 0 - 26
drivers/media/video/cx231xx/cx231xx-core.c

@@ -66,32 +66,6 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
 static LIST_HEAD(cx231xx_devlist);
 static DEFINE_MUTEX(cx231xx_devlist_mutex);
 
-struct cx231xx *cx231xx_get_device(int minor,
-				   enum v4l2_buf_type *fh_type, int *has_radio)
-{
-	struct cx231xx *h, *dev = NULL;
-
-	*fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	*has_radio = 0;
-
-	mutex_lock(&cx231xx_devlist_mutex);
-	list_for_each_entry(h, &cx231xx_devlist, devlist) {
-		if (h->vdev->minor == minor)
-			dev = h;
-		if (h->vbi_dev->minor == minor) {
-			dev = h;
-			*fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
-		}
-		if (h->radio_dev && h->radio_dev->minor == minor) {
-			dev = h;
-			*has_radio = 1;
-		}
-	}
-	mutex_unlock(&cx231xx_devlist_mutex);
-
-	return dev;
-}
-
 /*
  * cx231xx_realease_resources()
  * unregisters the v4l2,i2c and usb devices

+ 3 - 7
drivers/media/video/cx231xx/cx231xx-input.c

@@ -197,8 +197,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
 	usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
 	strlcat(ir->phys, "/input0", sizeof(ir->phys));
 
-	err = 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);
 	if (err < 0)
 		goto err_out_free;
 
@@ -217,7 +216,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
 	cx231xx_ir_start(ir);
 
 	/* all done */
-	err = input_register_device(ir->input);
+	err = ir_input_register(ir->input, dev->board.ir_codes);
 	if (err)
 		goto err_out_stop;
 
@@ -226,8 +225,6 @@ 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;
 }
@@ -241,8 +238,7 @@ int cx231xx_ir_fini(struct cx231xx *dev)
 		return 0;
 
 	cx231xx_ir_stop(ir);
-	ir_input_free(ir->input);
-	input_unregister_device(ir->input);
+	ir_input_unregister(ir->input);
 	kfree(ir);
 
 	/* done */

+ 33 - 25
drivers/media/video/cx231xx/cx231xx-video.c

@@ -1916,20 +1916,29 @@ static int radio_queryctrl(struct file *file, void *priv,
  */
 static int cx231xx_v4l2_open(struct file *filp)
 {
-	int minor = video_devdata(filp)->minor;
 	int errCode = 0, radio = 0;
-	struct cx231xx *dev = NULL;
+	struct video_device *vdev = video_devdata(filp);
+	struct cx231xx *dev = video_drvdata(filp);
 	struct cx231xx_fh *fh;
 	enum v4l2_buf_type fh_type = 0;
 
-	dev = cx231xx_get_device(minor, &fh_type, &radio);
-	if (NULL == dev)
-		return -ENODEV;
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case VFL_TYPE_VBI:
+		fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		break;
+	case VFL_TYPE_RADIO:
+		radio = 1;
+		break;
+	}
 
 	mutex_lock(&dev->lock);
 
-	cx231xx_videodbg("open minor=%d type=%s users=%d\n",
-			 minor, v4l2_type_names[fh_type], dev->users);
+	cx231xx_videodbg("open dev=%s type=%s users=%d\n",
+			 video_device_node_name(vdev), v4l2_type_names[fh_type],
+			 dev->users);
 
 #if 0
 	errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
@@ -2020,25 +2029,25 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
 	/*FIXME: I2C IR should be disconnected */
 
 	if (dev->radio_dev) {
-		if (-1 != dev->radio_dev->minor)
+		if (video_is_registered(dev->radio_dev))
 			video_unregister_device(dev->radio_dev);
 		else
 			video_device_release(dev->radio_dev);
 		dev->radio_dev = NULL;
 	}
 	if (dev->vbi_dev) {
-		cx231xx_info("V4L2 device /dev/vbi%d deregistered\n",
-			     dev->vbi_dev->num);
-		if (-1 != dev->vbi_dev->minor)
+		cx231xx_info("V4L2 device %s deregistered\n",
+			     video_device_node_name(dev->vbi_dev));
+		if (video_is_registered(dev->vbi_dev))
 			video_unregister_device(dev->vbi_dev);
 		else
 			video_device_release(dev->vbi_dev);
 		dev->vbi_dev = NULL;
 	}
 	if (dev->vdev) {
-		cx231xx_info("V4L2 device /dev/video%d deregistered\n",
-			     dev->vdev->num);
-		if (-1 != dev->vdev->minor)
+		cx231xx_info("V4L2 device %s deregistered\n",
+			     video_device_node_name(dev->vdev));
+		if (video_is_registered(dev->vdev))
 			video_unregister_device(dev->vdev);
 		else
 			video_device_release(dev->vdev);
@@ -2268,7 +2277,6 @@ static const struct video_device cx231xx_video_template = {
 	.fops         = &cx231xx_v4l_fops,
 	.release      = video_device_release,
 	.ioctl_ops    = &video_ioctl_ops,
-	.minor        = -1,
 	.tvnorms      = V4L2_STD_ALL,
 	.current_norm = V4L2_STD_PAL,
 };
@@ -2303,7 +2311,6 @@ static struct video_device cx231xx_radio_template = {
 	.name      = "cx231xx-radio",
 	.fops      = &radio_fops,
 	.ioctl_ops = &radio_ioctl_ops,
-	.minor     = -1,
 };
 
 /******************************** usb interface ******************************/
@@ -2319,13 +2326,13 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
 		return NULL;
 
 	*vfd = *template;
-	vfd->minor = -1;
 	vfd->v4l2_dev = &dev->v4l2_dev;
 	vfd->release = video_device_release;
 	vfd->debug = video_debug;
 
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
 
+	video_set_drvdata(vfd, dev);
 	return vfd;
 }
 
@@ -2374,8 +2381,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
 		return ret;
 	}
 
-	cx231xx_info("%s/0: registered device video%d [v4l2]\n",
-		     dev->name, dev->vdev->num);
+	cx231xx_info("%s/0: registered device %s [v4l2]\n",
+		     dev->name, video_device_node_name(dev->vdev));
 
 	/* Initialize VBI template */
 	memcpy(&cx231xx_vbi_template, &cx231xx_video_template,
@@ -2393,8 +2400,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
 		return ret;
 	}
 
-	cx231xx_info("%s/0: registered device vbi%d\n",
-		     dev->name, dev->vbi_dev->num);
+	cx231xx_info("%s/0: registered device %s\n",
+		     dev->name, video_device_node_name(dev->vbi_dev));
 
 	if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
 		dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template,
@@ -2409,12 +2416,13 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
 			cx231xx_errdev("can't register radio device\n");
 			return ret;
 		}
-		cx231xx_info("Registered radio device as /dev/radio%d\n",
-			     dev->radio_dev->num);
+		cx231xx_info("Registered radio device as %s\n",
+			     video_device_node_name(dev->radio_dev));
 	}
 
-	cx231xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
-		     dev->vdev->num, dev->vbi_dev->num);
+	cx231xx_info("V4L2 device registered as %s and %s\n",
+		     video_device_node_name(dev->vdev),
+		     video_device_node_name(dev->vbi_dev));
 
 	return 0;
 }

+ 0 - 2
drivers/media/video/cx231xx/cx231xx.h

@@ -689,8 +689,6 @@ void cx231xx_release_analog_resources(struct cx231xx *dev);
 int cx231xx_register_analog_devices(struct cx231xx *dev);
 void cx231xx_remove_from_devlist(struct cx231xx *dev);
 void cx231xx_add_into_devlist(struct cx231xx *dev);
-struct cx231xx *cx231xx_get_device(int minor,
-				   enum v4l2_buf_type *fh_type, int *has_radio);
 void cx231xx_init_extension(struct cx231xx *dev);
 void cx231xx_close_extension(struct cx231xx *dev);
 

+ 78 - 29
drivers/media/video/cx23885/cimax2.c

@@ -53,6 +53,8 @@
 #define NETUP_CI_CTL		0x04
 #define NETUP_CI_RD		1
 
+#define NETUP_IRQ_DETAM 	0x1
+#define NETUP_IRQ_IRQAM		0x4
 
 static unsigned int ci_dbg;
 module_param(ci_dbg, int, 0644);
@@ -73,6 +75,9 @@ struct netup_ci_state {
 	int status;
 	struct work_struct work;
 	void *priv;
+	u8 current_irq_mode;
+	int current_ci_flag;
+	unsigned long next_status_checked_time;
 };
 
 
@@ -169,24 +174,26 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
 	if (0 != slot)
 		return -EINVAL;
 
-	ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
-							0, &store, 1);
-	if (ret != 0)
-		return ret;
+	if (state->current_ci_flag != flag) {
+		ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+				0, &store, 1);
+		if (ret != 0)
+			return ret;
 
-	store &= ~0x0c;
-	store |= flag;
+		store &= ~0x0c;
+		store |= flag;
 
-	ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
-							0, &store, 1);
-	if (ret != 0)
-		return ret;
+		ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+				0, &store, 1);
+		if (ret != 0)
+			return ret;
+	};
+	state->current_ci_flag = flag;
 
 	mutex_lock(&dev->gpio_lock);
 
 	/* write addr */
 	cx_write(MC417_OEN, NETUP_EN_ALL);
-	msleep(2);
 	cx_write(MC417_RWD, NETUP_CTRL_OFF |
 				NETUP_ADLO | (0xff & addr));
 	cx_clear(MC417_RWD, NETUP_ADLO);
@@ -196,7 +203,6 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
 
 	if (read) { /* data in */
 		cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA);
-		msleep(2);
 	} else /* data out */
 		cx_write(MC417_RWD, NETUP_CTRL_OFF | data);
 
@@ -213,8 +219,8 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
 		if (mem < 0)
 			return -EREMOTEIO;
 
-	ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__,
-			(read) ? "read" : "write", addr,
+	ci_dbg_print("%s: %s: chipaddr=[0x%x] addr=[0x%02x], %s=%x\n", __func__,
+			(read) ? "read" : "write", state->ci_i2c_addr, addr,
 			(flag == NETUP_CI_CTL) ? "ctl" : "mem",
 			(read) ? mem : data);
 
@@ -283,14 +289,39 @@ int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
 	return 0;
 }
 
+int netup_ci_set_irq(struct dvb_ca_en50221 *en50221, u8 irq_mode)
+{
+	struct netup_ci_state *state = en50221->data;
+	int ret;
+
+	if (irq_mode == state->current_irq_mode)
+		return 0;
+
+	ci_dbg_print("%s: chipaddr=[0x%x] setting ci IRQ to [0x%x] \n",
+			__func__, state->ci_i2c_addr, irq_mode);
+	ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
+							0x1b, &irq_mode, 1);
+
+	if (ret != 0)
+		return ret;
+
+	state->current_irq_mode = irq_mode;
+
+	return 0;
+}
+
 int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)
 {
 	struct netup_ci_state *state = en50221->data;
-	u8 buf = 0x60;
+	u8 buf;
 
 	if (0 != slot)
 		return -EINVAL;
 
+	netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+			0, &buf, 1);
+	buf |= 0x60;
+
 	return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
 							0, &buf, 1);
 }
@@ -303,21 +334,35 @@ static void netup_read_ci_status(struct work_struct *work)
 	u8 buf[33];
 	int ret;
 
-	ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
-							0, &buf[0], 33);
+	/* CAM module IRQ processing. fast operation */
+	dvb_ca_en50221_frda_irq(&state->ca, 0);
 
-	if (ret != 0)
-		return;
+	/* CAM module INSERT/REMOVE processing. slow operation because of i2c
+	 * transfers */
+	if (time_after(jiffies, state->next_status_checked_time)
+			|| !state->status) {
+		ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr,
+				0, &buf[0], 33);
+
+		state->next_status_checked_time = jiffies
+			+ msecs_to_jiffies(1000);
+
+		if (ret != 0)
+			return;
 
-	ci_dbg_print("%s: Slot Status Addr=[0x%04x], Reg=[0x%02x], data=%02x, "
-		"TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0],
-		buf[32]);
+		ci_dbg_print("%s: Slot Status Addr=[0x%04x], "
+				"Reg=[0x%02x], data=%02x, "
+				"TS config = %02x\n", __func__,
+				state->ci_i2c_addr, 0, buf[0],
+				buf[0]);
 
-	if (buf[0] & 1)
-		state->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
-			DVB_CA_EN50221_POLL_CAM_READY;
-	else
-		state->status = 0;
+
+		if (buf[0] & 1)
+			state->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
+				DVB_CA_EN50221_POLL_CAM_READY;
+		else
+			state->status = 0;
+	};
 }
 
 /* CI irq handler */
@@ -347,6 +392,9 @@ int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open
 	if (0 != slot)
 		return -EINVAL;
 
+	netup_ci_set_irq(en50221, open ? (NETUP_IRQ_DETAM | NETUP_IRQ_IRQAM)
+			: NETUP_IRQ_DETAM);
+
 	return state->status;
 }
 
@@ -381,8 +429,8 @@ int netup_ci_init(struct cx23885_tsport *port)
 		0x01, /* power on (use it like store place) */
 		0x00, /* RFU */
 		0x00, /* int status read only */
-		0x01, /* all int unmasked */
-		0x04, /* int config */
+		NETUP_IRQ_IRQAM | NETUP_IRQ_DETAM, /* DETAM, IRQAM unmasked */
+		0x05, /* EXTINT=active-high, INT=push-pull */
 		0x00, /* USCG1 */
 		0x04, /* ack active low */
 		0x00, /* LOCK = 0 */
@@ -422,6 +470,7 @@ int netup_ci_init(struct cx23885_tsport *port)
 	state->ca.poll_slot_status = netup_poll_ci_slot_status;
 	state->ca.data = state;
 	state->priv = port;
+	state->current_irq_mode = NETUP_IRQ_IRQAM | NETUP_IRQ_DETAM;
 
 	ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr,
 						0, &cimax_init[0], 34);

+ 7 - 22
drivers/media/video/cx23885/cx23885-417.c

@@ -1568,28 +1568,11 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 
 static int mpeg_open(struct file *file)
 {
-	int minor = video_devdata(file)->minor;
-	struct cx23885_dev *h, *dev = NULL;
-	struct list_head *list;
+	struct cx23885_dev *dev = video_drvdata(file);
 	struct cx23885_fh *fh;
 
 	dprintk(2, "%s()\n", __func__);
 
-	lock_kernel();
-	list_for_each(list, &cx23885_devlist) {
-		h = list_entry(list, struct cx23885_dev, devlist);
-		if (h->v4l_device &&
-		    h->v4l_device->minor == minor) {
-			dev = h;
-			break;
-		}
-	}
-
-	if (dev == NULL) {
-		unlock_kernel();
-		return -ENODEV;
-	}
-
 	/* allocate + initialize per filehandle data */
 	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
 	if (NULL == fh) {
@@ -1597,6 +1580,8 @@ static int mpeg_open(struct file *file)
 		return -ENOMEM;
 	}
 
+	lock_kernel();
+
 	file->private_data = fh;
 	fh->dev      = dev;
 
@@ -1736,7 +1721,6 @@ static struct video_device cx23885_mpeg_template = {
 	.name          = "cx23885",
 	.fops          = &mpeg_fops,
 	.ioctl_ops     = &mpeg_ioctl_ops,
-	.minor         = -1,
 	.tvnorms       = CX23885_NORMS,
 	.current_norm  = V4L2_STD_NTSC_M,
 };
@@ -1746,7 +1730,7 @@ void cx23885_417_unregister(struct cx23885_dev *dev)
 	dprintk(1, "%s()\n", __func__);
 
 	if (dev->v4l_device) {
-		if (-1 != dev->v4l_device->minor)
+		if (video_is_registered(dev->v4l_device))
 			video_unregister_device(dev->v4l_device);
 		else
 			video_device_release(dev->v4l_device);
@@ -1803,6 +1787,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
 	/* Allocate and initialize V4L video device */
 	dev->v4l_device = cx23885_video_dev_alloc(tsport,
 		dev->pci, &cx23885_mpeg_template, "mpeg");
+	video_set_drvdata(dev->v4l_device, dev);
 	err = video_register_device(dev->v4l_device,
 		VFL_TYPE_GRABBER, -1);
 	if (err < 0) {
@@ -1810,8 +1795,8 @@ int cx23885_417_register(struct cx23885_dev *dev)
 		return err;
 	}
 
-	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
-	       dev->name, dev->v4l_device->num);
+	printk(KERN_INFO "%s: registered device %s [mpeg]\n",
+	       dev->name, video_device_node_name(dev->v4l_device));
 
 	return 0;
 }

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů