Răsfoiți Sursa

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb

* git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (277 commits)
  V4L/DVB (8415): gspca: Infinite loop in i2c_w() of etoms.
  V4L/DVB (8414): videodev/cx18: fix get_index bug and error-handling lock-ups
  V4L/DVB (8411): videobuf-dma-contig.c: fix 64-bit build for pre-2.6.24 kernels
  V4L/DVB (8410): sh_mobile_ceu_camera: fix 64-bit compiler warnings
  V4L/DVB (8397): video: convert select VIDEO_ZORAN_ZR36060 into depends on
  V4L/DVB (8396): video: Fix Kbuild dependency for VIDEO_IR_I2C
  V4L/DVB (8395): saa7134: Fix Kbuild dependency of ir-kbd-i2c
  V4L/DVB (8394): ir-common: CodingStyle fix: move EXPORT_SYMBOL_GPL to their proper places
  V4L/DVB (8393): media/video: Fix depencencies for VIDEOBUF
  V4L/DVB (8392): media/Kconfig: Convert V4L1_COMPAT select into "depends on"
  V4L/DVB (8390): videodev: add comment and remove magic number.
  V4L/DVB (8389): videodev: simplify get_index()
  V4L/DVB (8387): Some cosmetic changes
  V4L/DVB (8381): ov7670: fix compile warnings
  V4L/DVB (8380): saa7115: use saa7115_auto instead of saa711x as the autodetect driver name.
  V4L/DVB (8379): saa7127: Make device detection optional
  V4L/DVB (8378): cx18: move cx18_av_vbi_setup to av-core.c and rename to cx18_av_std_setup
  V4L/DVB (8377): ivtv/cx18: ensure the default control values are correct
  V4L/DVB (8376): cx25840: move cx25840_vbi_setup to core.c and rename to cx25840_std_setup
  V4L/DVB (8374): gspca: No conflict of 0c45:6011 with the sn9c102 driver.
  ...
Linus Torvalds 17 ani în urmă
părinte
comite
f894d18380
100 a modificat fișierele cu 6236 adăugiri și 1622 ștergeri
  1. 1 0
      Documentation/video4linux/CARDLIST.cx23885
  2. 4 1
      Documentation/video4linux/CARDLIST.em28xx
  3. 6 2
      Documentation/video4linux/CARDLIST.saa7134
  4. 15 21
      Documentation/video4linux/cx18.txt
  5. 243 0
      Documentation/video4linux/gspca.txt
  6. 2 3
      drivers/media/Kconfig
  7. 8 18
      drivers/media/common/ir-functions.c
  8. 2 2
      drivers/media/common/saa7146_core.c
  9. 1 1
      drivers/media/common/saa7146_hlp.c
  10. 17 17
      drivers/media/common/saa7146_i2c.c
  11. 2 2
      drivers/media/common/saa7146_video.c
  12. 1 0
      drivers/media/common/tuners/Kconfig
  13. 1 1
      drivers/media/common/tuners/tda18271-maps.c
  14. 14 11
      drivers/media/common/tuners/tuner-xc2028.c
  15. 7 0
      drivers/media/common/tuners/xc5000.c
  16. 1 0
      drivers/media/dvb/Kconfig
  17. 1 1
      drivers/media/dvb/Makefile
  18. 1 1
      drivers/media/dvb/bt8xx/bt878.h
  19. 1 1
      drivers/media/dvb/dvb-core/demux.h
  20. 1 1
      drivers/media/dvb/dvb-core/dmxdev.c
  21. 4 4
      drivers/media/dvb/dvb-core/dvb_ca_en50221.c
  22. 14 3
      drivers/media/dvb/dvb-core/dvb_demux.c
  23. 1 1
      drivers/media/dvb/dvb-core/dvb_net.c
  24. 53 25
      drivers/media/dvb/dvb-core/dvb_ringbuffer.c
  25. 8 4
      drivers/media/dvb/dvb-core/dvb_ringbuffer.h
  26. 15 0
      drivers/media/dvb/dvb-usb/Kconfig
  27. 3 0
      drivers/media/dvb/dvb-usb/Makefile
  28. 553 0
      drivers/media/dvb/dvb-usb/anysee.c
  29. 304 0
      drivers/media/dvb/dvb-usb/anysee.h
  30. 41 42
      drivers/media/dvb/dvb-usb/au6610.c
  31. 21 1
      drivers/media/dvb/dvb-usb/au6610.h
  32. 142 4
      drivers/media/dvb/dvb-usb/cxusb.c
  33. 3 0
      drivers/media/dvb/dvb-usb/cxusb.h
  34. 6 1
      drivers/media/dvb/dvb-usb/dib0700_devices.c
  35. 0 4
      drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
  36. 8 0
      drivers/media/dvb/dvb-usb/dvb-usb-ids.h
  37. 19 19
      drivers/media/dvb/dvb-usb/gl861.c
  38. 1 1
      drivers/media/dvb/dvb-usb/gl861.h
  39. 0 1
      drivers/media/dvb/frontends/au8522.c
  40. 47 0
      drivers/media/dvb/frontends/dvb-pll.c
  41. 1 0
      drivers/media/dvb/frontends/dvb-pll.h
  42. 19 5
      drivers/media/dvb/frontends/lgdt330x.c
  43. 0 1
      drivers/media/dvb/frontends/s5h1409.c
  44. 0 1
      drivers/media/dvb/frontends/s5h1411.c
  45. 116 81
      drivers/media/dvb/frontends/tda10023.c
  46. 34 7
      drivers/media/dvb/frontends/tda1002x.h
  47. 1 1
      drivers/media/dvb/pluto2/pluto2.c
  48. 26 0
      drivers/media/dvb/siano/Kconfig
  49. 8 0
      drivers/media/dvb/siano/Makefile
  50. 102 0
      drivers/media/dvb/siano/sms-cards.c
  51. 45 0
      drivers/media/dvb/siano/sms-cards.h
  52. 1251 0
      drivers/media/dvb/siano/smscoreapi.c
  53. 434 0
      drivers/media/dvb/siano/smscoreapi.h
  54. 449 0
      drivers/media/dvb/siano/smsdvb.c
  55. 459 0
      drivers/media/dvb/siano/smsusb.c
  56. 2 0
      drivers/media/dvb/ttpci/Kconfig
  57. 6 1
      drivers/media/dvb/ttpci/Makefile
  58. 21 26
      drivers/media/dvb/ttpci/av7110.c
  59. 0 1
      drivers/media/dvb/ttpci/av7110.h
  60. 1 1
      drivers/media/dvb/ttpci/av7110_av.c
  61. 1 1
      drivers/media/dvb/ttpci/av7110_ca.c
  62. 0 3
      drivers/media/dvb/ttpci/av7110_hw.h
  63. 9 3
      drivers/media/dvb/ttpci/budget-av.c
  64. 24 0
      drivers/media/dvb/ttpci/budget-ci.c
  65. 0 4
      drivers/media/dvb/ttpci/budget-core.c
  66. 22 22
      drivers/media/dvb/ttpci/budget-patch.c
  67. 3 19
      drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
  68. 345 138
      drivers/media/radio/radio-si470x.c
  69. 69 30
      drivers/media/video/Kconfig
  70. 5 0
      drivers/media/video/Makefile
  71. 1 1
      drivers/media/video/bt819.c
  72. 0 1
      drivers/media/video/bt8xx/bt832.c
  73. 26 25
      drivers/media/video/bt8xx/bttv-driver.c
  74. 14 35
      drivers/media/video/bt8xx/bttv-i2c.c
  75. 3 3
      drivers/media/video/bt8xx/bttv-vbi.c
  76. 0 1
      drivers/media/video/bt8xx/bttv.h
  77. 3 6
      drivers/media/video/bt8xx/bttvp.h
  78. 9 9
      drivers/media/video/cafe_ccic.c
  79. 1 0
      drivers/media/video/compat_ioctl32.c
  80. 0 1
      drivers/media/video/cs5345.c
  81. 0 2
      drivers/media/video/cs53l32a.c
  82. 14 1
      drivers/media/video/cx18/cx18-audio.c
  83. 6 6
      drivers/media/video/cx18/cx18-av-audio.c
  84. 156 69
      drivers/media/video/cx18/cx18-av-core.c
  85. 4 12
      drivers/media/video/cx18/cx18-av-core.h
  86. 45 27
      drivers/media/video/cx18/cx18-av-firmware.c
  87. 4 148
      drivers/media/video/cx18/cx18-av-vbi.c
  88. 75 14
      drivers/media/video/cx18/cx18-cards.c
  89. 9 0
      drivers/media/video/cx18/cx18-cards.h
  90. 112 104
      drivers/media/video/cx18/cx18-controls.c
  91. 6 1
      drivers/media/video/cx18/cx18-controls.h
  92. 16 5
      drivers/media/video/cx18/cx18-driver.c
  93. 4 3
      drivers/media/video/cx18/cx18-driver.h
  94. 6 4
      drivers/media/video/cx18/cx18-firmware.c
  95. 88 2
      drivers/media/video/cx18/cx18-gpio.c
  96. 2 0
      drivers/media/video/cx18/cx18-gpio.h
  97. 20 5
      drivers/media/video/cx18/cx18-i2c.c
  98. 582 597
      drivers/media/video/cx18/cx18-ioctl.c
  99. 4 2
      drivers/media/video/cx18/cx18-ioctl.h
  100. 1 0
      drivers/media/video/cx18/cx18-mailbox.c

+ 1 - 0
Documentation/video4linux/CARDLIST.cx23885

@@ -8,3 +8,4 @@
   7 -> Hauppauge WinTV-HVR1200                             [0070:71d1,0070:71d3]
   7 -> Hauppauge WinTV-HVR1200                             [0070:71d1,0070:71d3]
   8 -> Hauppauge WinTV-HVR1700                             [0070:8101]
   8 -> Hauppauge WinTV-HVR1700                             [0070:8101]
   9 -> Hauppauge WinTV-HVR1400                             [0070:8010]
   9 -> Hauppauge WinTV-HVR1400                             [0070:8010]
+ 10 -> DViCO FusionHDTV7 Dual Express                      [18ac:d618]

+ 4 - 1
Documentation/video4linux/CARDLIST.em28xx

@@ -8,10 +8,13 @@
   7 -> Leadtek Winfast USB II                   (em2800)
   7 -> Leadtek Winfast USB II                   (em2800)
   8 -> Kworld USB2800                           (em2800)
   8 -> Kworld USB2800                           (em2800)
   9 -> Pinnacle Dazzle DVC 90/DVC 100           (em2820/em2840) [2304:0207,2304:021a]
   9 -> Pinnacle Dazzle DVC 90/DVC 100           (em2820/em2840) [2304:0207,2304:021a]
- 10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500,2040:6502]
+ 10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500]
  11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
  13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
  13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
  14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
  14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
  15 -> V-Gear PocketTV                          (em2800)
  15 -> V-Gear PocketTV                          (em2800)
  16 -> Hauppauge WinTV HVR 950                  (em2880)        [2040:6513,2040:6517,2040:651b,2040:651f]
  16 -> Hauppauge WinTV HVR 950                  (em2880)        [2040:6513,2040:6517,2040:651b,2040:651f]
+ 17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
+ 18 -> Hauppauge WinTV HVR 900 (R2)             (em2880)        [2040:6502]
+ 19 -> PointNix Intra-Oral Camera               (em2860)

+ 6 - 2
Documentation/video4linux/CARDLIST.saa7134

@@ -37,7 +37,7 @@
  36 -> UPMOST PURPLE TV                         [12ab:0800]
  36 -> UPMOST PURPLE TV                         [12ab:0800]
  37 -> Items MuchTV Plus / IT-005
  37 -> Items MuchTV Plus / IT-005
  38 -> Terratec Cinergy 200 TV                  [153b:1152]
  38 -> Terratec Cinergy 200 TV                  [153b:1152]
- 39 -> LifeView FlyTV Platinum Mini             [5168:0212,4e42:0212]
+ 39 -> LifeView FlyTV Platinum Mini             [5168:0212,4e42:0212,5169:1502]
  40 -> Compro VideoMate TV PVR/FM               [185b:c100]
  40 -> Compro VideoMate TV PVR/FM               [185b:c100]
  41 -> Compro VideoMate TV Gold+                [185b:c100]
  41 -> Compro VideoMate TV Gold+                [185b:c100]
  42 -> Sabrent SBT-TVFM (saa7130)
  42 -> Sabrent SBT-TVFM (saa7130)
@@ -128,7 +128,7 @@
 127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
 127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
 128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
 128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
 129 -> Beholder BeholdTV 607 / BeholdTV 609     [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
 129 -> Beholder BeholdTV 607 / BeholdTV 609     [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
-130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193,5ace:6191]
+130 -> Beholder BeholdTV M6                     [5ace:6190]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
 132 -> Genius TVGO AM11MCE
 132 -> Genius TVGO AM11MCE
 133 -> NXP Snake DVB-S reference design
 133 -> NXP Snake DVB-S reference design
@@ -141,3 +141,7 @@
 140 -> Avermedia DVB-S Pro A700                 [1461:a7a1]
 140 -> Avermedia DVB-S Pro A700                 [1461:a7a1]
 141 -> Avermedia DVB-S Hybrid+FM A700           [1461:a7a2]
 141 -> Avermedia DVB-S Hybrid+FM A700           [1461:a7a2]
 142 -> Beholder BeholdTV H6                     [5ace:6290]
 142 -> Beholder BeholdTV H6                     [5ace:6290]
+143 -> Beholder BeholdTV M63                    [5ace:6191]
+144 -> Beholder BeholdTV M6 Extra               [5ace:6193]
+145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636]
+146 -> ASUSTeK P7131 Analog

+ 15 - 21
Documentation/video4linux/cx18.txt

@@ -1,36 +1,30 @@
 Some notes regarding the cx18 driver for the Conexant CX23418 MPEG
 Some notes regarding the cx18 driver for the Conexant CX23418 MPEG
 encoder chip:
 encoder chip:
 
 
-1) The only hardware currently supported is the Hauppauge HVR-1600
-   card and the Compro VideoMate H900 (note that this card only
-   supports analog input, it has no digital tuner!).
+1) Currently supported are:
 
 
-2) Some people have problems getting the i2c bus to work. Cause unknown.
-   The symptom is that the eeprom cannot be read and the card is
-   unusable.
+	- Hauppauge HVR-1600
+	- Compro VideoMate H900
+	- Yuan MPC718
+	- Conexant Raptor PAL/SECAM devkit
 
 
-3) The audio from the analog tuner is mono only. Probably caused by
-   incorrect audio register information in the datasheet. We are
-   waiting for updated information from Conexant.
+2) Some people have problems getting the i2c bus to work.
+   The symptom is that the eeprom cannot be read and the card is
+   unusable. This is probably fixed, but if you have problems
+   then post to the video4linux or ivtv-users mailinglist.
 
 
-4) VBI (raw or sliced) has not yet been implemented.
+3) VBI (raw or sliced) has not yet been implemented.
 
 
-5) MPEG indexing is not yet implemented.
+4) MPEG indexing is not yet implemented.
 
 
-6) The driver is still a bit rough around the edges, this should
+5) The driver is still a bit rough around the edges, this should
    improve over time.
    improve over time.
 
 
 
 
 Firmware:
 Firmware:
 
 
-The firmware needs to be extracted from the Windows Hauppauge HVR-1600
-driver, available here:
-
-http://hauppauge.lightpath.net/software/install_cd/hauppauge_cd_3.4d1.zip
+You can obtain the firmware files here:
 
 
-Unzip, then copy the following files to the firmware directory
-and rename them as follows:
+http://dl.ivtvdriver.org/ivtv/firmware/cx18-firmware.tar.gz
 
 
-Drivers/Driver18/hcw18apu.rom -> v4l-cx23418-apu.fw
-Drivers/Driver18/hcw18enc.rom -> v4l-cx23418-cpu.fw
-Drivers/Driver18/hcw18mlC.rom -> v4l-cx23418-dig.fw
+Untar and copy the .fw files to your firmware directory.

+ 243 - 0
Documentation/video4linux/gspca.txt

@@ -0,0 +1,243 @@
+List of the webcams know by gspca.
+
+The modules are:
+	gspca_main	main driver
+	gspca_xxxx	subdriver module with xxxx as follows
+
+xxxx		vend:prod
+----
+spca501		0000:0000	MystFromOri Unknow Camera
+spca501		040a:0002	Kodak DVC-325
+spca500		040a:0300	Kodak EZ200
+zc3xx		041e:041e	Creative WebCam Live!
+spca500		041e:400a	Creative PC-CAM 300
+sunplus		041e:400b	Creative PC-CAM 600
+sunplus		041e:4012	PC-Cam350
+sunplus		041e:4013	Creative Pccam750
+zc3xx		041e:4017	Creative Webcam Mobile PD1090
+spca508		041e:4018	Creative Webcam Vista (PD1100)
+spca561		041e:401a	Creative Webcam Vista (PD1100)
+zc3xx		041e:401c	Creative NX
+spca505		041e:401d	Creative Webcam NX ULTRA
+zc3xx		041e:401e	Creative Nx Pro
+zc3xx		041e:401f	Creative Webcam Notebook PD1171
+pac207		041e:4028	Creative Webcam Vista Plus
+zc3xx		041e:4029	Creative WebCam Vista Pro
+zc3xx		041e:4034	Creative Instant P0620
+zc3xx		041e:4035	Creative Instant P0620D
+zc3xx		041e:4036	Creative Live !
+zc3xx		041e:403a	Creative Nx Pro 2
+spca561		041e:403b	Creative Webcam Vista (VF0010)
+zc3xx		041e:4051	Creative Live!Cam Notebook Pro (VF0250)
+ov519		041e:4052	Creative Live! VISTA IM
+zc3xx		041e:4053	Creative Live!Cam Video IM
+ov519		041e:405f	Creative Live! VISTA VF0330
+ov519		041e:4060	Creative Live! VISTA VF0350
+ov519		041e:4061	Creative Live! VISTA VF0400
+ov519		041e:4064	Creative Live! VISTA VF0420
+ov519		041e:4068	Creative Live! VISTA VF0470
+spca561		0458:7004	Genius VideoCAM Express V2
+sunplus		0458:7006	Genius Dsc 1.3 Smart
+zc3xx		0458:7007	Genius VideoCam V2
+zc3xx		0458:700c	Genius VideoCam V3
+zc3xx		0458:700f	Genius VideoCam Web V2
+sonixj		0458:7025	Genius Eye 311Q
+sonixj		045e:00f5	MicroSoft VX3000
+sonixj		045e:00f7	MicroSoft VX1000
+ov519		045e:028c	Micro$oft xbox cam
+spca508		0461:0815	Micro Innovation IC200
+sunplus		0461:0821	Fujifilm MV-1
+zc3xx		0461:0a00	MicroInnovation WebCam320
+spca500		046d:0890	Logitech QuickCam traveler
+vc032x		046d:0892	Logitech Orbicam
+vc032x		046d:0896	Logitech Orbicam
+zc3xx		046d:08a0	Logitech QC IM
+zc3xx		046d:08a1	Logitech QC IM 0x08A1 +sound
+zc3xx		046d:08a2	Labtec Webcam Pro
+zc3xx		046d:08a3	Logitech QC Chat
+zc3xx		046d:08a6	Logitech QCim
+zc3xx		046d:08a7	Logitech QuickCam Image
+zc3xx		046d:08a9	Logitech Notebook Deluxe
+zc3xx		046d:08aa	Labtec Webcam  Notebook
+zc3xx		046d:08ac	Logitech QuickCam Cool
+zc3xx		046d:08ad	Logitech QCCommunicate STX
+zc3xx		046d:08ae	Logitech QuickCam for Notebooks
+zc3xx		046d:08af	Logitech QuickCam Cool
+zc3xx		046d:08b9	Logitech QC IM ???
+zc3xx		046d:08d7	Logitech QCam STX
+zc3xx		046d:08d9	Logitech QuickCam IM/Connect
+zc3xx		046d:08d8	Logitech Notebook Deluxe
+zc3xx		046d:08da	Logitech QuickCam Messenger
+zc3xx		046d:08dd	Logitech QuickCam for Notebooks
+spca500		046d:0900	Logitech Inc. ClickSmart 310
+spca500		046d:0901	Logitech Inc. ClickSmart 510
+sunplus		046d:0905	Logitech ClickSmart 820
+tv8532		046d:0920	QC Express
+tv8532		046d:0921	Labtec Webcam
+spca561		046d:0928	Logitech QC Express Etch2
+spca561		046d:0929	Labtec Webcam Elch2
+spca561		046d:092a	Logitech QC for Notebook
+spca561		046d:092b	Labtec Webcam Plus
+spca561		046d:092c	Logitech QC chat Elch2
+spca561		046d:092d	Logitech QC Elch2
+spca561		046d:092e	Logitech QC Elch2
+spca561		046d:092f	Logitech QC Elch2
+sunplus		046d:0960	Logitech ClickSmart 420
+sunplus		0471:0322	Philips DMVC1300K
+zc3xx		0471:0325	Philips SPC 200 NC
+zc3xx		0471:0326	Philips SPC 300 NC
+sonixj		0471:0327	Philips SPC 600 NC
+sonixj		0471:0328	Philips SPC 700 NC
+zc3xx		0471:032d	Philips spc210nc
+zc3xx		0471:032e	Philips spc315nc
+sonixj		0471:0330	Philips SPC 710NC
+spca501		0497:c001	Smile International
+sunplus		04a5:3003	Benq DC 1300
+sunplus		04a5:3008	Benq DC 1500
+sunplus		04a5:300a	Benq DC3410
+spca500		04a5:300c	Benq DC1016
+sunplus		04f1:1001	JVC GC A50
+spca561		04fc:0561	Flexcam 100
+sunplus		04fc:500c	Sunplus CA500C
+sunplus		04fc:504a	Aiptek Mini PenCam 1.3
+sunplus		04fc:504b	Maxell MaxPocket LE 1.3
+sunplus		04fc:5330	Digitrex 2110
+sunplus		04fc:5360	Sunplus Generic
+spca500		04fc:7333	PalmPixDC85
+sunplus		04fc:ffff	Pure DigitalDakota
+spca501		0506:00df	3Com HomeConnect Lite
+sunplus		052b:1513	Megapix V4
+tv8532		0545:808b	Veo Stingray
+tv8532		0545:8333	Veo Stingray
+sunplus		0546:3155	Polaroid PDC3070
+sunplus		0546:3191	Polaroid Ion 80
+sunplus		0546:3273	Polaroid PDC2030
+ov519		054c:0154	Sonny toy4
+ov519		054c:0155	Sonny toy5
+zc3xx		055f:c005	Mustek Wcam300A
+spca500		055f:c200	Mustek Gsmart 300
+sunplus		055f:c211	Kowa Bs888e Microcamera
+spca500		055f:c220	Gsmart Mini
+sunplus		055f:c230	Mustek Digicam 330K
+sunplus		055f:c232	Mustek MDC3500
+sunplus		055f:c360	Mustek DV4000 Mpeg4
+sunplus		055f:c420	Mustek gSmart Mini 2
+sunplus		055f:c430	Mustek Gsmart LCD 2
+sunplus		055f:c440	Mustek DV 3000
+sunplus		055f:c520	Mustek gSmart Mini 3
+sunplus		055f:c530	Mustek Gsmart LCD 3
+sunplus		055f:c540	Gsmart D30
+sunplus		055f:c630	Mustek MDC4000
+sunplus		055f:c650	Mustek MDC5500Z
+zc3xx		055f:d003	Mustek WCam300A
+zc3xx		055f:d004	Mustek WCam300 AN
+conex		0572:0041	Creative Notebook cx11646
+ov519		05a9:0519	OmniVision
+ov519		05a9:0530	OmniVision
+ov519		05a9:4519	OmniVision
+ov519		05a9:8519	OmniVision
+sunplus		05da:1018	Digital Dream Enigma 1.3
+stk014		05e1:0893	Syntek DV4000
+spca561		060b:a001	Maxell Compact Pc PM3
+zc3xx		0698:2003	CTX M730V built in
+spca500		06bd:0404	Agfa CL20
+spca500		06be:0800	Optimedia
+sunplus		06d6:0031	Trust 610 LCD PowerC@m Zoom
+spca506		06e1:a190	ADS Instant VCD
+spca508		0733:0110	ViewQuest VQ110
+spca508		0130:0130	Clone Digital Webcam 11043
+spca501		0733:0401	Intel Create and Share
+spca501		0733:0402	ViewQuest M318B
+spca505		0733:0430	Intel PC Camera Pro
+sunplus		0733:1311	Digital Dream Epsilon 1.3
+sunplus		0733:1314	Mercury 2.1MEG Deluxe Classic Cam
+sunplus		0733:2211	Jenoptik jdc 21 LCD
+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
+spca500		084d:0003	D-Link DSC-350
+spca500		08ca:0103	Aiptek PocketDV
+sunplus		08ca:0104	Aiptek PocketDVII 1.3
+sunplus		08ca:0106	Aiptek Pocket DV3100+
+sunplus		08ca:2008	Aiptek Mini PenCam 2 M
+sunplus		08ca:2010	Aiptek PocketCam 3M
+sunplus		08ca:2016	Aiptek PocketCam 2 Mega
+sunplus		08ca:2018	Aiptek Pencam SD 2M
+sunplus		08ca:2020	Aiptek Slim 3000F
+sunplus		08ca:2022	Aiptek Slim 3200
+sunplus		08ca:2024	Aiptek DV3500 Mpeg4
+sunplus		08ca:2028	Aiptek PocketCam4M
+sunplus		08ca:2040	Aiptek PocketDV4100M
+sunplus		08ca:2042	Aiptek PocketDV5100
+sunplus		08ca:2050	Medion MD 41437
+sunplus		08ca:2060	Aiptek PocketDV5300
+tv8532		0923:010f	ICM532 cams
+mars		093a:050f	Mars-Semi Pc-Camera
+pac207		093a:2460	PAC207 Qtec Webcam 100
+pac207		093a:2463	Philips spc200nc pac207
+pac207		093a:2464	Labtec Webcam 1200
+pac207		093a:2468	PAC207
+pac207		093a:2470	Genius GF112
+pac207		093a:2471	PAC207 Genius VideoCam ge111
+pac207		093a:2472	PAC207 Genius VideoCam ge110
+pac7311		093a:2600	PAC7311 Typhoon
+pac7311		093a:2601	PAC7311 Phillips SPC610NC
+pac7311		093a:2603	PAC7312
+pac7311		093a:2608	PAC7311 Trust WB-3300p
+pac7311		093a:260e	PAC7311 Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
+pac7311		093a:260f	PAC7311 SnakeCam
+pac7311		093a:2621	PAC731x
+zc3xx		0ac8:0302	Z-star Vimicro zc0302
+vc032x		0ac8:0321	Vimicro generic vc0321
+vc032x		0ac8:0323	Vimicro Vc0323
+vc032x		0ac8:0328	A4Tech PK-130MG
+zc3xx		0ac8:301b	Z-Star zc301b
+zc3xx		0ac8:303b	Vimicro 0x303b
+zc3xx		0ac8:305b	Z-star Vimicro zc0305b
+zc3xx		0ac8:307b	Ldlc VC302+Ov7620
+vc032x		0ac8:c001	Sony embedded vimicro
+vc032x		0ac8:c002	Sony embedded vimicro
+spca508		0af9:0010	Hama USB Sightcam 100
+spca508		0af9:0011	Hama USB Sightcam 100
+sonixb		0c45:6001	Genius VideoCAM NB
+sonixb		0c45:6005	Microdia Sweex Mini Webcam
+sonixb		0c45:6007	Sonix sn9c101 + Tas5110D
+sonixb		0c45:6009	spcaCam@120
+sonixb		0c45:600d	spcaCam@120
+sonixb		0c45:6011	Microdia PC Camera (SN9C102)
+sonixb		0c45:6019	Generic Sonix OV7630
+sonixb		0c45:6024	Generic Sonix Tas5130c
+sonixb		0c45:6025	Xcam Shanga
+sonixb		0c45:6028	Sonix Btc Pc380
+sonixb		0c45:6029	spcaCam@150
+sonixb		0c45:602c	Generic Sonix OV7630
+sonixb		0c45:602d	LIC-200 LG
+sonixb		0c45:602e	Genius VideoCam Messenger
+sonixj		0c45:6040	Speed NVC 350K
+sonixj		0c45:607c	Sonix sn9c102p Hv7131R
+sonixj		0c45:60c0	Sangha Sn535
+sonixj		0c45:60ec	SN9C105+MO4000
+sonixj		0c45:60fb	Surfer NoName
+sonixj		0c45:60fc	LG-LIC300
+sonixj		0c45:612a	Avant Camera
+sonixj		0c45:612c	Typhoon Rasy Cam 1.3MPix
+sonixj		0c45:6130	Sonix Pccam
+sonixj		0c45:6138	Sn9c120 Mo4000
+sonixj		0c45:613b	Surfer SN-206
+sonixj		0c45:613c	Sonix Pccam168
+sunplus		0d64:0303	Sunplus FashionCam DXG
+etoms		102c:6151	Qcam Sangha CIF
+etoms		102c:6251	Qcam xxxxxx VGA
+zc3xx		10fd:0128	Typhoon Webshot II USB 300k 0x0128
+spca561		10fd:7e50	FlyCam Usb 100
+zc3xx		10fd:8050	Typhoon Webshot II USB 300k
+spca501		1776:501c	Arowana 300K CMOS Camera
+t613		17a1:0128	T613/TAS5130A
+vc032x		17ef:4802	Lenovo Vc0323+MI1310_SOC
+pac207		2001:f115	D-Link DSB-C120
+spca500		2899:012c	Toptro Industrial
+spca508		8086:0110	Intel Easy PC Camera
+spca500		8086:0630	Intel Pocket PC Camera
+spca506		99fa:8988	Grandtec V.cap
+spca561		abcd:cdee	Petcam

+ 2 - 3
drivers/media/Kconfig

@@ -38,7 +38,6 @@ config VIDEO_ALLOW_V4L1
 	bool "Enable Video For Linux API 1 (DEPRECATED)"
 	bool "Enable Video For Linux API 1 (DEPRECATED)"
 	depends on VIDEO_DEV && VIDEO_V4L2_COMMON
 	depends on VIDEO_DEV && VIDEO_V4L2_COMMON
 	default VIDEO_DEV && VIDEO_V4L2_COMMON
 	default VIDEO_DEV && VIDEO_V4L2_COMMON
-	select VIDEO_V4L1_COMPAT
 	---help---
 	---help---
 	  Enables drivers based on the legacy V4L1 API.
 	  Enables drivers based on the legacy V4L1 API.
 
 
@@ -49,9 +48,9 @@ config VIDEO_ALLOW_V4L1
 	  If you are unsure as to whether this is required, answer Y.
 	  If you are unsure as to whether this is required, answer Y.
 
 
 config VIDEO_V4L1_COMPAT
 config VIDEO_V4L1_COMPAT
-	bool "Enable Video For Linux API 1 compatible Layer"
+	bool "Enable Video For Linux API 1 compatible Layer" if !VIDEO_ALLOW_V4L1
 	depends on VIDEO_DEV
 	depends on VIDEO_DEV
-	default VIDEO_DEV
+	default y
 	---help---
 	---help---
 	  Enables a compatibility API used by most V4L2 devices to allow
 	  Enables a compatibility API used by most V4L2 devices to allow
 	  its usage with legacy applications that supports only V4L1 api.
 	  its usage with legacy applications that supports only V4L1 api.

+ 8 - 18
drivers/media/common/ir-functions.c

@@ -66,7 +66,6 @@ void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
 	if (ir_codes)
 	if (ir_codes)
 		memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
 		memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
 
 
-
 	dev->keycode     = ir->ir_codes;
 	dev->keycode     = ir->ir_codes;
 	dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
 	dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
 	dev->keycodemax  = IR_KEYTAB_SIZE;
 	dev->keycodemax  = IR_KEYTAB_SIZE;
@@ -78,6 +77,7 @@ void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
 	if (repeat)
 	if (repeat)
 		set_bit(EV_REP, dev->evbit);
 		set_bit(EV_REP, dev->evbit);
 }
 }
+EXPORT_SYMBOL_GPL(ir_input_init);
 
 
 void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
 void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
 {
 {
@@ -86,6 +86,7 @@ void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
 		ir_input_key_event(dev,ir);
 		ir_input_key_event(dev,ir);
 	}
 	}
 }
 }
+EXPORT_SYMBOL_GPL(ir_input_nokey);
 
 
 void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
 void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
 		      u32 ir_key, u32 ir_raw)
 		      u32 ir_key, u32 ir_raw)
@@ -104,6 +105,7 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
 		ir_input_key_event(dev,ir);
 		ir_input_key_event(dev,ir);
 	}
 	}
 }
 }
+EXPORT_SYMBOL_GPL(ir_input_keydown);
 
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* extract mask bits out of data and pack them into the result */
 /* extract mask bits out of data and pack them into the result */
@@ -122,6 +124,7 @@ u32 ir_extract_bits(u32 data, u32 mask)
 
 
 	return value;
 	return value;
 }
 }
+EXPORT_SYMBOL_GPL(ir_extract_bits);
 
 
 static int inline getbit(u32 *samples, int bit)
 static int inline getbit(u32 *samples, int bit)
 {
 {
@@ -146,6 +149,7 @@ int ir_dump_samples(u32 *samples, int count)
 	printk("\n");
 	printk("\n");
 	return 0;
 	return 0;
 }
 }
+EXPORT_SYMBOL_GPL(ir_dump_samples);
 
 
 /* decode raw samples, pulse distance coding used by NEC remotes */
 /* decode raw samples, pulse distance coding used by NEC remotes */
 int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
 int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
@@ -212,6 +216,7 @@ int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
 
 
 	return value;
 	return value;
 }
 }
+EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
 
 
 /* decode raw samples, biphase coding, used by rc5 for example */
 /* decode raw samples, biphase coding, used by rc5 for example */
 int ir_decode_biphase(u32 *samples, int count, int low, int high)
 int ir_decode_biphase(u32 *samples, int count, int low, int high)
@@ -253,6 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
 	}
 	}
 	return value;
 	return value;
 }
 }
+EXPORT_SYMBOL_GPL(ir_decode_biphase);
 
 
 /* RC5 decoding stuff, moved from bttv-input.c to share it with
 /* RC5 decoding stuff, moved from bttv-input.c to share it with
  * saa7134 */
  * saa7134 */
@@ -353,6 +359,7 @@ void ir_rc5_timer_end(unsigned long data)
 		}
 		}
 	}
 	}
 }
 }
+EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
 
 
 void ir_rc5_timer_keyup(unsigned long data)
 void ir_rc5_timer_keyup(unsigned long data)
 {
 {
@@ -361,21 +368,4 @@ void ir_rc5_timer_keyup(unsigned long data)
 	dprintk(1, "ir-common: key released\n");
 	dprintk(1, "ir-common: key released\n");
 	ir_input_nokey(ir->dev, &ir->ir);
 	ir_input_nokey(ir->dev, &ir->ir);
 }
 }
-
-EXPORT_SYMBOL_GPL(ir_input_init);
-EXPORT_SYMBOL_GPL(ir_input_nokey);
-EXPORT_SYMBOL_GPL(ir_input_keydown);
-
-EXPORT_SYMBOL_GPL(ir_extract_bits);
-EXPORT_SYMBOL_GPL(ir_dump_samples);
-EXPORT_SYMBOL_GPL(ir_decode_biphase);
-EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
-
-EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
 EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
 EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */

+ 2 - 2
drivers/media/common/saa7146_core.c

@@ -233,7 +233,7 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
 
 
 int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
 int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
 {
 {
-	u32          *cpu;
+	__le32       *cpu;
 	dma_addr_t   dma_addr;
 	dma_addr_t   dma_addr;
 
 
 	cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
 	cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
@@ -250,7 +250,7 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
 int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
 int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
 	struct scatterlist *list, int sglen  )
 	struct scatterlist *list, int sglen  )
 {
 {
-	u32 *ptr, fill;
+	__le32 *ptr, fill;
 	int nr_pages = 0;
 	int nr_pages = 0;
 	int i,p;
 	int i,p;
 
 

+ 1 - 1
drivers/media/common/saa7146_hlp.c

@@ -338,7 +338,7 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa
 	struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
 	struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
 {
 {
 	struct saa7146_vv *vv = dev->vv_data;
 	struct saa7146_vv *vv = dev->vv_data;
-	u32 *clipping = vv->d_clipping.cpu_addr;
+	__le32 *clipping = vv->d_clipping.cpu_addr;
 
 
 	int width = fh->ov.win.w.width;
 	int width = fh->ov.win.w.width;
 	int height =  fh->ov.win.w.height;
 	int height =  fh->ov.win.w.height;

+ 17 - 17
drivers/media/common/saa7146_i2c.c

@@ -24,7 +24,7 @@ static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
    sent through the saa7146. have a look at the specifications p. 122 ff
    sent through the saa7146. have a look at the specifications p. 122 ff
    to understand this. it returns the number of u32s to send, or -1
    to understand this. it returns the number of u32s to send, or -1
    in case of an error. */
    in case of an error. */
-static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
+static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
 {
 {
 	int h1, h2;
 	int h1, h2;
 	int i, j, addr;
 	int i, j, addr;
@@ -47,7 +47,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
 	}
 	}
 
 
 	/* be careful: clear out the i2c-mem first */
 	/* be careful: clear out the i2c-mem first */
-	memset(op,0,sizeof(u32)*mem);
+	memset(op,0,sizeof(__le32)*mem);
 
 
 	/* loop through all messages */
 	/* loop through all messages */
 	for(i = 0; i < num; i++) {
 	for(i = 0; i < num; i++) {
@@ -57,16 +57,16 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
 		   so we have to perform a translation */
 		   so we have to perform a translation */
 		addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0);
 		addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0);
 		h1 = op_count/3; h2 = op_count%3;
 		h1 = op_count/3; h2 = op_count%3;
-		op[h1] |= (	    (u8)addr << ((3-h2)*8));
-		op[h1] |= (SAA7146_I2C_START << ((3-h2)*2));
+		op[h1] |= cpu_to_le32(	    (u8)addr << ((3-h2)*8));
+		op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2));
 		op_count++;
 		op_count++;
 
 
 		/* loop through all bytes of message i */
 		/* loop through all bytes of message i */
 		for(j = 0; j < m[i].len; j++) {
 		for(j = 0; j < m[i].len; j++) {
 			/* insert the data bytes */
 			/* insert the data bytes */
 			h1 = op_count/3; h2 = op_count%3;
 			h1 = op_count/3; h2 = op_count%3;
-			op[h1] |= ( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
-			op[h1] |= (       SAA7146_I2C_CONT << ((3-h2)*2));
+			op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
+			op[h1] |= cpu_to_le32(       SAA7146_I2C_CONT << ((3-h2)*2));
 			op_count++;
 			op_count++;
 		}
 		}
 
 
@@ -75,9 +75,9 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
 	/* have a look at the last byte inserted:
 	/* have a look at the last byte inserted:
 	  if it was: ...CONT change it to ...STOP */
 	  if it was: ...CONT change it to ...STOP */
 	h1 = (op_count-1)/3; h2 = (op_count-1)%3;
 	h1 = (op_count-1)/3; h2 = (op_count-1)%3;
-	if ( SAA7146_I2C_CONT == (0x3 & (op[h1] >> ((3-h2)*2))) ) {
-		op[h1] &= ~(0x2 << ((3-h2)*2));
-		op[h1] |= (SAA7146_I2C_STOP << ((3-h2)*2));
+	if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) {
+		op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2));
+		op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2));
 	}
 	}
 
 
 	/* return the number of u32s to send */
 	/* return the number of u32s to send */
@@ -88,7 +88,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
    which bytes were read through the adapter and write them back to the corresponding
    which bytes were read through the adapter and write them back to the corresponding
    i2c-message. but instead, we simply write back all bytes.
    i2c-message. but instead, we simply write back all bytes.
    fixme: this could be improved. */
    fixme: this could be improved. */
-static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op)
+static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
 {
 {
 	int i, j;
 	int i, j;
 	int op_count = 0;
 	int op_count = 0;
@@ -101,7 +101,7 @@ static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op)
 		/* loop throgh all bytes of message i */
 		/* loop throgh all bytes of message i */
 		for(j = 0; j < m[i].len; j++) {
 		for(j = 0; j < m[i].len; j++) {
 			/* write back all bytes that could have been read */
 			/* write back all bytes that could have been read */
-			m[i].buf[j] = (op[op_count/3] >> ((3-(op_count%3))*8));
+			m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
 			op_count++;
 			op_count++;
 		}
 		}
 	}
 	}
@@ -174,7 +174,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
 /* this functions writes out the data-byte 'dword' to the i2c-device.
 /* this functions writes out the data-byte 'dword' to the i2c-device.
    it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
    it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
    failed badly (e.g. address error) */
    failed badly (e.g. address error) */
-static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_delay)
+static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay)
 {
 {
 	u32 status = 0, mc2 = 0;
 	u32 status = 0, mc2 = 0;
 	int trial = 0;
 	int trial = 0;
@@ -186,7 +186,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
 	if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
 	if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
 
 
 		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
 		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
-		saa7146_write(dev, I2C_TRANSFER, *dword);
+		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
 
 
 		dev->i2c_op = 1;
 		dev->i2c_op = 1;
 		SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
 		SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
@@ -209,7 +209,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
 		status = saa7146_read(dev, I2C_STATUS);
 		status = saa7146_read(dev, I2C_STATUS);
 	} else {
 	} else {
 		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
 		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
-		saa7146_write(dev, I2C_TRANSFER, *dword);
+		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
 
 
 		/* do not poll for i2c-status before upload is complete */
 		/* do not poll for i2c-status before upload is complete */
@@ -282,7 +282,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
 	}
 	}
 
 
 	/* read back data, just in case we were reading ... */
 	/* read back data, just in case we were reading ... */
-	*dword = saa7146_read(dev, I2C_TRANSFER);
+	*dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
 
 
 	DEB_I2C(("after: 0x%08x\n",*dword));
 	DEB_I2C(("after: 0x%08x\n",*dword));
 	return 0;
 	return 0;
@@ -291,7 +291,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
 static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
 static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
 {
 {
 	int i = 0, count = 0;
 	int i = 0, count = 0;
-	u32* buffer = dev->d_i2c.cpu_addr;
+	__le32 *buffer = dev->d_i2c.cpu_addr;
 	int err = 0;
 	int err = 0;
 	int address_err = 0;
 	int address_err = 0;
 	int short_delay = 0;
 	int short_delay = 0;
@@ -376,7 +376,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
 	/* another bug in revision 0: the i2c-registers get uploaded randomly by other
 	/* another bug in revision 0: the i2c-registers get uploaded randomly by other
 	   uploads, so we better clear them out before continueing */
 	   uploads, so we better clear them out before continueing */
 	if( 0 == dev->revision ) {
 	if( 0 == dev->revision ) {
-		u32 zero = 0;
+		__le32 zero = 0;
 		saa7146_i2c_reset(dev);
 		saa7146_i2c_reset(dev);
 		if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
 		if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
 			INFO(("revision 0 error. this should never happen.\n"));
 			INFO(("revision 0 error. this should never happen.\n"));

+ 2 - 2
drivers/media/common/saa7146_video.c

@@ -605,8 +605,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
 		struct saa7146_pgtable *pt1 = &buf->pt[0];
 		struct saa7146_pgtable *pt1 = &buf->pt[0];
 		struct saa7146_pgtable *pt2 = &buf->pt[1];
 		struct saa7146_pgtable *pt2 = &buf->pt[1];
 		struct saa7146_pgtable *pt3 = &buf->pt[2];
 		struct saa7146_pgtable *pt3 = &buf->pt[2];
-		u32  *ptr1, *ptr2, *ptr3;
-		u32 fill;
+		__le32  *ptr1, *ptr2, *ptr3;
+		__le32 fill;
 
 
 		int size = buf->fmt->width*buf->fmt->height;
 		int size = buf->fmt->width*buf->fmt->height;
 		int i,p,m1,m2,m3,o1,o2;
 		int i,p,m1,m2,m3,o1,o2;

+ 1 - 0
drivers/media/common/tuners/Kconfig

@@ -34,6 +34,7 @@ config MEDIA_TUNER
 menuconfig MEDIA_TUNER_CUSTOMIZE
 menuconfig MEDIA_TUNER_CUSTOMIZE
 	bool "Customize analog and hybrid tuner modules to build"
 	bool "Customize analog and hybrid tuner modules to build"
 	depends on MEDIA_TUNER
 	depends on MEDIA_TUNER
+	default n
 	help
 	help
 	  This allows the user to deselect tuner drivers unnecessary
 	  This allows the user to deselect tuner drivers unnecessary
 	  for their hardware from the build. Use this option with care
 	  for their hardware from the build. Use this option with care

+ 1 - 1
drivers/media/common/tuners/tda18271-maps.c

@@ -1,5 +1,5 @@
 /*
 /*
-    tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner
+    tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner
 
 
     Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
     Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
 
 

+ 14 - 11
drivers/media/common/tuners/tuner-xc2028.c

@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <media/tuner.h>
 #include <media/tuner.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
+#include <asm/unaligned.h>
 #include "tuner-i2c.h"
 #include "tuner-i2c.h"
 #include "tuner-xc2028.h"
 #include "tuner-xc2028.h"
 #include "tuner-xc2028-types.h"
 #include "tuner-xc2028-types.h"
@@ -292,10 +293,10 @@ static int load_all_firmwares(struct dvb_frontend *fe)
 	name[sizeof(name) - 1] = 0;
 	name[sizeof(name) - 1] = 0;
 	p += sizeof(name) - 1;
 	p += sizeof(name) - 1;
 
 
-	priv->firm_version = le16_to_cpu(*(__u16 *) p);
+	priv->firm_version = get_unaligned_le16(p);
 	p += 2;
 	p += 2;
 
 
-	n_array = le16_to_cpu(*(__u16 *) p);
+	n_array = get_unaligned_le16(p);
 	p += 2;
 	p += 2;
 
 
 	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
 	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
@@ -324,26 +325,26 @@ static int load_all_firmwares(struct dvb_frontend *fe)
 		}
 		}
 
 
 		/* Checks if there's enough bytes to read */
 		/* Checks if there's enough bytes to read */
-		if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
-			tuner_err("Firmware header is incomplete!\n");
-			goto corrupt;
-		}
+		if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
+			goto header;
 
 
-		type = le32_to_cpu(*(__u32 *) p);
+		type = get_unaligned_le32(p);
 		p += sizeof(type);
 		p += sizeof(type);
 
 
-		id = le64_to_cpu(*(v4l2_std_id *) p);
+		id = get_unaligned_le64(p);
 		p += sizeof(id);
 		p += sizeof(id);
 
 
 		if (type & HAS_IF) {
 		if (type & HAS_IF) {
-			int_freq = le16_to_cpu(*(__u16 *) p);
+			int_freq = get_unaligned_le16(p);
 			p += sizeof(int_freq);
 			p += sizeof(int_freq);
+			if (endp - p < sizeof(size))
+				goto header;
 		}
 		}
 
 
-		size = le32_to_cpu(*(__u32 *) p);
+		size = get_unaligned_le32(p);
 		p += sizeof(size);
 		p += sizeof(size);
 
 
-		if ((!size) || (size + p > endp)) {
+		if (!size || size > endp - p) {
 			tuner_err("Firmware type ");
 			tuner_err("Firmware type ");
 			dump_firm_type(type);
 			dump_firm_type(type);
 			printk("(%x), id %llx is corrupted "
 			printk("(%x), id %llx is corrupted "
@@ -382,6 +383,8 @@ static int load_all_firmwares(struct dvb_frontend *fe)
 
 
 	goto done;
 	goto done;
 
 
+header:
+	tuner_err("Firmware header is incomplete!\n");
 corrupt:
 corrupt:
 	rc = -EINVAL;
 	rc = -EINVAL;
 	tuner_err("Error: firmware file is corrupted!\n");
 	tuner_err("Error: firmware file is corrupted!\n");

+ 7 - 0
drivers/media/common/tuners/xc5000.c

@@ -36,6 +36,10 @@ static int debug;
 module_param(debug, int, 0644);
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
 
+static int xc5000_load_fw_on_attach;
+module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
+MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
+
 #define dprintk(level,fmt, arg...) if (debug >= level) \
 #define dprintk(level,fmt, arg...) if (debug >= level) \
 	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
 
@@ -972,6 +976,9 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
 
 
 	fe->tuner_priv = priv;
 	fe->tuner_priv = priv;
 
 
+	if (xc5000_load_fw_on_attach)
+		xc5000_init(fe);
+
 	return fe;
 	return fe;
 }
 }
 EXPORT_SYMBOL(xc5000_attach);
 EXPORT_SYMBOL(xc5000_attach);

+ 1 - 0
drivers/media/dvb/Kconfig

@@ -21,6 +21,7 @@ source "drivers/media/dvb/dvb-usb/Kconfig"
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
 source "drivers/media/dvb/cinergyT2/Kconfig"
 source "drivers/media/dvb/cinergyT2/Kconfig"
+source "drivers/media/dvb/siano/Kconfig"
 
 
 comment "Supported FlexCopII (B2C2) Adapters"
 comment "Supported FlexCopII (B2C2) Adapters"
 	depends on DVB_CORE && (PCI || USB) && I2C
 	depends on DVB_CORE && (PCI || USB) && I2C

+ 1 - 1
drivers/media/dvb/Makefile

@@ -2,4 +2,4 @@
 # Makefile for the kernel multimedia device drivers.
 # Makefile for the kernel multimedia device drivers.
 #
 #
 
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/

+ 1 - 1
drivers/media/dvb/bt8xx/bt878.h

@@ -128,7 +128,7 @@ struct bt878 {
 	dma_addr_t buf_dma;
 	dma_addr_t buf_dma;
 
 
 	u32 risc_size;
 	u32 risc_size;
-	u32 *risc_cpu;
+	__le32 *risc_cpu;
 	dma_addr_t risc_dma;
 	dma_addr_t risc_dma;
 	u32 risc_pos;
 	u32 risc_pos;
 
 

+ 1 - 1
drivers/media/dvb/dvb-core/demux.h

@@ -247,7 +247,7 @@ struct dmx_demux {
 	void* priv;                  /* Pointer to private data of the API client */
 	void* priv;                  /* Pointer to private data of the API client */
 	int (*open) (struct dmx_demux* demux);
 	int (*open) (struct dmx_demux* demux);
 	int (*close) (struct dmx_demux* demux);
 	int (*close) (struct dmx_demux* demux);
-	int (*write) (struct dmx_demux* demux, const char* buf, size_t count);
+	int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
 	int (*allocate_ts_feed) (struct dmx_demux* demux,
 	int (*allocate_ts_feed) (struct dmx_demux* demux,
 				 struct dmx_ts_feed** feed,
 				 struct dmx_ts_feed** feed,
 				 dmx_ts_cb callback);
 				 dmx_ts_cb callback);

+ 1 - 1
drivers/media/dvb/dvb-core/dmxdev.c

@@ -96,7 +96,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
 		if (avail > todo)
 		if (avail > todo)
 			avail = todo;
 			avail = todo;
 
 
-		ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
+		ret = dvb_ringbuffer_read_user(src, buf, avail);
 		if (ret < 0)
 		if (ret < 0)
 			break;
 			break;
 
 

+ 4 - 4
drivers/media/dvb/dvb-core/dvb_ca_en50221.c

@@ -1357,7 +1357,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
 
 
 		idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
 		idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
 		while (idx != -1) {
 		while (idx != -1) {
-			dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+			dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
 			if (connection_id == -1)
 			if (connection_id == -1)
 				connection_id = hdr[0];
 				connection_id = hdr[0];
 			if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
 			if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
@@ -1438,7 +1438,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
 			goto exit;
 			goto exit;
 		}
 		}
 
 
-		dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+		dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
 		if (connection_id == -1)
 		if (connection_id == -1)
 			connection_id = hdr[0];
 			connection_id = hdr[0];
 		if (hdr[0] == connection_id) {
 		if (hdr[0] == connection_id) {
@@ -1449,8 +1449,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
 					fraglen -= 2;
 					fraglen -= 2;
 				}
 				}
 
 
-				if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
-								      (u8 *)buf + pktlen, fraglen, 1)) < 0) {
+				if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
+								      buf + pktlen, fraglen)) < 0) {
 					goto exit;
 					goto exit;
 				}
 				}
 				pktlen += fraglen;
 				pktlen += fraglen;

+ 14 - 3
drivers/media/dvb/dvb-core/dvb_demux.c

@@ -1056,16 +1056,27 @@ static int dvbdmx_close(struct dmx_demux *demux)
 	return 0;
 	return 0;
 }
 }
 
 
-static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
+static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
 {
 {
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+	void *p;
 
 
 	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
 	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
 		return -EINVAL;
 		return -EINVAL;
 
 
-	if (mutex_lock_interruptible(&dvbdemux->mutex))
+	p = kmalloc(count, GFP_USER);
+	if (!p)
+		return -ENOMEM;
+	if (copy_from_user(p, buf, count)) {
+		kfree(p);
+		return -EFAULT;
+	}
+	if (mutex_lock_interruptible(&dvbdemux->mutex)) {
+		kfree(p);
 		return -ERESTARTSYS;
 		return -ERESTARTSYS;
-	dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
+	}
+	dvb_dmx_swfilter(dvbdemux, p, count);
+	kfree(p);
 	mutex_unlock(&dvbdemux->mutex);
 	mutex_unlock(&dvbdemux->mutex);
 
 
 	if (signal_pending(current))
 	if (signal_pending(current))

+ 1 - 1
drivers/media/dvb/dvb-core/dvb_net.c

@@ -606,7 +606,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 			if (priv->ule_dbit) {
 			if (priv->ule_dbit) {
 				/* Set D-bit for CRC32 verification,
 				/* Set D-bit for CRC32 verification,
 				 * if it was set originally. */
 				 * if it was set originally. */
-				ulen |= 0x0080;
+				ulen |= htons(0x8000);
 			}
 			}
 
 
 			ule_crc = iov_crc32(ule_crc, iov, 3);
 			ule_crc = iov_crc32(ule_crc, iov, 3);

+ 53 - 25
drivers/media/dvb/dvb-core/dvb_ringbuffer.c

@@ -107,35 +107,43 @@ void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
 	wake_up(&rbuf->queue);
 	wake_up(&rbuf->queue);
 }
 }
 
 
-
-
-ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, int usermem)
+ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
 {
 {
 	size_t todo = len;
 	size_t todo = len;
 	size_t split;
 	size_t split;
 
 
 	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
 	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
 	if (split > 0) {
 	if (split > 0) {
-		if (!usermem)
-			memcpy(buf, rbuf->data+rbuf->pread, split);
-		else
-			if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
-				return -EFAULT;
+		if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+			return -EFAULT;
 		buf += split;
 		buf += split;
 		todo -= split;
 		todo -= split;
 		rbuf->pread = 0;
 		rbuf->pread = 0;
 	}
 	}
-	if (!usermem)
-		memcpy(buf, rbuf->data+rbuf->pread, todo);
-	else
-		if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
-			return -EFAULT;
+	if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
+		return -EFAULT;
 
 
 	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
 	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
 
 
 	return len;
 	return len;
 }
 }
 
 
+void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
+{
+	size_t todo = len;
+	size_t split;
+
+	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+	if (split > 0) {
+		memcpy(buf, rbuf->data+rbuf->pread, split);
+		buf += split;
+		todo -= split;
+		rbuf->pread = 0;
+	}
+	memcpy(buf, rbuf->data+rbuf->pread, todo);
+
+	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+}
 
 
 
 
 ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
 ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
@@ -171,8 +179,8 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le
 	return status;
 	return status;
 }
 }
 
 
-ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-				int offset, u8* buf, size_t len, int usermem)
+ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+				int offset, u8 __user *buf, size_t len)
 {
 {
 	size_t todo;
 	size_t todo;
 	size_t split;
 	size_t split;
@@ -187,21 +195,40 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
 	todo = len;
 	todo = len;
 	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
 	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
 	if (split > 0) {
 	if (split > 0) {
-		if (!usermem)
-			memcpy(buf, rbuf->data+idx, split);
-		else
-			if (copy_to_user(buf, rbuf->data+idx, split))
-				return -EFAULT;
+		if (copy_to_user(buf, rbuf->data+idx, split))
+			return -EFAULT;
 		buf += split;
 		buf += split;
 		todo -= split;
 		todo -= split;
 		idx = 0;
 		idx = 0;
 	}
 	}
-	if (!usermem)
-		memcpy(buf, rbuf->data+idx, todo);
-	else
-		if (copy_to_user(buf, rbuf->data+idx, todo))
-			return -EFAULT;
+	if (copy_to_user(buf, rbuf->data+idx, todo))
+		return -EFAULT;
+
+	return len;
+}
 
 
+ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
+				int offset, u8* buf, size_t len)
+{
+	size_t todo;
+	size_t split;
+	size_t pktlen;
+
+	pktlen = rbuf->data[idx] << 8;
+	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
+	if (offset > pktlen) return -EINVAL;
+	if ((offset + len) > pktlen) len = pktlen - offset;
+
+	idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
+	todo = len;
+	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
+	if (split > 0) {
+		memcpy(buf, rbuf->data+idx, split);
+		buf += split;
+		todo -= split;
+		idx = 0;
+	}
+	memcpy(buf, rbuf->data+idx, todo);
 	return len;
 	return len;
 }
 }
 
 
@@ -266,5 +293,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_empty);
 EXPORT_SYMBOL(dvb_ringbuffer_free);
 EXPORT_SYMBOL(dvb_ringbuffer_free);
 EXPORT_SYMBOL(dvb_ringbuffer_avail);
 EXPORT_SYMBOL(dvb_ringbuffer_avail);
 EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
 EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
+EXPORT_SYMBOL(dvb_ringbuffer_read_user);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_write);
 EXPORT_SYMBOL(dvb_ringbuffer_write);

+ 8 - 4
drivers/media/dvb/dvb-core/dvb_ringbuffer.h

@@ -61,7 +61,7 @@ struct dvb_ringbuffer {
 **     *** read min. 1000, max. <bufsize> bytes ***
 **     *** read min. 1000, max. <bufsize> bytes ***
 **     avail = dvb_ringbuffer_avail(rbuf);
 **     avail = dvb_ringbuffer_avail(rbuf);
 **     if (avail >= 1000)
 **     if (avail >= 1000)
-**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize), 0);
+**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
 **     else
 **     else
 **         ...
 **         ...
 **
 **
@@ -114,8 +114,10 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
 ** <usermem> specifies whether <buf> resides in user space
 ** <usermem> specifies whether <buf> resides in user space
 ** returns number of bytes transferred or -EFAULT
 ** returns number of bytes transferred or -EFAULT
 */
 */
-extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
-				   size_t len, int usermem);
+extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
+				   u8 __user *buf, size_t len);
+extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
+				   u8 *buf, size_t len);
 
 
 
 
 /* write routines & macros */
 /* write routines & macros */
@@ -157,8 +159,10 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
  * <usermem> Set to 1 if <buf> is in userspace.
  * <usermem> Set to 1 if <buf> is in userspace.
  * returns Number of bytes read, or -EFAULT.
  * returns Number of bytes read, or -EFAULT.
  */
  */
+extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+				       int offset, u8 __user *buf, size_t len);
 extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
 extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-				       int offset, u8* buf, size_t len, int usermem);
+				       int offset, u8 *buf, size_t len);
 
 
 /**
 /**
  * Dispose of a packet in the ring buffer.
  * Dispose of a packet in the ring buffer.

+ 15 - 0
drivers/media/dvb/dvb-usb/Kconfig

@@ -76,6 +76,7 @@ config DVB_USB_DIB0700
 	select DVB_DIB3000MC
 	select DVB_DIB3000MC
 	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
 	select DVB_TUNER_DIB0070
 	select DVB_TUNER_DIB0070
 	help
 	help
 	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
 	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
@@ -107,6 +108,8 @@ config DVB_USB_CXUSB
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
 	help
 	help
 	  Say Y here to support the Conexant USB2.0 hybrid reference design.
 	  Say Y here to support the Conexant USB2.0 hybrid reference design.
 	  Currently, only DVB and ATSC modes are supported, analog mode
 	  Currently, only DVB and ATSC modes are supported, analog mode
@@ -120,6 +123,8 @@ config DVB_USB_M920X
 	depends on DVB_USB
 	depends on DVB_USB
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	help
 	help
 	  Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
 	  Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
 	  Currently, only devices with a product id of
 	  Currently, only devices with a product id of
@@ -241,3 +246,13 @@ config DVB_USB_AF9005_REMOTE
 	  Say Y here to support the default remote control decoding for the
 	  Say Y here to support the default remote control decoding for the
 	  Afatech AF9005 based receiver.
 	  Afatech AF9005 based receiver.
 
 
+config DVB_USB_ANYSEE
+	tristate "Anysee DVB-T/C USB2.0 support"
+	depends on DVB_USB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Anysee E30, Anysee E30 Plus or
+	  Anysee E30 C Plus DVB USB2.0 receiver.

+ 3 - 0
drivers/media/dvb/dvb-usb/Makefile

@@ -61,6 +61,9 @@ obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
 dvb-usb-af9005-remote-objs = af9005-remote.o
 dvb-usb-af9005-remote-objs = af9005-remote.o
 obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
 obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
 
 
+dvb-usb-anysee-objs = anysee.o
+obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 # due to tuner-xc3028
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
 EXTRA_CFLAGS += -Idrivers/media/common/tuners

+ 553 - 0
drivers/media/dvb/dvb-usb/anysee.c

@@ -0,0 +1,553 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#include "anysee.h"
+#include "tda1002x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "zl10353.h"
+
+/* debug */
+static int dvb_usb_anysee_debug;
+module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct mutex anysee_usb_mutex;
+
+static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
+	u8 *rbuf, u8 rlen)
+{
+	struct anysee_state *state = d->priv;
+	int act_len, ret;
+	u8 buf[64];
+
+	if (slen > sizeof(buf))
+		slen = sizeof(buf);
+	memcpy(&buf[0], sbuf, slen);
+	buf[60] = state->seq++;
+
+	if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
+		return -EAGAIN;
+
+	/* We need receive one message more after dvb_usb_generic_rw due
+	   to weird transaction flow, which is 1 x send + 2 x receive. */
+	ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
+
+	if (!ret) {
+		/* receive 2nd answer */
+		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+			d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
+			&act_len, 2000);
+		if (ret)
+			err("%s: recv bulk message failed: %d", __func__, ret);
+		else {
+			deb_xfer("<<< ");
+			debug_dump(buf, act_len, deb_xfer);
+		}
+	}
+
+	/* read request, copy returned data to return buf */
+	if (!ret && rbuf && rlen)
+		memcpy(rbuf, buf, rlen);
+
+	mutex_unlock(&anysee_usb_mutex);
+
+	return ret;
+}
+
+static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+{
+	u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01};
+	int ret;
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1);
+	deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val);
+	return ret;
+}
+
+static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+	u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val};
+	deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val);
+	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
+{
+	u8 buf[] = {CMD_GET_HW_INFO};
+	return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
+}
+
+static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
+	deb_info("%s: onoff:%02x\n", __func__, onoff);
+	return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
+{
+	u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval};
+	deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval);
+	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
+{
+	u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff};
+	deb_info("%s: onoff:%02x\n", __func__, onoff);
+	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_init(struct dvb_usb_device *d)
+{
+	int ret;
+	/* LED light */
+	ret = anysee_led_ctrl(d, 0x01, 0x03);
+	if (ret)
+		return ret;
+
+	/* enable IR */
+	ret = anysee_ir_ctrl(d, 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/* I2C */
+static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+	int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret, inc, i = 0;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	while (i < num) {
+		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+			u8 buf[6];
+			buf[0] = CMD_I2C_READ;
+			buf[1] = msg[i].addr + 1;
+			buf[2] = msg[i].buf[0];
+			buf[3] = 0x00;
+			buf[4] = 0x00;
+			buf[5] = 0x01;
+			ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf,
+				msg[i+1].len);
+			inc = 2;
+		} else {
+			u8 buf[4+msg[i].len];
+			buf[0] = CMD_I2C_WRITE;
+			buf[1] = msg[i].addr;
+			buf[2] = msg[i].len;
+			buf[3] = 0x01;
+			memcpy(&buf[4], msg[i].buf, msg[i].len);
+			ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+			inc = 1;
+		}
+		if (ret)
+			return ret;
+
+		i += inc;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return i;
+}
+
+static u32 anysee_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm anysee_i2c_algo = {
+	.master_xfer   = anysee_master_xfer,
+	.functionality = anysee_i2c_func,
+};
+
+static int anysee_mt352_demod_init(struct dvb_frontend *fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
+/* Callbacks for DVB USB */
+static struct tda10023_config anysee_tda10023_config = {
+	.demod_address = 0x1a,
+	.invert = 0,
+	.xtal   = 16000000,
+	.pll_m  = 11,
+	.pll_p  = 3,
+	.pll_n  = 1,
+	.output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
+	.deltaf = 0xfeeb,
+};
+
+static struct mt352_config anysee_mt352_config = {
+	.demod_address = 0x1e,
+	.demod_init    = anysee_mt352_demod_init,
+};
+
+static struct zl10353_config anysee_zl10353_config = {
+	.demod_address = 0x1e,
+	.parallel_ts = 1,
+};
+
+static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct anysee_state *state = adap->dev->priv;
+	u8 hw_info[3];
+	u8 io_d; /* IO port D */
+
+	/* check which hardware we have
+	   We must do this call two times to get reliable values (hw bug). */
+	ret = anysee_get_hw_info(adap->dev, hw_info);
+	if (ret)
+		return ret;
+	ret = anysee_get_hw_info(adap->dev, hw_info);
+	if (ret)
+		return ret;
+
+	/* Meaning of these info bytes are guessed. */
+	info("firmware version:%d.%d.%d hardware id:%d",
+		0, hw_info[1], hw_info[2], hw_info[0]);
+
+	ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */
+	if (ret)
+		return ret;
+	deb_info("%s: IO port D:%02x\n", __func__, io_d);
+
+	/* Select demod using trial and error method. */
+
+	/* Try to attach demodulator in following order:
+	      model      demod     hw  firmware
+	   1. E30        MT352     02  0.2.1
+	   2. E30        ZL10353   02  0.2.1
+	   3. E30 Plus   ZL10353   06  0.1.0
+	   4. E30C Plus  TDA10023  0a  0.1.0    rev 0.2
+	   4. E30C Plus  TDA10023  0f  0.1.2    rev 0.4
+	*/
+
+	/* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
+	adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe != NULL) {
+		state->tuner = DVB_PLL_THOMSON_DTT7579;
+		return 0;
+	}
+
+	/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
+	adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe != NULL) {
+		state->tuner = DVB_PLL_THOMSON_DTT7579;
+		return 0;
+	}
+
+	/* connect demod on IO port D for TDA10023 & ZL10353 */
+	ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
+	if (ret)
+		return ret;
+
+	/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
+	adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe != NULL) {
+		state->tuner = DVB_PLL_THOMSON_DTT7579;
+		return 0;
+	}
+
+	/* IO port E - E30C rev 0.4 board requires this */
+	ret = anysee_write_reg(adap->dev, 0xb1, 0xa7);
+	if (ret)
+		return ret;
+
+	/* Philips TDA10023 DVB-C demod */
+	adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
+			      &adap->dev->i2c_adap, 0x48);
+	if (adap->fe != NULL) {
+		state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
+		return 0;
+	}
+
+	/* return IO port D to init value for safe */
+	ret = anysee_write_reg(adap->dev, 0xb0, io_d);
+	if (ret)
+		return ret;
+
+	err("Unkown Anysee version: %02x %02x %02x. "\
+	    "Please report the <linux-dvb@linuxtv.org>.",
+	    hw_info[0], hw_info[1], hw_info[2]);
+
+	return -ENODEV;
+}
+
+static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct anysee_state *state = adap->dev->priv;
+	deb_info("%s: \n", __func__);
+
+	switch (state->tuner) {
+	case DVB_PLL_THOMSON_DTT7579:
+		/* Thomson dtt7579 (not sure) PLL inside of:
+		   Samsung DNOS404ZH102A NIM
+		   Samsung DNOS404ZH103A NIM */
+		dvb_attach(dvb_pll_attach, adap->fe, 0x61,
+			   NULL, DVB_PLL_THOMSON_DTT7579);
+		break;
+	case DVB_PLL_SAMSUNG_DTOS403IH102A:
+		/* Unknown PLL inside of Samsung DTOS403IH102A tuner module */
+		dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
+			   &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+		break;
+	}
+
+	return 0;
+}
+
+static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 buf[] = {CMD_GET_IR_CODE};
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	u8 ircode[2];
+	int i, ret;
+
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2);
+	if (ret)
+		return ret;
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (keymap[i].custom == ircode[0] &&
+		    keymap[i].data == ircode[1]) {
+			*event = keymap[i].event;
+			*state = REMOTE_KEY_PRESSED;
+			return 0;
+		}
+	}
+	return 0;
+}
+
+static struct dvb_usb_rc_key anysee_rc_keys[] = {
+	{ 0x01, 0x00, KEY_0 },
+	{ 0x01, 0x01, KEY_1 },
+	{ 0x01, 0x02, KEY_2 },
+	{ 0x01, 0x03, KEY_3 },
+	{ 0x01, 0x04, KEY_4 },
+	{ 0x01, 0x05, KEY_5 },
+	{ 0x01, 0x06, KEY_6 },
+	{ 0x01, 0x07, KEY_7 },
+	{ 0x01, 0x08, KEY_8 },
+	{ 0x01, 0x09, KEY_9 },
+	{ 0x01, 0x0a, KEY_POWER },
+	{ 0x01, 0x0b, KEY_DOCUMENTS },    /* * */
+	{ 0x01, 0x19, KEY_FAVORITES },
+	{ 0x01, 0x20, KEY_SLEEP },
+	{ 0x01, 0x21, KEY_MODE },         /* 4:3 / 16:9 select */
+	{ 0x01, 0x22, KEY_ZOOM },
+	{ 0x01, 0x47, KEY_TEXT },
+	{ 0x01, 0x16, KEY_TV },           /* TV / radio select */
+	{ 0x01, 0x1e, KEY_LANGUAGE },     /* Second Audio Program */
+	{ 0x01, 0x1a, KEY_SUBTITLE },
+	{ 0x01, 0x1b, KEY_CAMERA },       /* screenshot */
+	{ 0x01, 0x42, KEY_MUTE },
+	{ 0x01, 0x0e, KEY_MENU },
+	{ 0x01, 0x0f, KEY_EPG },
+	{ 0x01, 0x17, KEY_INFO },
+	{ 0x01, 0x10, KEY_EXIT },
+	{ 0x01, 0x13, KEY_VOLUMEUP },
+	{ 0x01, 0x12, KEY_VOLUMEDOWN },
+	{ 0x01, 0x11, KEY_CHANNELUP },
+	{ 0x01, 0x14, KEY_CHANNELDOWN },
+	{ 0x01, 0x15, KEY_OK },
+	{ 0x01, 0x1d, KEY_RED },
+	{ 0x01, 0x1f, KEY_GREEN },
+	{ 0x01, 0x1c, KEY_YELLOW },
+	{ 0x01, 0x44, KEY_BLUE },
+	{ 0x01, 0x0c, KEY_SHUFFLE },      /* snapshot */
+	{ 0x01, 0x48, KEY_STOP },
+	{ 0x01, 0x50, KEY_PLAY },
+	{ 0x01, 0x51, KEY_PAUSE },
+	{ 0x01, 0x49, KEY_RECORD },
+	{ 0x01, 0x18, KEY_PREVIOUS },     /* |<< */
+	{ 0x01, 0x0d, KEY_NEXT },         /* >>| */
+	{ 0x01, 0x24, KEY_PROG1 },        /* F1 */
+	{ 0x01, 0x25, KEY_PROG2 },        /* F2 */
+};
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties anysee_properties;
+
+static int anysee_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct dvb_usb_device *d;
+	struct usb_host_interface *alt;
+	int ret;
+
+	mutex_init(&anysee_usb_mutex);
+
+	/* There is one interface with two alternate settings.
+	   Alternate setting 0 is for bulk transfer.
+	   Alternate setting 1 is for isochronous transfer.
+	   We use bulk transfer (alternate setting 0). */
+	if (intf->num_altsetting < 1)
+		return -ENODEV;
+
+	ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
+		adapter_nr);
+	if (ret)
+		return ret;
+
+	alt = usb_altnum_to_altsetting(intf, 0);
+	if (alt == NULL) {
+		deb_info("%s: no alt found!\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+		alt->desc.bAlternateSetting);
+	if (ret)
+		return ret;
+
+	if (d)
+		ret = anysee_init(d);
+
+	return ret;
+}
+
+static struct usb_device_id anysee_table [] = {
+	{ USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
+	{ USB_DEVICE(USB_VID_AMT,     USB_PID_ANYSEE) },
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, anysee_table);
+
+static struct dvb_usb_device_properties anysee_properties = {
+	.caps             = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = DEVICE_SPECIFIC,
+
+	.size_of_priv     = sizeof(struct anysee_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = anysee_streaming_ctrl,
+			.frontend_attach  = anysee_frontend_attach,
+			.tuner_attach     = anysee_tuner_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 512,
+					}
+				}
+			},
+		}
+	},
+
+	.rc_key_map       = anysee_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(anysee_rc_keys),
+	.rc_query         = anysee_rc_query,
+	.rc_interval      = 200,  /* windows driver uses 500ms */
+
+	.i2c_algo         = &anysee_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			.name = "Anysee DVB USB2.0",
+			.cold_ids = {NULL},
+			.warm_ids = {&anysee_table[0],
+				     &anysee_table[1], NULL},
+		},
+	}
+};
+
+static struct usb_driver anysee_driver = {
+	.name       = "dvb_usb_anysee",
+	.probe      = anysee_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table   = anysee_table,
+};
+
+/* module stuff */
+static int __init anysee_module_init(void)
+{
+	int ret;
+
+	ret = usb_register(&anysee_driver);
+	if (ret)
+		err("%s: usb_register failed. Error number %d", __func__, ret);
+
+	return ret;
+}
+
+static void __exit anysee_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&anysee_driver);
+}
+
+module_init(anysee_module_init);
+module_exit(anysee_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
+MODULE_LICENSE("GPL");

+ 304 - 0
drivers/media/dvb/dvb-usb/anysee.h

@@ -0,0 +1,304 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#ifndef _DVB_USB_ANYSEE_H_
+#define _DVB_USB_ANYSEE_H_
+
+#define DVB_USB_LOG_PREFIX "anysee"
+#include "dvb-usb.h"
+
+#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_anysee_debug, 0x04, args)
+#define deb_reg(args...)  dprintk(dvb_usb_anysee_debug, 0x08, args)
+#define deb_i2c(args...)  dprintk(dvb_usb_anysee_debug, 0x10, args)
+#define deb_fw(args...)   dprintk(dvb_usb_anysee_debug, 0x20, args)
+
+enum cmd {
+	CMD_I2C_READ            = 0x33,
+	CMD_I2C_WRITE           = 0x31,
+	CMD_REG_READ            = 0xb0,
+	CMD_REG_WRITE           = 0xb1,
+	CMD_STREAMING_CTRL      = 0x12,
+	CMD_LED_AND_IR_CTRL     = 0x16,
+	CMD_GET_IR_CODE         = 0x41,
+	CMD_GET_HW_INFO         = 0x19,
+	CMD_SMARTCARD           = 0x34,
+};
+
+struct anysee_state {
+	u8 tuner;
+	u8 seq;
+};
+
+#endif
+
+/***************************************************************************
+ * USB API description (reverse engineered)
+ ***************************************************************************
+
+Transaction flow:
+=================
+BULK[00001] >>> REQUEST PACKET 64 bytes
+BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY)
+BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY)
+
+General reply packet(s) are always used if not own reply defined.
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY)
+============================================================================
+|    00 | reply data (if any) from previous transaction
+|       | Just same reply packet as returned during previous transaction.
+|       | Needed only if reply is missed in previous transaction.
+|       | Just skip normally.
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY)
+============================================================================
+|    00 | reply data (if any)
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C WRITE REQUEST PACKET
+============================================================================
+|    00 | 0x31 I2C write command
+----------------------------------------------------------------------------
+|    01 | i2c address
+----------------------------------------------------------------------------
+|    02 | data length
+|       | 0x02 (for typical I2C reg / val pair)
+----------------------------------------------------------------------------
+|    03 | 0x01
+----------------------------------------------------------------------------
+| 04-   | data
+----------------------------------------------------------------------------
+|   -59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C READ REQUEST PACKET
+============================================================================
+|    00 | 0x33 I2C read command
+----------------------------------------------------------------------------
+|    01 | i2c address + 1
+----------------------------------------------------------------------------
+|    02 | register
+----------------------------------------------------------------------------
+|    03 | 0x00
+----------------------------------------------------------------------------
+|    04 | 0x00
+----------------------------------------------------------------------------
+|    05 | 0x01
+----------------------------------------------------------------------------
+| 06-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET
+============================================================================
+|    00 | 0xb1 register write command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+|    03 | 0x01
+----------------------------------------------------------------------------
+|    04 | value
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET
+============================================================================
+|    00 | 0xb0 register read command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+|    03 | 0x01
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | LED CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+|    01 | 0x01 (LED)
+----------------------------------------------------------------------------
+|    03 | 0x00 blink
+|       | 0x01 lights continuously
+----------------------------------------------------------------------------
+|    04 | blink interval
+|       | 0x00 fastest (looks like LED lights continuously)
+|       | 0xff slowest
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | IR CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+|    01 | 0x02 (IR)
+----------------------------------------------------------------------------
+|    03 | 0x00 IR disabled
+|       | 0x01 IR enabled
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | STREAMING CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x12 streaming control command
+----------------------------------------------------------------------------
+|    01 | 0x00 streaming disabled
+|       | 0x01 streaming enabled
+----------------------------------------------------------------------------
+|    02 | 0x00
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x41 remote control command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REPLY PACKET
+============================================================================
+|    00 | 0x00 code not received
+|       | 0x01 code received
+----------------------------------------------------------------------------
+|    01 | remote control code
+----------------------------------------------------------------------------
+| 02-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REQUEST PACKET
+============================================================================
+|    00 | 0x19 get hardware info command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REPLY PACKET
+============================================================================
+|    00 | hardware id
+----------------------------------------------------------------------------
+| 01-02 | firmware version
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | SMART CARD READER PACKET
+============================================================================
+|    00 | 0x34 smart card reader command
+----------------------------------------------------------------------------
+|    xx |
+----------------------------------------------------------------------------
+| xx-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+*/

+ 41 - 42
drivers/media/dvb/dvb-usb/au6610.c

@@ -1,24 +1,31 @@
-/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
  *
  *
  * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
  * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
  *
  *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
+ *    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.
  *
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
 #include "au6610.h"
 #include "au6610.h"
-
 #include "zl10353.h"
 #include "zl10353.h"
 #include "qt1010.h"
 #include "qt1010.h"
 
 
 /* debug */
 /* debug */
 static int dvb_usb_au6610_debug;
 static int dvb_usb_au6610_debug;
 module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
 module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 
 static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
 static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
@@ -42,9 +49,8 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
 	}
 	}
 
 
 	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
 	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
-			      USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf,
-			      sizeof(usb_buf), AU6610_USB_TIMEOUT);
-
+			      USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
+			      usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
@@ -116,15 +122,6 @@ static struct i2c_algorithm au6610_i2c_algo = {
 };
 };
 
 
 /* Callbacks for DVB USB */
 /* Callbacks for DVB USB */
-static int au6610_identify_state(struct usb_device *udev,
-				 struct dvb_usb_device_properties *props,
-				 struct dvb_usb_device_description **desc,
-				 int *cold)
-{
-	*cold = 0;
-	return 0;
-}
-
 static struct zl10353_config au6610_zl10353_config = {
 static struct zl10353_config au6610_zl10353_config = {
 	.demod_address = 0x0f,
 	.demod_address = 0x0f,
 	.no_tuner = 1,
 	.no_tuner = 1,
@@ -133,12 +130,12 @@ static struct zl10353_config au6610_zl10353_config = {
 
 
 static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
 static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
 {
 {
-	if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
-				   &adap->dev->i2c_adap)) != NULL) {
-		return 0;
-	}
+	adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+		&adap->dev->i2c_adap);
+	if (adap->fe == NULL)
+		return -ENODEV;
 
 
-	return -EIO;
+	return 0;
 }
 }
 
 
 static struct qt1010_config au6610_qt1010_config = {
 static struct qt1010_config au6610_qt1010_config = {
@@ -171,7 +168,7 @@ static int au6610_probe(struct usb_interface *intf,
 		alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
 		alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
 
 
 		if (alt == NULL) {
 		if (alt == NULL) {
-			deb_rc("no alt found!\n");
+			deb_info("%s: no alt found!\n", __func__);
 			return -ENODEV;
 			return -ENODEV;
 		}
 		}
 		ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
 		ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
@@ -181,18 +178,19 @@ static int au6610_probe(struct usb_interface *intf,
 	return ret;
 	return ret;
 }
 }
 
 
-
 static struct usb_device_id au6610_table [] = {
 static struct usb_device_id au6610_table [] = {
 	{ USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
 	{ USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
 	{ }		/* Terminating entry */
 	{ }		/* Terminating entry */
 };
 };
-MODULE_DEVICE_TABLE (usb, au6610_table);
+MODULE_DEVICE_TABLE(usb, au6610_table);
 
 
 static struct dvb_usb_device_properties au6610_properties = {
 static struct dvb_usb_device_properties au6610_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
 	.usb_ctrl = DEVICE_SPECIFIC,
 	.usb_ctrl = DEVICE_SPECIFIC,
-	.size_of_priv     = 0,
-	.identify_state   = au6610_identify_state,
+
+	.size_of_priv = 0,
+
 	.num_adapters = 1,
 	.num_adapters = 1,
 	.adapter = {
 	.adapter = {
 		{
 		{
@@ -206,20 +204,22 @@ static struct dvb_usb_device_properties au6610_properties = {
 				.u = {
 				.u = {
 					.isoc = {
 					.isoc = {
 						.framesperurb = 40,
 						.framesperurb = 40,
-						.framesize = 942,   /* maximum packet size */
-						.interval = 1.25,   /* 125 us */
+						.framesize = 942,
+						.interval = 1,
 					}
 					}
 				}
 				}
 			},
 			},
 		}
 		}
 	},
 	},
+
 	.i2c_algo = &au6610_i2c_algo,
 	.i2c_algo = &au6610_i2c_algo,
+
 	.num_device_descs = 1,
 	.num_device_descs = 1,
 	.devices = {
 	.devices = {
 		{
 		{
-			"Sigmatek DVB-110 DVB-T USB2.0",
-			{ &au6610_table[0], NULL },
-			{ NULL },
+			.name = "Sigmatek DVB-110 DVB-T USB2.0",
+			.cold_ids = {NULL},
+			.warm_ids = {&au6610_table[0], NULL},
 		},
 		},
 	}
 	}
 };
 };
@@ -236,12 +236,11 @@ static int __init au6610_module_init(void)
 {
 {
 	int ret;
 	int ret;
 
 
-	if ((ret = usb_register(&au6610_driver))) {
+	ret = usb_register(&au6610_driver);
+	if (ret)
 		err("usb_register failed. Error number %d", ret);
 		err("usb_register failed. Error number %d", ret);
-		return ret;
-	}
 
 
-	return 0;
+	return ret;
 }
 }
 
 
 static void __exit au6610_module_exit(void)
 static void __exit au6610_module_exit(void)
@@ -250,10 +249,10 @@ static void __exit au6610_module_exit(void)
 	usb_deregister(&au6610_driver);
 	usb_deregister(&au6610_driver);
 }
 }
 
 
-module_init (au6610_module_init);
-module_exit (au6610_module_exit);
+module_init(au6610_module_init);
+module_exit(au6610_module_exit);
 
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
+MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");
 MODULE_VERSION("0.1");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 21 - 1
drivers/media/dvb/dvb-usb/au6610.h

@@ -1,10 +1,30 @@
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
 #ifndef _DVB_USB_AU6610_H_
 #ifndef _DVB_USB_AU6610_H_
 #define _DVB_USB_AU6610_H_
 #define _DVB_USB_AU6610_H_
 
 
 #define DVB_USB_LOG_PREFIX "au6610"
 #define DVB_USB_LOG_PREFIX "au6610"
 #include "dvb-usb.h"
 #include "dvb-usb.h"
 
 
-#define deb_rc(args...)   dprintk(dvb_usb_au6610_debug,0x01,args)
+#define deb_info(args...)   dprintk(dvb_usb_au6610_debug, 0x01, args)
 
 
 #define AU6610_REQ_I2C_WRITE	0x14
 #define AU6610_REQ_I2C_WRITE	0x14
 #define AU6610_REQ_I2C_READ	0x13
 #define AU6610_REQ_I2C_READ	0x13

+ 142 - 4
drivers/media/dvb/dvb-usb/cxusb.c

@@ -35,6 +35,7 @@
 #include "zl10353.h"
 #include "zl10353.h"
 #include "tuner-xc2028.h"
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
 #include "tuner-simple.h"
+#include "mxl5005s.h"
 
 
 /* debug */
 /* debug */
 static int dvb_usb_cxusb_debug;
 static int dvb_usb_cxusb_debug;
@@ -43,9 +44,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_ST
 
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 
-#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
-#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
-				dprintk(dvb_usb_cxusb_debug,0x01,args)
+#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug, 0x03, args)
+#define deb_i2c(args...)    dprintk(dvb_usb_cxusb_debug, 0x02, args)
 
 
 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
 			  u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
 			  u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
@@ -202,6 +202,46 @@ static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
 		return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
 		return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
 }
 }
 
 
+static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	if (!onoff)
+		return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0);
+	if (d->state == DVB_USB_STATE_INIT &&
+	    usb_set_interface(d->udev, 0, 0) < 0)
+		err("set interface failed");
+	do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
+		   !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
+		   !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
+	if (!ret) {
+		/* FIXME: We don't know why, but we need to configure the
+		 * lgdt3303 with the register settings below on resume */
+		int i;
+		u8 buf, bufs[] = {
+			0x0e, 0x2, 0x00, 0x7f,
+			0x0e, 0x2, 0x02, 0xfe,
+			0x0e, 0x2, 0x02, 0x01,
+			0x0e, 0x2, 0x00, 0x03,
+			0x0e, 0x2, 0x0d, 0x40,
+			0x0e, 0x2, 0x0e, 0x87,
+			0x0e, 0x2, 0x0f, 0x8e,
+			0x0e, 0x2, 0x10, 0x01,
+			0x0e, 0x2, 0x14, 0xd7,
+			0x0e, 0x2, 0x47, 0x88,
+		};
+		msleep(20);
+		for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) {
+			ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE,
+					     bufs+i, 4, &buf, 1);
+			if (ret)
+				break;
+			if (buf != 0x8)
+				return -EREMOTEIO;
+		}
+	}
+	return ret;
+}
+
 static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
 static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
 {
 	u8 b = 0;
 	u8 b = 0;
@@ -233,6 +273,16 @@ static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 	return 0;
 	return 0;
 }
 }
 
 
+static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	if (onoff)
+		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0);
+	else
+		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF,
+			       NULL, 0, NULL, 0);
+	return 0;
+}
+
 static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 {
 	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
 	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
@@ -423,6 +473,12 @@ static struct lgdt330x_config cxusb_lgdt3303_config = {
 	.demod_chip    = LGDT3303,
 	.demod_chip    = LGDT3303,
 };
 };
 
 
+static struct lgdt330x_config cxusb_aver_lgdt3303_config = {
+	.demod_address       = 0x0e,
+	.demod_chip          = LGDT3303,
+	.clock_polarity_flip = 2,
+};
+
 static struct mt352_config cxusb_dee1601_config = {
 static struct mt352_config cxusb_dee1601_config = {
 	.demod_address = 0x0f,
 	.demod_address = 0x0f,
 	.demod_init    = cxusb_dee1601_demod_init,
 	.demod_init    = cxusb_dee1601_demod_init,
@@ -453,6 +509,24 @@ static struct mt352_config cxusb_mt352_xc3028_config = {
 	.demod_init = cxusb_mt352_demod_init,
 	.demod_init = cxusb_mt352_demod_init,
 };
 };
 
 
+/* FIXME: needs tweaking */
+static struct mxl5005s_config aver_a868r_tuner = {
+	.i2c_address     = 0x63,
+	.if_freq         = 6000000UL,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
 /* Callbacks for DVB USB */
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
 {
@@ -533,6 +607,13 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
 	return 0;
 	return 0;
 }
 }
 
 
+static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(mxl5005s_attach, adap->fe,
+		   &adap->dev->i2c_adap, &aver_a868r_tuner);
+	return 0;
+}
+
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 {
 {
 	u8 b;
 	u8 b;
@@ -562,6 +643,16 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
 	return -EIO;
 	return -EIO;
 }
 }
 
 
+static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe != NULL)
+		return 0;
+
+	return -EIO;
+}
+
 static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 {
 {
 	/* used in both lgz201 and th7579 */
 	/* used in both lgz201 and th7579 */
@@ -736,6 +827,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
+static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
 
 
 static int cxusb_probe(struct usb_interface *intf,
 static int cxusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
 		       const struct usb_device_id *id)
@@ -756,7 +848,10 @@ static int cxusb_probe(struct usb_interface *intf,
 				     THIS_MODULE, NULL, adapter_nr) ||
 				     THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf,
 	    0 == dvb_usb_device_init(intf,
 				&cxusb_bluebird_nano2_needsfirmware_properties,
 				&cxusb_bluebird_nano2_needsfirmware_properties,
-				     THIS_MODULE, NULL, adapter_nr))
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0)
 		return 0;
 		return 0;
 
 
 	return -EINVAL;
 	return -EINVAL;
@@ -779,6 +874,7 @@ static struct usb_device_id cxusb_table [] = {
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
+	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
 	{}		/* Terminating entry */
 	{}		/* Terminating entry */
 };
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1182,6 +1278,48 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
 	}
 	}
 };
 };
 
 
+static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_aver_streaming_ctrl,
+			.frontend_attach  = cxusb_aver_lgdt3303_frontend_attach,
+			.tuner_attach     = cxusb_mxl5003s_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x04,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+
+		},
+	},
+	.power_ctrl       = cxusb_aver_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "AVerMedia AVerTVHD Volar (A868R)",
+			{ NULL },
+			{ &cxusb_table[16], NULL },
+		},
+	}
+};
+
 static struct usb_driver cxusb_driver = {
 static struct usb_driver cxusb_driver = {
 	.name		= "dvb_usb_cxusb",
 	.name		= "dvb_usb_cxusb",
 	.probe		= cxusb_probe,
 	.probe		= cxusb_probe,

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

@@ -20,6 +20,9 @@
 #define CMD_STREAMING_ON  0x36
 #define CMD_STREAMING_ON  0x36
 #define CMD_STREAMING_OFF 0x37
 #define CMD_STREAMING_OFF 0x37
 
 
+#define CMD_AVER_STREAM_ON  0x18
+#define CMD_AVER_STREAM_OFF 0x19
+
 #define CMD_GET_IR_CODE   0x47
 #define CMD_GET_IR_CODE   0x47
 
 
 #define CMD_ANALOG        0x50
 #define CMD_ANALOG        0x50

+ 6 - 1
drivers/media/dvb/dvb-usb/dib0700_devices.c

@@ -1117,6 +1117,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
 	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
 	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
 	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS) },
 	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS) },
 	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
 	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
 	{ 0 }		/* Terminating entry */
 	{ 0 }		/* Terminating entry */
 };
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1372,7 +1373,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			}
 			}
 		},
 		},
 
 
-		.num_device_descs = 2,
+		.num_device_descs = 3,
 		.devices = {
 		.devices = {
 			{   "DiBcom STK7070PD reference design",
 			{   "DiBcom STK7070PD reference design",
 				{ &dib0700_usb_id_table[17], NULL },
 				{ &dib0700_usb_id_table[17], NULL },
@@ -1381,6 +1382,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
 			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
 				{ &dib0700_usb_id_table[18], NULL },
 				{ &dib0700_usb_id_table[18], NULL },
 				{ NULL },
 				{ NULL },
+			},
+			{   "Hauppauge Nova-TD Stick (52009)",
+				{ &dib0700_usb_id_table[35], NULL },
+				{ NULL },
 			}
 			}
 		}
 		}
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,

+ 0 - 4
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c

@@ -20,11 +20,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
 	}
 	}
 
 
 	strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
 	strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
-#else
 	d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
 	d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
-#endif
 	d->i2c_adap.algo      = d->props.i2c_algo;
 	d->i2c_adap.algo      = d->props.i2c_algo;
 	d->i2c_adap.algo_data = NULL;
 	d->i2c_adap.algo_data = NULL;
 	d->i2c_adap.dev.parent = &d->udev->dev;
 	d->i2c_adap.dev.parent = &d->udev->dev;

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

@@ -14,6 +14,7 @@
 #define USB_VID_AFATECH				0x15a4
 #define USB_VID_AFATECH				0x15a4
 #define USB_VID_ALCOR_MICRO			0x058f
 #define USB_VID_ALCOR_MICRO			0x058f
 #define USB_VID_ALINK				0x05e3
 #define USB_VID_ALINK				0x05e3
+#define USB_VID_AMT				0x1c73
 #define USB_VID_ANCHOR				0x0547
 #define USB_VID_ANCHOR				0x0547
 #define USB_VID_ANSONIC				0x10b9
 #define USB_VID_ANSONIC				0x10b9
 #define USB_VID_ANUBIS_ELECTRONIC		0x10fd
 #define USB_VID_ANUBIS_ELECTRONIC		0x10fd
@@ -57,6 +58,7 @@
 #define USB_PID_AFATECH_AF9005				0x9020
 #define USB_PID_AFATECH_AF9005				0x9020
 #define USB_VID_ALINK_DTU				0xf170
 #define USB_VID_ALINK_DTU				0xf170
 #define USB_PID_ANSONIC_DVBT_USB			0x6000
 #define USB_PID_ANSONIC_DVBT_USB			0x6000
+#define USB_PID_ANYSEE					0x861f
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
@@ -132,9 +134,15 @@
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
 #define USB_PID_HAUPPAUGE_MYTV_T			0x7080
 #define USB_PID_HAUPPAUGE_MYTV_T			0x7080
 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009		0x5200
 #define USB_PID_AVERMEDIA_EXPRESS			0xb568
 #define USB_PID_AVERMEDIA_EXPRESS			0xb568
 #define USB_PID_AVERMEDIA_VOLAR				0xa807
 #define USB_PID_AVERMEDIA_VOLAR				0xa807
 #define USB_PID_AVERMEDIA_VOLAR_2			0xb808
 #define USB_PID_AVERMEDIA_VOLAR_2			0xb808
+#define USB_PID_AVERMEDIA_VOLAR_A868R			0xa868
+#define USB_PID_AVERMEDIA_MCE_USB_M038			0x1228
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R	0x0039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC	0x1039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT	0x2039
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058
 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058

+ 19 - 19
drivers/media/dvb/dvb-usb/gl861.c

@@ -1,8 +1,8 @@
 /* DVB USB compliant linux driver for GL861 USB2.0 devices.
 /* DVB USB compliant linux driver for GL861 USB2.0 devices.
  *
  *
  *	This program is free software; you can redistribute it and/or modify it
  *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the Free
- *	Software Foundation, version 2.
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation, version 2.
  *
  *
  * see Documentation/dvb/README.dvb-usb for more information
  * see Documentation/dvb/README.dvb-usb for more information
  */
  */
@@ -13,9 +13,9 @@
 
 
 /* debug */
 /* debug */
 static int dvb_usb_gl861_debug;
 static int dvb_usb_gl861_debug;
-module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-
+module_param_named(debug, dvb_usb_gl861_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))."
+	DVB_USB_DEBUG_STATUS);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 
 static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
 static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
@@ -70,7 +70,7 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 		/* write/read request */
 		/* write/read request */
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
 			if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
 			if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
-					  msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
+				msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
 				break;
 				break;
 			i++;
 			i++;
 		} else
 		} else
@@ -102,12 +102,13 @@ static struct zl10353_config gl861_zl10353_config = {
 
 
 static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
 static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
 {
 {
-	if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
-				   &adap->dev->i2c_adap)) != NULL) {
-		return 0;
-	}
 
 
-	return -EIO;
+	adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+		&adap->dev->i2c_adap);
+	if (adap->fe == NULL)
+		return -EIO;
+
+	return 0;
 }
 }
 
 
 static struct qt1010_config gl861_qt1010_config = {
 static struct qt1010_config gl861_qt1010_config = {
@@ -156,7 +157,7 @@ static struct usb_device_id gl861_table [] = {
 		{ USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
 		{ USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
 		{ }		/* Terminating entry */
 		{ }		/* Terminating entry */
 };
 };
-MODULE_DEVICE_TABLE (usb, gl861_table);
+MODULE_DEVICE_TABLE(usb, gl861_table);
 
 
 static struct dvb_usb_device_properties gl861_properties = {
 static struct dvb_usb_device_properties gl861_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -180,7 +181,7 @@ static struct dvb_usb_device_properties gl861_properties = {
 				}
 				}
 			}
 			}
 		},
 		},
-	}},
+	} },
 	.i2c_algo         = &gl861_i2c_algo,
 	.i2c_algo         = &gl861_i2c_algo,
 
 
 	.num_device_descs = 2,
 	.num_device_descs = 2,
@@ -210,12 +211,11 @@ static int __init gl861_module_init(void)
 {
 {
 	int ret;
 	int ret;
 
 
-	if ((ret = usb_register(&gl861_driver))) {
+	ret = usb_register(&gl861_driver);
+	if (ret)
 		err("usb_register failed. Error number %d", ret);
 		err("usb_register failed. Error number %d", ret);
-		return ret;
-	}
 
 
-	return 0;
+	return ret;
 }
 }
 
 
 static void __exit gl861_module_exit(void)
 static void __exit gl861_module_exit(void)
@@ -224,8 +224,8 @@ static void __exit gl861_module_exit(void)
 	usb_deregister(&gl861_driver);
 	usb_deregister(&gl861_driver);
 }
 }
 
 
-module_init (gl861_module_init);
-module_exit (gl861_module_exit);
+module_init(gl861_module_init);
+module_exit(gl861_module_exit);
 
 
 MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
 MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
 MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
 MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");

+ 1 - 1
drivers/media/dvb/dvb-usb/gl861.h

@@ -4,7 +4,7 @@
 #define DVB_USB_LOG_PREFIX "gl861"
 #define DVB_USB_LOG_PREFIX "gl861"
 #include "dvb-usb.h"
 #include "dvb-usb.h"
 
 
-#define deb_rc(args...)   dprintk(dvb_usb_gl861_debug,0x01,args)
+#define deb_rc(args...)   dprintk(dvb_usb_gl861_debug, 0x01, args)
 
 
 #define GL861_WRITE		0x40
 #define GL861_WRITE		0x40
 #define GL861_READ		0xc0
 #define GL861_READ		0xc0

+ 0 - 1
drivers/media/dvb/frontends/au8522.c

@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "au8522.h"
 #include "au8522.h"
 
 
 struct au8522_state {
 struct au8522_state {

+ 47 - 0
drivers/media/dvb/frontends/dvb-pll.c

@@ -343,6 +343,52 @@ static struct dvb_pll_desc dvb_pll_opera1 = {
 	}
 	}
 };
 };
 
 
+static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf,
+		       const struct dvb_frontend_parameters *params)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = {
+		.addr = priv->pll_i2c_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 4
+	};
+	int result;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	result = i2c_transfer(priv->i2c, &msg, 1);
+	if (result != 1)
+		printk(KERN_ERR "%s: i2c_transfer failed:%d",
+			__func__, result);
+
+	buf[2] = 0x9e;
+	buf[3] = 0x90;
+
+	return;
+}
+
+/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
+static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
+	.name   = "Samsung DTOS403IH102A",
+	.min    =  44250000,
+	.max    = 858000000,
+	.iffreq =  36125000,
+	.count  = 8,
+	.set    = samsung_dtos403ih102a_set,
+	.entries = {
+		{ 135000000, 62500, 0xbe, 0x01 },
+		{ 177000000, 62500, 0xf6, 0x01 },
+		{ 370000000, 62500, 0xbe, 0x02 },
+		{ 450000000, 62500, 0xf6, 0x02 },
+		{ 466000000, 62500, 0xfe, 0x02 },
+		{ 538000000, 62500, 0xbe, 0x08 },
+		{ 826000000, 62500, 0xf6, 0x08 },
+		{ 999999999, 62500, 0xfe, 0x08 },
+	}
+};
+
 /* ----------------------------------------------------------- */
 /* ----------------------------------------------------------- */
 
 
 static struct dvb_pll_desc *pll_list[] = {
 static struct dvb_pll_desc *pll_list[] = {
@@ -360,6 +406,7 @@ static struct dvb_pll_desc *pll_list[] = {
 	[DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
 	[DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
 	[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
 	[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
 	[DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
 	[DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
+	[DVB_PLL_SAMSUNG_DTOS403IH102A]  = &dvb_pll_samsung_dtos403ih102a,
 };
 };
 
 
 /* ----------------------------------------------------------- */
 /* ----------------------------------------------------------- */

+ 1 - 0
drivers/media/dvb/frontends/dvb-pll.h

@@ -22,6 +22,7 @@
 #define DVB_PLL_SAMSUNG_TBMV           11
 #define DVB_PLL_SAMSUNG_TBMV           11
 #define DVB_PLL_PHILIPS_SD1878_TDA8261 12
 #define DVB_PLL_PHILIPS_SD1878_TDA8261 12
 #define DVB_PLL_OPERA1                 13
 #define DVB_PLL_OPERA1                 13
+#define DVB_PLL_SAMSUNG_DTOS403IH102A  14
 
 
 /**
 /**
  * Attach a dvb-pll to the supplied frontend structure.
  * Attach a dvb-pll to the supplied frontend structure.

+ 19 - 5
drivers/media/dvb/frontends/lgdt330x.c

@@ -226,11 +226,16 @@ static int lgdt330x_init(struct dvb_frontend* fe)
 		0x4c, 0x14
 		0x4c, 0x14
 	};
 	};
 
 
-	static u8 flip_lgdt3303_init_data[] = {
+	static u8 flip_1_lgdt3303_init_data[] = {
 		0x4c, 0x14,
 		0x4c, 0x14,
 		0x87, 0xf3
 		0x87, 0xf3
 	};
 	};
 
 
+	static u8 flip_2_lgdt3303_init_data[] = {
+		0x4c, 0x14,
+		0x87, 0xda
+	};
+
 	struct lgdt330x_state* state = fe->demodulator_priv;
 	struct lgdt330x_state* state = fe->demodulator_priv;
 	char  *chip_name;
 	char  *chip_name;
 	int    err;
 	int    err;
@@ -243,10 +248,19 @@ static int lgdt330x_init(struct dvb_frontend* fe)
 		break;
 		break;
 	case LGDT3303:
 	case LGDT3303:
 		chip_name = "LGDT3303";
 		chip_name = "LGDT3303";
-		if (state->config->clock_polarity_flip) {
-			err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data,
-						    sizeof(flip_lgdt3303_init_data));
-		} else {
+		switch (state->config->clock_polarity_flip) {
+		case 2:
+			err = i2c_write_demod_bytes(state,
+					flip_2_lgdt3303_init_data,
+					sizeof(flip_2_lgdt3303_init_data));
+			break;
+		case 1:
+			err = i2c_write_demod_bytes(state,
+					flip_1_lgdt3303_init_data,
+					sizeof(flip_1_lgdt3303_init_data));
+			break;
+		case 0:
+		default:
 			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
 			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
 						    sizeof(lgdt3303_init_data));
 						    sizeof(lgdt3303_init_data));
 		}
 		}

+ 0 - 1
drivers/media/dvb/frontends/s5h1409.c

@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "s5h1409.h"
 #include "s5h1409.h"
 
 
 struct s5h1409_state {
 struct s5h1409_state {

+ 0 - 1
drivers/media/dvb/frontends/s5h1411.c

@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "s5h1411.h"
 #include "s5h1411.h"
 
 
 struct s5h1411_state {
 struct s5h1411_state {

+ 116 - 81
drivers/media/dvb/frontends/tda10023.c

@@ -38,75 +38,29 @@
 #include "dvb_frontend.h"
 #include "dvb_frontend.h"
 #include "tda1002x.h"
 #include "tda1002x.h"
 
 
+#define REG0_INIT_VAL 0x23
 
 
 struct tda10023_state {
 struct tda10023_state {
 	struct i2c_adapter* i2c;
 	struct i2c_adapter* i2c;
 	/* configuration settings */
 	/* configuration settings */
-	const struct tda1002x_config* config;
+	const struct tda10023_config *config;
 	struct dvb_frontend frontend;
 	struct dvb_frontend frontend;
 
 
 	u8 pwm;
 	u8 pwm;
 	u8 reg0;
 	u8 reg0;
-};
 
 
+	/* clock settings */
+	u32 xtal;
+	u8 pll_m;
+	u8 pll_p;
+	u8 pll_n;
+	u32 sysclk;
+};
 
 
 #define dprintk(x...)
 #define dprintk(x...)
 
 
 static int verbose;
 static int verbose;
 
 
-#define XTAL   28920000UL
-#define PLL_M  8UL
-#define PLL_P  4UL
-#define PLL_N  1UL
-#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P))  // -> 57840000
-
-static u8 tda10023_inittab[]={
-	// reg mask val
-	0x2a,0xff,0x02,  // PLL3, Bypass, Power Down
-	0xff,0x64,0x00,  // Sleep 100ms
-	0x2a,0xff,0x03,  // PLL3, Bypass, Power Down
-	0xff,0x64,0x00,  // Sleep 100ms
-	0x28,0xff,PLL_M-1,  // PLL1 M=8
-	0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1),  // PLL2
-	0x00,0xff,0x23,  // GPR FSAMPLING=1
-	0x2a,0xff,0x08,  // PLL3 PSACLK=1
-	0xff,0x64,0x00,  // Sleep 100ms
-	0x1f,0xff,0x00,  // RESET
-	0xff,0x64,0x00,  // Sleep 100ms
-	0xe6,0x0c,0x04,  // RSCFG_IND
-	0x10,0xc0,0x80,  // DECDVBCFG1 PBER=1
-
-	0x0e,0xff,0x82,  // GAIN1
-	0x03,0x08,0x08,  // CLKCONF DYN=1
-	0x2e,0xbf,0x30,  // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0
-	0x01,0xff,0x30,  // AGCREF
-	0x1e,0x84,0x84,  // CONTROL SACLK_ON=1
-	0x1b,0xff,0xc8,  // ADC TWOS=1
-	0x3b,0xff,0xff,  // IFMAX
-	0x3c,0xff,0x00,  // IFMIN
-	0x34,0xff,0x00,  // PWMREF
-	0x35,0xff,0xff,  // TUNMAX
-	0x36,0xff,0x00,  // TUNMIN
-	0x06,0xff,0x7f,  // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1    // 0x77
-	0x1c,0x30,0x30,  // EQCONF2 STEPALGO=SGNALGO=1
-	0x37,0xff,0xf6,  // DELTAF_LSB
-	0x38,0xff,0xff,  // DELTAF_MSB
-	0x02,0xff,0x93,  // AGCCONF1  IFS=1 KAGCIF=2 KAGCTUN=3
-	0x2d,0xff,0xf6,  // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2
-	0x04,0x10,0x00,   // SWRAMP=1
-	0x12,0xff,0xa1,  // INTP1 POCLKP=1 FEL=1 MFS=0
-	0x2b,0x01,0xa1,  // INTS1
-	0x20,0xff,0x04,  // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=?
-	0x2c,0xff,0x0d,  // INTP/S TRIP=0 TRIS=0
-	0xc4,0xff,0x00,
-	0xc3,0x30,0x00,
-	0xb5,0xff,0x19,  // ERAGC_THD
-	0x00,0x03,0x01,  // GPR, CLBS soft reset
-	0x00,0x03,0x03,  // GPR, CLBS soft reset
-	0xff,0x64,0x00,  // Sleep 100ms
-	0xff,0xff,0xff
-};
-
 static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
 static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
 {
 {
 	u8 b0 [] = { reg };
 	u8 b0 [] = { reg };
@@ -219,30 +173,34 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
 	s16 SFIL=0;
 	s16 SFIL=0;
 	u16 NDEC = 0;
 	u16 NDEC = 0;
 
 
-	if (sr < (u32)(SYSCLK/98.40)) {
+	/* avoid floating point operations multiplying syscloc and divider
+	   by 10 */
+	u32 sysclk_x_10 = state->sysclk * 10;
+
+	if (sr < (u32)(sysclk_x_10/984)) {
 		NDEC=3;
 		NDEC=3;
 		SFIL=1;
 		SFIL=1;
-	} else if (sr<(u32)(SYSCLK/64.0)) {
+	} else if (sr < (u32)(sysclk_x_10/640)) {
 		NDEC=3;
 		NDEC=3;
 		SFIL=0;
 		SFIL=0;
-	} else if (sr<(u32)(SYSCLK/49.2)) {
+	} else if (sr < (u32)(sysclk_x_10/492)) {
 		NDEC=2;
 		NDEC=2;
 		SFIL=1;
 		SFIL=1;
-	} else if (sr<(u32)(SYSCLK/32.0)) {
+	} else if (sr < (u32)(sysclk_x_10/320)) {
 		NDEC=2;
 		NDEC=2;
 		SFIL=0;
 		SFIL=0;
-	} else if (sr<(u32)(SYSCLK/24.6)) {
+	} else if (sr < (u32)(sysclk_x_10/246)) {
 		NDEC=1;
 		NDEC=1;
 		SFIL=1;
 		SFIL=1;
-	} else if (sr<(u32)(SYSCLK/16.0)) {
+	} else if (sr < (u32)(sysclk_x_10/160)) {
 		NDEC=1;
 		NDEC=1;
 		SFIL=0;
 		SFIL=0;
-	} else if (sr<(u32)(SYSCLK/12.3)) {
+	} else if (sr < (u32)(sysclk_x_10/123)) {
 		NDEC=0;
 		NDEC=0;
 		SFIL=1;
 		SFIL=1;
 	}
 	}
 
 
-	BDRI=SYSCLK*16;
+	BDRI = (state->sysclk)*16;
 	BDRI>>=NDEC;
 	BDRI>>=NDEC;
 	BDRI +=sr/2;
 	BDRI +=sr/2;
 	BDRI /=sr;
 	BDRI /=sr;
@@ -255,11 +213,12 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
 
 
 		BDRX=1<<(24+NDEC);
 		BDRX=1<<(24+NDEC);
 		BDRX*=sr;
 		BDRX*=sr;
-		do_div(BDRX,SYSCLK); 	// BDRX/=SYSCLK;
+		do_div(BDRX, state->sysclk); 	/* BDRX/=SYSCLK; */
 
 
 		BDR=(s32)BDRX;
 		BDR=(s32)BDRX;
 	}
 	}
-//	printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC);
+	dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",
+		sr, BDR, BDRI, NDEC);
 	tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
 	tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
 	tda10023_writereg (state, 0x0a, BDR&255);
 	tda10023_writereg (state, 0x0a, BDR&255);
 	tda10023_writereg (state, 0x0b, (BDR>>8)&255);
 	tda10023_writereg (state, 0x0b, (BDR>>8)&255);
@@ -272,8 +231,67 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
 static int tda10023_init (struct dvb_frontend *fe)
 static int tda10023_init (struct dvb_frontend *fe)
 {
 {
 	struct tda10023_state* state = fe->demodulator_priv;
 	struct tda10023_state* state = fe->demodulator_priv;
+	u8 tda10023_inittab[] = {
+/*        reg  mask val */
+/* 000 */ 0x2a, 0xff, 0x02,  /* PLL3, Bypass, Power Down */
+/* 003 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 006 */ 0x2a, 0xff, 0x03,  /* PLL3, Bypass, Power Down */
+/* 009 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+			   /* PLL1 */
+/* 012 */ 0x28, 0xff, (state->pll_m-1),
+			   /* PLL2 */
+/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1),
+			   /* GPR FSAMPLING=1 */
+/* 018 */ 0x00, 0xff, REG0_INIT_VAL,
+/* 021 */ 0x2a, 0xff, 0x08,  /* PLL3 PSACLK=1 */
+/* 024 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 027 */ 0x1f, 0xff, 0x00,  /* RESET */
+/* 030 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 033 */ 0xe6, 0x0c, 0x04,  /* RSCFG_IND */
+/* 036 */ 0x10, 0xc0, 0x80,  /* DECDVBCFG1 PBER=1 */
+
+/* 039 */ 0x0e, 0xff, 0x82,  /* GAIN1 */
+/* 042 */ 0x03, 0x08, 0x08,  /* CLKCONF DYN=1 */
+/* 045 */ 0x2e, 0xbf, 0x30,  /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1
+				       PPWMTUN=0 PPWMIF=0 */
+/* 048 */ 0x01, 0xff, 0x30,  /* AGCREF */
+/* 051 */ 0x1e, 0x84, 0x84,  /* CONTROL SACLK_ON=1 */
+/* 054 */ 0x1b, 0xff, 0xc8,  /* ADC TWOS=1 */
+/* 057 */ 0x3b, 0xff, 0xff,  /* IFMAX */
+/* 060 */ 0x3c, 0xff, 0x00,  /* IFMIN */
+/* 063 */ 0x34, 0xff, 0x00,  /* PWMREF */
+/* 066 */ 0x35, 0xff, 0xff,  /* TUNMAX */
+/* 069 */ 0x36, 0xff, 0x00,  /* TUNMIN */
+/* 072 */ 0x06, 0xff, 0x7f,  /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */
+/* 075 */ 0x1c, 0x30, 0x30,  /* EQCONF2 STEPALGO=SGNALGO=1 */
+/* 078 */ 0x37, 0xff, 0xf6,  /* DELTAF_LSB */
+/* 081 */ 0x38, 0xff, 0xff,  /* DELTAF_MSB */
+/* 084 */ 0x02, 0xff, 0x93,  /* AGCCONF1  IFS=1 KAGCIF=2 KAGCTUN=3 */
+/* 087 */ 0x2d, 0xff, 0xf6,  /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */
+/* 090 */ 0x04, 0x10, 0x00,  /* SWRAMP=1 */
+/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /*
+				INTP1 POCLKP=1 FEL=1 MFS=0 */
+/* 096 */ 0x2b, 0x01, 0xa1,  /* INTS1 */
+/* 099 */ 0x20, 0xff, 0x04,  /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */
+/* 102 */ 0x2c, 0xff, 0x0d,  /* INTP/S TRIP=0 TRIS=0 */
+/* 105 */ 0xc4, 0xff, 0x00,
+/* 108 */ 0xc3, 0x30, 0x00,
+/* 111 */ 0xb5, 0xff, 0x19,  /* ERAGC_THD */
+/* 114 */ 0x00, 0x03, 0x01,  /* GPR, CLBS soft reset */
+/* 117 */ 0x00, 0x03, 0x03,  /* GPR, CLBS soft reset */
+/* 120 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 123 */ 0xff, 0xff, 0xff
+};
+	dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num);
+
+	/* override default values if set in config */
+	if (state->config->deltaf) {
+		tda10023_inittab[80] = (state->config->deltaf & 0xff);
+		tda10023_inittab[83] = (state->config->deltaf >> 8);
+	}
 
 
-	dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num);
+	if (state->config->output_mode)
+		tda10023_inittab[95] = state->config->output_mode;
 
 
 	tda10023_writetab(state, tda10023_inittab);
 	tda10023_writetab(state, tda10023_inittab);
 
 
@@ -460,12 +478,11 @@ static void tda10023_release(struct dvb_frontend* fe)
 
 
 static struct dvb_frontend_ops tda10023_ops;
 static struct dvb_frontend_ops tda10023_ops;
 
 
-struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
-				     struct i2c_adapter* i2c,
+struct dvb_frontend *tda10023_attach(const struct tda10023_config *config,
+				     struct i2c_adapter *i2c,
 				     u8 pwm)
 				     u8 pwm)
 {
 {
 	struct tda10023_state* state = NULL;
 	struct tda10023_state* state = NULL;
-	int i;
 
 
 	/* allocate memory for the internal state */
 	/* allocate memory for the internal state */
 	state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
 	state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
@@ -474,22 +491,40 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
 	/* setup the state */
 	/* setup the state */
 	state->config = config;
 	state->config = config;
 	state->i2c = i2c;
 	state->i2c = i2c;
-	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
-	state->pwm = pwm;
-	for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
-		if (tda10023_inittab[i] == 0x00) {
-			state->reg0 = tda10023_inittab[i+2];
-			break;
-		}
-	}
 
 
-	// Wakeup if in standby
+	/* wakeup if in standby */
 	tda10023_writereg (state, 0x00, 0x33);
 	tda10023_writereg (state, 0x00, 0x33);
 	/* check if the demod is there */
 	/* check if the demod is there */
 	if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
 	if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
 
 
 	/* create dvb_frontend */
 	/* create dvb_frontend */
 	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
 	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
+	state->pwm = pwm;
+	state->reg0 = REG0_INIT_VAL;
+	if (state->config->xtal) {
+		state->xtal  = state->config->xtal;
+		state->pll_m = state->config->pll_m;
+		state->pll_p = state->config->pll_p;
+		state->pll_n = state->config->pll_n;
+	} else {
+		/* set default values if not defined in config */
+		state->xtal  = 28920000;
+		state->pll_m = 8;
+		state->pll_p = 4;
+		state->pll_n = 1;
+	}
+
+	/* calc sysclk */
+	state->sysclk = (state->xtal * state->pll_m / \
+			(state->pll_n * state->pll_p));
+
+	state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64;
+	state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4;
+
+	dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n",
+		__func__, state->xtal, state->pll_m, state->pll_p,
+		state->pll_n);
+
 	state->frontend.demodulator_priv = state;
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 	return &state->frontend;
 
 
@@ -504,10 +539,10 @@ static struct dvb_frontend_ops tda10023_ops = {
 		.name = "Philips TDA10023 DVB-C",
 		.name = "Philips TDA10023 DVB-C",
 		.type = FE_QAM,
 		.type = FE_QAM,
 		.frequency_stepsize = 62500,
 		.frequency_stepsize = 62500,
-		.frequency_min = 47000000,
+		.frequency_min =  47000000,
 		.frequency_max = 862000000,
 		.frequency_max = 862000000,
-		.symbol_rate_min = (SYSCLK/2)/64,     /* SACLK/64 == (SYSCLK/2)/64 */
-		.symbol_rate_max = (SYSCLK/2)/4,      /* SACLK/4 */
+		.symbol_rate_min = 0,  /* set in tda10023_attach */
+		.symbol_rate_max = 0,  /* set in tda10023_attach */
 		.caps = 0x400 | //FE_CAN_QAM_4
 		.caps = 0x400 | //FE_CAN_QAM_4
 			FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
 			FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
 			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
 			FE_CAN_QAM_128 | FE_CAN_QAM_256 |

+ 34 - 7
drivers/media/dvb/frontends/tda1002x.h

@@ -26,13 +26,37 @@
 
 
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/frontend.h>
 
 
-struct tda1002x_config
-{
+struct tda1002x_config {
 	/* the demodulator's i2c address */
 	/* the demodulator's i2c address */
 	u8 demod_address;
 	u8 demod_address;
 	u8 invert;
 	u8 invert;
 };
 };
 
 
+enum tda10023_output_mode {
+	TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0,
+	TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1,
+	TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0,
+	TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */
+};
+
+struct tda10023_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+	u8 invert;
+
+	/* clock settings */
+	u32 xtal; /* defaults: 28920000 */
+	u8 pll_m; /* defaults: 8 */
+	u8 pll_p; /* defaults: 4 */
+	u8 pll_n; /* defaults: 1 */
+
+	/* MPEG2 TS output mode */
+	u8 output_mode;
+
+	/* input freq offset + baseband conversion type */
+	u16 deltaf;
+};
+
 #if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
 #if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
 extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
 extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
 					    struct i2c_adapter* i2c, u8 pwm);
 					    struct i2c_adapter* i2c, u8 pwm);
@@ -45,12 +69,15 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config*
 }
 }
 #endif // CONFIG_DVB_TDA10021
 #endif // CONFIG_DVB_TDA10021
 
 
-#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
-					    struct i2c_adapter* i2c, u8 pwm);
+#if defined(CONFIG_DVB_TDA10023) || \
+	(defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10023_attach(
+	const struct tda10023_config *config,
+	struct i2c_adapter *i2c, u8 pwm);
 #else
 #else
-static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
-					    struct i2c_adapter* i2c, u8 pwm)
+static inline struct dvb_frontend *tda10023_attach(
+	const struct tda10023_config *config,
+	struct i2c_adapter *i2c, u8 pwm)
 {
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 	return NULL;

+ 1 - 1
drivers/media/dvb/pluto2/pluto2.c

@@ -234,7 +234,7 @@ static void pluto_reset_ts(struct pluto *pluto, int reenable)
 
 
 static void pluto_set_dma_addr(struct pluto *pluto)
 static void pluto_set_dma_addr(struct pluto *pluto)
 {
 {
-	pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr));
+	pluto_writereg(pluto, REG_PCAR, pluto->dma_addr);
 }
 }
 
 
 static int __devinit pluto_dma_map(struct pluto *pluto)
 static int __devinit pluto_dma_map(struct pluto *pluto)

+ 26 - 0
drivers/media/dvb/siano/Kconfig

@@ -0,0 +1,26 @@
+#
+# Siano Mobile Silicon Digital TV device configuration
+#
+
+config DVB_SIANO_SMS1XXX
+	tristate "Siano SMS1XXX USB dongle support"
+	depends on DVB_CORE && USB
+	---help---
+	  Choose Y here if you have a USB dongle with a SMS1XXX chipset.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sms1xxx.
+
+config DVB_SIANO_SMS1XXX_SMS_IDS
+	bool "Enable support for Siano Mobile Silicon default USB IDs"
+	depends on DVB_SIANO_SMS1XXX
+	default y
+	---help---
+	  Choose Y here if you have a USB dongle with a SMS1XXX chipset
+	  that uses Siano Mobile Silicon's default usb vid:pid.
+
+	  Choose N here if you would prefer to use Siano's external driver.
+
+	  Further documentation on this driver can be found on the WWW at
+	  <http://www.siano-ms.com/>.
+

+ 8 - 0
drivers/media/dvb/siano/Makefile

@@ -0,0 +1,8 @@
+sms1xxx-objs := smscoreapi.o smsusb.o smsdvb.o sms-cards.o
+
+obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+

+ 102 - 0
drivers/media/dvb/siano/sms-cards.c

@@ -0,0 +1,102 @@
+/*
+ *  Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "sms-cards.h"
+
+struct usb_device_id smsusb_id_table[] = {
+#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
+	{ USB_DEVICE(0x187f, 0x0010),
+		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+	{ USB_DEVICE(0x187f, 0x0100),
+		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+	{ USB_DEVICE(0x187f, 0x0200),
+		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
+	{ USB_DEVICE(0x187f, 0x0201),
+		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
+	{ USB_DEVICE(0x187f, 0x0300),
+		.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
+#endif
+	{ USB_DEVICE(0x2040, 0x1700),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
+	{ USB_DEVICE(0x2040, 0x1800),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
+	{ USB_DEVICE(0x2040, 0x1801),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
+	{ USB_DEVICE(0x2040, 0x5500),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0x5580),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0x5590),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, smsusb_id_table);
+
+static struct sms_board sms_boards[] = {
+	[SMS_BOARD_UNKNOWN] = {
+		.name	= "Unknown board",
+	},
+	[SMS1XXX_BOARD_SIANO_STELLAR] = {
+		.name	= "Siano Stellar Digital Receiver",
+		.type	= SMS_STELLAR,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_SIANO_NOVA_A] = {
+		.name	= "Siano Nova A Digital Receiver",
+		.type	= SMS_NOVA_A0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_SIANO_NOVA_B] = {
+		.name	= "Siano Nova B Digital Receiver",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_SIANO_VEGA] = {
+		.name	= "Siano Vega Digital Receiver",
+		.type	= SMS_VEGA,
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
+		.name	= "Hauppauge Catamount",
+		.type	= SMS_STELLAR,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
+		.name	= "Hauppauge Okemo-A",
+		.type	= SMS_NOVA_A0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
+		.name	= "Hauppauge Okemo-B",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
+		.name	= "Hauppauge WinTV-Nova-T-MiniStick",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw",
+	},
+};
+
+struct sms_board *sms_get_board(int id)
+{
+	BUG_ON(id >= ARRAY_SIZE(sms_boards));
+
+	return &sms_boards[id];
+}
+

+ 45 - 0
drivers/media/dvb/siano/sms-cards.h

@@ -0,0 +1,45 @@
+/*
+ *  Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SMS_CARDS_H__
+#define __SMS_CARDS_H__
+
+#include <linux/usb.h>
+#include "smscoreapi.h"
+
+#define SMS_BOARD_UNKNOWN 0
+#define SMS1XXX_BOARD_SIANO_STELLAR 1
+#define SMS1XXX_BOARD_SIANO_NOVA_A  2
+#define SMS1XXX_BOARD_SIANO_NOVA_B  3
+#define SMS1XXX_BOARD_SIANO_VEGA    4
+#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
+#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
+
+struct sms_board {
+	enum sms_device_type_st type;
+	char *name, *fw[DEVICE_MODE_MAX];
+};
+
+struct sms_board *sms_get_board(int id);
+
+extern struct usb_device_id smsusb_id_table[];
+
+#endif /* __SMS_CARDS_H__ */

+ 1251 - 0
drivers/media/dvb/siano/smscoreapi.c

@@ -0,0 +1,1251 @@
+/*
+ *  Siano core API module
+ *
+ *  This file contains implementation for the interface to sms core component
+ *
+ *  author: Anatoly Greenblat
+ *
+ *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <linux/firmware.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+int sms_debug;
+module_param_named(debug, sms_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+struct smscore_device_notifyee_t {
+	struct list_head entry;
+	hotplug_t hotplug;
+};
+
+struct smscore_idlist_t {
+	struct list_head entry;
+	int		id;
+	int		data_type;
+};
+
+struct smscore_client_t {
+	struct list_head entry;
+	struct smscore_device_t *coredev;
+	void			*context;
+	struct list_head 	idlist;
+	onresponse_t	onresponse_handler;
+	onremove_t		onremove_handler;
+};
+
+struct smscore_device_t {
+	struct list_head entry;
+
+	struct list_head clients;
+	struct list_head subclients;
+	spinlock_t		clientslock;
+
+	struct list_head buffers;
+	spinlock_t		bufferslock;
+	int				num_buffers;
+
+	void			*common_buffer;
+	int				common_buffer_size;
+	dma_addr_t		common_buffer_phys;
+
+	void			*context;
+	struct device	*device;
+
+	char			devpath[32];
+	unsigned long	device_flags;
+
+	setmode_t		setmode_handler;
+	detectmode_t	detectmode_handler;
+	sendrequest_t	sendrequest_handler;
+	preload_t		preload_handler;
+	postload_t		postload_handler;
+
+	int				mode, modes_supported;
+
+	struct completion version_ex_done, data_download_done, trigger_done;
+	struct completion init_device_done, reload_start_done, resume_done;
+
+	int board_id;
+};
+
+void smscore_set_board_id(struct smscore_device_t *core, int id)
+{
+	core->board_id = id;
+}
+
+int smscore_get_board_id(struct smscore_device_t *core)
+{
+	return core->board_id;
+}
+
+struct smscore_registry_entry_t {
+	struct list_head entry;
+	char			devpath[32];
+	int				mode;
+	enum sms_device_type_st	type;
+};
+
+struct list_head g_smscore_notifyees;
+struct list_head g_smscore_devices;
+struct mutex g_smscore_deviceslock;
+
+struct list_head g_smscore_registry;
+struct mutex g_smscore_registrylock;
+
+static int default_mode = 4;
+
+module_param(default_mode, int, 0644);
+MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
+
+static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
+{
+	struct smscore_registry_entry_t *entry;
+	struct list_head *next;
+
+	kmutex_lock(&g_smscore_registrylock);
+	for (next = g_smscore_registry.next;
+	     next != &g_smscore_registry;
+	     next = next->next) {
+		entry = (struct smscore_registry_entry_t *) next;
+		if (!strcmp(entry->devpath, devpath)) {
+			kmutex_unlock(&g_smscore_registrylock);
+			return entry;
+		}
+	}
+	entry = (struct smscore_registry_entry_t *)
+			kmalloc(sizeof(struct smscore_registry_entry_t),
+				GFP_KERNEL);
+	if (entry) {
+		entry->mode = default_mode;
+		strcpy(entry->devpath, devpath);
+		list_add(&entry->entry, &g_smscore_registry);
+	} else
+		sms_err("failed to create smscore_registry.");
+	kmutex_unlock(&g_smscore_registrylock);
+	return entry;
+}
+
+int smscore_registry_getmode(char *devpath)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		return entry->mode;
+	else
+		sms_err("No registry found.");
+
+	return default_mode;
+}
+
+static enum sms_device_type_st smscore_registry_gettype(char *devpath)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		return entry->type;
+	else
+		sms_err("No registry found.");
+
+	return -1;
+}
+
+void smscore_registry_setmode(char *devpath, int mode)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		entry->mode = mode;
+	else
+		sms_err("No registry found.");
+}
+
+static void smscore_registry_settype(char *devpath,
+				     enum sms_device_type_st type)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		entry->type = type;
+	else
+		sms_err("No registry found.");
+}
+
+
+static void list_add_locked(struct list_head *new, struct list_head *head,
+			    spinlock_t *lock)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(lock, flags);
+
+	list_add(new, head);
+
+	spin_unlock_irqrestore(lock, flags);
+}
+
+/**
+ * register a client callback that called when device plugged in/unplugged
+ * NOTE: if devices exist callback is called immediately for each device
+ *
+ * @param hotplug callback
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_hotplug(hotplug_t hotplug)
+{
+	struct smscore_device_notifyee_t *notifyee;
+	struct list_head *next, *first;
+	int rc = 0;
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
+			   GFP_KERNEL);
+	if (notifyee) {
+		/* now notify callback about existing devices */
+		first = &g_smscore_devices;
+		for (next = first->next;
+		     next != first && !rc;
+		     next = next->next) {
+			struct smscore_device_t *coredev =
+				(struct smscore_device_t *) next;
+			rc = hotplug(coredev, coredev->device, 1);
+		}
+
+		if (rc >= 0) {
+			notifyee->hotplug = hotplug;
+			list_add(&notifyee->entry, &g_smscore_notifyees);
+		} else
+			kfree(notifyee);
+	} else
+		rc = -ENOMEM;
+
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	return rc;
+}
+
+/**
+ * unregister a client callback that called when device plugged in/unplugged
+ *
+ * @param hotplug callback
+ *
+ */
+void smscore_unregister_hotplug(hotplug_t hotplug)
+{
+	struct list_head *next, *first;
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	first = &g_smscore_notifyees;
+
+	for (next = first->next; next != first;) {
+		struct smscore_device_notifyee_t *notifyee =
+			(struct smscore_device_notifyee_t *) next;
+		next = next->next;
+
+		if (notifyee->hotplug == hotplug) {
+			list_del(&notifyee->entry);
+			kfree(notifyee);
+		}
+	}
+
+	kmutex_unlock(&g_smscore_deviceslock);
+}
+
+static void smscore_notify_clients(struct smscore_device_t *coredev)
+{
+	struct smscore_client_t *client;
+
+	/* the client must call smscore_unregister_client from remove handler */
+	while (!list_empty(&coredev->clients)) {
+		client = (struct smscore_client_t *) coredev->clients.next;
+		client->onremove_handler(client->context);
+	}
+}
+
+static int smscore_notify_callbacks(struct smscore_device_t *coredev,
+				    struct device *device, int arrival)
+{
+	struct list_head *next, *first;
+	int rc = 0;
+
+	/* note: must be called under g_deviceslock */
+
+	first = &g_smscore_notifyees;
+
+	for (next = first->next; next != first; next = next->next) {
+		rc = ((struct smscore_device_notifyee_t *) next)->
+				hotplug(coredev, device, arrival);
+		if (rc < 0)
+			break;
+	}
+
+	return rc;
+}
+
+static struct
+smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
+				       dma_addr_t common_buffer_phys)
+{
+	struct smscore_buffer_t *cb =
+		kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
+	if (!cb) {
+		sms_info("kmalloc(...) failed");
+		return NULL;
+	}
+
+	cb->p = buffer;
+	cb->offset_in_common = buffer - (u8 *) common_buffer;
+	cb->phys = common_buffer_phys + cb->offset_in_common;
+
+	return cb;
+}
+
+/**
+ * creates coredev object for a device, prepares buffers,
+ * creates buffer mappings, notifies registered hotplugs about new device.
+ *
+ * @param params device pointer to struct with device specific parameters
+ *               and handlers
+ * @param coredev pointer to a value that receives created coredev object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_device(struct smsdevice_params_t *params,
+			    struct smscore_device_t **coredev)
+{
+	struct smscore_device_t *dev;
+	u8 *buffer;
+
+	dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
+	if (!dev) {
+		sms_info("kzalloc(...) failed");
+		return -ENOMEM;
+	}
+
+	/* init list entry so it could be safe in smscore_unregister_device */
+	INIT_LIST_HEAD(&dev->entry);
+
+	/* init queues */
+	INIT_LIST_HEAD(&dev->clients);
+	INIT_LIST_HEAD(&dev->buffers);
+
+	/* init locks */
+	spin_lock_init(&dev->clientslock);
+	spin_lock_init(&dev->bufferslock);
+
+	/* init completion events */
+	init_completion(&dev->version_ex_done);
+	init_completion(&dev->data_download_done);
+	init_completion(&dev->trigger_done);
+	init_completion(&dev->init_device_done);
+	init_completion(&dev->reload_start_done);
+	init_completion(&dev->resume_done);
+
+	/* alloc common buffer */
+	dev->common_buffer_size = params->buffer_size * params->num_buffers;
+	dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
+						&dev->common_buffer_phys,
+						GFP_KERNEL | GFP_DMA);
+	if (!dev->common_buffer) {
+		smscore_unregister_device(dev);
+		return -ENOMEM;
+	}
+
+	/* prepare dma buffers */
+	for (buffer = dev->common_buffer;
+	     dev->num_buffers < params->num_buffers;
+	     dev->num_buffers++, buffer += params->buffer_size) {
+		struct smscore_buffer_t *cb =
+			smscore_createbuffer(buffer, dev->common_buffer,
+					     dev->common_buffer_phys);
+		if (!cb) {
+			smscore_unregister_device(dev);
+			return -ENOMEM;
+		}
+
+		smscore_putbuffer(dev, cb);
+	}
+
+	sms_info("allocated %d buffers", dev->num_buffers);
+
+	dev->mode = DEVICE_MODE_NONE;
+	dev->context = params->context;
+	dev->device = params->device;
+	dev->setmode_handler = params->setmode_handler;
+	dev->detectmode_handler = params->detectmode_handler;
+	dev->sendrequest_handler = params->sendrequest_handler;
+	dev->preload_handler = params->preload_handler;
+	dev->postload_handler = params->postload_handler;
+
+	dev->device_flags = params->flags;
+	strcpy(dev->devpath, params->devpath);
+
+	smscore_registry_settype(dev->devpath, params->device_type);
+
+	/* add device to devices list */
+	kmutex_lock(&g_smscore_deviceslock);
+	list_add(&dev->entry, &g_smscore_devices);
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	*coredev = dev;
+
+	sms_info("device %p created", dev);
+
+	return 0;
+}
+
+/**
+ * sets initial device mode and notifies client hotplugs that device is ready
+ *
+ * @param coredev pointer to a coredev object returned by
+ * 		  smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_start_device(struct smscore_device_t *coredev)
+{
+	int rc = smscore_set_device_mode(
+			coredev, smscore_registry_getmode(coredev->devpath));
+	if (rc < 0) {
+		sms_info("set device mode faile , rc %d", rc);
+		return rc;
+	}
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+
+	sms_info("device %p started, rc %d", coredev, rc);
+
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	return rc;
+}
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+					void *buffer, size_t size,
+					struct completion *completion)
+{
+	int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+	if (rc < 0) {
+		sms_info("sendrequest returned error %d", rc);
+		return rc;
+	}
+
+	return wait_for_completion_timeout(completion,
+					   msecs_to_jiffies(10000)) ?
+						0 : -ETIME;
+}
+
+static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
+					 void *buffer, size_t size)
+{
+	struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
+	struct SmsMsgHdr_ST *msg;
+	u32 mem_address = firmware->StartAddress;
+	u8 *payload = firmware->Payload;
+	int rc = 0;
+
+	sms_info("loading FW to addr 0x%x size %d",
+		 mem_address, firmware->Length);
+	if (coredev->preload_handler) {
+		rc = coredev->preload_handler(coredev->context);
+		if (rc < 0)
+			return rc;
+	}
+
+	/* PAGE_SIZE buffer shall be enough and dma aligned */
+	msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+	if (!msg)
+		return -ENOMEM;
+
+	if (coredev->mode != DEVICE_MODE_NONE) {
+		sms_debug("sending reload command.");
+		SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
+			     sizeof(struct SmsMsgHdr_ST));
+		rc = smscore_sendrequest_and_wait(coredev, msg,
+						  msg->msgLength,
+						  &coredev->reload_start_done);
+		mem_address = *(u32 *) &payload[20];
+	}
+
+	while (size && rc >= 0) {
+		struct SmsDataDownload_ST *DataMsg =
+			(struct SmsDataDownload_ST *) msg;
+		int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
+
+		SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
+			     (u16)(sizeof(struct SmsMsgHdr_ST) +
+				      sizeof(u32) + payload_size));
+
+		DataMsg->MemAddr = mem_address;
+		memcpy(DataMsg->Payload, payload, payload_size);
+
+		if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
+		    (coredev->mode == DEVICE_MODE_NONE))
+			rc = coredev->sendrequest_handler(
+				coredev->context, DataMsg,
+				DataMsg->xMsgHeader.msgLength);
+		else
+			rc = smscore_sendrequest_and_wait(
+				coredev, DataMsg,
+				DataMsg->xMsgHeader.msgLength,
+				&coredev->data_download_done);
+
+		payload += payload_size;
+		size -= payload_size;
+		mem_address += payload_size;
+	}
+
+	if (rc >= 0) {
+		if (coredev->mode == DEVICE_MODE_NONE) {
+			struct SmsMsgData_ST *TriggerMsg =
+				(struct SmsMsgData_ST *) msg;
+
+			SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
+				     sizeof(struct SmsMsgHdr_ST) +
+				     sizeof(u32) * 5);
+
+			TriggerMsg->msgData[0] = firmware->StartAddress;
+						/* Entry point */
+			TriggerMsg->msgData[1] = 5; /* Priority */
+			TriggerMsg->msgData[2] = 0x200; /* Stack size */
+			TriggerMsg->msgData[3] = 0; /* Parameter */
+			TriggerMsg->msgData[4] = 4; /* Task ID */
+
+			if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
+				rc = coredev->sendrequest_handler(
+					coredev->context, TriggerMsg,
+					TriggerMsg->xMsgHeader.msgLength);
+				msleep(100);
+			} else
+				rc = smscore_sendrequest_and_wait(
+					coredev, TriggerMsg,
+					TriggerMsg->xMsgHeader.msgLength,
+					&coredev->trigger_done);
+		} else {
+			SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
+				     sizeof(struct SmsMsgHdr_ST));
+
+			rc = coredev->sendrequest_handler(coredev->context,
+							  msg, msg->msgLength);
+		}
+		msleep(500);
+	}
+
+	sms_debug("rc=%d, postload=%p ", rc,
+		  coredev->postload_handler);
+
+	kfree(msg);
+
+	return ((rc >= 0) && coredev->postload_handler) ?
+		coredev->postload_handler(coredev->context) :
+		rc;
+}
+
+/**
+ * loads specified firmware into a buffer and calls device loadfirmware_handler
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param filename null-terminated string specifies firmware file name
+ * @param loadfirmware_handler device handler that loads firmware
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
+					   char *filename,
+					   loadfirmware_t loadfirmware_handler)
+{
+	int rc = -ENOENT;
+	const struct firmware *fw;
+	u8 *fw_buffer;
+
+	if (loadfirmware_handler == NULL && !(coredev->device_flags &
+					      SMS_DEVICE_FAMILY2))
+		return -EINVAL;
+
+	rc = request_firmware(&fw, filename, coredev->device);
+	if (rc < 0) {
+		sms_info("failed to open \"%s\"", filename);
+		return rc;
+	}
+	sms_info("read FW %s, size=%zd", filename, fw->size);
+	fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
+			    GFP_KERNEL | GFP_DMA);
+	if (fw_buffer) {
+		memcpy(fw_buffer, fw->data, fw->size);
+
+		rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
+		      smscore_load_firmware_family2(coredev,
+						    fw_buffer,
+						    fw->size) :
+		      loadfirmware_handler(coredev->context,
+					   fw_buffer, fw->size);
+
+		kfree(fw_buffer);
+	} else {
+		sms_info("failed to allocate firmware buffer");
+		rc = -ENOMEM;
+	}
+
+	release_firmware(fw);
+
+	return rc;
+}
+
+/**
+ * notifies all clients registered with the device, notifies hotplugs,
+ * frees all buffers and coredev object
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+void smscore_unregister_device(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb;
+	int num_buffers = 0;
+	int retry = 0;
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	smscore_notify_clients(coredev);
+	smscore_notify_callbacks(coredev, NULL, 0);
+
+	/* at this point all buffers should be back
+	 * onresponse must no longer be called */
+
+	while (1) {
+		while ((cb = smscore_getbuffer(coredev))) {
+			kfree(cb);
+			num_buffers++;
+		}
+		if (num_buffers == coredev->num_buffers)
+			break;
+		if (++retry > 10) {
+			sms_info("exiting although "
+				 "not all buffers released.");
+			break;
+		}
+
+		sms_info("waiting for %d buffer(s)",
+			 coredev->num_buffers - num_buffers);
+		msleep(100);
+	}
+
+	sms_info("freed %d buffers", num_buffers);
+
+	if (coredev->common_buffer)
+		dma_free_coherent(NULL, coredev->common_buffer_size,
+				  coredev->common_buffer,
+				  coredev->common_buffer_phys);
+
+	list_del(&coredev->entry);
+	kfree(coredev);
+
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	sms_info("device %p destroyed", coredev);
+}
+
+static int smscore_detect_mode(struct smscore_device_t *coredev)
+{
+	void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
+			       GFP_KERNEL | GFP_DMA);
+	struct SmsMsgHdr_ST *msg =
+		(struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
+	int rc;
+
+	if (!buffer)
+		return -ENOMEM;
+
+	SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
+		     sizeof(struct SmsMsgHdr_ST));
+
+	rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
+					  &coredev->version_ex_done);
+	if (rc == -ETIME) {
+		sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
+
+		if (wait_for_completion_timeout(&coredev->resume_done,
+						msecs_to_jiffies(5000))) {
+			rc = smscore_sendrequest_and_wait(
+				coredev, msg, msg->msgLength,
+				&coredev->version_ex_done);
+			if (rc < 0)
+				sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
+					"second try, rc %d", rc);
+		} else
+			rc = -ETIME;
+	}
+
+	kfree(buffer);
+
+	return rc;
+}
+
+static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
+	/*Stellar		NOVA A0		Nova B0		VEGA*/
+	/*DVBT*/
+	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+	/*DVBH*/
+	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+	/*TDMB*/
+	{"none", "tdmb_nova_12mhz.inp", "none", "none"},
+	/*DABIP*/
+	{"none", "none", "none", "none"},
+	/*BDA*/
+	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+	/*ISDBT*/
+	{"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
+	/*ISDBTBDA*/
+	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
+	/*CMMB*/
+	{"none", "none", "none", "cmmb_vega_12mhz.inp"}
+};
+
+static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
+				    int mode, enum sms_device_type_st type)
+{
+	char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
+	return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
+}
+
+/**
+ * calls device handler to change mode of operation
+ * NOTE: stellar/usb may disconnect when changing mode
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param mode requested mode of operation
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
+{
+	void *buffer;
+	int rc = 0;
+	enum sms_device_type_st type;
+
+	sms_debug("set device mode to %d", mode);
+	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
+			sms_err("invalid mode specified %d", mode);
+			return -EINVAL;
+		}
+
+		smscore_registry_setmode(coredev->devpath, mode);
+
+		if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
+			rc = smscore_detect_mode(coredev);
+			if (rc < 0) {
+				sms_err("mode detect failed %d", rc);
+				return rc;
+			}
+		}
+
+		if (coredev->mode == mode) {
+			sms_info("device mode %d already set", mode);
+			return 0;
+		}
+
+		if (!(coredev->modes_supported & (1 << mode))) {
+			char *fw_filename;
+
+			type = smscore_registry_gettype(coredev->devpath);
+			fw_filename = sms_get_fw_name(coredev, mode, type);
+
+			rc = smscore_load_firmware_from_file(coredev,
+							     fw_filename, NULL);
+			if (rc < 0) {
+				sms_warn("error %d loading firmware: %s, "
+					 "trying again with default firmware",
+					 rc, fw_filename);
+
+				/* try again with the default firmware */
+				fw_filename = smscore_fw_lkup[mode][type];
+				rc = smscore_load_firmware_from_file(coredev,
+							     fw_filename, NULL);
+
+				if (rc < 0) {
+					sms_warn("error %d loading "
+						 "firmware: %s", rc,
+						 fw_filename);
+					return rc;
+				}
+			}
+			sms_log("firmware download success: %s", fw_filename);
+		} else
+			sms_info("mode %d supported by running "
+				 "firmware", mode);
+
+		buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
+				 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+		if (buffer) {
+			struct SmsMsgData_ST *msg =
+				(struct SmsMsgData_ST *)
+					SMS_ALIGN_ADDRESS(buffer);
+
+			SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
+				     sizeof(struct SmsMsgData_ST));
+			msg->msgData[0] = mode;
+
+			rc = smscore_sendrequest_and_wait(
+				coredev, msg, msg->xMsgHeader.msgLength,
+				&coredev->init_device_done);
+
+			kfree(buffer);
+		} else {
+			sms_err("Could not allocate buffer for "
+				"init device message.");
+			rc = -ENOMEM;
+		}
+	} else {
+		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
+			sms_err("invalid mode specified %d", mode);
+			return -EINVAL;
+		}
+
+		smscore_registry_setmode(coredev->devpath, mode);
+
+		if (coredev->detectmode_handler)
+			coredev->detectmode_handler(coredev->context,
+						    &coredev->mode);
+
+		if (coredev->mode != mode && coredev->setmode_handler)
+			rc = coredev->setmode_handler(coredev->context, mode);
+	}
+
+	if (rc >= 0) {
+		coredev->mode = mode;
+		coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
+	}
+
+	if (rc != 0)
+		sms_err("return error code %d.", rc);
+	return rc;
+}
+
+/**
+ * calls device handler to get current mode of operation
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return current mode
+ */
+int smscore_get_device_mode(struct smscore_device_t *coredev)
+{
+	return coredev->mode;
+}
+
+/**
+ * find client by response id & type within the clients list.
+ * return client handle or NULL.
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param data_type client data type (SMS_DONT_CARE for all types)
+ * @param id client id (SMS_DONT_CARE for all id)
+ *
+ */
+static struct
+smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
+				      int data_type, int id)
+{
+	struct smscore_client_t *client = NULL;
+	struct list_head *next, *first;
+	unsigned long flags;
+	struct list_head *firstid, *nextid;
+
+
+	spin_lock_irqsave(&coredev->clientslock, flags);
+	first = &coredev->clients;
+	for (next = first->next;
+	     (next != first) && !client;
+	     next = next->next) {
+		firstid = &((struct smscore_client_t *)next)->idlist;
+		for (nextid = firstid->next;
+		     nextid != firstid;
+		     nextid = nextid->next) {
+			if ((((struct smscore_idlist_t *)nextid)->id == id) &&
+			    (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
+			    (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
+				client = (struct smscore_client_t *) next;
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&coredev->clientslock, flags);
+	return client;
+}
+
+/**
+ * find client by response id/type, call clients onresponse handler
+ * return buffer to pool on error
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param cb pointer to response buffer descriptor
+ *
+ */
+void smscore_onresponse(struct smscore_device_t *coredev,
+			struct smscore_buffer_t *cb)
+{
+	struct SmsMsgHdr_ST *phdr =
+		(struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
+	struct smscore_client_t *client =
+		smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+	int rc = -EBUSY;
+
+	static unsigned long last_sample_time; /* = 0; */
+	static int data_total; /* = 0; */
+	unsigned long time_now = jiffies_to_msecs(jiffies);
+
+	if (!last_sample_time)
+		last_sample_time = time_now;
+
+	if (time_now - last_sample_time > 10000) {
+		sms_debug("\ndata rate %d bytes/secs",
+			  (int)((data_total * 1000) /
+				(time_now - last_sample_time)));
+
+		last_sample_time = time_now;
+		data_total = 0;
+	}
+
+	data_total += cb->size;
+	/* If no client registered for type & id,
+	 * check for control client where type is not registered */
+	if (client)
+		rc = client->onresponse_handler(client->context, cb);
+
+	if (rc < 0) {
+		switch (phdr->msgType) {
+		case MSG_SMS_GET_VERSION_EX_RES:
+		{
+			struct SmsVersionRes_ST *ver =
+				(struct SmsVersionRes_ST *) phdr;
+			sms_debug("MSG_SMS_GET_VERSION_EX_RES "
+				  "id %d prots 0x%x ver %d.%d",
+				  ver->FirmwareId, ver->SupportedProtocols,
+				  ver->RomVersionMajor, ver->RomVersionMinor);
+
+			coredev->mode = ver->FirmwareId == 255 ?
+				DEVICE_MODE_NONE : ver->FirmwareId;
+			coredev->modes_supported = ver->SupportedProtocols;
+
+			complete(&coredev->version_ex_done);
+			break;
+		}
+		case MSG_SMS_INIT_DEVICE_RES:
+			sms_debug("MSG_SMS_INIT_DEVICE_RES");
+			complete(&coredev->init_device_done);
+			break;
+		case MSG_SW_RELOAD_START_RES:
+			sms_debug("MSG_SW_RELOAD_START_RES");
+			complete(&coredev->reload_start_done);
+			break;
+		case MSG_SMS_DATA_DOWNLOAD_RES:
+			complete(&coredev->data_download_done);
+			break;
+		case MSG_SW_RELOAD_EXEC_RES:
+			sms_debug("MSG_SW_RELOAD_EXEC_RES");
+			break;
+		case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
+			sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
+			complete(&coredev->trigger_done);
+			break;
+		case MSG_SMS_SLEEP_RESUME_COMP_IND:
+			complete(&coredev->resume_done);
+			break;
+		default:
+			break;
+		}
+		smscore_putbuffer(coredev, cb);
+	}
+}
+
+/**
+ * return pointer to next free buffer descriptor from core pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return pointer to descriptor on success, NULL on error.
+ */
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&coredev->bufferslock, flags);
+
+	if (!list_empty(&coredev->buffers)) {
+		cb = (struct smscore_buffer_t *) coredev->buffers.next;
+		list_del(&cb->entry);
+	}
+
+	spin_unlock_irqrestore(&coredev->bufferslock, flags);
+
+	return cb;
+}
+
+/**
+ * return buffer descriptor to a pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param cb pointer buffer descriptor
+ *
+ */
+void smscore_putbuffer(struct smscore_device_t *coredev,
+		       struct smscore_buffer_t *cb)
+{
+	list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
+}
+
+static int smscore_validate_client(struct smscore_device_t *coredev,
+				   struct smscore_client_t *client,
+				   int data_type, int id)
+{
+	struct smscore_idlist_t *listentry;
+	struct smscore_client_t *registered_client;
+
+	if (!client) {
+		sms_err("bad parameter.");
+		return -EFAULT;
+	}
+	registered_client = smscore_find_client(coredev, data_type, id);
+	if (registered_client == client)
+		return 0;
+
+	if (registered_client) {
+		sms_err("The msg ID already registered to another client.");
+		return -EEXIST;
+	}
+	listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
+	if (!listentry) {
+		sms_err("Can't allocate memory for client id.");
+		return -ENOMEM;
+	}
+	listentry->id = id;
+	listentry->data_type = data_type;
+	list_add_locked(&listentry->entry, &client->idlist,
+			&coredev->clientslock);
+	return 0;
+}
+
+/**
+ * creates smsclient object, check that id is taken by another client
+ *
+ * @param coredev pointer to a coredev object from clients hotplug
+ * @param initial_id all messages with this id would be sent to this client
+ * @param data_type all messages of this type would be sent to this client
+ * @param onresponse_handler client handler that is called to
+ *                           process incoming messages
+ * @param onremove_handler client handler that is called when device is removed
+ * @param context client-specific context
+ * @param client pointer to a value that receives created smsclient object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_client(struct smscore_device_t *coredev,
+			    struct smsclient_params_t *params,
+			    struct smscore_client_t **client)
+{
+	struct smscore_client_t *newclient;
+	/* check that no other channel with same parameters exists */
+	if (smscore_find_client(coredev, params->data_type,
+				params->initial_id)) {
+		sms_err("Client already exist.");
+		return -EEXIST;
+	}
+
+	newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
+	if (!newclient) {
+		sms_err("Failed to allocate memory for client.");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&newclient->idlist);
+	newclient->coredev = coredev;
+	newclient->onresponse_handler = params->onresponse_handler;
+	newclient->onremove_handler = params->onremove_handler;
+	newclient->context = params->context;
+	list_add_locked(&newclient->entry, &coredev->clients,
+			&coredev->clientslock);
+	smscore_validate_client(coredev, newclient, params->data_type,
+				params->initial_id);
+	*client = newclient;
+	sms_debug("%p %d %d", params->context, params->data_type,
+		  params->initial_id);
+
+	return 0;
+}
+
+/**
+ * frees smsclient object and all subclients associated with it
+ *
+ * @param client pointer to smsclient object returned by
+ *               smscore_register_client
+ *
+ */
+void smscore_unregister_client(struct smscore_client_t *client)
+{
+	struct smscore_device_t *coredev = client->coredev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&coredev->clientslock, flags);
+
+
+	while (!list_empty(&client->idlist)) {
+		struct smscore_idlist_t *identry =
+			(struct smscore_idlist_t *) client->idlist.next;
+		list_del(&identry->entry);
+		kfree(identry);
+	}
+
+	sms_info("%p", client->context);
+
+	list_del(&client->entry);
+	kfree(client);
+
+	spin_unlock_irqrestore(&coredev->clientslock, flags);
+}
+
+/**
+ * verifies that source id is not taken by another client,
+ * calls device handler to send requests to the device
+ *
+ * @param client pointer to smsclient object returned by
+ *               smscore_register_client
+ * @param buffer pointer to a request buffer
+ * @param size size (in bytes) of request buffer
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smsclient_sendrequest(struct smscore_client_t *client,
+			  void *buffer, size_t size)
+{
+	struct smscore_device_t *coredev;
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
+	int rc;
+
+	if (client == NULL) {
+		sms_err("Got NULL client");
+		return -EINVAL;
+	}
+
+	coredev = client->coredev;
+
+	/* check that no other channel with same id exists */
+	if (coredev == NULL) {
+		sms_err("Got NULL coredev");
+		return -EINVAL;
+	}
+
+	rc = smscore_validate_client(client->coredev, client, 0,
+				     phdr->msgSrcId);
+	if (rc < 0)
+		return rc;
+
+	return coredev->sendrequest_handler(coredev->context, buffer, size);
+}
+
+
+int smscore_module_init(void)
+{
+	int rc = 0;
+
+	INIT_LIST_HEAD(&g_smscore_notifyees);
+	INIT_LIST_HEAD(&g_smscore_devices);
+	kmutex_init(&g_smscore_deviceslock);
+
+	INIT_LIST_HEAD(&g_smscore_registry);
+	kmutex_init(&g_smscore_registrylock);
+
+	/* USB Register */
+	rc = smsusb_register();
+
+	/* DVB Register */
+	rc = smsdvb_register();
+
+	sms_debug("rc %d", rc);
+
+	return rc;
+}
+
+void smscore_module_exit(void)
+{
+
+	kmutex_lock(&g_smscore_deviceslock);
+	while (!list_empty(&g_smscore_notifyees)) {
+		struct smscore_device_notifyee_t *notifyee =
+			(struct smscore_device_notifyee_t *)
+				g_smscore_notifyees.next;
+
+		list_del(&notifyee->entry);
+		kfree(notifyee);
+	}
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	kmutex_lock(&g_smscore_registrylock);
+	while (!list_empty(&g_smscore_registry)) {
+		struct smscore_registry_entry_t *entry =
+			(struct smscore_registry_entry_t *)
+				g_smscore_registry.next;
+
+		list_del(&entry->entry);
+		kfree(entry);
+	}
+	kmutex_unlock(&g_smscore_registrylock);
+
+	/* DVB UnRegister */
+	smsdvb_unregister();
+
+	/* Unregister USB */
+	smsusb_unregister();
+
+	sms_debug("");
+}
+
+module_init(smscore_module_init);
+module_exit(smscore_module_exit);
+
+MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
+MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
+MODULE_LICENSE("GPL");

+ 434 - 0
drivers/media/dvb/siano/smscoreapi.h

@@ -0,0 +1,434 @@
+/*
+ *  Driver for the Siano SMS1xxx USB dongle
+ *
+ *  author: Anatoly Greenblat
+ *
+ *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __smscoreapi_h__
+#define __smscoreapi_h__
+
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/types.h>
+#include <asm/page.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include <linux/mutex.h>
+
+#define kmutex_init(_p_) mutex_init(_p_)
+#define kmutex_lock(_p_) mutex_lock(_p_)
+#define kmutex_trylock(_p_) mutex_trylock(_p_)
+#define kmutex_unlock(_p_) mutex_unlock(_p_)
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define SMS_ALLOC_ALIGNMENT					128
+#define SMS_DMA_ALIGNMENT					16
+#define SMS_ALIGN_ADDRESS(addr) \
+	((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
+
+#define SMS_DEVICE_FAMILY2					1
+#define SMS_ROM_NO_RESPONSE					2
+#define SMS_DEVICE_NOT_READY				0x8000000
+
+enum sms_device_type_st {
+	SMS_STELLAR = 0,
+	SMS_NOVA_A0,
+	SMS_NOVA_B0,
+	SMS_VEGA,
+	SMS_NUM_OF_DEVICE_TYPES
+};
+
+struct smscore_device_t;
+struct smscore_client_t;
+struct smscore_buffer_t;
+
+typedef int (*hotplug_t)(struct smscore_device_t *coredev,
+			 struct device *device, int arrival);
+
+typedef int (*setmode_t)(void *context, int mode);
+typedef void (*detectmode_t)(void *context, int *mode);
+typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
+typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
+typedef int (*preload_t)(void *context);
+typedef int (*postload_t)(void *context);
+
+typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb);
+typedef void (*onremove_t)(void *context);
+
+struct smscore_buffer_t {
+	/* public members, once passed to clients can be changed freely */
+	struct list_head entry;
+	int				size;
+	int				offset;
+
+	/* private members, read-only for clients */
+	void			*p;
+	dma_addr_t		phys;
+	unsigned long	offset_in_common;
+};
+
+struct smsdevice_params_t {
+	struct device	*device;
+
+	int				buffer_size;
+	int				num_buffers;
+
+	char			devpath[32];
+	unsigned long	flags;
+
+	setmode_t		setmode_handler;
+	detectmode_t	detectmode_handler;
+	sendrequest_t	sendrequest_handler;
+	preload_t		preload_handler;
+	postload_t		postload_handler;
+
+	void			*context;
+	enum sms_device_type_st device_type;
+};
+
+struct smsclient_params_t {
+	int				initial_id;
+	int				data_type;
+	onresponse_t	onresponse_handler;
+	onremove_t		onremove_handler;
+
+	void			*context;
+};
+
+/* GPIO definitions for antenna frequency domain control (SMS8021) */
+#define SMS_ANTENNA_GPIO_0					1
+#define SMS_ANTENNA_GPIO_1					0
+
+#define BW_8_MHZ							0
+#define BW_7_MHZ							1
+#define BW_6_MHZ							2
+#define BW_5_MHZ							3
+#define BW_ISDBT_1SEG						4
+#define BW_ISDBT_3SEG						5
+
+#define MSG_HDR_FLAG_SPLIT_MSG				4
+
+#define MAX_GPIO_PIN_NUMBER					31
+
+#define HIF_TASK							11
+#define SMS_HOST_LIB						150
+#define DVBT_BDA_CONTROL_MSG_ID				201
+
+#define SMS_MAX_PAYLOAD_SIZE				240
+#define SMS_TUNE_TIMEOUT					500
+
+#define MSG_SMS_GPIO_CONFIG_REQ				507
+#define MSG_SMS_GPIO_CONFIG_RES				508
+#define MSG_SMS_GPIO_SET_LEVEL_REQ			509
+#define MSG_SMS_GPIO_SET_LEVEL_RES			510
+#define MSG_SMS_GPIO_GET_LEVEL_REQ			511
+#define MSG_SMS_GPIO_GET_LEVEL_RES			512
+#define MSG_SMS_RF_TUNE_REQ					561
+#define MSG_SMS_RF_TUNE_RES					562
+#define MSG_SMS_INIT_DEVICE_REQ				578
+#define MSG_SMS_INIT_DEVICE_RES				579
+#define MSG_SMS_ADD_PID_FILTER_REQ			601
+#define MSG_SMS_ADD_PID_FILTER_RES			602
+#define MSG_SMS_REMOVE_PID_FILTER_REQ		603
+#define MSG_SMS_REMOVE_PID_FILTER_RES		604
+#define MSG_SMS_DAB_CHANNEL					607
+#define MSG_SMS_GET_PID_FILTER_LIST_REQ		608
+#define MSG_SMS_GET_PID_FILTER_LIST_RES		609
+#define MSG_SMS_GET_STATISTICS_REQ			615
+#define MSG_SMS_GET_STATISTICS_RES			616
+#define MSG_SMS_SET_ANTENNA_CONFIG_REQ		651
+#define MSG_SMS_SET_ANTENNA_CONFIG_RES		652
+#define MSG_SMS_GET_STATISTICS_EX_REQ		653
+#define MSG_SMS_GET_STATISTICS_EX_RES		654
+#define MSG_SMS_SLEEP_RESUME_COMP_IND		655
+#define MSG_SMS_DATA_DOWNLOAD_REQ			660
+#define MSG_SMS_DATA_DOWNLOAD_RES			661
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ		664
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES		665
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ		666
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES		667
+#define MSG_SMS_GET_VERSION_EX_REQ			668
+#define MSG_SMS_GET_VERSION_EX_RES			669
+#define MSG_SMS_SET_CLOCK_OUTPUT_REQ		670
+#define MSG_SMS_I2C_SET_FREQ_REQ			685
+#define MSG_SMS_GENERIC_I2C_REQ				687
+#define MSG_SMS_GENERIC_I2C_RES				688
+#define MSG_SMS_DVBT_BDA_DATA				693
+#define MSG_SW_RELOAD_REQ					697
+#define MSG_SMS_DATA_MSG					699
+#define MSG_SW_RELOAD_START_REQ				702
+#define MSG_SW_RELOAD_START_RES				703
+#define MSG_SW_RELOAD_EXEC_REQ				704
+#define MSG_SW_RELOAD_EXEC_RES				705
+#define MSG_SMS_SPI_INT_LINE_SET_REQ		710
+#define MSG_SMS_ISDBT_TUNE_REQ				776
+#define MSG_SMS_ISDBT_TUNE_RES				777
+
+#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
+	(ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
+	(ptr)->msgLength = len; (ptr)->msgFlags = 0; \
+} while (0)
+#define SMS_INIT_MSG(ptr, type, len) \
+	SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
+
+enum SMS_DEVICE_MODE {
+	DEVICE_MODE_NONE = -1,
+	DEVICE_MODE_DVBT = 0,
+	DEVICE_MODE_DVBH,
+	DEVICE_MODE_DAB_TDMB,
+	DEVICE_MODE_DAB_TDMB_DABIP,
+	DEVICE_MODE_DVBT_BDA,
+	DEVICE_MODE_ISDBT,
+	DEVICE_MODE_ISDBT_BDA,
+	DEVICE_MODE_CMMB,
+	DEVICE_MODE_RAW_TUNER,
+	DEVICE_MODE_MAX,
+};
+
+struct SmsMsgHdr_ST {
+	u16	msgType;
+	u8	msgSrcId;
+	u8	msgDstId;
+	u16	msgLength; /* Length of entire message, including header */
+	u16	msgFlags;
+};
+
+struct SmsMsgData_ST {
+	struct SmsMsgHdr_ST	xMsgHeader;
+	u32			msgData[1];
+};
+
+struct SmsDataDownload_ST {
+	struct SmsMsgHdr_ST	xMsgHeader;
+	u32			MemAddr;
+	u8			Payload[SMS_MAX_PAYLOAD_SIZE];
+};
+
+struct SmsVersionRes_ST {
+	struct SmsMsgHdr_ST	xMsgHeader;
+
+	u16		ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */
+	u8		Step; /* 0 - Step A */
+	u8		MetalFix; /* 0 - Metal 0 */
+
+	u8		FirmwareId; /* 0xFF � ROM, otherwise the
+				     * value indicated by
+				     * SMSHOSTLIB_DEVICE_MODES_E */
+	u8		SupportedProtocols; /* Bitwise OR combination of
+					     * supported protocols */
+
+	u8		VersionMajor;
+	u8		VersionMinor;
+	u8		VersionPatch;
+	u8		VersionFieldPatch;
+
+	u8		RomVersionMajor;
+	u8		RomVersionMinor;
+	u8		RomVersionPatch;
+	u8		RomVersionFieldPatch;
+
+	u8		TextLabel[34];
+};
+
+struct SmsFirmware_ST {
+	u32			CheckSum;
+	u32			Length;
+	u32			StartAddress;
+	u8			Payload[1];
+};
+
+struct SMSHOSTLIB_STATISTICS_ST {
+	u32 Reserved; /* Reserved */
+
+	/* Common parameters */
+	u32 IsRfLocked; /* 0 - not locked, 1 - locked */
+	u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
+	u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+
+	/* Reception quality */
+	s32  SNR; /* dB */
+	u32 BER; /* Post Viterbi BER [1E-5] */
+	u32 FIB_CRC;	/* CRC errors percentage, valid only for DAB */
+	u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A,
+		     * valid only for DVB-T/H */
+	u32 MFER; /* DVB-H frame error rate in percentage,
+		   * 0xFFFFFFFF indicate N/A, valid only for DVB-H */
+	s32  RSSI; /* dBm */
+	s32  InBandPwr; /* In band power in dBM */
+	s32  CarrierOffset; /* Carrier Offset in bin/1024 */
+
+	/* Transmission parameters, valid only for DVB-T/H */
+	u32 Frequency; /* Frequency in Hz */
+	u32 Bandwidth; /* Bandwidth in MHz */
+	u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
+			       * for DVB-T/H FFT mode carriers in Kilos */
+	u32 ModemState; /* from SMS_DvbModemState_ET */
+	u32 GuardInterval; /* Guard Interval, 1 divided by value */
+	u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */
+	u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */
+	u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */
+	u32 Constellation; /* Constellation from SMS_Constellation_ET */
+
+	/* Burst parameters, valid only for DVB-H */
+	u32 BurstSize; /* Current burst size in bytes */
+	u32 BurstDuration; /* Current burst duration in mSec */
+	u32 BurstCycleTime; /* Current burst cycle time in mSec */
+	u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec,
+				       * as calculated by demodulator */
+	u32 NumOfRows; /* Number of rows in MPE table */
+	u32 NumOfPaddCols; /* Number of padding columns in MPE table */
+	u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */
+	/* Burst parameters */
+	u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
+	u32 TotalTSPackets; /* Total number of transport-stream packets */
+	u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
+				* errors after MPE RS decoding */
+	u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors
+				  * after MPE RS decoding */
+	u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
+				    * by MPE RS decoding */
+
+	/* Common params */
+	u32 BERErrorCount; /* Number of errornous SYNC bits. */
+	u32 BERBitCount; /* Total number of SYNC bits. */
+
+	/* Interface information */
+	u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+
+	/* DAB/T-DMB */
+	u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
+
+	/* DVB-H TPS parameters */
+	u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+		     * if set to 0xFFFFFFFF cell_id not yet recovered */
+
+};
+
+struct SmsMsgStatisticsInfo_ST {
+	u32 RequestResult;
+
+	struct SMSHOSTLIB_STATISTICS_ST Stat;
+
+	/* Split the calc of the SNR in DAB */
+	u32 Signal; /* dB */
+	u32 Noise; /* dB */
+
+};
+
+
+struct smsdvb_client_t {
+	struct list_head entry;
+
+	struct smscore_device_t	*coredev;
+	struct smscore_client_t	*smsclient;
+
+	struct dvb_adapter	adapter;
+	struct dvb_demux	demux;
+	struct dmxdev		dmxdev;
+	struct dvb_frontend	frontend;
+
+	fe_status_t		fe_status;
+	int			fe_ber, fe_snr, fe_signal_strength;
+
+	struct completion	tune_done, stat_done;
+
+	/* todo: save freq/band instead whole struct */
+	struct dvb_frontend_parameters fe_params;
+
+};
+
+extern void smscore_registry_setmode(char *devpath, int mode);
+extern int smscore_registry_getmode(char *devpath);
+
+extern int smscore_register_hotplug(hotplug_t hotplug);
+extern void smscore_unregister_hotplug(hotplug_t hotplug);
+
+extern int smscore_register_device(struct smsdevice_params_t *params,
+				   struct smscore_device_t **coredev);
+extern void smscore_unregister_device(struct smscore_device_t *coredev);
+
+extern int smscore_start_device(struct smscore_device_t *coredev);
+extern int smscore_load_firmware(struct smscore_device_t *coredev,
+				 char *filename,
+				 loadfirmware_t loadfirmware_handler);
+
+extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
+extern int smscore_get_device_mode(struct smscore_device_t *coredev);
+
+extern int smscore_register_client(struct smscore_device_t *coredev,
+				    struct smsclient_params_t *params,
+				    struct smscore_client_t **client);
+extern void smscore_unregister_client(struct smscore_client_t *client);
+
+extern int smsclient_sendrequest(struct smscore_client_t *client,
+				 void *buffer, size_t size);
+extern void smscore_onresponse(struct smscore_device_t *coredev,
+			       struct smscore_buffer_t *cb);
+
+
+extern
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
+extern void smscore_putbuffer(struct smscore_device_t *coredev,
+			      struct smscore_buffer_t *cb);
+
+void smscore_set_board_id(struct smscore_device_t *core, int id);
+int smscore_get_board_id(struct smscore_device_t *core);
+
+/* smsdvb.c */
+int smsdvb_register(void);
+void smsdvb_unregister(void);
+
+/* smsusb.c */
+int smsusb_register(void);
+void smsusb_unregister(void);
+
+/* ------------------------------------------------------------------------ */
+
+extern int sms_debug;
+
+#define DBG_INFO 1
+#define DBG_ADV  2
+
+#define sms_printk(kern, fmt, arg...) \
+	printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define dprintk(kern, lvl, fmt, arg...) do {\
+	if (sms_debug & lvl) \
+		sms_printk(kern, fmt, ##arg); } while (0)
+
+#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
+#define sms_err(fmt, arg...) \
+	sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
+#define sms_warn(fmt, arg...)  sms_printk(KERN_WARNING, fmt, ##arg)
+#define sms_info(fmt, arg...) \
+	dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
+#define sms_debug(fmt, arg...) \
+	dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
+
+
+#endif /* __smscoreapi_h__ */

+ 449 - 0
drivers/media/dvb/siano/smsdvb.c

@@ -0,0 +1,449 @@
+/*
+ *  Driver for the Siano SMS1xxx USB dongle
+ *
+ *  author: Anatoly Greenblat
+ *
+ *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct list_head g_smsdvb_clients;
+struct mutex g_smsdvb_clientslock;
+
+static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
+{
+	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
+	struct SmsMsgHdr_ST *phdr =
+		(struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
+
+	switch (phdr->msgType) {
+	case MSG_SMS_DVBT_BDA_DATA:
+		dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
+				 cb->size - sizeof(struct SmsMsgHdr_ST));
+		break;
+
+	case MSG_SMS_RF_TUNE_RES:
+		complete(&client->tune_done);
+		break;
+
+	case MSG_SMS_GET_STATISTICS_RES:
+	{
+		struct SmsMsgStatisticsInfo_ST *p =
+			(struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
+
+		if (p->Stat.IsDemodLocked) {
+			client->fe_status = FE_HAS_SIGNAL |
+					    FE_HAS_CARRIER |
+					    FE_HAS_VITERBI |
+					    FE_HAS_SYNC |
+					    FE_HAS_LOCK;
+
+			client->fe_snr = p->Stat.SNR;
+			client->fe_ber = p->Stat.BER;
+
+			if (p->Stat.InBandPwr < -95)
+				client->fe_signal_strength = 0;
+			else if (p->Stat.InBandPwr > -29)
+				client->fe_signal_strength = 100;
+			else
+				client->fe_signal_strength =
+					(p->Stat.InBandPwr + 95) * 3 / 2;
+		} else {
+			client->fe_status = 0;
+			client->fe_snr =
+			client->fe_ber =
+			client->fe_signal_strength = 0;
+		}
+
+		complete(&client->stat_done);
+		break;
+	} }
+
+	smscore_putbuffer(client->coredev, cb);
+
+	return 0;
+}
+
+static void smsdvb_unregister_client(struct smsdvb_client_t *client)
+{
+	/* must be called under clientslock */
+
+	list_del(&client->entry);
+
+	smscore_unregister_client(client->smsclient);
+	dvb_unregister_frontend(&client->frontend);
+	dvb_dmxdev_release(&client->dmxdev);
+	dvb_dmx_release(&client->demux);
+	dvb_unregister_adapter(&client->adapter);
+	kfree(client);
+}
+
+static void smsdvb_onremove(void *context)
+{
+	kmutex_lock(&g_smsdvb_clientslock);
+
+	smsdvb_unregister_client((struct smsdvb_client_t *) context);
+
+	kmutex_unlock(&g_smsdvb_clientslock);
+}
+
+static int smsdvb_start_feed(struct dvb_demux_feed *feed)
+{
+	struct smsdvb_client_t *client =
+		container_of(feed->demux, struct smsdvb_client_t, demux);
+	struct SmsMsgData_ST PidMsg;
+
+	sms_debug("add pid %d(%x)",
+		  feed->pid, feed->pid);
+
+	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
+	PidMsg.xMsgHeader.msgFlags = 0;
+	PidMsg.xMsgHeader.msgType  = MSG_SMS_ADD_PID_FILTER_REQ;
+	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
+	PidMsg.msgData[0] = feed->pid;
+
+	return smsclient_sendrequest(client->smsclient,
+				     &PidMsg, sizeof(PidMsg));
+}
+
+static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct smsdvb_client_t *client =
+		container_of(feed->demux, struct smsdvb_client_t, demux);
+	struct SmsMsgData_ST PidMsg;
+
+	sms_debug("remove pid %d(%x)",
+		  feed->pid, feed->pid);
+
+	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
+	PidMsg.xMsgHeader.msgFlags = 0;
+	PidMsg.xMsgHeader.msgType  = MSG_SMS_REMOVE_PID_FILTER_REQ;
+	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
+	PidMsg.msgData[0] = feed->pid;
+
+	return smsclient_sendrequest(client->smsclient,
+				     &PidMsg, sizeof(PidMsg));
+}
+
+static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
+					void *buffer, size_t size,
+					struct completion *completion)
+{
+	int rc = smsclient_sendrequest(client->smsclient, buffer, size);
+	if (rc < 0)
+		return rc;
+
+	return wait_for_completion_timeout(completion,
+					   msecs_to_jiffies(2000)) ?
+						0 : -ETIME;
+}
+
+static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
+{
+	struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
+			     DVBT_BDA_CONTROL_MSG_ID,
+			     HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
+	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+					   &client->stat_done);
+}
+
+static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	int rc = smsdvb_send_statistics_request(client);
+
+	if (!rc)
+		*stat = client->fe_status;
+
+	return rc;
+}
+
+static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	int rc = smsdvb_send_statistics_request(client);
+
+	if (!rc)
+		*ber = client->fe_ber;
+
+	return rc;
+}
+
+static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	int rc = smsdvb_send_statistics_request(client);
+
+	if (!rc)
+		*strength = client->fe_signal_strength;
+
+	return rc;
+}
+
+static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	int rc = smsdvb_send_statistics_request(client);
+
+	if (!rc)
+		*snr = client->fe_snr;
+
+	return rc;
+}
+
+static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
+				    struct dvb_frontend_tune_settings *tune)
+{
+	sms_debug("");
+
+	tune->min_delay_ms = 400;
+	tune->step_size = 250000;
+	tune->max_drift = 0;
+	return 0;
+}
+
+static int smsdvb_set_frontend(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *fep)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+
+	struct {
+		struct SmsMsgHdr_ST	Msg;
+		u32		Data[3];
+	} Msg;
+
+	Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
+	Msg.Msg.msgDstId  = HIF_TASK;
+	Msg.Msg.msgFlags  = 0;
+	Msg.Msg.msgType   = MSG_SMS_RF_TUNE_REQ;
+	Msg.Msg.msgLength = sizeof(Msg);
+	Msg.Data[0] = fep->frequency;
+	Msg.Data[2] = 12000000;
+
+	sms_debug("freq %d band %d",
+		  fep->frequency, fep->u.ofdm.bandwidth);
+
+	switch (fep->u.ofdm.bandwidth) {
+	case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
+	case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
+	case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
+	case BANDWIDTH_AUTO: return -EOPNOTSUPP;
+	default: return -EINVAL;
+	}
+
+	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+					   &client->tune_done);
+}
+
+static int smsdvb_get_frontend(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *fep)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+
+	sms_debug("");
+
+	/* todo: */
+	memcpy(fep, &client->fe_params,
+	       sizeof(struct dvb_frontend_parameters));
+	return 0;
+}
+
+static void smsdvb_release(struct dvb_frontend *fe)
+{
+	/* do nothing */
+}
+
+static struct dvb_frontend_ops smsdvb_fe_ops = {
+	.info = {
+		.name			= "Siano Mobile Digital SMS1xxx",
+		.type			= FE_OFDM,
+		.frequency_min		= 44250000,
+		.frequency_max		= 867250000,
+		.frequency_stepsize	= 250000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = smsdvb_release,
+
+	.set_frontend = smsdvb_set_frontend,
+	.get_frontend = smsdvb_get_frontend,
+	.get_tune_settings = smsdvb_get_tune_settings,
+
+	.read_status = smsdvb_read_status,
+	.read_ber = smsdvb_read_ber,
+	.read_signal_strength = smsdvb_read_signal_strength,
+	.read_snr = smsdvb_read_snr,
+};
+
+static int smsdvb_hotplug(struct smscore_device_t *coredev,
+			  struct device *device, int arrival)
+{
+	struct smsclient_params_t params;
+	struct smsdvb_client_t *client;
+	int rc;
+
+	/* device removal handled by onremove callback */
+	if (!arrival)
+		return 0;
+
+	if (smscore_get_device_mode(coredev) != 4) {
+		sms_err("SMS Device mode is not set for "
+			"DVB operation.");
+		return 0;
+	}
+
+	client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
+	if (!client) {
+		sms_err("kmalloc() failed");
+		return -ENOMEM;
+	}
+
+	/* register dvb adapter */
+	rc = dvb_register_adapter(&client->adapter,
+				  sms_get_board(
+					smscore_get_board_id(coredev))->name,
+				  THIS_MODULE, device, adapter_nr);
+	if (rc < 0) {
+		sms_err("dvb_register_adapter() failed %d", rc);
+		goto adapter_error;
+	}
+
+	/* init dvb demux */
+	client->demux.dmx.capabilities = DMX_TS_FILTERING;
+	client->demux.filternum = 32; /* todo: nova ??? */
+	client->demux.feednum = 32;
+	client->demux.start_feed = smsdvb_start_feed;
+	client->demux.stop_feed = smsdvb_stop_feed;
+
+	rc = dvb_dmx_init(&client->demux);
+	if (rc < 0) {
+		sms_err("dvb_dmx_init failed %d", rc);
+		goto dvbdmx_error;
+	}
+
+	/* init dmxdev */
+	client->dmxdev.filternum = 32;
+	client->dmxdev.demux = &client->demux.dmx;
+	client->dmxdev.capabilities = 0;
+
+	rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
+	if (rc < 0) {
+		sms_err("dvb_dmxdev_init failed %d", rc);
+		goto dmxdev_error;
+	}
+
+	/* init and register frontend */
+	memcpy(&client->frontend.ops, &smsdvb_fe_ops,
+	       sizeof(struct dvb_frontend_ops));
+
+	rc = dvb_register_frontend(&client->adapter, &client->frontend);
+	if (rc < 0) {
+		sms_err("frontend registration failed %d", rc);
+		goto frontend_error;
+	}
+
+	params.initial_id = 1;
+	params.data_type = MSG_SMS_DVBT_BDA_DATA;
+	params.onresponse_handler = smsdvb_onresponse;
+	params.onremove_handler = smsdvb_onremove;
+	params.context = client;
+
+	rc = smscore_register_client(coredev, &params, &client->smsclient);
+	if (rc < 0) {
+		sms_err("smscore_register_client() failed %d", rc);
+		goto client_error;
+	}
+
+	client->coredev = coredev;
+
+	init_completion(&client->tune_done);
+	init_completion(&client->stat_done);
+
+	kmutex_lock(&g_smsdvb_clientslock);
+
+	list_add(&client->entry, &g_smsdvb_clients);
+
+	kmutex_unlock(&g_smsdvb_clientslock);
+
+	sms_info("success");
+
+	return 0;
+
+client_error:
+	dvb_unregister_frontend(&client->frontend);
+
+frontend_error:
+	dvb_dmxdev_release(&client->dmxdev);
+
+dmxdev_error:
+	dvb_dmx_release(&client->demux);
+
+dvbdmx_error:
+	dvb_unregister_adapter(&client->adapter);
+
+adapter_error:
+	kfree(client);
+	return rc;
+}
+
+int smsdvb_register(void)
+{
+	int rc;
+
+	INIT_LIST_HEAD(&g_smsdvb_clients);
+	kmutex_init(&g_smsdvb_clientslock);
+
+	rc = smscore_register_hotplug(smsdvb_hotplug);
+
+	sms_debug("");
+
+	return rc;
+}
+
+void smsdvb_unregister(void)
+{
+	smscore_unregister_hotplug(smsdvb_hotplug);
+
+	kmutex_lock(&g_smsdvb_clientslock);
+
+	while (!list_empty(&g_smsdvb_clients))
+	       smsdvb_unregister_client(
+			(struct smsdvb_client_t *) g_smsdvb_clients.next);
+
+	kmutex_unlock(&g_smsdvb_clientslock);
+}

+ 459 - 0
drivers/media/dvb/siano/smsusb.c

@@ -0,0 +1,459 @@
+/*
+ *  Driver for the Siano SMS1xxx USB dongle
+ *
+ *  author: Anatoly Greenblat
+ *
+ *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+#define USB1_BUFFER_SIZE		0x1000
+#define USB2_BUFFER_SIZE		0x4000
+
+#define MAX_BUFFERS		50
+#define MAX_URBS		10
+
+struct smsusb_device_t;
+
+struct smsusb_urb_t {
+	struct smscore_buffer_t *cb;
+	struct smsusb_device_t	*dev;
+
+	struct urb urb;
+};
+
+struct smsusb_device_t {
+	struct usb_device *udev;
+	struct smscore_device_t *coredev;
+
+	struct smsusb_urb_t 	surbs[MAX_URBS];
+
+	int		response_alignment;
+	int		buffer_size;
+};
+
+static int smsusb_submit_urb(struct smsusb_device_t *dev,
+			     struct smsusb_urb_t *surb);
+
+static void smsusb_onresponse(struct urb *urb)
+{
+	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
+	struct smsusb_device_t *dev = surb->dev;
+
+	if (urb->status < 0) {
+		sms_err("error, urb status %d, %d bytes",
+			urb->status, urb->actual_length);
+		return;
+	}
+
+	if (urb->actual_length > 0) {
+		struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
+
+		if (urb->actual_length >= phdr->msgLength) {
+			surb->cb->size = phdr->msgLength;
+
+			if (dev->response_alignment &&
+			    (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {
+
+				surb->cb->offset =
+					dev->response_alignment +
+					((phdr->msgFlags >> 8) & 3);
+
+				/* sanity check */
+				if (((int) phdr->msgLength +
+				     surb->cb->offset) > urb->actual_length) {
+					sms_err("invalid response "
+						"msglen %d offset %d "
+						"size %d",
+						phdr->msgLength,
+						surb->cb->offset,
+						urb->actual_length);
+					goto exit_and_resubmit;
+				}
+
+				/* move buffer pointer and
+				 * copy header to its new location */
+				memcpy((char *) phdr + surb->cb->offset,
+				       phdr, sizeof(struct SmsMsgHdr_ST));
+			} else
+				surb->cb->offset = 0;
+
+			smscore_onresponse(dev->coredev, surb->cb);
+			surb->cb = NULL;
+		} else {
+			sms_err("invalid response "
+				"msglen %d actual %d",
+				phdr->msgLength, urb->actual_length);
+		}
+	}
+
+exit_and_resubmit:
+	smsusb_submit_urb(dev, surb);
+}
+
+static int smsusb_submit_urb(struct smsusb_device_t *dev,
+			     struct smsusb_urb_t *surb)
+{
+	if (!surb->cb) {
+		surb->cb = smscore_getbuffer(dev->coredev);
+		if (!surb->cb) {
+			sms_err("smscore_getbuffer(...) returned NULL");
+			return -ENOMEM;
+		}
+	}
+
+	usb_fill_bulk_urb(
+		&surb->urb,
+		dev->udev,
+		usb_rcvbulkpipe(dev->udev, 0x81),
+		surb->cb->p,
+		dev->buffer_size,
+		smsusb_onresponse,
+		surb
+	);
+	surb->urb.transfer_dma = surb->cb->phys;
+	surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	return usb_submit_urb(&surb->urb, GFP_ATOMIC);
+}
+
+static void smsusb_stop_streaming(struct smsusb_device_t *dev)
+{
+	int i;
+
+	for (i = 0; i < MAX_URBS; i++) {
+		usb_kill_urb(&dev->surbs[i].urb);
+
+		if (dev->surbs[i].cb) {
+			smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
+			dev->surbs[i].cb = NULL;
+		}
+	}
+}
+
+static int smsusb_start_streaming(struct smsusb_device_t *dev)
+{
+	int i, rc;
+
+	for (i = 0; i < MAX_URBS; i++) {
+		rc = smsusb_submit_urb(dev, &dev->surbs[i]);
+		if (rc < 0) {
+			sms_err("smsusb_submit_urb(...) failed");
+			smsusb_stop_streaming(dev);
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int smsusb_sendrequest(void *context, void *buffer, size_t size)
+{
+	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
+	int dummy;
+
+	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
+			    buffer, size, &dummy, 1000);
+}
+
+static char *smsusb1_fw_lkup[] = {
+	"dvbt_stellar_usb.inp",
+	"dvbh_stellar_usb.inp",
+	"tdmb_stellar_usb.inp",
+	"none",
+	"dvbt_bda_stellar_usb.inp",
+};
+
+static inline char *sms_get_fw_name(int mode, int board_id)
+{
+	char **fw = sms_get_board(board_id)->fw;
+	return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
+}
+
+static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
+{
+	const struct firmware *fw;
+	u8 *fw_buffer;
+	int rc, dummy;
+	char *fw_filename;
+
+	if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
+		sms_err("invalid firmware id specified %d", id);
+		return -EINVAL;
+	}
+
+	fw_filename = sms_get_fw_name(id, board_id);
+
+	rc = request_firmware(&fw, fw_filename, &udev->dev);
+	if (rc < 0) {
+		sms_warn("failed to open \"%s\" mode %d, "
+			 "trying again with default firmware", fw_filename, id);
+
+		fw_filename = smsusb1_fw_lkup[id];
+		rc = request_firmware(&fw, fw_filename, &udev->dev);
+		if (rc < 0) {
+			sms_warn("failed to open \"%s\" mode %d",
+				 fw_filename, id);
+
+			return rc;
+		}
+	}
+
+	fw_buffer = kmalloc(fw->size, GFP_KERNEL);
+	if (fw_buffer) {
+		memcpy(fw_buffer, fw->data, fw->size);
+
+		rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
+				  fw_buffer, fw->size, &dummy, 1000);
+
+		sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
+
+		kfree(fw_buffer);
+	} else {
+		sms_err("failed to allocate firmware buffer");
+		rc = -ENOMEM;
+	}
+	sms_info("read FW %s, size=%zd", fw_filename, fw->size);
+
+	release_firmware(fw);
+
+	return rc;
+}
+
+static void smsusb1_detectmode(void *context, int *mode)
+{
+	char *product_string =
+		((struct smsusb_device_t *) context)->udev->product;
+
+	*mode = DEVICE_MODE_NONE;
+
+	if (!product_string) {
+		product_string = "none";
+		sms_err("product string not found");
+	} else if (strstr(product_string, "DVBH"))
+		*mode = 1;
+	else if (strstr(product_string, "BDA"))
+		*mode = 4;
+	else if (strstr(product_string, "DVBT"))
+		*mode = 0;
+	else if (strstr(product_string, "TDMB"))
+		*mode = 2;
+
+	sms_info("%d \"%s\"", *mode, product_string);
+}
+
+static int smsusb1_setmode(void *context, int mode)
+{
+	struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
+			     sizeof(struct SmsMsgHdr_ST), 0 };
+
+	if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
+		sms_err("invalid firmware id specified %d", mode);
+		return -EINVAL;
+	}
+
+	return smsusb_sendrequest(context, &Msg, sizeof(Msg));
+}
+
+static void smsusb_term_device(struct usb_interface *intf)
+{
+	struct smsusb_device_t *dev =
+		(struct smsusb_device_t *) usb_get_intfdata(intf);
+
+	if (dev) {
+		smsusb_stop_streaming(dev);
+
+		/* unregister from smscore */
+		if (dev->coredev)
+			smscore_unregister_device(dev->coredev);
+
+		kfree(dev);
+
+		sms_info("device %p destroyed", dev);
+	}
+
+	usb_set_intfdata(intf, NULL);
+}
+
+static int smsusb_init_device(struct usb_interface *intf, int board_id)
+{
+	struct smsdevice_params_t params;
+	struct smsusb_device_t *dev;
+	int i, rc;
+
+	/* create device object */
+	dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
+	if (!dev) {
+		sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
+		return -ENOMEM;
+	}
+
+	memset(&params, 0, sizeof(params));
+	usb_set_intfdata(intf, dev);
+	dev->udev = interface_to_usbdev(intf);
+
+	params.device_type = sms_get_board(board_id)->type;
+
+	switch (params.device_type) {
+	case SMS_STELLAR:
+		dev->buffer_size = USB1_BUFFER_SIZE;
+
+		params.setmode_handler = smsusb1_setmode;
+		params.detectmode_handler = smsusb1_detectmode;
+		break;
+	default:
+		sms_err("Unspecified sms device type!");
+		/* fall-thru */
+	case SMS_NOVA_A0:
+	case SMS_NOVA_B0:
+	case SMS_VEGA:
+		dev->buffer_size = USB2_BUFFER_SIZE;
+		dev->response_alignment =
+			dev->udev->ep_in[1]->desc.wMaxPacketSize -
+			sizeof(struct SmsMsgHdr_ST);
+
+		params.flags |= SMS_DEVICE_FAMILY2;
+		break;
+	}
+
+	params.device = &dev->udev->dev;
+	params.buffer_size = dev->buffer_size;
+	params.num_buffers = MAX_BUFFERS;
+	params.sendrequest_handler = smsusb_sendrequest;
+	params.context = dev;
+	snprintf(params.devpath, sizeof(params.devpath),
+		 "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
+
+	/* register in smscore */
+	rc = smscore_register_device(&params, &dev->coredev);
+	if (rc < 0) {
+		sms_err("smscore_register_device(...) failed, rc %d", rc);
+		smsusb_term_device(intf);
+		return rc;
+	}
+
+	smscore_set_board_id(dev->coredev, board_id);
+
+	/* initialize urbs */
+	for (i = 0; i < MAX_URBS; i++) {
+		dev->surbs[i].dev = dev;
+		usb_init_urb(&dev->surbs[i].urb);
+	}
+
+	sms_info("smsusb_start_streaming(...).");
+	rc = smsusb_start_streaming(dev);
+	if (rc < 0) {
+		sms_err("smsusb_start_streaming(...) failed");
+		smsusb_term_device(intf);
+		return rc;
+	}
+
+	rc = smscore_start_device(dev->coredev);
+	if (rc < 0) {
+		sms_err("smscore_start_device(...) failed");
+		smsusb_term_device(intf);
+		return rc;
+	}
+
+	sms_info("device %p created", dev);
+
+	return rc;
+}
+
+static int smsusb_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	char devpath[32];
+	int i, rc;
+
+	rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
+	rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
+
+	if (intf->num_altsetting > 0) {
+		rc = usb_set_interface(
+			udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
+		if (rc < 0) {
+			sms_err("usb_set_interface failed, rc %d", rc);
+			return rc;
+		}
+	}
+
+	sms_info("smsusb_probe %d",
+	       intf->cur_altsetting->desc.bInterfaceNumber);
+	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
+		sms_info("endpoint %d %02x %02x %d", i,
+		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
+		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
+		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
+
+	if ((udev->actconfig->desc.bNumInterfaces == 2) &&
+	    (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
+		sms_err("rom interface 0 is not used");
+		return -ENODEV;
+	}
+
+	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+		snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
+			 udev->bus->busnum, udev->devpath);
+		sms_info("stellar device was found.");
+		return smsusb1_load_firmware(
+				udev, smscore_registry_getmode(devpath),
+				id->driver_info);
+	}
+
+	rc = smsusb_init_device(intf, id->driver_info);
+	sms_info("rc %d", rc);
+	return rc;
+}
+
+static void smsusb_disconnect(struct usb_interface *intf)
+{
+	smsusb_term_device(intf);
+}
+
+static struct usb_driver smsusb_driver = {
+	.name			= "sms1xxx",
+	.probe			= smsusb_probe,
+	.disconnect		= smsusb_disconnect,
+	.id_table		= smsusb_id_table,
+};
+
+int smsusb_register(void)
+{
+	int rc = usb_register(&smsusb_driver);
+	if (rc)
+		sms_err("usb_register failed. Error number %d", rc);
+
+	sms_debug("");
+
+	return rc;
+}
+
+void smsusb_unregister(void)
+{
+	sms_debug("");
+	/* Regular USB Cleanup */
+	usb_deregister(&smsusb_driver);
+}
+

+ 2 - 0
drivers/media/dvb/ttpci/Kconfig

@@ -106,6 +106,8 @@ config DVB_BUDGET_CI
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
 	select VIDEO_IR
 	select VIDEO_IR
 	help
 	help
 	  Support for simple SAA7146 based DVB cards
 	  Support for simple SAA7146 based DVB cards

+ 6 - 1
drivers/media/dvb/ttpci/Makefile

@@ -3,7 +3,11 @@
 # and the AV7110 DVB device driver
 # and the AV7110 DVB device driver
 #
 #
 
 
-dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o
+dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
+
+ifdef CONFIG_INPUT_EVDEV
+dvb-ttpci-objs += av7110_ir.o
+endif
 
 
 obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
 obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
 obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
 obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
@@ -14,6 +18,7 @@ obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
 obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
 obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
 
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
 
 
 hostprogs-y	:= fdump
 hostprogs-y	:= fdump
 
 

+ 21 - 26
drivers/media/dvb/ttpci/av7110.c

@@ -587,7 +587,7 @@ static void gpioirq(unsigned long data)
 		}
 		}
 		DVB_RINGBUFFER_SKIP(cibuf, 2);
 		DVB_RINGBUFFER_SKIP(cibuf, 2);
 
 
-		dvb_ringbuffer_read(cibuf, av7110->debi_virt, len, 0);
+		dvb_ringbuffer_read(cibuf, av7110->debi_virt, len);
 
 
 		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
 		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
 		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
 		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
@@ -1198,7 +1198,6 @@ static int start_ts_capture(struct av7110 *budget)
 	if (budget->feeding1)
 	if (budget->feeding1)
 		return ++budget->feeding1;
 		return ++budget->feeding1;
 	memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
 	memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
-	budget->tsf = 0xff;
 	budget->ttbp = 0;
 	budget->ttbp = 0;
 	SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
 	SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
 	saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
 	saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
@@ -2403,18 +2402,18 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
 		saa7146_write(dev, MC1, MASK_29);
 		saa7146_write(dev, MC1, MASK_29);
 		/* RPS1 timeout disable */
 		/* RPS1 timeout disable */
 		saa7146_write(dev, RPS_TOV1, 0);
 		saa7146_write(dev, RPS_TOV1, 0);
-		WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
-		WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-		WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-		WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+		WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
+		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+		WRITE_RPS1(GPIO3_MSK);
+		WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
 #if RPS_IRQ
 #if RPS_IRQ
 		/* issue RPS1 interrupt to increment counter */
 		/* issue RPS1 interrupt to increment counter */
-		WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+		WRITE_RPS1(CMD_INTERRUPT);
 #endif
 #endif
-		WRITE_RPS1(cpu_to_le32(CMD_STOP));
+		WRITE_RPS1(CMD_STOP);
 		/* Jump to begin of RPS program as safety measure               (p37) */
 		/* Jump to begin of RPS program as safety measure               (p37) */
-		WRITE_RPS1(cpu_to_le32(CMD_JUMP));
-		WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+		WRITE_RPS1(CMD_JUMP);
+		WRITE_RPS1(dev->d_rps1.dma_handle);
 
 
 #if RPS_IRQ
 #if RPS_IRQ
 		/* set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
 		/* set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
@@ -2472,11 +2471,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
 	   get recognized before the main driver is fully loaded */
 	   get recognized before the main driver is fully loaded */
 	saa7146_write(dev, GPIO_CTRL, 0x500000);
 	saa7146_write(dev, GPIO_CTRL, 0x500000);
 
 
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	av7110->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
 	av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
 	av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-#endif
 	strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
 	strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
 
 
 	saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
 	saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
@@ -2527,28 +2522,28 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
 		count = 0;
 		count = 0;
 
 
 		/* Wait Source Line Counter Threshold                           (p36) */
 		/* Wait Source Line Counter Threshold                           (p36) */
-		WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
+		WRITE_RPS1(CMD_PAUSE | EVT_HS);
 		/* Set GPIO3=1                                                  (p42) */
 		/* Set GPIO3=1                                                  (p42) */
-		WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-		WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-		WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
+		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+		WRITE_RPS1(GPIO3_MSK);
+		WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
 #if RPS_IRQ
 #if RPS_IRQ
 		/* issue RPS1 interrupt */
 		/* issue RPS1 interrupt */
-		WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+		WRITE_RPS1(CMD_INTERRUPT);
 #endif
 #endif
 		/* Wait reset Source Line Counter Threshold                     (p36) */
 		/* Wait reset Source Line Counter Threshold                     (p36) */
-		WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
+		WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
 		/* Set GPIO3=0                                                  (p42) */
 		/* Set GPIO3=0                                                  (p42) */
-		WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-		WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-		WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+		WRITE_RPS1(GPIO3_MSK);
+		WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
 #if RPS_IRQ
 #if RPS_IRQ
 		/* issue RPS1 interrupt */
 		/* issue RPS1 interrupt */
-		WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+		WRITE_RPS1(CMD_INTERRUPT);
 #endif
 #endif
 		/* Jump to begin of RPS program                                 (p37) */
 		/* Jump to begin of RPS program                                 (p37) */
-		WRITE_RPS1(cpu_to_le32(CMD_JUMP));
-		WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+		WRITE_RPS1(CMD_JUMP);
+		WRITE_RPS1(dev->d_rps1.dma_handle);
 
 
 		/* Fix VSYNC level */
 		/* Fix VSYNC level */
 		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
 		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);

+ 0 - 1
drivers/media/dvb/ttpci/av7110.h

@@ -188,7 +188,6 @@ struct av7110 {
 	struct dvb_net		dvb_net1;
 	struct dvb_net		dvb_net1;
 	spinlock_t		feedlock1;
 	spinlock_t		feedlock1;
 	int			feeding1;
 	int			feeding1;
-	u8			tsf;
 	u32			ttbp;
 	u32			ttbp;
 	unsigned char           *grabbing;
 	unsigned char           *grabbing;
 	struct saa7146_pgtable  pt;
 	struct saa7146_pgtable  pt;

+ 1 - 1
drivers/media/dvb/ttpci/av7110_av.c

@@ -269,7 +269,7 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	dvb_ringbuffer_read(buf, dest, (size_t) blen, 0);
+	dvb_ringbuffer_read(buf, dest, (size_t) blen);
 
 
 	dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",
 	dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",
 	       (unsigned long) buf->pread, (unsigned long) buf->pwrite);
 	       (unsigned long) buf->pread, (unsigned long) buf->pwrite);

+ 1 - 1
drivers/media/dvb/ttpci/av7110_ca.c

@@ -208,7 +208,7 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
 		return -EINVAL;
 		return -EINVAL;
 	DVB_RINGBUFFER_SKIP(cibuf, 2);
 	DVB_RINGBUFFER_SKIP(cibuf, 2);
 
 
-	return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
+	return dvb_ringbuffer_read_user(cibuf, buf, len);
 }
 }
 
 
 static int dvb_ca_open(struct inode *inode, struct file *file)
 static int dvb_ca_open(struct inode *inode, struct file *file)

+ 0 - 3
drivers/media/dvb/ttpci/av7110_hw.h

@@ -305,7 +305,6 @@ enum av7110_command_type {
 #define IRQ_STATE	(DPRAM_BASE + 0x0F4)
 #define IRQ_STATE	(DPRAM_BASE + 0x0F4)
 #define IRQ_STATE_EXT	(DPRAM_BASE + 0x0F6)
 #define IRQ_STATE_EXT	(DPRAM_BASE + 0x0F6)
 #define MSGSTATE	(DPRAM_BASE + 0x0F8)
 #define MSGSTATE	(DPRAM_BASE + 0x0F8)
-#define FILT_STATE	(DPRAM_BASE + 0x0FA)
 #define COMMAND		(DPRAM_BASE + 0x0FC)
 #define COMMAND		(DPRAM_BASE + 0x0FC)
 #define COM_BUFF	(DPRAM_BASE + 0x100)
 #define COM_BUFF	(DPRAM_BASE + 0x100)
 #define COM_BUFF_SIZE	0x20
 #define COM_BUFF_SIZE	0x20
@@ -332,8 +331,6 @@ enum av7110_command_type {
 
 
 /* firmware status area */
 /* firmware status area */
 #define STATUS_BASE	(DPRAM_BASE + 0x1FC0)
 #define STATUS_BASE	(DPRAM_BASE + 0x1FC0)
-#define STATUS_SCR	(STATUS_BASE + 0x00)
-#define STATUS_MODES	(STATUS_BASE + 0x04)
 #define STATUS_LOOPS	(STATUS_BASE + 0x08)
 #define STATUS_LOOPS	(STATUS_BASE + 0x08)
 
 
 #define STATUS_MPEG_WIDTH     (STATUS_BASE + 0x0C)
 #define STATUS_MPEG_WIDTH     (STATUS_BASE + 0x0C)

+ 9 - 3
drivers/media/dvb/ttpci/budget-av.c

@@ -667,6 +667,11 @@ static struct tda1002x_config philips_cu1216_config_altaddress = {
 	.invert = 0,
 	.invert = 0,
 };
 };
 
 
+static struct tda10023_config philips_cu1216_tda10023_config = {
+	.demod_address = 0x0c,
+	.invert = 1,
+};
+
 static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
 static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
 {
 {
 	struct budget *budget = (struct budget *) fe->dvb->priv;
 	struct budget *budget = (struct budget *) fe->dvb->priv;
@@ -1019,9 +1024,10 @@ static void frontend_init(struct budget_av *budget_av)
 	case SUBID_DVBC_KNC1_PLUS_MK3:
 	case SUBID_DVBC_KNC1_PLUS_MK3:
 		budget_av->reinitialise_demod = 1;
 		budget_av->reinitialise_demod = 1;
 		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
 		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
-		fe = dvb_attach(tda10023_attach, &philips_cu1216_config,
-				     &budget_av->budget.i2c_adap,
-				     read_pwm(budget_av));
+		fe = dvb_attach(tda10023_attach,
+			&philips_cu1216_tda10023_config,
+			&budget_av->budget.i2c_adap,
+			read_pwm(budget_av));
 		if (fe) {
 		if (fe) {
 			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
 			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
 		}
 		}

+ 24 - 0
drivers/media/dvb/ttpci/budget-ci.c

@@ -46,6 +46,8 @@
 #include "lnbp21.h"
 #include "lnbp21.h"
 #include "bsbe1.h"
 #include "bsbe1.h"
 #include "bsru6.h"
 #include "bsru6.h"
+#include "tda1002x.h"
+#include "tda827x.h"
 
 
 /*
 /*
  * Regarding DEBIADDR_IR:
  * Regarding DEBIADDR_IR:
@@ -225,6 +227,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 		break;
 		break;
 	case 0x1010:
 	case 0x1010:
 	case 0x1017:
 	case 0x1017:
+	case 0x101a:
 		/* for the Technotrend 1500 bundled remote */
 		/* for the Technotrend 1500 bundled remote */
 		ir_input_init(input_dev, &budget_ci->ir.state,
 		ir_input_init(input_dev, &budget_ci->ir.state,
 			      IR_TYPE_RC5, ir_codes_tt_1500);
 			      IR_TYPE_RC5, ir_codes_tt_1500);
@@ -1056,6 +1059,15 @@ static struct stv0297_config dvbc_philips_tdm1316l_config = {
 	.stop_during_read = 1,
 	.stop_during_read = 1,
 };
 };
 
 
+static struct tda10023_config tda10023_config = {
+	.demod_address = 0xc,
+	.invert = 0,
+	.xtal = 16000000,
+	.pll_m = 11,
+	.pll_p = 3,
+	.pll_n = 1,
+	.deltaf = 0xa511,
+};
 
 
 
 
 
 
@@ -1126,7 +1138,17 @@ static void frontend_init(struct budget_ci *budget_ci)
 				budget_ci->budget.dvb_frontend = NULL;
 				budget_ci->budget.dvb_frontend = NULL;
 			}
 			}
 		}
 		}
+		break;
 
 
+	case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
+		budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
+		if (budget_ci->budget.dvb_frontend) {
+			if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
+				printk(KERN_ERR "%s: No tda827x found!\n", __func__);
+				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+				budget_ci->budget.dvb_frontend = NULL;
+			}
+		}
 		break;
 		break;
 	}
 	}
 
 
@@ -1216,6 +1238,7 @@ MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T	 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T	 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
 
 
 static struct pci_device_id pci_tbl[] = {
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
 	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
@@ -1224,6 +1247,7 @@ static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
 	MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
 	MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
 	MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
 	MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
 	MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
+	MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
 	{
 	{
 	 .vendor = 0,
 	 .vendor = 0,
 	 }
 	 }

+ 0 - 4
drivers/media/dvb/ttpci/budget-core.c

@@ -497,11 +497,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
 	if (bi->type != BUDGET_FS_ACTIVY)
 	if (bi->type != BUDGET_FS_ACTIVY)
 		saa7146_write(dev, GPIO_CTRL, 0x500000);	/* GPIO 3 = 1 */
 		saa7146_write(dev, GPIO_CTRL, 0x500000);	/* GPIO 3 = 1 */
 
 
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
 	budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
 	budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-#endif
 
 
 	strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
 	strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
 
 

+ 22 - 22
drivers/media/dvb/ttpci/budget-patch.c

@@ -431,22 +431,22 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
 	// in budget patch GPIO3 is connected to VSYNC_B
 	// in budget patch GPIO3 is connected to VSYNC_B
 	count = 0;
 	count = 0;
 #if 0
 #if 0
-	WRITE_RPS1(cpu_to_le32(CMD_UPLOAD |
-	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ));
+	WRITE_RPS1(CMD_UPLOAD |
+	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 );
 #endif
 #endif
-	WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
-	WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-	WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-	WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+	WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
+	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+	WRITE_RPS1(GPIO3_MSK);
+	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
 #if RPS_IRQ
 #if RPS_IRQ
 	// issue RPS1 interrupt to increment counter
 	// issue RPS1 interrupt to increment counter
-	WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+	WRITE_RPS1(CMD_INTERRUPT);
 	// at least a NOP is neede between two interrupts
 	// at least a NOP is neede between two interrupts
-	WRITE_RPS1(cpu_to_le32(CMD_NOP));
+	WRITE_RPS1(CMD_NOP);
 	// interrupt again
 	// interrupt again
-	WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+	WRITE_RPS1(CMD_INTERRUPT);
 #endif
 #endif
-	WRITE_RPS1(cpu_to_le32(CMD_STOP));
+	WRITE_RPS1(CMD_STOP);
 
 
 #if RPS_IRQ
 #if RPS_IRQ
 	// set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
 	// set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
@@ -558,28 +558,28 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
 
 
 
 
 	// Wait Source Line Counter Threshold                           (p36)
 	// Wait Source Line Counter Threshold                           (p36)
-	WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
+	WRITE_RPS1(CMD_PAUSE | EVT_HS);
 	// Set GPIO3=1                                                  (p42)
 	// Set GPIO3=1                                                  (p42)
-	WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-	WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-	WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
+	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+	WRITE_RPS1(GPIO3_MSK);
+	WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
 #if RPS_IRQ
 #if RPS_IRQ
 	// issue RPS1 interrupt
 	// issue RPS1 interrupt
-	WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+	WRITE_RPS1(CMD_INTERRUPT);
 #endif
 #endif
 	// Wait reset Source Line Counter Threshold                     (p36)
 	// Wait reset Source Line Counter Threshold                     (p36)
-	WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
+	WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
 	// Set GPIO3=0                                                  (p42)
 	// Set GPIO3=0                                                  (p42)
-	WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-	WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-	WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+	WRITE_RPS1(GPIO3_MSK);
+	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
 #if RPS_IRQ
 #if RPS_IRQ
 	// issue RPS1 interrupt
 	// issue RPS1 interrupt
-	WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+	WRITE_RPS1(CMD_INTERRUPT);
 #endif
 #endif
 	// Jump to begin of RPS program                                 (p37)
 	// Jump to begin of RPS program                                 (p37)
-	WRITE_RPS1(cpu_to_le32(CMD_JUMP));
-	WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+	WRITE_RPS1(CMD_JUMP);
+	WRITE_RPS1(dev->d_rps1.dma_handle);
 
 
 	// Fix VSYNC level
 	// Fix VSYNC level
 	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
 	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);

+ 3 - 19
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c

@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
+#include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
@@ -990,22 +991,9 @@ static int stc_open(struct inode *inode, struct file *file)
 }
 }
 
 
 static ssize_t stc_read(struct file *file, char *buf, size_t count,
 static ssize_t stc_read(struct file *file, char *buf, size_t count,
-		 loff_t * offset)
+		 loff_t *offset)
 {
 {
-	int tc = count;
-
-	if ((tc + *offset) > 8192)
-		tc = 8192 - *offset;
-
-	if (tc < 0)
-		return 0;
-
-	if (copy_to_user(buf, stc_firmware + *offset, tc))
-		return -EFAULT;
-
-	*offset += tc;
-
-	return tc;
+	return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192);
 }
 }
 
 
 static int stc_release(struct inode *inode, struct file *file)
 static int stc_release(struct inode *inode, struct file *file)
@@ -1693,11 +1681,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 
 
 	i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
 	i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
 
 
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	ttusb->i2c_adap.class		  = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
 	ttusb->i2c_adap.class		  = I2C_CLASS_TV_DIGITAL;
 	ttusb->i2c_adap.class		  = I2C_CLASS_TV_DIGITAL;
-#endif
 	ttusb->i2c_adap.algo              = &ttusb_dec_algo;
 	ttusb->i2c_adap.algo              = &ttusb_dec_algo;
 	ttusb->i2c_adap.algo_data         = NULL;
 	ttusb->i2c_adap.algo_data         = NULL;
 	ttusb->i2c_adap.dev.parent	  = &udev->dev;
 	ttusb->i2c_adap.dev.parent	  = &udev->dev;

+ 345 - 138
drivers/media/radio/radio-si470x.c

@@ -23,6 +23,19 @@
  */
  */
 
 
 
 
+/*
+ * User Notes:
+ * - USB Audio is provided by the alsa snd_usb_audio module.
+ *   For listing you have to redirect the sound, for example using:
+ *   arecord -D hw:1,0 -r96000 -c2 -f S16_LE | artsdsp aplay -B -
+ * - regarding module parameters in /sys/module/radio_si470x/parameters:
+ *   the contents of read-only files (0444) are not updated, even if
+ *   space, band and de are changed using private video controls
+ * - increase tune_timeout, if you often get -EIO errors
+ * - hw_freq_seek returns -EAGAIN, when timed out or band limit is reached
+ */
+
+
 /*
 /*
  * History:
  * History:
  * 2008-01-12	Tobias Lorenz <tobias.lorenz@gmx.net>
  * 2008-01-12	Tobias Lorenz <tobias.lorenz@gmx.net>
@@ -85,10 +98,14 @@
  *		Oliver Neukum <oliver@neukum.org>
  *		Oliver Neukum <oliver@neukum.org>
  *		Version 1.0.7
  *		Version 1.0.7
  *		- usb autosuspend support
  *		- usb autosuspend support
- *             - unplugging fixed
+ *		- unplugging fixed
+ * 2008-05-07	Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.8
+ *		- hardware frequency seek support
+ *		- afc indication
+ *		- more safety checks, let si470x_get_freq return errno
  *
  *
  * ToDo:
  * ToDo:
- * - add seeking support
  * - add firmware download/update support
  * - add firmware download/update support
  * - RDS support: interrupt mode, instead of polling
  * - RDS support: interrupt mode, instead of polling
  * - add LED status output (check if that's not already done in firmware)
  * - add LED status output (check if that's not already done in firmware)
@@ -98,10 +115,10 @@
 /* driver definitions */
 /* driver definitions */
 #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
 #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
 #define DRIVER_NAME "radio-si470x"
 #define DRIVER_NAME "radio-si470x"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 7)
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 8)
 #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
 #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
 #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
 #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.7"
+#define DRIVER_VERSION "1.0.8"
 
 
 
 
 /* kernel includes */
 /* kernel includes */
@@ -175,6 +192,11 @@ static unsigned int tune_timeout = 3000;
 module_param(tune_timeout, uint, 0);
 module_param(tune_timeout, uint, 0);
 MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
 MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
 
 
+/* Seek timeout */
+static unsigned int seek_timeout = 5000;
+module_param(seek_timeout, uint, 0);
+MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
+
 /* RDS buffer blocks */
 /* RDS buffer blocks */
 static unsigned int rds_buf = 100;
 static unsigned int rds_buf = 100;
 module_param(rds_buf, uint, 0);
 module_param(rds_buf, uint, 0);
@@ -425,7 +447,8 @@ struct si470x_device {
 
 
 	/* driver management */
 	/* driver management */
 	unsigned int users;
 	unsigned int users;
-       unsigned char disconnected;
+	unsigned char disconnected;
+	struct mutex disconnect_lock;
 
 
 	/* Silabs internal registers (0..15) */
 	/* Silabs internal registers (0..15) */
 	unsigned short registers[RADIO_REGISTER_NUM];
 	unsigned short registers[RADIO_REGISTER_NUM];
@@ -441,12 +464,6 @@ struct si470x_device {
 };
 };
 
 
 
 
-/*
- * Lock to prevent kfree of data before all users have releases the device.
- */
-static DEFINE_MUTEX(open_close_lock);
-
-
 /*
 /*
  * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
  * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
  * 62.5 kHz otherwise.
  * 62.5 kHz otherwise.
@@ -476,11 +493,11 @@ static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
 		report[0], 2,
 		report[0], 2,
 		buf, size, usb_timeout);
 		buf, size, usb_timeout);
+
 	if (retval < 0)
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 		printk(KERN_WARNING DRIVER_NAME
 			": si470x_get_report: usb_control_msg returned %d\n",
 			": si470x_get_report: usb_control_msg returned %d\n",
 			retval);
 			retval);
-
 	return retval;
 	return retval;
 }
 }
 
 
@@ -499,11 +516,11 @@ static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
 		report[0], 2,
 		report[0], 2,
 		buf, size, usb_timeout);
 		buf, size, usb_timeout);
+
 	if (retval < 0)
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 		printk(KERN_WARNING DRIVER_NAME
 			": si470x_set_report: usb_control_msg returned %d\n",
 			": si470x_set_report: usb_control_msg returned %d\n",
 			retval);
 			retval);
-
 	return retval;
 	return retval;
 }
 }
 
 
@@ -521,8 +538,7 @@ static int si470x_get_register(struct si470x_device *radio, int regnr)
 	retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
 	retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
 
 
 	if (retval >= 0)
 	if (retval >= 0)
-		radio->registers[regnr] = be16_to_cpu(get_unaligned(
-			(unsigned short *) &buf[1]));
+		radio->registers[regnr] = get_unaligned_be16(&buf[1]);
 
 
 	return (retval < 0) ? -EINVAL : 0;
 	return (retval < 0) ? -EINVAL : 0;
 }
 }
@@ -537,8 +553,7 @@ static int si470x_set_register(struct si470x_device *radio, int regnr)
 	int retval;
 	int retval;
 
 
 	buf[0] = REGISTER_REPORT(regnr);
 	buf[0] = REGISTER_REPORT(regnr);
-	put_unaligned(cpu_to_be16(radio->registers[regnr]),
-		(unsigned short *) &buf[1]);
+	put_unaligned_be16(radio->registers[regnr], &buf[1]);
 
 
 	retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
 	retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
 
 
@@ -561,9 +576,8 @@ static int si470x_get_all_registers(struct si470x_device *radio)
 
 
 	if (retval >= 0)
 	if (retval >= 0)
 		for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
 		for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
-			radio->registers[regnr] = be16_to_cpu(get_unaligned(
-				(unsigned short *)
-				&buf[regnr * RADIO_REGISTER_SIZE + 1]));
+			radio->registers[regnr] = get_unaligned_be16(
+				&buf[regnr * RADIO_REGISTER_SIZE + 1]);
 
 
 	return (retval < 0) ? -EINVAL : 0;
 	return (retval < 0) ? -EINVAL : 0;
 }
 }
@@ -585,7 +599,7 @@ static int si470x_get_rds_registers(struct si470x_device *radio)
 		usb_rcvintpipe(radio->usbdev, 1),
 		usb_rcvintpipe(radio->usbdev, 1),
 		(void *) &buf, sizeof(buf), &size, usb_timeout);
 		(void *) &buf, sizeof(buf), &size, usb_timeout);
 	if (size != sizeof(buf))
 	if (size != sizeof(buf))
-	       printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
+		printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
 			"return size differs: %d != %zu\n", size, sizeof(buf));
 			"return size differs: %d != %zu\n", size, sizeof(buf));
 	if (retval < 0)
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
 		printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
@@ -594,8 +608,8 @@ static int si470x_get_rds_registers(struct si470x_device *radio)
 	if (retval >= 0)
 	if (retval >= 0)
 		for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
 		for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
 			radio->registers[STATUSRSSI + regnr] =
 			radio->registers[STATUSRSSI + regnr] =
-				be16_to_cpu(get_unaligned((unsigned short *)
-				&buf[regnr * RADIO_REGISTER_SIZE + 1]));
+				get_unaligned_be16(
+				&buf[regnr * RADIO_REGISTER_SIZE + 1]);
 
 
 	return (retval < 0) ? -EINVAL : 0;
 	return (retval < 0) ? -EINVAL : 0;
 }
 }
@@ -615,33 +629,39 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
 	radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
 	radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
 	retval = si470x_set_register(radio, CHANNEL);
 	retval = si470x_set_register(radio, CHANNEL);
 	if (retval < 0)
 	if (retval < 0)
-		return retval;
+		goto done;
 
 
-	/* wait till seek operation has completed */
+	/* wait till tune operation has completed */
 	timeout = jiffies + msecs_to_jiffies(tune_timeout);
 	timeout = jiffies + msecs_to_jiffies(tune_timeout);
 	do {
 	do {
 		retval = si470x_get_register(radio, STATUSRSSI);
 		retval = si470x_get_register(radio, STATUSRSSI);
 		if (retval < 0)
 		if (retval < 0)
-			return retval;
+			goto stop;
 		timed_out = time_after(jiffies, timeout);
 		timed_out = time_after(jiffies, timeout);
 	} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
 	} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
 		(!timed_out));
 		(!timed_out));
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+		printk(KERN_WARNING DRIVER_NAME ": tune does not complete\n");
 	if (timed_out)
 	if (timed_out)
 		printk(KERN_WARNING DRIVER_NAME
 		printk(KERN_WARNING DRIVER_NAME
-			": seek does not finish after %u ms\n", tune_timeout);
+			": tune timed out after %u ms\n", tune_timeout);
 
 
+stop:
 	/* stop tuning */
 	/* stop tuning */
 	radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
 	radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
-	return si470x_set_register(radio, CHANNEL);
+	retval = si470x_set_register(radio, CHANNEL);
+
+done:
+	return retval;
 }
 }
 
 
 
 
 /*
 /*
  * si470x_get_freq - get the frequency
  * si470x_get_freq - get the frequency
  */
  */
-static unsigned int si470x_get_freq(struct si470x_device *radio)
+static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
 {
 {
-	unsigned int spacing, band_bottom, freq;
+	unsigned int spacing, band_bottom;
 	unsigned short chan;
 	unsigned short chan;
 	int retval;
 	int retval;
 
 
@@ -667,14 +687,12 @@ static unsigned int si470x_get_freq(struct si470x_device *radio)
 
 
 	/* read channel */
 	/* read channel */
 	retval = si470x_get_register(radio, READCHAN);
 	retval = si470x_get_register(radio, READCHAN);
-	if (retval < 0)
-		return retval;
 	chan = radio->registers[READCHAN] & READCHAN_READCHAN;
 	chan = radio->registers[READCHAN] & READCHAN_READCHAN;
 
 
 	/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
 	/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
-	freq = chan * spacing + band_bottom;
+	*freq = chan * spacing + band_bottom;
 
 
-	return freq;
+	return retval;
 }
 }
 
 
 
 
@@ -713,6 +731,62 @@ static int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
 }
 }
 
 
 
 
+/*
+ * si470x_set_seek - set seek
+ */
+static int si470x_set_seek(struct si470x_device *radio,
+		unsigned int wrap_around, unsigned int seek_upward)
+{
+	int retval = 0;
+	unsigned long timeout;
+	bool timed_out = 0;
+
+	/* start seeking */
+	radio->registers[POWERCFG] |= POWERCFG_SEEK;
+	if (wrap_around == 1)
+		radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
+	else
+		radio->registers[POWERCFG] |= POWERCFG_SKMODE;
+	if (seek_upward == 1)
+		radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
+	else
+		radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
+	retval = si470x_set_register(radio, POWERCFG);
+	if (retval < 0)
+		goto done;
+
+	/* wait till seek operation has completed */
+	timeout = jiffies + msecs_to_jiffies(seek_timeout);
+	do {
+		retval = si470x_get_register(radio, STATUSRSSI);
+		if (retval < 0)
+			goto stop;
+		timed_out = time_after(jiffies, timeout);
+	} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
+		(!timed_out));
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+		printk(KERN_WARNING DRIVER_NAME ": seek does not complete\n");
+	if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
+		printk(KERN_WARNING DRIVER_NAME
+			": seek failed / band limit reached\n");
+	if (timed_out)
+		printk(KERN_WARNING DRIVER_NAME
+			": seek timed out after %u ms\n", seek_timeout);
+
+stop:
+	/* stop seeking */
+	radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
+	retval = si470x_set_register(radio, POWERCFG);
+
+done:
+	/* try again, if timed out */
+	if ((retval == 0) && timed_out)
+		retval = -EAGAIN;
+
+	return retval;
+}
+
+
 /*
 /*
  * si470x_start - switch on radio
  * si470x_start - switch on radio
  */
  */
@@ -725,27 +799,30 @@ static int si470x_start(struct si470x_device *radio)
 		POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
 		POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
 	retval = si470x_set_register(radio, POWERCFG);
 	retval = si470x_set_register(radio, POWERCFG);
 	if (retval < 0)
 	if (retval < 0)
-		return retval;
+		goto done;
 
 
 	/* sysconfig 1 */
 	/* sysconfig 1 */
 	radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
 	radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
 	retval = si470x_set_register(radio, SYSCONFIG1);
 	retval = si470x_set_register(radio, SYSCONFIG1);
 	if (retval < 0)
 	if (retval < 0)
-		return retval;
+		goto done;
 
 
 	/* sysconfig 2 */
 	/* sysconfig 2 */
 	radio->registers[SYSCONFIG2] =
 	radio->registers[SYSCONFIG2] =
-		(0x3f  << 8) |	/* SEEKTH */
-		(band  << 6) |	/* BAND */
-		(space << 4) |	/* SPACE */
-		15;		/* VOLUME (max) */
+		(0x3f  << 8) |				/* SEEKTH */
+		((band  << 6) & SYSCONFIG2_BAND)  |	/* BAND */
+		((space << 4) & SYSCONFIG2_SPACE) |	/* SPACE */
+		15;					/* VOLUME (max) */
 	retval = si470x_set_register(radio, SYSCONFIG2);
 	retval = si470x_set_register(radio, SYSCONFIG2);
 	if (retval < 0)
 	if (retval < 0)
-		return retval;
+		goto done;
 
 
 	/* reset last channel */
 	/* reset last channel */
-	return si470x_set_chan(radio,
+	retval = si470x_set_chan(radio,
 		radio->registers[CHANNEL] & CHANNEL_CHAN);
 		radio->registers[CHANNEL] & CHANNEL_CHAN);
+
+done:
+	return retval;
 }
 }
 
 
 
 
@@ -760,13 +837,16 @@ static int si470x_stop(struct si470x_device *radio)
 	radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
 	radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
 	retval = si470x_set_register(radio, SYSCONFIG1);
 	retval = si470x_set_register(radio, SYSCONFIG1);
 	if (retval < 0)
 	if (retval < 0)
-		return retval;
+		goto done;
 
 
 	/* powercfg */
 	/* powercfg */
 	radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
 	radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
 	/* POWERCFG_ENABLE has to automatically go low */
 	/* POWERCFG_ENABLE has to automatically go low */
 	radio->registers[POWERCFG] |= POWERCFG_ENABLE |	POWERCFG_DISABLE;
 	radio->registers[POWERCFG] |= POWERCFG_ENABLE |	POWERCFG_DISABLE;
-	return si470x_set_register(radio, POWERCFG);
+	retval = si470x_set_register(radio, POWERCFG);
+
+done:
+	return retval;
 }
 }
 
 
 
 
@@ -843,7 +923,7 @@ static void si470x_rds(struct si470x_device *radio)
 		};
 		};
 
 
 		/* Fill the V4L2 RDS buffer */
 		/* Fill the V4L2 RDS buffer */
-		put_unaligned(cpu_to_le16(rds), (unsigned short *) &tmpbuf);
+		put_unaligned_le16(rds, &tmpbuf);
 		tmpbuf[2] = blocknum;		/* offset name */
 		tmpbuf[2] = blocknum;		/* offset name */
 		tmpbuf[2] |= blocknum << 3;	/* received offset */
 		tmpbuf[2] |= blocknum << 3;	/* received offset */
 		if (bler > max_rds_errors)
 		if (bler > max_rds_errors)
@@ -883,8 +963,9 @@ static void si470x_work(struct work_struct *work)
 	struct si470x_device *radio = container_of(work, struct si470x_device,
 	struct si470x_device *radio = container_of(work, struct si470x_device,
 		work.work);
 		work.work);
 
 
-       if (radio->disconnected)
-	       return;
+	/* safety checks */
+	if (radio->disconnected)
+		return;
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 		return;
 		return;
 
 
@@ -917,11 +998,15 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
 
 
 	/* block if no new data available */
 	/* block if no new data available */
 	while (radio->wr_index == radio->rd_index) {
 	while (radio->wr_index == radio->rd_index) {
-		if (file->f_flags & O_NONBLOCK)
-			return -EWOULDBLOCK;
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EWOULDBLOCK;
+			goto done;
+		}
 		if (wait_event_interruptible(radio->read_queue,
 		if (wait_event_interruptible(radio->read_queue,
-			radio->wr_index != radio->rd_index) < 0)
-			return -EINTR;
+			radio->wr_index != radio->rd_index) < 0) {
+			retval = -EINTR;
+			goto done;
+		}
 	}
 	}
 
 
 	/* calculate block count from byte count */
 	/* calculate block count from byte count */
@@ -950,6 +1035,7 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
 	}
 	}
 	mutex_unlock(&radio->lock);
 	mutex_unlock(&radio->lock);
 
 
+done:
 	return retval;
 	return retval;
 }
 }
 
 
@@ -961,6 +1047,7 @@ static unsigned int si470x_fops_poll(struct file *file,
 		struct poll_table_struct *pts)
 		struct poll_table_struct *pts)
 {
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
 
 
 	/* switch on rds reception */
 	/* switch on rds reception */
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
@@ -972,9 +1059,9 @@ static unsigned int si470x_fops_poll(struct file *file,
 	poll_wait(file, &radio->read_queue, pts);
 	poll_wait(file, &radio->read_queue, pts);
 
 
 	if (radio->rd_index != radio->wr_index)
 	if (radio->rd_index != radio->wr_index)
-		return POLLIN | POLLRDNORM;
+		retval = POLLIN | POLLRDNORM;
 
 
-	return 0;
+	return retval;
 }
 }
 
 
 
 
@@ -991,17 +1078,18 @@ static int si470x_fops_open(struct inode *inode, struct file *file)
 	retval = usb_autopm_get_interface(radio->intf);
 	retval = usb_autopm_get_interface(radio->intf);
 	if (retval < 0) {
 	if (retval < 0) {
 		radio->users--;
 		radio->users--;
-		return -EIO;
+		retval = -EIO;
+		goto done;
 	}
 	}
 
 
 	if (radio->users == 1) {
 	if (radio->users == 1) {
 		retval = si470x_start(radio);
 		retval = si470x_start(radio);
 		if (retval < 0)
 		if (retval < 0)
 			usb_autopm_put_interface(radio->intf);
 			usb_autopm_put_interface(radio->intf);
-		return retval;
 	}
 	}
 
 
-	return 0;
+done:
+	return retval;
 }
 }
 
 
 
 
@@ -1011,20 +1099,23 @@ static int si470x_fops_open(struct inode *inode, struct file *file)
 static int si470x_fops_release(struct inode *inode, struct file *file)
 static int si470x_fops_release(struct inode *inode, struct file *file)
 {
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-       int retval = 0;
+	int retval = 0;
 
 
-	if (!radio)
-		return -ENODEV;
+	/* safety check */
+	if (!radio) {
+		retval = -ENODEV;
+		goto done;
+	}
 
 
-       mutex_lock(&open_close_lock);
+	mutex_lock(&radio->disconnect_lock);
 	radio->users--;
 	radio->users--;
 	if (radio->users == 0) {
 	if (radio->users == 0) {
-	       if (radio->disconnected) {
-		       video_unregister_device(radio->videodev);
-		       kfree(radio->buffer);
-		       kfree(radio);
-		       goto done;
-	       }
+		if (radio->disconnected) {
+			video_unregister_device(radio->videodev);
+			kfree(radio->buffer);
+			kfree(radio);
+			goto unlock;
+		}
 
 
 		/* stop rds reception */
 		/* stop rds reception */
 		cancel_delayed_work_sync(&radio->work);
 		cancel_delayed_work_sync(&radio->work);
@@ -1036,9 +1127,11 @@ static int si470x_fops_release(struct inode *inode, struct file *file)
 		usb_autopm_put_interface(radio->intf);
 		usb_autopm_put_interface(radio->intf);
 	}
 	}
 
 
+unlock:
+	mutex_unlock(&radio->disconnect_lock);
+
 done:
 done:
-       mutex_unlock(&open_close_lock);
-       return retval;
+	return retval;
 }
 }
 
 
 
 
@@ -1116,7 +1209,8 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
 	sprintf(capability->bus_info, "USB");
 	sprintf(capability->bus_info, "USB");
 	capability->version = DRIVER_KERNEL_VERSION;
 	capability->version = DRIVER_KERNEL_VERSION;
-	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+		V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1125,7 +1219,7 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
 /*
 /*
  * si470x_vidioc_g_input - get input
  * si470x_vidioc_g_input - get input
  */
  */
-static int si470x_vidioc_g_input(struct file *filp, void *priv,
+static int si470x_vidioc_g_input(struct file *file, void *priv,
 		unsigned int *i)
 		unsigned int *i)
 {
 {
 	*i = 0;
 	*i = 0;
@@ -1137,12 +1231,18 @@ static int si470x_vidioc_g_input(struct file *filp, void *priv,
 /*
 /*
  * si470x_vidioc_s_input - set input
  * si470x_vidioc_s_input - set input
  */
  */
-static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+static int si470x_vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
 {
+	int retval = 0;
+
+	/* safety checks */
 	if (i != 0)
 	if (i != 0)
-		return -EINVAL;
+		retval = -EINVAL;
 
 
-	return 0;
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": set input failed with %d\n", retval);
+	return retval;
 }
 }
 
 
 
 
@@ -1155,17 +1255,22 @@ static int si470x_vidioc_queryctrl(struct file *file, void *priv,
 	unsigned char i;
 	unsigned char i;
 	int retval = -EINVAL;
 	int retval = -EINVAL;
 
 
+	/* safety checks */
+	if (!qc->id)
+		goto done;
+
 	for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
 	for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
-		if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) {
+		if (qc->id == si470x_v4l2_queryctrl[i].id) {
 			memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
 			memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
 			retval = 0;
 			retval = 0;
 			break;
 			break;
 		}
 		}
 	}
 	}
+
+done:
 	if (retval < 0)
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 		printk(KERN_WARNING DRIVER_NAME
-			": query control failed with %d\n", retval);
-
+			": query controls failed with %d\n", retval);
 	return retval;
 	return retval;
 }
 }
 
 
@@ -1177,9 +1282,13 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
 		struct v4l2_control *ctrl)
 		struct v4l2_control *ctrl)
 {
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
 
 
-       if (radio->disconnected)
-	       return -EIO;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
 
 
 	switch (ctrl->id) {
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
 	case V4L2_CID_AUDIO_VOLUME:
@@ -1190,9 +1299,15 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
 		ctrl->value = ((radio->registers[POWERCFG] &
 		ctrl->value = ((radio->registers[POWERCFG] &
 				POWERCFG_DMUTE) == 0) ? 1 : 0;
 				POWERCFG_DMUTE) == 0) ? 1 : 0;
 		break;
 		break;
+	default:
+		retval = -EINVAL;
 	}
 	}
 
 
-	return 0;
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": get control failed with %d\n", retval);
+	return retval;
 }
 }
 
 
 
 
@@ -1203,10 +1318,13 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
 		struct v4l2_control *ctrl)
 		struct v4l2_control *ctrl)
 {
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
+	int retval = 0;
 
 
-       if (radio->disconnected)
-	       return -EIO;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
 
 
 	switch (ctrl->id) {
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
 	case V4L2_CID_AUDIO_VOLUME:
@@ -1224,10 +1342,11 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
 	default:
 	default:
 		retval = -EINVAL;
 		retval = -EINVAL;
 	}
 	}
+
+done:
 	if (retval < 0)
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 		printk(KERN_WARNING DRIVER_NAME
 			": set control failed with %d\n", retval);
 			": set control failed with %d\n", retval);
-
 	return retval;
 	return retval;
 }
 }
 
 
@@ -1238,13 +1357,22 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
 static int si470x_vidioc_g_audio(struct file *file, void *priv,
 static int si470x_vidioc_g_audio(struct file *file, void *priv,
 		struct v4l2_audio *audio)
 		struct v4l2_audio *audio)
 {
 {
-	if (audio->index > 1)
-		return -EINVAL;
+	int retval = 0;
+
+	/* safety checks */
+	if (audio->index != 0) {
+		retval = -EINVAL;
+		goto done;
+	}
 
 
 	strcpy(audio->name, "Radio");
 	strcpy(audio->name, "Radio");
 	audio->capability = V4L2_AUDCAP_STEREO;
 	audio->capability = V4L2_AUDCAP_STEREO;
 
 
-	return 0;
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": get audio failed with %d\n", retval);
+	return retval;
 }
 }
 
 
 
 
@@ -1254,10 +1382,19 @@ static int si470x_vidioc_g_audio(struct file *file, void *priv,
 static int si470x_vidioc_s_audio(struct file *file, void *priv,
 static int si470x_vidioc_s_audio(struct file *file, void *priv,
 		struct v4l2_audio *audio)
 		struct v4l2_audio *audio)
 {
 {
-	if (audio->index != 0)
-		return -EINVAL;
+	int retval = 0;
 
 
-	return 0;
+	/* safety checks */
+	if (audio->index != 0) {
+		retval = -EINVAL;
+		goto done;
+	}
+
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": set audio failed with %d\n", retval);
+	return retval;
 }
 }
 
 
 
 
@@ -1268,20 +1405,23 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
 		struct v4l2_tuner *tuner)
 		struct v4l2_tuner *tuner)
 {
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
+	int retval = 0;
 
 
-       if (radio->disconnected)
-	       return -EIO;
-	if (tuner->index > 0)
-		return -EINVAL;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
 
 
-	/* read status rssi */
 	retval = si470x_get_register(radio, STATUSRSSI);
 	retval = si470x_get_register(radio, STATUSRSSI);
 	if (retval < 0)
 	if (retval < 0)
-		return retval;
+		goto done;
 
 
 	strcpy(tuner->name, "FM");
 	strcpy(tuner->name, "FM");
-	tuner->type = V4L2_TUNER_RADIO;
 	switch (band) {
 	switch (band) {
 	/* 0: 87.5 - 108 MHz (USA, Europe, default) */
 	/* 0: 87.5 - 108 MHz (USA, Europe, default) */
 	default:
 	default:
@@ -1313,9 +1453,14 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
 				* 0x0101;
 				* 0x0101;
 
 
 	/* automatic frequency control: -1: freq to low, 1 freq to high */
 	/* automatic frequency control: -1: freq to low, 1 freq to high */
-	tuner->afc = 0;
+	/* AFCRL does only indicate that freq. differs, not if too low/high */
+	tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
 
 
-	return 0;
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": get tuner failed with %d\n", retval);
+	return retval;
 }
 }
 
 
 
 
@@ -1326,12 +1471,17 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
 		struct v4l2_tuner *tuner)
 		struct v4l2_tuner *tuner)
 {
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
+	int retval = 0;
 
 
-       if (radio->disconnected)
-	       return -EIO;
-	if (tuner->index > 0)
-		return -EINVAL;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
 
 
 	if (tuner->audmode == V4L2_TUNER_MODE_MONO)
 	if (tuner->audmode == V4L2_TUNER_MODE_MONO)
 		radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
 		radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
@@ -1339,10 +1489,11 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
 		radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
 		radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
 
 
 	retval = si470x_set_register(radio, POWERCFG);
 	retval = si470x_set_register(radio, POWERCFG);
+
+done:
 	if (retval < 0)
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 		printk(KERN_WARNING DRIVER_NAME
 			": set tuner failed with %d\n", retval);
 			": set tuner failed with %d\n", retval);
-
 	return retval;
 	return retval;
 }
 }
 
 
@@ -1354,14 +1505,25 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
 		struct v4l2_frequency *freq)
 		struct v4l2_frequency *freq)
 {
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
 
 
-       if (radio->disconnected)
-	       return -EIO;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
 
 
-	freq->type = V4L2_TUNER_RADIO;
-	freq->frequency = si470x_get_freq(radio);
+	retval = si470x_get_freq(radio, &freq->frequency);
 
 
-	return 0;
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": get frequency failed with %d\n", retval);
+	return retval;
 }
 }
 
 
 
 
@@ -1372,19 +1534,55 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
 		struct v4l2_frequency *freq)
 		struct v4l2_frequency *freq)
 {
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
+	int retval = 0;
 
 
-       if (radio->disconnected)
-	       return -EIO;
-	if (freq->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
 
 
 	retval = si470x_set_freq(radio, freq->frequency);
 	retval = si470x_set_freq(radio, freq->frequency);
+
+done:
 	if (retval < 0)
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 		printk(KERN_WARNING DRIVER_NAME
 			": set frequency failed with %d\n", retval);
 			": set frequency failed with %d\n", retval);
+	return retval;
+}
 
 
-	return 0;
+
+/*
+ * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
+ */
+static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+		struct v4l2_hw_freq_seek *seek)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((seek->tuner != 0) && (seek->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
+
+	retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
+
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": set hardware frequency seek failed with %d\n",
+			retval);
+	return retval;
 }
 }
 
 
 
 
@@ -1408,6 +1606,7 @@ static struct video_device si470x_viddev_template = {
 	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
 	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
 	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
 	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
 	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
 	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
+	.vidioc_s_hw_freq_seek	= si470x_vidioc_s_hw_freq_seek,
 	.owner			= THIS_MODULE,
 	.owner			= THIS_MODULE,
 };
 };
 
 
@@ -1424,31 +1623,36 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 		const struct usb_device_id *id)
 {
 {
 	struct si470x_device *radio;
 	struct si470x_device *radio;
-	int retval = -ENOMEM;
+	int retval = 0;
 
 
-	/* private data allocation */
+	/* private data allocation and initialization */
 	radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
 	radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
-	if (!radio)
+	if (!radio) {
+		retval = -ENOMEM;
 		goto err_initial;
 		goto err_initial;
+	}
+	radio->users = 0;
+	radio->disconnected = 0;
+	radio->usbdev = interface_to_usbdev(intf);
+	radio->intf = intf;
+	mutex_init(&radio->disconnect_lock);
+	mutex_init(&radio->lock);
 
 
-	/* video device allocation */
+	/* video device allocation and initialization */
 	radio->videodev = video_device_alloc();
 	radio->videodev = video_device_alloc();
-	if (!radio->videodev)
+	if (!radio->videodev) {
+		retval = -ENOMEM;
 		goto err_radio;
 		goto err_radio;
-
-	/* initial configuration */
+	}
 	memcpy(radio->videodev, &si470x_viddev_template,
 	memcpy(radio->videodev, &si470x_viddev_template,
 			sizeof(si470x_viddev_template));
 			sizeof(si470x_viddev_template));
-	radio->users = 0;
-	radio->usbdev = interface_to_usbdev(intf);
-	radio->intf = intf;
-	mutex_init(&radio->lock);
 	video_set_drvdata(radio->videodev, radio);
 	video_set_drvdata(radio->videodev, radio);
 
 
 	/* show some infos about the specific device */
 	/* show some infos about the specific device */
-	retval = -EIO;
-	if (si470x_get_all_registers(radio) < 0)
+	if (si470x_get_all_registers(radio) < 0) {
+		retval = -EIO;
 		goto err_all;
 		goto err_all;
+	}
 	printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
 	printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
 			radio->registers[DEVICEID], radio->registers[CHIPID]);
 			radio->registers[DEVICEID], radio->registers[CHIPID]);
 
 
@@ -1474,8 +1678,10 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
 	/* rds buffer allocation */
 	/* rds buffer allocation */
 	radio->buf_size = rds_buf * 3;
 	radio->buf_size = rds_buf * 3;
 	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
 	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
-	if (!radio->buffer)
+	if (!radio->buffer) {
+		retval = -EIO;
 		goto err_all;
 		goto err_all;
+	}
 
 
 	/* rds buffer configuration */
 	/* rds buffer configuration */
 	radio->wr_index = 0;
 	radio->wr_index = 0;
@@ -1487,6 +1693,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
 
 
 	/* register video device */
 	/* register video device */
 	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
 	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+		retval = -EIO;
 		printk(KERN_WARNING DRIVER_NAME
 		printk(KERN_WARNING DRIVER_NAME
 				": Could not register video device\n");
 				": Could not register video device\n");
 		goto err_all;
 		goto err_all;
@@ -1546,16 +1753,16 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
 {
 {
 	struct si470x_device *radio = usb_get_intfdata(intf);
 	struct si470x_device *radio = usb_get_intfdata(intf);
 
 
-       mutex_lock(&open_close_lock);
-       radio->disconnected = 1;
+	mutex_lock(&radio->disconnect_lock);
+	radio->disconnected = 1;
 	cancel_delayed_work_sync(&radio->work);
 	cancel_delayed_work_sync(&radio->work);
 	usb_set_intfdata(intf, NULL);
 	usb_set_intfdata(intf, NULL);
-       if (radio->users == 0) {
-	       video_unregister_device(radio->videodev);
-	       kfree(radio->buffer);
-	       kfree(radio);
-       }
-       mutex_unlock(&open_close_lock);
+	if (radio->users == 0) {
+		video_unregister_device(radio->videodev);
+		kfree(radio->buffer);
+		kfree(radio);
+	}
+	mutex_unlock(&radio->disconnect_lock);
 }
 }
 
 
 
 

+ 69 - 30
drivers/media/video/Kconfig

@@ -24,21 +24,21 @@ config VIDEOBUF_VMALLOC
 	select VIDEOBUF_GEN
 	select VIDEOBUF_GEN
 	tristate
 	tristate
 
 
+config VIDEOBUF_DMA_CONTIG
+	depends on HAS_DMA
+	select VIDEOBUF_GEN
+	tristate
+
 config VIDEOBUF_DVB
 config VIDEOBUF_DVB
 	tristate
 	tristate
 	select VIDEOBUF_GEN
 	select VIDEOBUF_GEN
-	select VIDEOBUF_DMA_SG
 
 
 config VIDEO_BTCX
 config VIDEO_BTCX
 	tristate
 	tristate
 
 
-config VIDEO_IR_I2C
-	tristate
-
 config VIDEO_IR
 config VIDEO_IR
 	tristate
 	tristate
 	depends on INPUT
 	depends on INPUT
-	select VIDEO_IR_I2C if I2C
 
 
 config VIDEO_TVEEPROM
 config VIDEO_TVEEPROM
 	tristate
 	tristate
@@ -84,6 +84,19 @@ config VIDEO_HELPER_CHIPS_AUTO
 
 
 	  In doubt, say Y.
 	  In doubt, say Y.
 
 
+config VIDEO_IR_I2C
+	tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO
+	depends on I2C && VIDEO_IR
+	default y
+	---help---
+	  Most boards have an IR chip directly connected via GPIO. However,
+	  some video boards have the IR connected via I2C bus.
+
+	  If your board doesn't have an I2C IR chip, you may disable this
+	  option.
+
+	  In doubt, say Y.
+
 #
 #
 # Encoder / Decoder module configuration
 # Encoder / Decoder module configuration
 #
 #
@@ -600,9 +613,6 @@ config VIDEO_STRADIS
 	  driver for PCI.  There is a product page at
 	  driver for PCI.  There is a product page at
 	  <http://www.stradis.com/>.
 	  <http://www.stradis.com/>.
 
 
-config VIDEO_ZORAN_ZR36060
-	tristate
-
 config VIDEO_ZORAN
 config VIDEO_ZORAN
 	tristate "Zoran ZR36057/36067 Video For Linux"
 	tristate "Zoran ZR36057/36067 Video For Linux"
 	depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
 	depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
@@ -616,61 +626,64 @@ config VIDEO_ZORAN
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called zr36067.
 	  module will be called zr36067.
 
 
+config VIDEO_ZORAN_DC30
+	tristate "Pinnacle/Miro DC30(+) support"
+	depends on VIDEO_ZORAN
+	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
+	  card. This also supports really old DC10 cards based on the
+	  zr36050 MJPEG codec and zr36016 VFE.
+
+config VIDEO_ZORAN_ZR36060
+	tristate "Zoran ZR36060"
+	depends on VIDEO_ZORAN
+	help
+	  Say Y to support Zoran boards based on 36060 chips.
+	  This includes Iomega Bus, Pinnacle DC10, Linux media Labs 33
+	  and 33 R10 and AverMedia 6 boards.
+
 config VIDEO_ZORAN_BUZ
 config VIDEO_ZORAN_BUZ
 	tristate "Iomega Buz support"
 	tristate "Iomega Buz support"
-	depends on VIDEO_ZORAN
+	depends on VIDEO_ZORAN_ZR36060
 	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
 	help
 	help
 	  Support for the Iomega Buz MJPEG capture/playback card.
 	  Support for the Iomega Buz MJPEG capture/playback card.
 
 
 config VIDEO_ZORAN_DC10
 config VIDEO_ZORAN_DC10
 	tristate "Pinnacle/Miro DC10(+) support"
 	tristate "Pinnacle/Miro DC10(+) support"
-	depends on VIDEO_ZORAN
-	select VIDEO_SAA7110
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
 	help
 	help
 	  Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
 	  Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
 	  card.
 	  card.
 
 
-config VIDEO_ZORAN_DC30
-	tristate "Pinnacle/Miro DC30(+) support"
-	depends on VIDEO_ZORAN
-	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
-	help
-	  Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
-	  card. This also supports really old DC10 cards based on the
-	  zr36050 MJPEG codec and zr36016 VFE.
-
 config VIDEO_ZORAN_LML33
 config VIDEO_ZORAN_LML33
 	tristate "Linux Media Labs LML33 support"
 	tristate "Linux Media Labs LML33 support"
-	depends on VIDEO_ZORAN
+	depends on VIDEO_ZORAN_ZR36060
 	select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
 	help
 	help
 	  Support for the Linux Media Labs LML33 MJPEG capture/playback
 	  Support for the Linux Media Labs LML33 MJPEG capture/playback
 	  card.
 	  card.
 
 
 config VIDEO_ZORAN_LML33R10
 config VIDEO_ZORAN_LML33R10
 	tristate "Linux Media Labs LML33R10 support"
 	tristate "Linux Media Labs LML33R10 support"
-	depends on VIDEO_ZORAN
+	depends on VIDEO_ZORAN_ZR36060
 	select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
 	help
 	help
 	  support for the Linux Media Labs LML33R10 MJPEG capture/playback
 	  support for the Linux Media Labs LML33R10 MJPEG capture/playback
 	  card.
 	  card.
 
 
 config VIDEO_ZORAN_AVS6EYES
 config VIDEO_ZORAN_AVS6EYES
 	tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
 	tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
-	depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+	depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
 	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
 	help
 	help
 	  Support for the AverMedia 6 Eyes video surveillance card.
 	  Support for the AverMedia 6 Eyes video surveillance card.
 
 
@@ -801,6 +814,8 @@ config USB_VIDEO_CLASS
 
 
 	  For more information see: <http://linux-uvc.berlios.de/>
 	  For more information see: <http://linux-uvc.berlios.de/>
 
 
+source "drivers/media/video/gspca/Kconfig"
+
 source "drivers/media/video/pvrusb2/Kconfig"
 source "drivers/media/video/pvrusb2/Kconfig"
 
 
 source "drivers/media/video/em28xx/Kconfig"
 source "drivers/media/video/em28xx/Kconfig"
@@ -905,12 +920,21 @@ config USB_STKWEBCAM
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called stkwebcam.
 	  module will be called stkwebcam.
 
 
+config USB_S2255
+	tristate "USB Sensoray 2255 video capture device"
+	depends on VIDEO_V4L2
+	select VIDEOBUF_VMALLOC
+	default n
+	help
+	  Say Y here if you want support for the Sensoray 2255 USB device.
+	  This driver can be compiled as a module, called s2255drv.
+
 endif # V4L_USB_DRIVERS
 endif # V4L_USB_DRIVERS
 
 
 config SOC_CAMERA
 config SOC_CAMERA
 	tristate "SoC camera support"
 	tristate "SoC camera support"
 	depends on VIDEO_V4L2 && HAS_DMA
 	depends on VIDEO_V4L2 && HAS_DMA
-	select VIDEOBUF_DMA_SG
+	select VIDEOBUF_GEN
 	help
 	help
 	  SoC Camera is a common API to several cameras, not connecting
 	  SoC Camera is a common API to several cameras, not connecting
 	  over a bus like PCI or USB. For example some i2c camera connected
 	  over a bus like PCI or USB. For example some i2c camera connected
@@ -945,11 +969,26 @@ config MT9V022_PCA9536_SWITCH
 	  Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
 	  Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
 	  extender to switch between 8 and 10 bit datawidth modes
 	  extender to switch between 8 and 10 bit datawidth modes
 
 
+config SOC_CAMERA_PLATFORM
+	tristate "platform camera support"
+	depends on SOC_CAMERA
+	help
+	  This is a generic SoC camera platform driver, useful for testing
+
 config VIDEO_PXA27x
 config VIDEO_PXA27x
 	tristate "PXA27x Quick Capture Interface driver"
 	tristate "PXA27x Quick Capture Interface driver"
 	depends on VIDEO_DEV && PXA27x
 	depends on VIDEO_DEV && PXA27x
 	select SOC_CAMERA
 	select SOC_CAMERA
+	select VIDEOBUF_DMA_SG
 	---help---
 	---help---
 	  This is a v4l2 driver for the PXA27x Quick Capture Interface
 	  This is a v4l2 driver for the PXA27x Quick Capture Interface
 
 
+config VIDEO_SH_MOBILE_CEU
+	tristate "SuperH Mobile CEU Interface driver"
+	depends on VIDEO_DEV
+	select SOC_CAMERA
+	select VIDEOBUF_DMA_CONTIG
+	---help---
+	  This is a v4l2 driver for the SuperH Mobile CEU Interface
+
 endif # VIDEO_CAPTURE_DRIVERS
 endif # VIDEO_CAPTURE_DRIVERS

+ 5 - 0
drivers/media/video/Makefile

@@ -88,6 +88,7 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
 obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
 obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
@@ -117,11 +118,13 @@ obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
 obj-$(CONFIG_USB_PWC)           += pwc/
 obj-$(CONFIG_USB_PWC)           += pwc/
 obj-$(CONFIG_USB_ZC0301)        += zc0301/
 obj-$(CONFIG_USB_ZC0301)        += zc0301/
+obj-$(CONFIG_USB_GSPCA)         += gspca/
 
 
 obj-$(CONFIG_USB_IBMCAM)        += usbvideo/
 obj-$(CONFIG_USB_IBMCAM)        += usbvideo/
 obj-$(CONFIG_USB_KONICAWC)      += usbvideo/
 obj-$(CONFIG_USB_KONICAWC)      += usbvideo/
 obj-$(CONFIG_USB_VICAM)         += usbvideo/
 obj-$(CONFIG_USB_VICAM)         += usbvideo/
 obj-$(CONFIG_USB_QUICKCAM_MESSENGER)	+= usbvideo/
 obj-$(CONFIG_USB_QUICKCAM_MESSENGER)	+= usbvideo/
+obj-$(CONFIG_USB_S2255)		+= s2255drv.o
 
 
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_CX18) += cx18/
 obj-$(CONFIG_VIDEO_CX18) += cx18/
@@ -130,9 +133,11 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 
 obj-$(CONFIG_VIDEO_PXA27x)	+= pxa_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)	+= pxa_camera.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 obj-$(CONFIG_SOC_CAMERA)	+= soc_camera.o
 obj-$(CONFIG_SOC_CAMERA)	+= soc_camera.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_PLATFORM)	+= soc_camera_platform.o
 
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 
 

+ 1 - 1
drivers/media/video/bt819.c

@@ -516,7 +516,7 @@ bt819_detect_client (struct i2c_adapter *adapter,
 
 
 	dprintk(1,
 	dprintk(1,
 		KERN_INFO
 		KERN_INFO
-		"saa7111.c: detecting bt819 client on address 0x%x\n",
+		"bt819: detecting bt819 client on address 0x%x\n",
 		address << 1);
 		address << 1);
 
 
 	/* Check if the adapter supports the needed features */
 	/* Check if the adapter supports the needed features */

+ 0 - 1
drivers/media/video/bt8xx/bt832.c

@@ -179,7 +179,6 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
 
 
 	v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
 	v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
 
 
-
 	if(! bt832_init(&t->client)) {
 	if(! bt832_init(&t->client)) {
 		bt832_detach(&t->client);
 		bt832_detach(&t->client);
 		return -1;
 		return -1;

+ 26 - 25
drivers/media/video/bt8xx/bttv-driver.c

@@ -2448,7 +2448,7 @@ pix_format_set_size     (struct v4l2_pix_format *       f,
 	}
 	}
 }
 }
 
 
-static int bttv_g_fmt_cap(struct file *file, void *priv,
+static int bttv_g_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 					struct v4l2_format *f)
 {
 {
 	struct bttv_fh *fh  = priv;
 	struct bttv_fh *fh  = priv;
@@ -2461,7 +2461,7 @@ static int bttv_g_fmt_cap(struct file *file, void *priv,
 	return 0;
 	return 0;
 }
 }
 
 
-static int bttv_g_fmt_overlay(struct file *file, void *priv,
+static int bttv_g_fmt_vid_overlay(struct file *file, void *priv,
 					struct v4l2_format *f)
 					struct v4l2_format *f)
 {
 {
 	struct bttv_fh *fh  = priv;
 	struct bttv_fh *fh  = priv;
@@ -2472,7 +2472,7 @@ static int bttv_g_fmt_overlay(struct file *file, void *priv,
 	return 0;
 	return 0;
 }
 }
 
 
-static int bttv_try_fmt_cap(struct file *file, void *priv,
+static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
 						struct v4l2_format *f)
 						struct v4l2_format *f)
 {
 {
 	const struct bttv_format *fmt;
 	const struct bttv_format *fmt;
@@ -2532,7 +2532,7 @@ static int bttv_try_fmt_cap(struct file *file, void *priv,
 	return 0;
 	return 0;
 }
 }
 
 
-static int bttv_try_fmt_overlay(struct file *file, void *priv,
+static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
 						struct v4l2_format *f)
 						struct v4l2_format *f)
 {
 {
 	struct bttv_fh *fh = priv;
 	struct bttv_fh *fh = priv;
@@ -2542,7 +2542,7 @@ static int bttv_try_fmt_overlay(struct file *file, void *priv,
 			/* adjust_crop */ 0);
 			/* adjust_crop */ 0);
 }
 }
 
 
-static int bttv_s_fmt_cap(struct file *file, void *priv,
+static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 				struct v4l2_format *f)
 {
 {
 	int retval;
 	int retval;
@@ -2556,7 +2556,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv,
 	if (0 != retval)
 	if (0 != retval)
 		return retval;
 		return retval;
 
 
-	retval = bttv_try_fmt_cap(file, priv, f);
+	retval = bttv_try_fmt_vid_cap(file, priv, f);
 	if (0 != retval)
 	if (0 != retval)
 		return retval;
 		return retval;
 
 
@@ -2591,7 +2591,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv,
 	return 0;
 	return 0;
 }
 }
 
 
-static int bttv_s_fmt_overlay(struct file *file, void *priv,
+static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
 				struct v4l2_format *f)
 				struct v4l2_format *f)
 {
 {
 	struct bttv_fh *fh = priv;
 	struct bttv_fh *fh = priv;
@@ -2661,7 +2661,7 @@ static int bttv_querycap(struct file *file, void  *priv,
 	return 0;
 	return 0;
 }
 }
 
 
-static int bttv_enum_fmt_vbi(struct file *file, void  *priv,
+static int bttv_enum_fmt_vbi_cap(struct file *file, void  *priv,
 				struct v4l2_fmtdesc *f)
 				struct v4l2_fmtdesc *f)
 {
 {
 	if (0 != f->index)
 	if (0 != f->index)
@@ -2692,7 +2692,7 @@ static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
 	return i;
 	return i;
 }
 }
 
 
-static int bttv_enum_fmt_cap(struct file *file, void  *priv,
+static int bttv_enum_fmt_vid_cap(struct file *file, void  *priv,
 				struct v4l2_fmtdesc *f)
 				struct v4l2_fmtdesc *f)
 {
 {
 	int rc = bttv_enum_fmt_cap_ovr(f);
 	int rc = bttv_enum_fmt_cap_ovr(f);
@@ -2703,7 +2703,7 @@ static int bttv_enum_fmt_cap(struct file *file, void  *priv,
 	return 0;
 	return 0;
 }
 }
 
 
-static int bttv_enum_fmt_overlay(struct file *file, void  *priv,
+static int bttv_enum_fmt_vid_overlay(struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 					struct v4l2_fmtdesc *f)
 {
 {
 	int rc;
 	int rc;
@@ -3362,18 +3362,18 @@ static struct video_device bttv_video_template =
 	.fops     = &bttv_fops,
 	.fops     = &bttv_fops,
 	.minor    = -1,
 	.minor    = -1,
 	.vidioc_querycap                = bttv_querycap,
 	.vidioc_querycap                = bttv_querycap,
-	.vidioc_enum_fmt_cap            = bttv_enum_fmt_cap,
-	.vidioc_g_fmt_cap               = bttv_g_fmt_cap,
-	.vidioc_try_fmt_cap             = bttv_try_fmt_cap,
-	.vidioc_s_fmt_cap               = bttv_s_fmt_cap,
-	.vidioc_enum_fmt_overlay        = bttv_enum_fmt_overlay,
-	.vidioc_g_fmt_overlay           = bttv_g_fmt_overlay,
-	.vidioc_try_fmt_overlay         = bttv_try_fmt_overlay,
-	.vidioc_s_fmt_overlay           = bttv_s_fmt_overlay,
-	.vidioc_enum_fmt_vbi            = bttv_enum_fmt_vbi,
-	.vidioc_g_fmt_vbi               = bttv_g_fmt_vbi,
-	.vidioc_try_fmt_vbi             = bttv_try_fmt_vbi,
-	.vidioc_s_fmt_vbi               = bttv_s_fmt_vbi,
+	.vidioc_enum_fmt_vid_cap        = bttv_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap           = bttv_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap         = bttv_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap           = bttv_s_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_overlay    = bttv_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay       = bttv_g_fmt_vid_overlay,
+	.vidioc_try_fmt_vid_overlay     = bttv_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay       = bttv_s_fmt_vid_overlay,
+	.vidioc_enum_fmt_vbi_cap        = bttv_enum_fmt_vbi_cap,
+	.vidioc_g_fmt_vbi_cap           = bttv_g_fmt_vbi_cap,
+	.vidioc_try_fmt_vbi_cap         = bttv_try_fmt_vbi_cap,
+	.vidioc_s_fmt_vbi_cap           = bttv_s_fmt_vbi_cap,
 	.vidioc_g_audio                 = bttv_g_audio,
 	.vidioc_g_audio                 = bttv_g_audio,
 	.vidioc_s_audio                 = bttv_s_audio,
 	.vidioc_s_audio                 = bttv_s_audio,
 	.vidioc_cropcap                 = bttv_cropcap,
 	.vidioc_cropcap                 = bttv_cropcap,
@@ -3705,7 +3705,7 @@ static void bttv_risc_disasm(struct bttv *btv,
 	for (i = 0; i < (risc->size >> 2); i += n) {
 	for (i = 0; i < (risc->size >> 2); i += n) {
 		printk("%s:   0x%lx: ", btv->c.name,
 		printk("%s:   0x%lx: ", btv->c.name,
 		       (unsigned long)(risc->dma + (i<<2)));
 		       (unsigned long)(risc->dma + (i<<2)));
-		n = bttv_risc_decode(risc->cpu[i]);
+		n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));
 		for (j = 1; j < n; j++)
 		for (j = 1; j < n; j++)
 			printk("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
 			printk("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
 			       btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
 			       btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
@@ -3774,8 +3774,8 @@ static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
 	printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
 	printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
 	       btv->c.nr,
 	       btv->c.nr,
 	       (unsigned long)btv->main.dma,
 	       (unsigned long)btv->main.dma,
-	       (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
-	       (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
+	       (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]),
+	       (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]),
 	       (unsigned long)rc);
 	       (unsigned long)rc);
 
 
 	if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
 	if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
@@ -4188,6 +4188,7 @@ static struct video_device *vdev_init(struct bttv *btv,
 	vfd->dev     = &btv->c.pci->dev;
 	vfd->dev     = &btv->c.pci->dev;
 	vfd->release = video_device_release;
 	vfd->release = video_device_release;
 	vfd->type    = type;
 	vfd->type    = type;
+	vfd->debug   = bttv_debug;
 	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
 	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
 		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
 		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
 		 type_name, bttv_tvcards[btv->c.type].name);
 		 type_name, bttv_tvcards[btv->c.type].name);

+ 14 - 35
drivers/media/video/bt8xx/bttv-i2c.c

@@ -36,11 +36,6 @@
 #include <linux/jiffies.h>
 #include <linux/jiffies.h>
 #include <asm/io.h>
 #include <asm/io.h>
 
 
-static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
-static struct i2c_adapter bttv_i2c_adap_sw_template;
-static struct i2c_adapter bttv_i2c_adap_hw_template;
-static struct i2c_client bttv_i2c_client_template;
-
 static int attach_inform(struct i2c_client *client);
 static int attach_inform(struct i2c_client *client);
 
 
 static int i2c_debug;
 static int i2c_debug;
@@ -104,7 +99,7 @@ static int bttv_bit_getsda(void *data)
 	return state;
 	return state;
 }
 }
 
 
-static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
+static struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = {
 	.setsda  = bttv_bit_setsda,
 	.setsda  = bttv_bit_setsda,
 	.setscl  = bttv_bit_setscl,
 	.setscl  = bttv_bit_setscl,
 	.getsda  = bttv_bit_getsda,
 	.getsda  = bttv_bit_getsda,
@@ -113,14 +108,6 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
 	.timeout = 200,
 	.timeout = 200,
 };
 };
 
 
-static struct i2c_adapter bttv_i2c_adap_sw_template = {
-	.owner             = THIS_MODULE,
-	.class             = I2C_CLASS_TV_ANALOG,
-	.name              = "bttv",
-	.id                = I2C_HW_B_BT848,
-	.client_register   = attach_inform,
-};
-
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
 /* I2C functions - hardware i2c                                            */
 /* I2C functions - hardware i2c                                            */
 
 
@@ -270,20 +257,11 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int
 	return retval;
 	return retval;
 }
 }
 
 
-static struct i2c_algorithm bttv_algo = {
+static const struct i2c_algorithm bttv_algo = {
 	.master_xfer   = bttv_i2c_xfer,
 	.master_xfer   = bttv_i2c_xfer,
 	.functionality = functionality,
 	.functionality = functionality,
 };
 };
 
 
-static struct i2c_adapter bttv_i2c_adap_hw_template = {
-	.owner             = THIS_MODULE,
-	.class         = I2C_CLASS_TV_ANALOG,
-	.name          = "bt878",
-	.id            = I2C_HW_B_BT848 /* FIXME */,
-	.algo          = &bttv_algo,
-	.client_register = attach_inform,
-};
-
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
 /* I2C functions - common stuff                                            */
 /* I2C functions - common stuff                                            */
 
 
@@ -332,10 +310,6 @@ void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
 	i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
 	i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
 }
 }
 
 
-static struct i2c_client bttv_i2c_client_template = {
-	.name	= "bttv internal",
-};
-
 
 
 /* read I2C */
 /* read I2C */
 int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
 int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
@@ -417,29 +391,34 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
 /* init + register i2c algo-bit adapter */
 /* init + register i2c algo-bit adapter */
 int __devinit init_bttv_i2c(struct bttv *btv)
 int __devinit init_bttv_i2c(struct bttv *btv)
 {
 {
-	memcpy(&btv->i2c_client, &bttv_i2c_client_template,
-	       sizeof(bttv_i2c_client_template));
+	strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
 
 
 	if (i2c_hw)
 	if (i2c_hw)
 		btv->use_i2c_hw = 1;
 		btv->use_i2c_hw = 1;
 	if (btv->use_i2c_hw) {
 	if (btv->use_i2c_hw) {
 		/* bt878 */
 		/* bt878 */
-		memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_hw_template,
-		       sizeof(bttv_i2c_adap_hw_template));
+		strlcpy(btv->c.i2c_adap.name, "bt878",
+			sizeof(btv->c.i2c_adap.name));
+		btv->c.i2c_adap.id = I2C_HW_B_BT848;	/* FIXME */
+		btv->c.i2c_adap.algo = &bttv_algo;
 	} else {
 	} else {
 		/* bt848 */
 		/* bt848 */
 	/* Prevents usage of invalid delay values */
 	/* Prevents usage of invalid delay values */
 		if (i2c_udelay<5)
 		if (i2c_udelay<5)
 			i2c_udelay=5;
 			i2c_udelay=5;
-		bttv_i2c_algo_bit_template.udelay=i2c_udelay;
 
 
-		memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template,
-		       sizeof(bttv_i2c_adap_sw_template));
+		strlcpy(btv->c.i2c_adap.name, "bttv",
+			sizeof(btv->c.i2c_adap.name));
+		btv->c.i2c_adap.id = I2C_HW_B_BT848;
 		memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
 		memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
 		       sizeof(bttv_i2c_algo_bit_template));
 		       sizeof(bttv_i2c_algo_bit_template));
+		btv->i2c_algo.udelay = i2c_udelay;
 		btv->i2c_algo.data = btv;
 		btv->i2c_algo.data = btv;
 		btv->c.i2c_adap.algo_data = &btv->i2c_algo;
 		btv->c.i2c_adap.algo_data = &btv->i2c_algo;
 	}
 	}
+	btv->c.i2c_adap.owner = THIS_MODULE;
+	btv->c.i2c_adap.class = I2C_CLASS_TV_ANALOG;
+	btv->c.i2c_adap.client_register = attach_inform;
 
 
 	btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
 	btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
 	snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
 	snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),

+ 3 - 3
drivers/media/video/bt8xx/bttv-vbi.c

@@ -303,7 +303,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
 	return 0;
 	return 0;
 }
 }
 
 
-int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
 {
 {
 	struct bttv_fh *fh = f;
 	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 	struct bttv *btv = fh->btv;
@@ -321,7 +321,7 @@ int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 }
 }
 
 
 
 
-int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
 {
 {
 	struct bttv_fh *fh = f;
 	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 	struct bttv *btv = fh->btv;
@@ -369,7 +369,7 @@ int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 }
 }
 
 
 
 
-int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
 {
 {
 	struct bttv_fh *fh = f;
 	struct bttv_fh *fh = f;
 	const struct bttv_tvnorm *tvnorm;
 	const struct bttv_tvnorm *tvnorm;

+ 0 - 1
drivers/media/video/bt8xx/bttv.h

@@ -299,7 +299,6 @@ extern int bttv_write_gpio(unsigned int card,
 /* ---------------------------------------------------------- */
 /* ---------------------------------------------------------- */
 /* sysfs/driver-moded based gpio access interface             */
 /* sysfs/driver-moded based gpio access interface             */
 
 
-
 struct bttv_sub_device {
 struct bttv_sub_device {
 	struct device    dev;
 	struct device    dev;
 	struct bttv_core *core;
 	struct bttv_core *core;

+ 3 - 6
drivers/media/video/bt8xx/bttvp.h

@@ -39,7 +39,6 @@
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 #include <asm/io.h>
 #include <asm/io.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-common.h>
-
 #include <linux/device.h>
 #include <linux/device.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/tveeprom.h>
 #include <media/tveeprom.h>
@@ -254,21 +253,19 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
 /* ---------------------------------------------------------- */
 /* ---------------------------------------------------------- */
 /* bttv-vbi.c                                                 */
 /* bttv-vbi.c                                                 */
 
 
-int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
-int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
-int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
 
 
 extern struct videobuf_queue_ops bttv_vbi_qops;
 extern struct videobuf_queue_ops bttv_vbi_qops;
 
 
 /* ---------------------------------------------------------- */
 /* ---------------------------------------------------------- */
 /* bttv-gpio.c */
 /* bttv-gpio.c */
 
 
-
 extern struct bus_type bttv_sub_bus_type;
 extern struct bus_type bttv_sub_bus_type;
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_del_devices(struct bttv_core *core);
 int bttv_sub_del_devices(struct bttv_core *core);
 
 
-
 /* ---------------------------------------------------------- */
 /* ---------------------------------------------------------- */
 /* bttv-driver.c                                              */
 /* bttv-driver.c                                              */
 
 

+ 9 - 9
drivers/media/video/cafe_ccic.c

@@ -1593,7 +1593,7 @@ static struct v4l2_pix_format cafe_def_pix_format = {
 	.sizeimage	= VGA_WIDTH*VGA_HEIGHT*2,
 	.sizeimage	= VGA_WIDTH*VGA_HEIGHT*2,
 };
 };
 
 
-static int cafe_vidioc_enum_fmt_cap(struct file *filp,
+static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
 		void *priv, struct v4l2_fmtdesc *fmt)
 		void *priv, struct v4l2_fmtdesc *fmt)
 {
 {
 	struct cafe_camera *cam = priv;
 	struct cafe_camera *cam = priv;
@@ -1608,7 +1608,7 @@ static int cafe_vidioc_enum_fmt_cap(struct file *filp,
 }
 }
 
 
 
 
-static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
+static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
 		struct v4l2_format *fmt)
 		struct v4l2_format *fmt)
 {
 {
 	struct cafe_camera *cam = priv;
 	struct cafe_camera *cam = priv;
@@ -1620,7 +1620,7 @@ static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
 	return ret;
 	return ret;
 }
 }
 
 
-static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
+static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
 		struct v4l2_format *fmt)
 		struct v4l2_format *fmt)
 {
 {
 	struct cafe_camera *cam = priv;
 	struct cafe_camera *cam = priv;
@@ -1635,7 +1635,7 @@ static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
 	/*
 	/*
 	 * See if the formatting works in principle.
 	 * See if the formatting works in principle.
 	 */
 	 */
-	ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt);
+	ret = cafe_vidioc_try_fmt_vid_cap(filp, priv, fmt);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 	/*
 	/*
@@ -1670,7 +1670,7 @@ static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
  * The V4l2 spec wants us to be smarter, and actually get this from
  * The V4l2 spec wants us to be smarter, and actually get this from
  * the camera (and not mess with it at open time).  Someday.
  * the camera (and not mess with it at open time).  Someday.
  */
  */
-static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv,
+static int cafe_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
 		struct v4l2_format *f)
 		struct v4l2_format *f)
 {
 {
 	struct cafe_camera *cam = priv;
 	struct cafe_camera *cam = priv;
@@ -1780,10 +1780,10 @@ static struct video_device cafe_v4l_template = {
 	.release = cafe_v4l_dev_release,
 	.release = cafe_v4l_dev_release,
 
 
 	.vidioc_querycap 	= cafe_vidioc_querycap,
 	.vidioc_querycap 	= cafe_vidioc_querycap,
-	.vidioc_enum_fmt_cap	= cafe_vidioc_enum_fmt_cap,
-	.vidioc_try_fmt_cap	= cafe_vidioc_try_fmt_cap,
-	.vidioc_s_fmt_cap	= cafe_vidioc_s_fmt_cap,
-	.vidioc_g_fmt_cap	= cafe_vidioc_g_fmt_cap,
+	.vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= cafe_vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= cafe_vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= cafe_vidioc_g_fmt_vid_cap,
 	.vidioc_enum_input	= cafe_vidioc_enum_input,
 	.vidioc_enum_input	= cafe_vidioc_enum_input,
 	.vidioc_g_input		= cafe_vidioc_g_input,
 	.vidioc_g_input		= cafe_vidioc_g_input,
 	.vidioc_s_input		= cafe_vidioc_s_input,
 	.vidioc_s_input		= cafe_vidioc_s_input,

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

@@ -884,6 +884,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
 	case VIDIOC_G_INPUT32:
 	case VIDIOC_G_INPUT32:
 	case VIDIOC_S_INPUT32:
 	case VIDIOC_S_INPUT32:
 	case VIDIOC_TRY_FMT32:
 	case VIDIOC_TRY_FMT32:
+	case VIDIOC_S_HW_FREQ_SEEK:
 		ret = do_video_ioctl(file, cmd, arg);
 		ret = do_video_ioctl(file, cmd, arg);
 		break;
 		break;
 
 

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

@@ -173,4 +173,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
 	.probe = cs5345_probe,
 	.probe = cs5345_probe,
 	.id_table = cs5345_id,
 	.id_table = cs5345_id,
 };
 };
-

+ 0 - 2
drivers/media/video/cs53l32a.c

@@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
 
 
 static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
 static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
 
 
-
 I2C_CLIENT_INSMOD;
 I2C_CLIENT_INSMOD;
 
 
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
@@ -189,4 +188,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
 	.probe = cs53l32a_probe,
 	.probe = cs53l32a_probe,
 	.id_table = cs53l32a_id,
 	.id_table = cs53l32a_id,
 };
 };
-

+ 14 - 1
drivers/media/video/cx18/cx18-audio.c

@@ -26,13 +26,17 @@
 #include "cx18-cards.h"
 #include "cx18-cards.h"
 #include "cx18-audio.h"
 #include "cx18-audio.h"
 
 
+#define CX18_AUDIO_ENABLE 0xc72014
+
 /* Selects the audio input and output according to the current
 /* Selects the audio input and output according to the current
    settings. */
    settings. */
 int cx18_audio_set_io(struct cx18 *cx)
 int cx18_audio_set_io(struct cx18 *cx)
 {
 {
 	struct v4l2_routing route;
 	struct v4l2_routing route;
 	u32 audio_input;
 	u32 audio_input;
+	u32 val;
 	int mux_input;
 	int mux_input;
+	int err;
 
 
 	/* Determine which input to use */
 	/* Determine which input to use */
 	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
 	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
@@ -51,8 +55,17 @@ int cx18_audio_set_io(struct cx18 *cx)
 	cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
 	cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
 
 
 	route.input = audio_input;
 	route.input = audio_input;
-	return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+	err = cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
 			VIDIOC_INT_S_AUDIO_ROUTING, &route);
 			VIDIOC_INT_S_AUDIO_ROUTING, &route);
+	if (err)
+		return err;
+
+	val = read_reg(CX18_AUDIO_ENABLE) & ~0x30;
+	val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
+					(audio_input << 4);
+	write_reg(val | 0xb00, CX18_AUDIO_ENABLE);
+	cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
+	return 0;
 }
 }
 
 
 void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
 void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)

+ 6 - 6
drivers/media/video/cx18/cx18-av-audio.c

@@ -34,7 +34,7 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
 	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
 	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
 	cx18_av_write(cx, 0x127, 0x50);
 	cx18_av_write(cx, 0x127, 0x50);
 
 
-	if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
 		switch (freq) {
 		switch (freq) {
 		case 32000:
 		case 32000:
 			/* VID_PLL and AUX_PLL */
 			/* VID_PLL and AUX_PLL */
@@ -148,7 +148,7 @@ void cx18_av_audio_set_path(struct cx18 *cx)
 	/* Mute everything to prevent the PFFT! */
 	/* Mute everything to prevent the PFFT! */
 	cx18_av_write(cx, 0x8d3, 0x1f);
 	cx18_av_write(cx, 0x8d3, 0x1f);
 
 
-	if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
+	if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) {
 		/* Set Path1 to Serial Audio Input */
 		/* Set Path1 to Serial Audio Input */
 		cx18_av_write4(cx, 0x8d0, 0x01011012);
 		cx18_av_write4(cx, 0x8d0, 0x01011012);
 
 
@@ -165,7 +165,7 @@ void cx18_av_audio_set_path(struct cx18 *cx)
 	/* deassert soft reset */
 	/* deassert soft reset */
 	cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
 	cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
 
 
-	if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
 		/* When the microcontroller detects the
 		/* When the microcontroller detects the
 		 * audio format, it will unmute the lines */
 		 * audio format, it will unmute the lines */
 		cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
 		cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
@@ -271,7 +271,7 @@ static void set_mute(struct cx18 *cx, int mute)
 {
 {
 	struct cx18_av_state *state = &cx->av_state;
 	struct cx18_av_state *state = &cx->av_state;
 
 
-	if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
 		/* Must turn off microcontroller in order to mute sound.
 		/* Must turn off microcontroller in order to mute sound.
 		 * Not sure if this is the best method, but it does work.
 		 * Not sure if this is the best method, but it does work.
 		 * If the microcontroller is running, then it will undo any
 		 * If the microcontroller is running, then it will undo any
@@ -298,14 +298,14 @@ int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-		if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+		if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
 			cx18_av_and_or(cx, 0x803, ~0x10, 0);
 			cx18_av_and_or(cx, 0x803, ~0x10, 0);
 			cx18_av_write(cx, 0x8d3, 0x1f);
 			cx18_av_write(cx, 0x8d3, 0x1f);
 		}
 		}
 		cx18_av_and_or(cx, 0x810, ~0x1, 1);
 		cx18_av_and_or(cx, 0x810, ~0x1, 1);
 		retval = set_audclk_freq(cx, *(u32 *)arg);
 		retval = set_audclk_freq(cx, *(u32 *)arg);
 		cx18_av_and_or(cx, 0x810, ~0x1, 0);
 		cx18_av_and_or(cx, 0x810, ~0x1, 0);
-		if (state->aud_input != CX18_AV_AUDIO_SERIAL)
+		if (state->aud_input > CX18_AV_AUDIO_SERIAL2)
 			cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
 			cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
 		return retval;
 		return retval;
 
 

+ 156 - 69
drivers/media/video/cx18/cx18-av-core.c

@@ -69,58 +69,6 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
 			     or_value);
 			     or_value);
 }
 }
 
 
-int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value, int no_acfg_mask)
-{
-	int retval;
-	u32 saved_reg[8] = {0};
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
-		saved_reg[0] = cx18_av_read4(cx, CXADEC_CHIP_CTRL);
-		saved_reg[1] = cx18_av_read4(cx, CXADEC_AFE_CTRL);
-	}
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
-		saved_reg[2] = cx18_av_read4(cx, CXADEC_PLL_CTRL1);
-		saved_reg[3] = cx18_av_read4(cx, CXADEC_VID_PLL_FRAC);
-	}
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
-		saved_reg[4] = cx18_av_read4(cx, CXADEC_HORIZ_TIM_CTRL);
-		saved_reg[5] = cx18_av_read4(cx, CXADEC_VERT_TIM_CTRL);
-		saved_reg[6] = cx18_av_read4(cx, CXADEC_SRC_COMB_CFG);
-		saved_reg[7] = cx18_av_read4(cx, CXADEC_CHROMA_VBIOFF_CFG);
-	}
-
-	retval = cx18_av_write(cx, addr, value);
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
-		cx18_av_write4(cx, CXADEC_CHIP_CTRL, saved_reg[0]);
-		cx18_av_write4(cx, CXADEC_AFE_CTRL,  saved_reg[1]);
-	}
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
-		cx18_av_write4(cx, CXADEC_PLL_CTRL1,    saved_reg[2]);
-		cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, saved_reg[3]);
-	}
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
-		cx18_av_write4(cx, CXADEC_HORIZ_TIM_CTRL,    saved_reg[4]);
-		cx18_av_write4(cx, CXADEC_VERT_TIM_CTRL,     saved_reg[5]);
-		cx18_av_write4(cx, CXADEC_SRC_COMB_CFG,      saved_reg[6]);
-		cx18_av_write4(cx, CXADEC_CHROMA_VBIOFF_CFG, saved_reg[7]);
-	}
-
-	return retval;
-}
-
-int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned and_mask,
-			   u8 or_value, int no_acfg_mask)
-{
-	return cx18_av_write_no_acfg(cx, addr,
-				     (cx18_av_read(cx, addr) & and_mask) |
-				     or_value, no_acfg_mask);
-}
-
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
 
 
 static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
 static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
@@ -132,6 +80,7 @@ static void log_video_status(struct cx18 *cx);
 
 
 static void cx18_av_initialize(struct cx18 *cx)
 static void cx18_av_initialize(struct cx18 *cx)
 {
 {
+	struct cx18_av_state *state = &cx->av_state;
 	u32 v;
 	u32 v;
 
 
 	cx18_av_loadfw(cx);
 	cx18_av_loadfw(cx);
@@ -211,6 +160,149 @@ static void cx18_av_initialize(struct cx18 *cx)
 /*      	CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
 /*      	CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
 /*    } */
 /*    } */
 	cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
 	cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
+	state->default_volume = 228 - cx18_av_read(cx, 0x8d4);
+	state->default_volume = ((state->default_volume / 2) + 23) << 9;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void cx18_av_std_setup(struct cx18 *cx)
+{
+	struct cx18_av_state *state = &cx->av_state;
+	v4l2_std_id std = state->std;
+	int hblank, hactive, burst, vblank, vactive, sc;
+	int vblank656, src_decimation;
+	int luma_lpf, uv_lpf, comb;
+	u32 pll_int, pll_frac, pll_post;
+
+	/* datasheet startup, step 8d */
+	if (std & ~V4L2_STD_NTSC)
+		cx18_av_write(cx, 0x49f, 0x11);
+	else
+		cx18_av_write(cx, 0x49f, 0x14);
+
+	if (std & V4L2_STD_625_50) {
+		hblank = 132;
+		hactive = 720;
+		burst = 93;
+		vblank = 36;
+		vactive = 580;
+		vblank656 = 40;
+		src_decimation = 0x21f;
+
+		luma_lpf = 2;
+		if (std & V4L2_STD_PAL) {
+			uv_lpf = 1;
+			comb = 0x20;
+			sc = 688739;
+		} else if (std == V4L2_STD_PAL_Nc) {
+			uv_lpf = 1;
+			comb = 0x20;
+			sc = 556453;
+		} else { /* SECAM */
+			uv_lpf = 0;
+			comb = 0;
+			sc = 672351;
+		}
+	} else {
+		hactive = 720;
+		hblank = 122;
+		vactive = 487;
+		luma_lpf = 1;
+		uv_lpf = 1;
+		vblank = 26;
+		vblank656 = 26;
+
+		src_decimation = 0x21f;
+		if (std == V4L2_STD_PAL_60) {
+			burst = 0x5b;
+			luma_lpf = 2;
+			comb = 0x20;
+			sc = 688739;
+		} else if (std == V4L2_STD_PAL_M) {
+			burst = 0x61;
+			comb = 0x20;
+			sc = 555452;
+		} else {
+			burst = 0x5b;
+			comb = 0x66;
+			sc = 556063;
+		}
+	}
+
+	/* DEBUG: Displays configured PLL frequency */
+	pll_int = cx18_av_read(cx, 0x108);
+	pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
+	pll_post = cx18_av_read(cx, 0x109);
+	CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
+			pll_int, pll_frac, pll_post);
+
+	if (pll_post) {
+		int fin, fsc;
+		int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
+
+		pll >>= 25;
+		pll /= pll_post;
+		CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
+					pll / 1000000, pll % 1000000);
+		CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
+					pll / 8000000, (pll / 8) % 1000000);
+
+		fin = ((u64)src_decimation * pll) >> 12;
+		CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
+					fin / 1000000, fin % 1000000);
+
+		fsc = (((u64)sc) * pll) >> 24L;
+		CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
+					fsc / 1000000, fsc % 1000000);
+
+		CX18_DEBUG_INFO("hblank %i, hactive %i, "
+			"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+			" sc 0x%06x\n",
+			hblank, hactive, vblank, vactive, vblank656,
+			src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+	}
+
+	/* Sets horizontal blanking delay and active lines */
+	cx18_av_write(cx, 0x470, hblank);
+	cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
+						(hactive << 4)));
+	cx18_av_write(cx, 0x472, hactive >> 4);
+
+	/* Sets burst gate delay */
+	cx18_av_write(cx, 0x473, burst);
+
+	/* Sets vertical blanking delay and active duration */
+	cx18_av_write(cx, 0x474, vblank);
+	cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
+						(vactive << 4)));
+	cx18_av_write(cx, 0x476, vactive >> 4);
+	cx18_av_write(cx, 0x477, vblank656);
+
+	/* Sets src decimation rate */
+	cx18_av_write(cx, 0x478, 0xff & src_decimation);
+	cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
+
+	/* Sets Luma and UV Low pass filters */
+	cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
+
+	/* Enables comb filters */
+	cx18_av_write(cx, 0x47b, comb);
+
+	/* Sets SC Step*/
+	cx18_av_write(cx, 0x47c, sc);
+	cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
+	cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
+
+	/* Sets VBI parameters */
+	if (std & V4L2_STD_625_50) {
+		cx18_av_write(cx, 0x47f, 0x01);
+		state->vbi_line_offset = 5;
+	} else {
+		cx18_av_write(cx, 0x47f, 0x00);
+		state->vbi_line_offset = 8;
+	}
 }
 }
 
 
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
@@ -221,16 +313,9 @@ static void input_change(struct cx18 *cx)
 	v4l2_std_id std = state->std;
 	v4l2_std_id std = state->std;
 
 
 	/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
 	/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
-	if (std & V4L2_STD_SECAM)
-		cx18_av_write_no_acfg(cx, 0x402, 0, CXADEC_NO_ACFG_ALL);
-	else {
-		cx18_av_write_no_acfg(cx, 0x402, 0x04, CXADEC_NO_ACFG_ALL);
-		cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
-	}
-	cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0,
-				CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
-	cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0x60,
-				CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
+	cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+	cx18_av_and_or(cx, 0x401, ~0x60, 0);
+	cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
 
 
 	if (std & V4L2_STD_525_60) {
 	if (std & V4L2_STD_525_60) {
 		if (std == V4L2_STD_NTSC_M_JP) {
 		if (std == V4L2_STD_NTSC_M_JP) {
@@ -300,7 +385,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
 	}
 	}
 
 
 	switch (aud_input) {
 	switch (aud_input) {
-	case CX18_AV_AUDIO_SERIAL:
+	case CX18_AV_AUDIO_SERIAL1:
+	case CX18_AV_AUDIO_SERIAL2:
 		/* do nothing, use serial audio input */
 		/* do nothing, use serial audio input */
 		break;
 		break;
 	case CX18_AV_AUDIO4: reg &= ~0x30; break;
 	case CX18_AV_AUDIO4: reg &= ~0x30; break;
@@ -316,8 +402,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
 
 
 	cx18_av_write(cx, 0x103, reg);
 	cx18_av_write(cx, 0x103, reg);
 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
-	cx18_av_and_or_no_acfg(cx, 0x401, ~0x6, is_composite ? 0 : 0x02,
-				CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
+	cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
 	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
 	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
 	cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
 	cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
 	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
 	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
@@ -373,13 +458,13 @@ static int set_v4lstd(struct cx18 *cx)
 	   This happens for example with the Yuan MPC622. */
 	   This happens for example with the Yuan MPC622. */
 	if (fmt >= 4 && fmt < 8) {
 	if (fmt >= 4 && fmt < 8) {
 		/* Set format to NTSC-M */
 		/* Set format to NTSC-M */
-		cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, 1, CXADEC_NO_ACFG_AFE);
+		cx18_av_and_or(cx, 0x400, ~0xf, 1);
 		/* Turn off LCOMB */
 		/* Turn off LCOMB */
 		cx18_av_and_or(cx, 0x47b, ~6, 0);
 		cx18_av_and_or(cx, 0x47b, ~6, 0);
 	}
 	}
-	cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, fmt, CXADEC_NO_ACFG_AFE);
-	cx18_av_and_or_no_acfg(cx, 0x403, ~0x3, pal_m, CXADEC_NO_ACFG_ALL);
-	cx18_av_vbi_setup(cx);
+	cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20);
+	cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
+	cx18_av_std_setup(cx);
 	input_change(cx);
 	input_change(cx);
 	return 0;
 	return 0;
 }
 }
@@ -618,6 +703,8 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
 
 
 		switch (qc->id) {
 		switch (qc->id) {
 		case V4L2_CID_AUDIO_VOLUME:
 		case V4L2_CID_AUDIO_VOLUME:
+			return v4l2_ctrl_query_fill(qc, 0, 65535,
+				65535 / 100, state->default_volume);
 		case V4L2_CID_AUDIO_MUTE:
 		case V4L2_CID_AUDIO_MUTE:
 		case V4L2_CID_AUDIO_BALANCE:
 		case V4L2_CID_AUDIO_BALANCE:
 		case V4L2_CID_AUDIO_BASS:
 		case V4L2_CID_AUDIO_BASS:

+ 4 - 12
drivers/media/video/cx18/cx18-av-core.h

@@ -62,7 +62,8 @@ enum cx18_av_video_input {
 
 
 enum cx18_av_audio_input {
 enum cx18_av_audio_input {
 	/* Audio inputs: serial or In4-In8 */
 	/* Audio inputs: serial or In4-In8 */
-	CX18_AV_AUDIO_SERIAL,
+	CX18_AV_AUDIO_SERIAL1,
+	CX18_AV_AUDIO_SERIAL2,
 	CX18_AV_AUDIO4 = 4,
 	CX18_AV_AUDIO4 = 4,
 	CX18_AV_AUDIO5,
 	CX18_AV_AUDIO5,
 	CX18_AV_AUDIO6,
 	CX18_AV_AUDIO6,
@@ -78,6 +79,7 @@ struct cx18_av_state {
 	u32 audclk_freq;
 	u32 audclk_freq;
 	int audmode;
 	int audmode;
 	int vbi_line_offset;
 	int vbi_line_offset;
+	int default_volume;
 	u32 id;
 	u32 id;
 	u32 rev;
 	u32 rev;
 	int is_initialized;
 	int is_initialized;
@@ -295,25 +297,16 @@ struct cx18_av_state {
 #define CXADEC_SELECT_AUDIO_STANDARD_FM    0xF9  /* FM radio */
 #define CXADEC_SELECT_AUDIO_STANDARD_FM    0xF9  /* FM radio */
 #define CXADEC_SELECT_AUDIO_STANDARD_AUTO  0xFF  /* Auto detect */
 #define CXADEC_SELECT_AUDIO_STANDARD_AUTO  0xFF  /* Auto detect */
 
 
-/* Flags on what to preserve on write to 0x400-0x403 with cx18_av_.*_no_acfg()*/
-#define CXADEC_NO_ACFG_AFE	0x01 /* Preserve 0x100-0x107 */
-#define CXADEC_NO_ACFG_PLL	0x02 /* Preserve 0x108-0x10f */
-#define CXADEC_NO_ACFG_VID	0x04 /* Preserve 0x470-0x47f */
-#define CXADEC_NO_ACFG_ALL	0x07
-
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
 /* cx18_av-core.c 							   */
 /* cx18_av-core.c 							   */
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
-int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value,
-				int no_acfg_mask);
 u8 cx18_av_read(struct cx18 *cx, u16 addr);
 u8 cx18_av_read(struct cx18 *cx, u16 addr);
 u32 cx18_av_read4(struct cx18 *cx, u16 addr);
 u32 cx18_av_read4(struct cx18 *cx, u16 addr);
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
 int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
 int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
-int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned mask, u8 value,
-				int no_acfg_mask);
 int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
 int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
+void cx18_av_std_setup(struct cx18 *cx);
 
 
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
 /* cx18_av-firmware.c                                                      */
 /* cx18_av-firmware.c                                                      */
@@ -326,7 +319,6 @@ void cx18_av_audio_set_path(struct cx18 *cx);
 
 
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
 /* cx18_av-vbi.c                                                           */
 /* cx18_av-vbi.c                                                           */
-void cx18_av_vbi_setup(struct cx18 *cx);
 int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
 int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
 
 
 #endif
 #endif

+ 45 - 27
drivers/media/video/cx18/cx18-av-firmware.c

@@ -22,6 +22,7 @@
 #include "cx18-driver.h"
 #include "cx18-driver.h"
 #include <linux/firmware.h>
 #include <linux/firmware.h>
 
 
+#define CX18_AUDIO_ENABLE 0xc72014
 #define FWFILE "v4l-cx23418-dig.fw"
 #define FWFILE "v4l-cx23418-dig.fw"
 
 
 int cx18_av_loadfw(struct cx18 *cx)
 int cx18_av_loadfw(struct cx18 *cx)
@@ -31,40 +32,58 @@ int cx18_av_loadfw(struct cx18 *cx)
 	u32 v;
 	u32 v;
 	const u8 *ptr;
 	const u8 *ptr;
 	int i;
 	int i;
+	int retries = 0;
 
 
 	if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
 	if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
 		CX18_ERR("unable to open firmware %s\n", FWFILE);
 		CX18_ERR("unable to open firmware %s\n", FWFILE);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
-	cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
-
-	/* Reset the Mako core (Register is undocumented.) */
-	cx18_av_write4(cx, 0x8100, 0x00010000);
-
-	/* Put the 8051 in reset and enable firmware upload */
-	cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
-
-	ptr = fw->data;
-	size = fw->size;
-
-	for (i = 0; i < size; i++) {
-		u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
-		u32 value = 0;
-		int retries;
-
-		for (retries = 0; retries < 5; retries++) {
-			cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
-			value = cx18_av_read4(cx, CXADEC_DL_CTL);
-			if ((value & 0x3F00) == (dl_control & 0x3F00))
+	/* The firmware load often has byte errors, so allow for several
+	   retries, both at byte level and at the firmware load level. */
+	while (retries < 5) {
+		cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
+		cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
+
+		/* Reset the Mako core (Register is undocumented.) */
+		cx18_av_write4(cx, 0x8100, 0x00010000);
+
+		/* Put the 8051 in reset and enable firmware upload */
+		cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+
+		ptr = fw->data;
+		size = fw->size;
+
+		for (i = 0; i < size; i++) {
+			u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
+			u32 value = 0;
+			int retries;
+
+			for (retries = 0; retries < 5; retries++) {
+				cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+				udelay(10);
+				value = cx18_av_read4(cx, CXADEC_DL_CTL);
+				if (value == dl_control)
+					break;
+				/* Check if we can correct the byte by changing
+				   the address.  We can only write the lower
+				   address byte of the address. */
+				if ((value & 0x3F00) != (dl_control & 0x3F00)) {
+					retries = 5;
+					break;
+				}
+			}
+			if (retries >= 5)
 				break;
 				break;
 		}
 		}
-		if (retries >= 5) {
-			CX18_ERR("unable to load firmware %s\n", FWFILE);
-			release_firmware(fw);
-			return -EIO;
-		}
+		if (i == size)
+			break;
+		retries++;
+	}
+	if (retries >= 5) {
+		CX18_ERR("unable to load firmware %s\n", FWFILE);
+		release_firmware(fw);
+		return -EIO;
 	}
 	}
 
 
 	cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
 	cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
@@ -100,7 +119,6 @@ int cx18_av_loadfw(struct cx18 *cx)
 	   have a name in the spec. */
 	   have a name in the spec. */
 	cx18_av_write4(cx, 0x09CC, 1);
 	cx18_av_write4(cx, 0x09CC, 1);
 
 
-#define CX18_AUDIO_ENABLE            	0xc72014
 	v = read_reg(CX18_AUDIO_ENABLE);
 	v = read_reg(CX18_AUDIO_ENABLE);
 	/* If bit 11 is 1 */
 	/* If bit 11 is 1 */
 	if (v & 0x800)
 	if (v & 0x800)

+ 4 - 148
drivers/media/video/cx18/cx18-av-vbi.c

@@ -83,150 +83,6 @@ static int decode_vps(u8 *dst, u8 *p)
 	return err & 0xf0;
 	return err & 0xf0;
 }
 }
 
 
-void cx18_av_vbi_setup(struct cx18 *cx)
-{
-	struct cx18_av_state *state = &cx->av_state;
-	v4l2_std_id std = state->std;
-	int hblank, hactive, burst, vblank, vactive, sc;
-	int vblank656, src_decimation;
-	int luma_lpf, uv_lpf, comb;
-	u32 pll_int, pll_frac, pll_post;
-
-	/* datasheet startup, step 8d */
-	if (std & ~V4L2_STD_NTSC)
-		cx18_av_write(cx, 0x49f, 0x11);
-	else
-		cx18_av_write(cx, 0x49f, 0x14);
-
-	if (std & V4L2_STD_625_50) {
-		hblank = 0x084;
-		hactive = 0x2d0;
-		burst = 0x5d;
-		vblank = 0x024;
-		vactive = 0x244;
-		vblank656 = 0x28;
-		src_decimation = 0x21f;
-
-		luma_lpf = 2;
-		if (std & V4L2_STD_SECAM) {
-			uv_lpf = 0;
-			comb = 0;
-			sc = 0x0a425f;
-		} else if (std == V4L2_STD_PAL_Nc) {
-			uv_lpf = 1;
-			comb = 0x20;
-			sc = 556453;
-		} else {
-			uv_lpf = 1;
-			comb = 0x20;
-			sc = 0x0a8263;
-		}
-	} else {
-		hactive = 720;
-		hblank = 122;
-		vactive = 487;
-		luma_lpf = 1;
-		uv_lpf = 1;
-
-		src_decimation = 0x21f;
-		if (std == V4L2_STD_PAL_60) {
-			vblank = 26;
-			vblank656 = 26;
-			burst = 0x5b;
-			luma_lpf = 2;
-			comb = 0x20;
-			sc = 0x0a8263;
-		} else if (std == V4L2_STD_PAL_M) {
-			vblank = 20;
-			vblank656 = 24;
-			burst = 0x61;
-			comb = 0x20;
-
-			sc = 555452;
-		} else {
-			vblank = 26;
-			vblank656 = 26;
-			burst = 0x5b;
-			comb = 0x66;
-			sc = 556063;
-		}
-	}
-
-	/* DEBUG: Displays configured PLL frequency */
-	pll_int = cx18_av_read(cx, 0x108);
-	pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
-	pll_post = cx18_av_read(cx, 0x109);
-	CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
-			pll_int, pll_frac, pll_post);
-
-	if (pll_post) {
-		int fin, fsc;
-		int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
-
-		pll >>= 25;
-		pll /= pll_post;
-		CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
-					pll / 1000000, pll % 1000000);
-		CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
-					pll / 8000000, (pll / 8) % 1000000);
-
-		fin = ((u64)src_decimation * pll) >> 12;
-		CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
-					fin / 1000000, fin % 1000000);
-
-		fsc = (((u64)sc) * pll) >> 24L;
-		CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
-					fsc / 1000000, fsc % 1000000);
-
-		CX18_DEBUG_INFO("hblank %i, hactive %i, "
-			"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
-			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
-			" sc 0x%06x\n",
-			hblank, hactive, vblank, vactive, vblank656,
-			src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
-	}
-
-	/* Sets horizontal blanking delay and active lines */
-	cx18_av_write(cx, 0x470, hblank);
-	cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
-						(hactive << 4)));
-	cx18_av_write(cx, 0x472, hactive >> 4);
-
-	/* Sets burst gate delay */
-	cx18_av_write(cx, 0x473, burst);
-
-	/* Sets vertical blanking delay and active duration */
-	cx18_av_write(cx, 0x474, vblank);
-	cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
-						(vactive << 4)));
-	cx18_av_write(cx, 0x476, vactive >> 4);
-	cx18_av_write(cx, 0x477, vblank656);
-
-	/* Sets src decimation rate */
-	cx18_av_write(cx, 0x478, 0xff & src_decimation);
-	cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
-
-	/* Sets Luma and UV Low pass filters */
-	cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
-
-	/* Enables comb filters */
-	cx18_av_write(cx, 0x47b, comb);
-
-	/* Sets SC Step*/
-	cx18_av_write(cx, 0x47c, sc);
-	cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
-	cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
-
-	/* Sets VBI parameters */
-	if (std & V4L2_STD_625_50) {
-		cx18_av_write(cx, 0x47f, 0x01);
-		state->vbi_line_offset = 5;
-	} else {
-		cx18_av_write(cx, 0x47f, 0x00);
-		state->vbi_line_offset = 8;
-	}
-}
-
 int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
 int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
 {
 {
 	struct cx18_av_state *state = &cx->av_state;
 	struct cx18_av_state *state = &cx->av_state;
@@ -292,8 +148,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
 			/* raw VBI */
 			/* raw VBI */
 			memset(svbi, 0, sizeof(*svbi));
 			memset(svbi, 0, sizeof(*svbi));
 
 
-			/* Setup VBI */
-			cx18_av_vbi_setup(cx);
+			/* Setup standard */
+			cx18_av_std_setup(cx);
 
 
 			/* VBI Offset */
 			/* VBI Offset */
 			cx18_av_write(cx, 0x47f, vbi_offset);
 			cx18_av_write(cx, 0x47f, vbi_offset);
@@ -304,8 +160,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
 		for (x = 0; x <= 23; x++)
 		for (x = 0; x <= 23; x++)
 			lcr[x] = 0x00;
 			lcr[x] = 0x00;
 
 
-		/* Setup VBI */
-		cx18_av_vbi_setup(cx);
+		/* Setup standard */
+		cx18_av_std_setup(cx);
 
 
 		/* Sliced VBI */
 		/* Sliced VBI */
 		cx18_av_write(cx, 0x404, 0x32);	/* Ancillary data */
 		cx18_av_write(cx, 0x404, 0x32);	/* Ancillary data */

+ 75 - 14
drivers/media/video/cx18/cx18-cards.c

@@ -27,6 +27,8 @@
 #include "cx18-i2c.h"
 #include "cx18-i2c.h"
 #include <media/cs5345.h>
 #include <media/cs5345.h>
 
 
+#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
+
 /********************** card configuration *******************************/
 /********************** card configuration *******************************/
 
 
 /* usual i2c tuner addresses to probe */
 /* usual i2c tuner addresses to probe */
@@ -65,12 +67,12 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
 		{ CX18_CARD_INPUT_AUD_TUNER,
 		{ CX18_CARD_INPUT_AUD_TUNER,
 		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
 		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
 		{ CX18_CARD_INPUT_LINE_IN1,
 		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
 		{ CX18_CARD_INPUT_LINE_IN2,
 		{ CX18_CARD_INPUT_LINE_IN2,
-		  CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
 	},
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
+			 CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
 	.ddr = {
 	.ddr = {
 		/* ESMT M13S128324A-5B memory */
 		/* ESMT M13S128324A-5B memory */
 		.chip_config = 0x003,
 		.chip_config = 0x003,
@@ -86,6 +88,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
 		.active_lo_mask = 0x3001,
 		.active_lo_mask = 0x3001,
 		.msecs_asserted = 10,
 		.msecs_asserted = 10,
 		.msecs_recovery = 40,
 		.msecs_recovery = 40,
+		.ir_reset_mask  = 0x0001,
 	},
 	},
 	.i2c = &cx18_i2c_std,
 	.i2c = &cx18_i2c_std,
 };
 };
@@ -110,12 +113,12 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
 		{ CX18_CARD_INPUT_AUD_TUNER,
 		{ CX18_CARD_INPUT_AUD_TUNER,
 		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
 		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
 		{ CX18_CARD_INPUT_LINE_IN1,
 		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
 		{ CX18_CARD_INPUT_LINE_IN2,
 		{ CX18_CARD_INPUT_LINE_IN2,
-		  CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
 	},
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
+			 CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
 	.ddr = {
 	.ddr = {
 		/* Samsung K4D263238G-VC33 memory */
 		/* Samsung K4D263238G-VC33 memory */
 		.chip_config = 0x003,
 		.chip_config = 0x003,
@@ -131,6 +134,7 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
 		.active_lo_mask = 0x3001,
 		.active_lo_mask = 0x3001,
 		.msecs_asserted = 10,
 		.msecs_asserted = 10,
 		.msecs_recovery = 40,
 		.msecs_recovery = 40,
+		.ir_reset_mask  = 0x0001,
 	},
 	},
 	.i2c = &cx18_i2c_std,
 	.i2c = &cx18_i2c_std,
 };
 };
@@ -161,10 +165,10 @@ static const struct cx18_card cx18_card_h900 = {
 		{ CX18_CARD_INPUT_AUD_TUNER,
 		{ CX18_CARD_INPUT_AUD_TUNER,
 		  CX18_AV_AUDIO8, 0 },
 		  CX18_AV_AUDIO8, 0 },
 		{ CX18_CARD_INPUT_LINE_IN1,
 		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX18_AV_AUDIO_SERIAL, 0 },
+		  CX18_AV_AUDIO_SERIAL1, 0 },
 	},
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX18_AV_AUDIO_SERIAL, 0 },
+			 CX18_AV_AUDIO_SERIAL1, 0 },
 	.tuners = {
 	.tuners = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 	},
 	},
@@ -194,7 +198,7 @@ static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
 static const struct cx18_card cx18_card_mpc718 = {
 static const struct cx18_card cx18_card_mpc718 = {
 	.type = CX18_CARD_YUAN_MPC718,
 	.type = CX18_CARD_YUAN_MPC718,
 	.name = "Yuan MPC718",
 	.name = "Yuan MPC718",
-	.comment = "Some Composite and S-Video inputs are currently working.\n",
+	.comment = "Analog video capture works; some audio line in may not.\n",
 	.v4l2_capabilities = CX18_CAP_ENCODER,
 	.v4l2_capabilities = CX18_CAP_ENCODER,
 	.hw_audio_ctrl = CX18_HW_CX23418,
 	.hw_audio_ctrl = CX18_HW_CX23418,
 	.hw_all = CX18_HW_TUNER,
 	.hw_all = CX18_HW_TUNER,
@@ -209,11 +213,11 @@ static const struct cx18_card cx18_card_mpc718 = {
 		{ CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 },
 		{ CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 },
 	},
 	},
 	.audio_inputs = {
 	.audio_inputs = {
-		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,       0 },
-		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL, 0 },
-		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL, 0 },
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,        0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 0 },
+		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL1, 0 },
 	},
 	},
-	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL, 0 },
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 0 },
 	.tuners = {
 	.tuners = {
 		/* XC3028 tuner */
 		/* XC3028 tuner */
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
@@ -227,16 +231,73 @@ static const struct cx18_card cx18_card_mpc718 = {
 		.tune_lane = 0,
 		.tune_lane = 0,
 		.initial_emrs = 2,
 		.initial_emrs = 2,
 	},
 	},
-	.xceive_pin = 15,
+	.xceive_pin = 0,
 	.pci_list = cx18_pci_mpc718,
 	.pci_list = cx18_pci_mpc718,
 	.i2c = &cx18_i2c_std,
 	.i2c = &cx18_i2c_std,
 };
 };
 
 
+/* ------------------------------------------------------------------------- */
+
+/* Conexant Raptor PAL/SECAM: note that this card is analog only! */
+
+static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 },
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_cnxt_raptor_pal = {
+	.type = CX18_CARD_CNXT_RAPTOR_PAL,
+	.name = "Conexant Raptor PAL/SECAM",
+	.comment = "VBI is not yet supported\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_CX23418,
+	.hw_muxer = CX18_HW_GPIO,
+	.hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2,
+			CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL2, 1 },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 },
+	.ddr = {
+		/* MT 46V16M16 memory */
+		.chip_config = 0x50306,
+		.refresh = 0x753,
+		.timing1 = 0x33220953,
+		.timing2 = 0x09,
+		.tune_lane = 0,
+		.initial_emrs = 0,
+	},
+	.gpio_init.initial_value = 0x1002,
+	.gpio_init.direction = 0xf002,
+	.gpio_audio_input = { .mask   = 0xf002,
+			      .tuner  = 0x1002,   /* LED D1  Tuner AF  */
+			      .linein = 0x2000,   /* LED D2  Line In 1 */
+			      .radio  = 0x4002 }, /* LED D3  Tuner AF  */
+	.pci_list = cx18_pci_cnxt_raptor_pal,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
 static const struct cx18_card *cx18_card_list[] = {
 static const struct cx18_card *cx18_card_list[] = {
 	&cx18_card_hvr1600_esmt,
 	&cx18_card_hvr1600_esmt,
 	&cx18_card_hvr1600_samsung,
 	&cx18_card_hvr1600_samsung,
 	&cx18_card_h900,
 	&cx18_card_h900,
 	&cx18_card_mpc718,
 	&cx18_card_mpc718,
+	&cx18_card_cnxt_raptor_pal,
 };
 };
 
 
 const struct cx18_card *cx18_get_card(u16 index)
 const struct cx18_card *cx18_get_card(u16 index)

+ 9 - 0
drivers/media/video/cx18/cx18-cards.h

@@ -83,6 +83,14 @@ struct cx18_gpio_i2c_slave_reset {
 	u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
 	u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
 	int msecs_asserted; /* time period reset must remain asserted */
 	int msecs_asserted; /* time period reset must remain asserted */
 	int msecs_recovery; /* time after deassert for chips to be ready */
 	int msecs_recovery; /* time after deassert for chips to be ready */
+	u32 ir_reset_mask;  /* GPIO to reset the Zilog Z8F0811 IR contoller */
+};
+
+struct cx18_gpio_audio_input { 	/* select tuner/line in input */
+	u32 mask; 		/* leave to 0 if not supported */
+	u32 tuner;
+	u32 linein;
+	u32 radio;
 };
 };
 
 
 struct cx18_card_tuner {
 struct cx18_card_tuner {
@@ -123,6 +131,7 @@ struct cx18_card {
 	u8 xceive_pin; 		/* XCeive tuner GPIO reset pin */
 	u8 xceive_pin; 		/* XCeive tuner GPIO reset pin */
 	struct cx18_gpio_init 		 gpio_init;
 	struct cx18_gpio_init 		 gpio_init;
 	struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;
 	struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;
+	struct cx18_gpio_audio_input    gpio_audio_input;
 
 
 	struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
 	struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
 	struct cx18_card_tuner_i2c *i2c;
 	struct cx18_card_tuner_i2c *i2c;

+ 112 - 104
drivers/media/video/cx18/cx18-controls.c

@@ -51,12 +51,11 @@ static const u32 *ctrl_classes[] = {
 	NULL
 	NULL
 };
 };
 
 
-static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
+int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
 {
 {
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 	const char *name;
 	const char *name;
 
 
-	CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
-
 	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
 	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
 	if (qctrl->id == 0)
 	if (qctrl->id == 0)
 		return -EINVAL;
 		return -EINVAL;
@@ -91,21 +90,35 @@ static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
 	return 0;
 	return 0;
 }
 }
 
 
-static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu)
+int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
 {
 {
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 	struct v4l2_queryctrl qctrl;
 	struct v4l2_queryctrl qctrl;
 
 
 	qctrl.id = qmenu->id;
 	qctrl.id = qmenu->id;
-	cx18_queryctrl(cx, &qctrl);
-	return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+	cx18_queryctrl(file, fh, &qctrl);
+	return v4l2_ctrl_query_menu(qmenu, &qctrl,
+			cx2341x_ctrl_get_menu(&cx->params, qmenu->id));
 }
 }
 
 
-static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+static int cx18_try_ctrl(struct file *file, void *fh,
+					struct v4l2_ext_control *vctrl)
 {
 {
-	s32 v = vctrl->value;
-
-	CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
+	struct v4l2_queryctrl qctrl;
+	const char **menu_items = NULL;
+	int err;
+
+	qctrl.id = vctrl->id;
+	err = cx18_queryctrl(file, fh, &qctrl);
+	if (err)
+		return err;
+	if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+		menu_items = v4l2_ctrl_get_menu(qctrl.id);
+	return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
+}
 
 
+static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+{
 	switch (vctrl->id) {
 	switch (vctrl->id) {
 		/* Standard V4L2 controls */
 		/* Standard V4L2 controls */
 	case V4L2_CID_BRIGHTNESS:
 	case V4L2_CID_BRIGHTNESS:
@@ -123,7 +136,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
 		return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
 		return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
 
 
 	default:
 	default:
-		CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+		CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	return 0;
 	return 0;
@@ -131,8 +144,6 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
 
 
 static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
 static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
 {
 {
-	CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
-
 	switch (vctrl->id) {
 	switch (vctrl->id) {
 		/* Standard V4L2 controls */
 		/* Standard V4L2 controls */
 	case V4L2_CID_BRIGHTNESS:
 	case V4L2_CID_BRIGHTNESS:
@@ -149,7 +160,7 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
 	case V4L2_CID_AUDIO_LOUDNESS:
 	case V4L2_CID_AUDIO_LOUDNESS:
 		return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
 		return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
 	default:
 	default:
-		CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+		CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	return 0;
 	return 0;
@@ -194,113 +205,110 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
 	return 0;
 	return 0;
 }
 }
 
 
-int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
+int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 {
 {
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 	struct v4l2_control ctrl;
 	struct v4l2_control ctrl;
 
 
-	switch (cmd) {
-	case VIDIOC_QUERYMENU:
-		CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
-		return cx18_querymenu(cx, arg);
-
-	case VIDIOC_QUERYCTRL:
-		return cx18_queryctrl(cx, arg);
-
-	case VIDIOC_S_CTRL:
-		return cx18_s_ctrl(cx, arg);
-
-	case VIDIOC_G_CTRL:
-		return cx18_g_ctrl(cx, arg);
-
-	case VIDIOC_S_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *c = arg;
-
-		if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
-			int i;
-			int err = 0;
-
-			for (i = 0; i < c->count; i++) {
-				ctrl.id = c->controls[i].id;
-				ctrl.value = c->controls[i].value;
-				err = cx18_s_ctrl(cx, &ctrl);
-				c->controls[i].value = ctrl.value;
-				if (err) {
-					c->error_idx = i;
-					break;
-				}
+	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+		int i;
+		int err = 0;
+
+		for (i = 0; i < c->count; i++) {
+			ctrl.id = c->controls[i].id;
+			ctrl.value = c->controls[i].value;
+			err = cx18_g_ctrl(cx, &ctrl);
+			c->controls[i].value = ctrl.value;
+			if (err) {
+				c->error_idx = i;
+				break;
 			}
 			}
-			return err;
 		}
 		}
-		CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
-		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
-			struct cx2341x_mpeg_params p = cx->params;
-			int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd);
+		return err;
+	}
+	if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+		return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS);
+	return -EINVAL;
+}
 
 
-			if (err)
-				return err;
+int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+	struct v4l2_control ctrl;
 
 
-			if (p.video_encoding != cx->params.video_encoding) {
-				int is_mpeg1 = p.video_encoding ==
-						V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
-				struct v4l2_format fmt;
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
 
 
-				/* fix videodecoder resolution */
-				fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-				fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1);
-				fmt.fmt.pix.height = cx->params.height;
-				cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
+	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+		int i;
+		int err = 0;
+
+		for (i = 0; i < c->count; i++) {
+			ctrl.id = c->controls[i].id;
+			ctrl.value = c->controls[i].value;
+			err = cx18_s_ctrl(cx, &ctrl);
+			c->controls[i].value = ctrl.value;
+			if (err) {
+				c->error_idx = i;
+				break;
 			}
 			}
-			err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
-			if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
-				err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
-			cx->params = p;
-			cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
-			cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
-			return err;
 		}
 		}
-		return -EINVAL;
+		return err;
 	}
 	}
+	if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+		struct cx2341x_mpeg_params p = cx->params;
+		int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
+						c, VIDIOC_S_EXT_CTRLS);
 
 
-	case VIDIOC_G_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *c = arg;
-
-		if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
-			int i;
-			int err = 0;
-
-			for (i = 0; i < c->count; i++) {
-				ctrl.id = c->controls[i].id;
-				ctrl.value = c->controls[i].value;
-				err = cx18_g_ctrl(cx, &ctrl);
-				c->controls[i].value = ctrl.value;
-				if (err) {
-					c->error_idx = i;
-					break;
-				}
-			}
+		if (err)
 			return err;
 			return err;
+
+		if (p.video_encoding != cx->params.video_encoding) {
+			int is_mpeg1 = p.video_encoding ==
+						V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+			struct v4l2_format fmt;
+
+			/* fix videodecoder resolution */
+			fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			fmt.fmt.pix.width = cx->params.width
+						/ (is_mpeg1 ? 2 : 1);
+			fmt.fmt.pix.height = cx->params.height;
+			cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
 		}
 		}
-		CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
-		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-			return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd);
-		return -EINVAL;
+		err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
+		if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
+			err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+		cx->params = p;
+		cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+		cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
+		return err;
 	}
 	}
+	return -EINVAL;
+}
 
 
-	case VIDIOC_TRY_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *c = arg;
+int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-		CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
-		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-			return cx2341x_ext_ctrls(&cx->params,
-					atomic_read(&cx->ana_capturing), arg, cmd);
-		return -EINVAL;
-	}
+	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+		int i;
+		int err = 0;
 
 
-	default:
-		return -EINVAL;
+		for (i = 0; i < c->count; i++) {
+			err = cx18_try_ctrl(file, fh, &c->controls[i]);
+			if (err) {
+				c->error_idx = i;
+				break;
+			}
+		}
+		return err;
 	}
 	}
-	return 0;
+	if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+		return cx2341x_ext_ctrls(&cx->params,
+						atomic_read(&cx->ana_capturing),
+						c, VIDIOC_TRY_EXT_CTRLS);
+	return -EINVAL;
 }
 }

+ 6 - 1
drivers/media/video/cx18/cx18-controls.h

@@ -21,4 +21,9 @@
  *  02111-1307  USA
  *  02111-1307  USA
  */
  */
 
 
-int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg);
+int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
+int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int cx18_try_ext_ctrls(struct file *file, void *fh,
+			struct v4l2_ext_controls *a);
+int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);

+ 16 - 5
drivers/media/video/cx18/cx18-driver.c

@@ -120,6 +120,7 @@ MODULE_PARM_DESC(cardtype,
 		 "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
 		 "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
 		 "\t\t\t 3 = Compro VideoMate H900\n"
 		 "\t\t\t 3 = Compro VideoMate H900\n"
 		 "\t\t\t 4 = Yuan MPC718\n"
 		 "\t\t\t 4 = Yuan MPC718\n"
+		 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t-1 = Ignore this card\n\t\t");
 		 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -420,6 +421,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
 	mutex_init(&cx->serialize_lock);
 	mutex_init(&cx->serialize_lock);
 	mutex_init(&cx->i2c_bus_lock[0]);
 	mutex_init(&cx->i2c_bus_lock[0]);
 	mutex_init(&cx->i2c_bus_lock[1]);
 	mutex_init(&cx->i2c_bus_lock[1]);
+	mutex_init(&cx->gpio_lock);
 
 
 	spin_lock_init(&cx->lock);
 	spin_lock_init(&cx->lock);
 	spin_lock_init(&cx->dma_reg_lock);
 	spin_lock_init(&cx->dma_reg_lock);
@@ -435,7 +437,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
 		(cx->params.video_temporal_filter_mode << 1) |
 		(cx->params.video_temporal_filter_mode << 1) |
 		(cx->params.video_median_filter_type << 2);
 		(cx->params.video_median_filter_type << 2);
 	cx->params.port = CX2341X_PORT_MEMORY;
 	cx->params.port = CX2341X_PORT_MEMORY;
-	cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+	cx->params.capabilities = CX2341X_CAP_HAS_TS;
 	init_waitqueue_head(&cx->cap_w);
 	init_waitqueue_head(&cx->cap_w);
 	init_waitqueue_head(&cx->mb_apu_waitq);
 	init_waitqueue_head(&cx->mb_apu_waitq);
 	init_waitqueue_head(&cx->mb_cpu_waitq);
 	init_waitqueue_head(&cx->mb_cpu_waitq);
@@ -614,7 +616,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
 	cx18_cards[cx18_cards_active] = cx;
 	cx18_cards[cx18_cards_active] = cx;
 	cx->dev = dev;
 	cx->dev = dev;
 	cx->num = cx18_cards_active++;
 	cx->num = cx18_cards_active++;
-	snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num);
+	snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num);
 	CX18_INFO("Initializing card #%d\n", cx->num);
 	CX18_INFO("Initializing card #%d\n", cx->num);
 
 
 	spin_unlock(&cx18_cards_lock);
 	spin_unlock(&cx18_cards_lock);
@@ -721,6 +723,12 @@ static int __devinit cx18_probe(struct pci_dev *dev,
 	/* if no tuner was found, then pick the first tuner in the card list */
 	/* if no tuner was found, then pick the first tuner in the card list */
 	if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
 	if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
 		cx->std = cx->card->tuners[0].std;
 		cx->std = cx->card->tuners[0].std;
+		if (cx->std & V4L2_STD_PAL)
+			cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+		else if (cx->std & V4L2_STD_NTSC)
+			cx->std = V4L2_STD_NTSC_M;
+		else if (cx->std & V4L2_STD_SECAM)
+			cx->std = V4L2_STD_SECAM_L;
 		cx->options.tuner = cx->card->tuners[0].tuner;
 		cx->options.tuner = cx->card->tuners[0].tuner;
 	}
 	}
 	if (cx->options.radio == -1)
 	if (cx->options.radio == -1)
@@ -818,6 +826,9 @@ int cx18_init_on_first_open(struct cx18 *cx)
 	int video_input;
 	int video_input;
 	int fw_retry_count = 3;
 	int fw_retry_count = 3;
 	struct v4l2_frequency vf;
 	struct v4l2_frequency vf;
+	struct cx18_open_id fh;
+
+	fh.cx = cx;
 
 
 	if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
 	if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
 		return -ENXIO;
 		return -ENXIO;
@@ -869,13 +880,13 @@ int cx18_init_on_first_open(struct cx18 *cx)
 
 
 	video_input = cx->active_input;
 	video_input = cx->active_input;
 	cx->active_input++;	/* Force update of input */
 	cx->active_input++;	/* Force update of input */
-	cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input);
+	cx18_s_input(NULL, &fh, video_input);
 
 
 	/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
 	/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
 	   in one place. */
 	   in one place. */
 	cx->std++;		/* Force full standard initialization */
 	cx->std++;		/* Force full standard initialization */
-	cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std);
-	cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf);
+	cx18_s_std(NULL, &fh, &cx->tuner_std);
+	cx18_s_frequency(NULL, &fh, &vf);
 	return 0;
 	return 0;
 }
 }
 
 

+ 4 - 3
drivers/media/video/cx18/cx18-driver.h

@@ -75,7 +75,8 @@
 #define CX18_CARD_HVR_1600_SAMSUNG    1	/* Hauppauge HVR 1600 (Samsung memory) */
 #define CX18_CARD_HVR_1600_SAMSUNG    1	/* Hauppauge HVR 1600 (Samsung memory) */
 #define CX18_CARD_COMPRO_H900 	      2	/* Compro VideoMate H900 */
 #define CX18_CARD_COMPRO_H900 	      2	/* Compro VideoMate H900 */
 #define CX18_CARD_YUAN_MPC718 	      3	/* Yuan MPC718 */
 #define CX18_CARD_YUAN_MPC718 	      3	/* Yuan MPC718 */
-#define CX18_CARD_LAST 		      3
+#define CX18_CARD_CNXT_RAPTOR_PAL     4	/* Conexant Raptor PAL */
+#define CX18_CARD_LAST 		      4
 
 
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_TS   1
 #define CX18_ENC_STREAM_TYPE_TS   1
@@ -94,6 +95,7 @@
 #define CX18_PCI_ID_HAUPPAUGE 		0x0070
 #define CX18_PCI_ID_HAUPPAUGE 		0x0070
 #define CX18_PCI_ID_COMPRO 		0x185b
 #define CX18_PCI_ID_COMPRO 		0x185b
 #define CX18_PCI_ID_YUAN 		0x12ab
 #define CX18_PCI_ID_YUAN 		0x12ab
+#define CX18_PCI_ID_CONEXANT		0x14f1
 
 
 /* ======================================================================== */
 /* ======================================================================== */
 /* ========================== START USER SETTABLE DMA VARIABLES =========== */
 /* ========================== START USER SETTABLE DMA VARIABLES =========== */
@@ -228,9 +230,7 @@ struct cx18_dvb {
 	struct dvb_net dvbnet;
 	struct dvb_net dvbnet;
 	int enabled;
 	int enabled;
 	int feeding;
 	int feeding;
-
 	struct mutex feedlock;
 	struct mutex feedlock;
-
 };
 };
 
 
 struct cx18;	 /* forward reference */
 struct cx18;	 /* forward reference */
@@ -427,6 +427,7 @@ struct cx18 {
 	/* gpio */
 	/* gpio */
 	u32 gpio_dir;
 	u32 gpio_dir;
 	u32 gpio_val;
 	u32 gpio_val;
+	struct mutex gpio_lock;
 
 
 	/* v4l2 and User settings */
 	/* v4l2 and User settings */
 
 

+ 6 - 4
drivers/media/video/cx18/cx18-firmware.c

@@ -41,9 +41,6 @@
 
 
 #define CX18_REG_BUS_TIMEOUT_EN      	0xc72024
 #define CX18_REG_BUS_TIMEOUT_EN      	0xc72024
 
 
-#define CX18_AUDIO_ENABLE            	0xc72014
-#define CX18_REG_BUS_TIMEOUT_EN      	0xc72024
-
 #define CX18_FAST_CLOCK_PLL_INT      	0xc78000
 #define CX18_FAST_CLOCK_PLL_INT      	0xc78000
 #define CX18_FAST_CLOCK_PLL_FRAC     	0xc78004
 #define CX18_FAST_CLOCK_PLL_FRAC     	0xc78004
 #define CX18_FAST_CLOCK_PLL_POST     	0xc78008
 #define CX18_FAST_CLOCK_PLL_POST     	0xc78008
@@ -90,7 +87,7 @@
 #define CX18_DSP0_INTERRUPT_MASK     	0xd0004C
 #define CX18_DSP0_INTERRUPT_MASK     	0xd0004C
 
 
 /* Encoder/decoder firmware sizes */
 /* Encoder/decoder firmware sizes */
-#define CX18_FW_CPU_SIZE 		(174716)
+#define CX18_FW_CPU_SIZE 		(158332)
 #define CX18_FW_APU_SIZE 		(141200)
 #define CX18_FW_APU_SIZE 		(141200)
 
 
 #define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
 #define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
@@ -345,6 +342,11 @@ int cx18_firmware_init(struct cx18 *cx)
 		int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
 		int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
 			       cx->enc_mem, cx, CX18_FW_APU_SIZE);
 			       cx->enc_mem, cx, CX18_FW_APU_SIZE);
 
 
+		write_enc(0xE51FF004, 0);
+		write_enc(0xa00000, 4);  /* todo: not hardcoded */
+		write_reg(0x00010000, CX18_PROC_SOFT_RESET); /* Start APU */
+		cx18_msleep_timeout(500, 0);
+
 		sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
 		sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
 					cx->enc_mem, cx, CX18_FW_CPU_SIZE);
 					cx->enc_mem, cx, CX18_FW_CPU_SIZE);
 
 

+ 88 - 2
drivers/media/video/cx18/cx18-gpio.c

@@ -69,6 +69,7 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
 	/* Assuming that the masks are a subset of the bits in gpio_dir */
 	/* Assuming that the masks are a subset of the bits in gpio_dir */
 
 
 	/* Assert */
 	/* Assert */
+	mutex_lock(&cx->gpio_lock);
 	cx->gpio_val =
 	cx->gpio_val =
 		(cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
 		(cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
 	gpio_write(cx);
 	gpio_write(cx);
@@ -79,10 +80,53 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
 		(cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
 		(cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
 	gpio_write(cx);
 	gpio_write(cx);
 	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
 	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+	mutex_unlock(&cx->gpio_lock);
 }
 }
 
 
+void cx18_reset_ir_gpio(void *data)
+{
+	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+	const struct cx18_gpio_i2c_slave_reset *p;
+
+	p = &cx->card->gpio_i2c_slave_reset;
+
+	if (p->ir_reset_mask == 0)
+		return;
+
+	CX18_DEBUG_INFO("Resetting IR microcontroller\n");
+
+	/*
+	   Assert timing for the Z8F0811 on HVR-1600 boards:
+	   1. Assert RESET for min of 4 clock cycles at 18.432 MHz to initiate
+	   2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock cycles
+		(6,601,085 nanoseconds ~= 7 milliseconds)
+	   3. DBG pin must be high before chip exits reset for normal operation.
+		DBG is open drain and hopefully pulled high since we don't
+		normally drive it (GPIO 1?) for the HVR-1600
+	   4. Z8F0811 won't exit reset until RESET is deasserted
+	*/
+	mutex_lock(&cx->gpio_lock);
+	cx->gpio_val = cx->gpio_val & ~p->ir_reset_mask;
+	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
+	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
+
+	/*
+	   Zilog comes out of reset, loads reset vector address and executes
+	   from there. Required recovery delay unknown.
+	*/
+	mutex_lock(&cx->gpio_lock);
+	cx->gpio_val = cx->gpio_val | p->ir_reset_mask;
+	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
+	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+}
+EXPORT_SYMBOL(cx18_reset_ir_gpio);
+/* This symbol is exported for use by an infrared module for the IR-blaster */
+
 void cx18_gpio_init(struct cx18 *cx)
 void cx18_gpio_init(struct cx18 *cx)
 {
 {
+	mutex_lock(&cx->gpio_lock);
 	cx->gpio_dir = cx->card->gpio_init.direction;
 	cx->gpio_dir = cx->card->gpio_init.direction;
 	cx->gpio_val = cx->card->gpio_init.initial_value;
 	cx->gpio_val = cx->card->gpio_init.initial_value;
 
 
@@ -91,14 +135,17 @@ void cx18_gpio_init(struct cx18 *cx)
 		cx->gpio_val |= 1 << cx->card->xceive_pin;
 		cx->gpio_val |= 1 << cx->card->xceive_pin;
 	}
 	}
 
 
-	if (cx->gpio_dir == 0)
+	if (cx->gpio_dir == 0) {
+		mutex_unlock(&cx->gpio_lock);
 		return;
 		return;
+	}
 
 
 	CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
 	CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
 		   read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
 		   read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
 		   read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
 		   read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
 
 
 	gpio_write(cx);
 	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
 }
 }
 
 
 /* Xceive tuner reset function */
 /* Xceive tuner reset function */
@@ -112,13 +159,52 @@ int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
 		return 0;
 		return 0;
 	CX18_DEBUG_INFO("Resetting tuner\n");
 	CX18_DEBUG_INFO("Resetting tuner\n");
 
 
+	mutex_lock(&cx->gpio_lock);
 	cx->gpio_val &= ~(1 << cx->card->xceive_pin);
 	cx->gpio_val &= ~(1 << cx->card->xceive_pin);
-
 	gpio_write(cx);
 	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
 	schedule_timeout_interruptible(msecs_to_jiffies(1));
 	schedule_timeout_interruptible(msecs_to_jiffies(1));
 
 
+	mutex_lock(&cx->gpio_lock);
 	cx->gpio_val |= 1 << cx->card->xceive_pin;
 	cx->gpio_val |= 1 << cx->card->xceive_pin;
 	gpio_write(cx);
 	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
 	schedule_timeout_interruptible(msecs_to_jiffies(1));
 	schedule_timeout_interruptible(msecs_to_jiffies(1));
 	return 0;
 	return 0;
 }
 }
+
+int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg)
+{
+	struct v4l2_routing *route = arg;
+	u32 mask, data;
+
+	switch (command) {
+	case VIDIOC_INT_S_AUDIO_ROUTING:
+		if (route->input > 2)
+			return -EINVAL;
+		mask = cx->card->gpio_audio_input.mask;
+		switch (route->input) {
+		case 0:
+			data = cx->card->gpio_audio_input.tuner;
+			break;
+		case 1:
+			data = cx->card->gpio_audio_input.linein;
+			break;
+		case 2:
+		default:
+			data = cx->card->gpio_audio_input.radio;
+			break;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	if (mask) {
+		mutex_lock(&cx->gpio_lock);
+		cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
+		gpio_write(cx);
+		mutex_unlock(&cx->gpio_lock);
+	}
+	return 0;
+}

+ 2 - 0
drivers/media/video/cx18/cx18-gpio.h

@@ -22,4 +22,6 @@
 
 
 void cx18_gpio_init(struct cx18 *cx);
 void cx18_gpio_init(struct cx18 *cx);
 void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
 void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
+void cx18_reset_ir_gpio(void *data);
 int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
 int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
+int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);

+ 20 - 5
drivers/media/video/cx18/cx18-i2c.c

@@ -39,10 +39,6 @@
 #define GETSCL_BIT      0x0004
 #define GETSCL_BIT      0x0004
 #define GETSDL_BIT      0x0008
 #define GETSDL_BIT      0x0008
 
 
-#ifndef I2C_ADAP_CLASS_TV_ANALOG
-#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
-#endif
-
 #define CX18_CS5345_I2C_ADDR		0x4c
 #define CX18_CS5345_I2C_ADDR		0x4c
 
 
 /* This array should match the CX18_HW_ defines */
 /* This array should match the CX18_HW_ defines */
@@ -311,8 +307,12 @@ int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
 {
 {
 	int addr;
 	int addr;
 
 
-	if (hw == CX18_HW_GPIO || hw == 0)
+	if (hw == 0)
 		return 0;
 		return 0;
+
+	if (hw == CX18_HW_GPIO)
+		return cx18_gpio(cx, cmd, arg);
+
 	if (hw == CX18_HW_CX23418)
 	if (hw == CX18_HW_CX23418)
 		return cx18_av_cmd(cx, cmd, arg);
 		return cx18_av_cmd(cx, cmd, arg);
 
 
@@ -350,6 +350,8 @@ void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
 	cx18_av_cmd(cx, cmd, arg);
 	cx18_av_cmd(cx, cmd, arg);
 	i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
 	i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
 	i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
 	i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
+	if (cx->hw_flags & CX18_HW_GPIO)
+		cx18_gpio(cx, cmd, arg);
 }
 }
 
 
 /* init + register i2c algo-bit adapter */
 /* init + register i2c algo-bit adapter */
@@ -358,6 +360,18 @@ int init_cx18_i2c(struct cx18 *cx)
 	int i;
 	int i;
 	CX18_DEBUG_I2C("i2c init\n");
 	CX18_DEBUG_I2C("i2c init\n");
 
 
+	/* Sanity checks for the I2C hardware arrays. They must be the
+	 * same size and GPIO/CX23418 must be the last entries.
+	 */
+	if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
+	    ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
+	    CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) ||
+	    CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
+	    hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+		CX18_ERR("Mismatched I2C hardware arrays\n");
+		return -ENODEV;
+	}
+
 	for (i = 0; i < 2; i++) {
 	for (i = 0; i < 2; i++) {
 		memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
 		memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
 			sizeof(struct i2c_adapter));
 			sizeof(struct i2c_adapter));
@@ -391,6 +405,7 @@ int init_cx18_i2c(struct cx18 *cx)
 	write_reg_sync(0x00c000c0, 0xc7001c);
 	write_reg_sync(0x00c000c0, 0xc7001c);
 	mdelay(10);
 	mdelay(10);
 	write_reg_sync(0x00c00000, 0xc7001c);
 	write_reg_sync(0x00c00000, 0xc7001c);
+	mdelay(10);
 
 
 	write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
 	write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
 	write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
 	write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */

+ 582 - 597
drivers/media/video/cx18/cx18-ioctl.c

@@ -100,19 +100,6 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
 	}
 	}
 }
 }
 
 
-static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
-{
-	int f, l;
-	u16 set = 0;
-
-	for (f = 0; f < 2; f++) {
-		for (l = 0; l < 24; l++) {
-			fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
-			set |= fmt->service_lines[f][l];
-		}
-	}
-	return set != 0;
-}
 
 
 u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 {
 {
@@ -126,35 +113,167 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 	return set;
 	return set;
 }
 }
 
 
-static const struct {
-	v4l2_std_id  std;
-	char        *name;
-} enum_stds[] = {
-	{ V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
-	{ V4L2_STD_PAL_DK,    "PAL-DK"    },
-	{ V4L2_STD_PAL_I,     "PAL-I"     },
-	{ V4L2_STD_PAL_M,     "PAL-M"     },
-	{ V4L2_STD_PAL_N,     "PAL-N"     },
-	{ V4L2_STD_PAL_Nc,    "PAL-Nc"    },
-	{ V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
-	{ V4L2_STD_SECAM_DK,  "SECAM-DK"  },
-	{ V4L2_STD_SECAM_L,   "SECAM-L"   },
-	{ V4L2_STD_SECAM_LC,  "SECAM-L'"  },
-	{ V4L2_STD_NTSC_M,    "NTSC-M"    },
-	{ V4L2_STD_NTSC_M_JP, "NTSC-J"    },
-	{ V4L2_STD_NTSC_M_KR, "NTSC-K"    },
-};
-
-static const struct v4l2_standard cx18_std_60hz = {
-	.frameperiod = {.numerator = 1001, .denominator = 30000},
-	.framelines = 525,
-};
-
-static const struct v4l2_standard cx18_std_50hz = {
-	.frameperiod = { .numerator = 1, .denominator = 25 },
-	.framelines = 625,
-};
+static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	pixfmt->width = cx->params.width;
+	pixfmt->height = cx->params.height;
+	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pixfmt->field = V4L2_FIELD_INTERLACED;
+	pixfmt->priv = 0;
+	if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+		pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+		/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+		pixfmt->sizeimage =
+			pixfmt->height * pixfmt->width +
+			pixfmt->height * (pixfmt->width / 2);
+		pixfmt->bytesperline = 720;
+	} else {
+		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+		pixfmt->sizeimage = 128 * 1024;
+		pixfmt->bytesperline = 0;
+	}
+	return 0;
+}
+
+static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+	struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
+
+	vbifmt->sampling_rate = 27000000;
+	vbifmt->offset = 248;
+	vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+	vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+	vbifmt->start[0] = cx->vbi.start[0];
+	vbifmt->start[1] = cx->vbi.start[1];
+	vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
+	vbifmt->flags = 0;
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	return 0;
+}
+
+static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_format *fmt)
+{
+	return -EINVAL;
+}
+
+static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+
+	int w = fmt->fmt.pix.width;
+	int h = fmt->fmt.pix.height;
+
+	w = min(w, 720);
+	w = max(w, 1);
+	h = min(h, cx->is_50hz ? 576 : 480);
+	h = max(h, 2);
+	cx18_g_fmt_vid_cap(file, fh, fmt);
+	fmt->fmt.pix.width = w;
+	fmt->fmt.pix.height = h;
+	return 0;
+}
+
+static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_format *fmt)
+{
+	return -EINVAL;
+}
+
+static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+	int w = fmt->fmt.pix.width;
+	int h = fmt->fmt.pix.height;
+
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	ret = cx18_try_fmt_vid_cap(file, fh, fmt);
+	if (ret)
+		return ret;
+
+	if (cx->params.width == w && cx->params.height == h)
+		return 0;
+
+	if (atomic_read(&cx->ana_capturing) > 0)
+		return -EBUSY;
+
+	cx->params.width = w;
+	cx->params.height = h;
+	cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+	return cx18_g_fmt_vid_cap(file, fh, fmt);
+}
+
+static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
+			cx->vbi.sliced_in->service_set &&
+			atomic_read(&cx->ana_capturing) > 0)
+		return -EBUSY;
+
+	cx->vbi.sliced_in->service_set = 0;
+	cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+	return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_format *fmt)
+{
+	return -EINVAL;
+}
 
 
+static int cx18_g_chip_ident(struct file *file, void *fh,
+				struct v4l2_chip_ident *chip)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
+		if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
+			chip->ident = V4L2_IDENT_CX23418;
+		return 0;
+	}
+	if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT,
+					chip);
+	if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+		return cx18_call_i2c_client(cx, chip->match_chip,
+						VIDIOC_G_CHIP_IDENT, chip);
+	return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
 static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
 static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
 {
 {
 	struct v4l2_register *regs = arg;
 	struct v4l2_register *regs = arg;
@@ -174,665 +293,478 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
 	return 0;
 	return 0;
 }
 }
 
 
-static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt)
-{
-	switch (fmt->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		fmt->fmt.pix.width = cx->params.width;
-		fmt->fmt.pix.height = cx->params.height;
-		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
-		if (streamtype == CX18_ENC_STREAM_TYPE_YUV) {
-			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
-			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-			fmt->fmt.pix.sizeimage =
-				fmt->fmt.pix.height * fmt->fmt.pix.width +
-				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
-		} else {
-			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
-			fmt->fmt.pix.sizeimage = 128 * 1024;
-		}
-		break;
-
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		fmt->fmt.vbi.sampling_rate = 27000000;
-		fmt->fmt.vbi.offset = 248;
-		fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4;
-		fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
-		fmt->fmt.vbi.start[0] = cx->vbi.start[0];
-		fmt->fmt.vbi.start[1] = cx->vbi.start[1];
-		fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count;
-		break;
+static int cx18_g_register(struct file *file, void *fh,
+				struct v4l2_register *reg)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
+	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
+					reg);
+	return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
+					reg);
+}
 
 
-	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-	{
-		struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+static int cx18_s_register(struct file *file, void *fh,
+				struct v4l2_register *reg)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
+	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
+					reg);
+	return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
+					reg);
+}
+#endif
 
 
-		vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-		memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
-		memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-		cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
-		vbifmt->service_set = cx18_get_service_set(vbifmt);
-		break;
-	}
-	default:
-		return -EINVAL;
-	}
+	*p = v4l2_prio_max(&cx->prio);
 	return 0;
 	return 0;
 }
 }
 
 
-static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
-		struct v4l2_format *fmt, int set_fmt)
+static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
 {
 {
-	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
-	u16 set;
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
 
 
-	/* set window size */
-	if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		int w = fmt->fmt.pix.width;
-		int h = fmt->fmt.pix.height;
+	return v4l2_prio_change(&cx->prio, &id->prio, prio);
+}
 
 
-		if (w > 720)
-			w = 720;
-		else if (w < 1)
-			w = 1;
-		if (h > (cx->is_50hz ? 576 : 480))
-			h = (cx->is_50hz ? 576 : 480);
-		else if (h < 2)
-			h = 2;
-		cx18_get_fmt(cx, streamtype, fmt);
-		fmt->fmt.pix.width = w;
-		fmt->fmt.pix.height = h;
+static int cx18_querycap(struct file *file, void *fh,
+				struct v4l2_capability *vcap)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-		if (!set_fmt || (cx->params.width == w && cx->params.height == h))
-			return 0;
-		if (atomic_read(&cx->ana_capturing) > 0)
-			return -EBUSY;
-
-		cx->params.width = w;
-		cx->params.height = h;
-		if (w != 720 || h != (cx->is_50hz ? 576 : 480))
-			cx->params.video_temporal_filter = 0;
-		else
-			cx->params.video_temporal_filter = 8;
-		cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
-		return cx18_get_fmt(cx, streamtype, fmt);
-	}
+	strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+	strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+	strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
+	vcap->version = CX18_DRIVER_VERSION; 	    /* version */
+	vcap->capabilities = cx->v4l2_cap; 	    /* capabilities */
+	return 0;
+}
 
 
-	/* set raw VBI format */
-	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
-		    cx->vbi.sliced_in->service_set &&
-		    atomic_read(&cx->ana_capturing) > 0)
-			return -EBUSY;
-		if (set_fmt) {
-			cx->vbi.sliced_in->service_set = 0;
-			cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
-		}
-		return cx18_get_fmt(cx, streamtype, fmt);
-	}
+static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-	/* any else but sliced VBI capture is an error */
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-		return -EINVAL;
+	return cx18_get_audio_input(cx, vin->index, vin);
+}
 
 
-	/* TODO: implement sliced VBI, for now silently return 0 */
-	return 0;
+static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-	/* set sliced VBI capture format */
-	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-	memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+	vin->index = cx->audio_input;
+	return cx18_get_audio_input(cx, vin->index, vin);
+}
 
 
-	if (vbifmt->service_set)
-		cx18_expand_service_set(vbifmt, cx->is_50hz);
-	set = check_service_set(vbifmt, cx->is_50hz);
-	vbifmt->service_set = cx18_get_service_set(vbifmt);
+static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-	if (!set_fmt)
-		return 0;
-	if (set == 0)
+	if (vout->index >= cx->nof_audio_inputs)
 		return -EINVAL;
 		return -EINVAL;
-	if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
-		return -EBUSY;
-	cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
-	memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
+	cx->audio_input = vout->index;
+	cx18_audio_set_io(cx);
 	return 0;
 	return 0;
 }
 }
 
 
-static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
 {
 {
-	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
-	struct cx18 *cx = id->cx;
-	struct v4l2_register *reg = arg;
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-	switch (cmd) {
-	/* ioctls to allow direct access to the encoder registers for testing */
-	case VIDIOC_DBG_G_REGISTER:
-		if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
-			return cx18_cxc(cx, cmd, arg);
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-			return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
-		return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-
-	case VIDIOC_DBG_S_REGISTER:
-		if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
-			return cx18_cxc(cx, cmd, arg);
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-			return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
-		return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-
-	case VIDIOC_G_CHIP_IDENT: {
-		struct v4l2_chip_ident *chip = arg;
-
-		chip->ident = V4L2_IDENT_NONE;
-		chip->revision = 0;
-		if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
-			if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
-				struct v4l2_chip_ident *chip = arg;
-
-				chip->ident = V4L2_IDENT_CX23418;
-			}
-			return 0;
-		}
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-			return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
-			return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-		return -EINVAL;
-	}
-
-	case VIDIOC_INT_S_AUDIO_ROUTING: {
-		struct v4l2_routing *route = arg;
+	/* set it to defaults from our table */
+	return cx18_get_input(cx, vin->index, vin);
+}
 
 
-		cx18_audio_set_route(cx, route);
-		break;
-	}
+static int cx18_cropcap(struct file *file, void *fh,
+			struct v4l2_cropcap *cropcap)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-	default:
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 		return -EINVAL;
-	}
+	cropcap->bounds.top = cropcap->bounds.left = 0;
+	cropcap->bounds.width = 720;
+	cropcap->bounds.height = cx->is_50hz ? 576 : 480;
+	cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
+	cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+	cropcap->defrect = cropcap->bounds;
 	return 0;
 	return 0;
 }
 }
 
 
-int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg)
+static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 {
 {
-	struct cx18_open_id *id = NULL;
-
-	if (filp)
-		id = (struct cx18_open_id *)filp->private_data;
-
-	switch (cmd) {
-	case VIDIOC_G_PRIORITY:
-	{
-		enum v4l2_priority *p = arg;
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
 
 
-		*p = v4l2_prio_max(&cx->prio);
-		break;
-	}
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
 
 
-	case VIDIOC_S_PRIORITY:
-	{
-		enum v4l2_priority *prio = arg;
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);
+}
 
 
-		return v4l2_prio_change(&cx->prio, &id->prio, *prio);
-	}
+static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-	case VIDIOC_QUERYCAP:{
-		struct v4l2_capability *vcap = arg;
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);
+}
 
 
-		memset(vcap, 0, sizeof(*vcap));
-		strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
-		strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
-		strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
-		vcap->version = CX18_DRIVER_VERSION; 	    /* version */
-		vcap->capabilities = cx->v4l2_cap; 	    /* capabilities */
+static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
+					struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+		  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
+		},
+		{ 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
+		  "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
+		}
+	};
 
 
-		/* reserved.. must set to 0! */
-		vcap->reserved[0] = vcap->reserved[1] =
-			vcap->reserved[2] = vcap->reserved[3] = 0;
-		break;
-	}
+	if (fmt->index > 1)
+		return -EINVAL;
+	*fmt = formats[fmt->index];
+	return 0;
+}
 
 
-	case VIDIOC_ENUMAUDIO:{
-		struct v4l2_audio *vin = arg;
+static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-		return cx18_get_audio_input(cx, vin->index, vin);
-	}
+	*i = cx->active_input;
+	return 0;
+}
 
 
-	case VIDIOC_G_AUDIO:{
-		struct v4l2_audio *vin = arg;
+int cx18_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
 
 
-		vin->index = cx->audio_input;
-		return cx18_get_audio_input(cx, vin->index, vin);
-	}
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
 
 
-	case VIDIOC_S_AUDIO:{
-		struct v4l2_audio *vout = arg;
+	if (inp < 0 || inp >= cx->nof_inputs)
+		return -EINVAL;
 
 
-		if (vout->index >= cx->nof_audio_inputs)
-			return -EINVAL;
-		cx->audio_input = vout->index;
-		cx18_audio_set_io(cx);
-		break;
+	if (inp == cx->active_input) {
+		CX18_DEBUG_INFO("Input unchanged\n");
+		return 0;
 	}
 	}
 
 
-	case VIDIOC_ENUMINPUT:{
-		struct v4l2_input *vin = arg;
-
-		/* set it to defaults from our table */
-		return cx18_get_input(cx, vin->index, vin);
-	}
+	CX18_DEBUG_INFO("Changing input from %d to %d\n",
+			cx->active_input, inp);
 
 
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_S_FMT: {
-		struct v4l2_format *fmt = arg;
+	cx->active_input = inp;
+	/* Set the audio input to whatever is appropriate for the input type. */
+	cx->audio_input = cx->card->video_inputs[inp].audio_index;
 
 
-		return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT);
-	}
+	/* prevent others from messing with the streams until
+	   we're finished changing inputs. */
+	cx18_mute(cx);
+	cx18_video_set_io(cx);
+	cx18_audio_set_io(cx);
+	cx18_unmute(cx);
+	return 0;
+}
 
 
-	case VIDIOC_G_FMT: {
-		struct v4l2_format *fmt = arg;
-		int type = fmt->type;
+static int cx18_g_frequency(struct file *file, void *fh,
+				struct v4l2_frequency *vf)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-		memset(fmt, 0, sizeof(*fmt));
-		fmt->type = type;
-		return cx18_get_fmt(cx, id->type, fmt);
-	}
+	if (vf->tuner != 0)
+		return -EINVAL;
 
 
-	case VIDIOC_CROPCAP: {
-		struct v4l2_cropcap *cropcap = arg;
-
-		if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		cropcap->bounds.top = cropcap->bounds.left = 0;
-		cropcap->bounds.width = 720;
-		cropcap->bounds.height = cx->is_50hz ? 576 : 480;
-		cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
-		cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
-		cropcap->defrect = cropcap->bounds;
-		return 0;
-	}
+	cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);
+	return 0;
+}
 
 
-	case VIDIOC_S_CROP: {
-		struct v4l2_crop *crop = arg;
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
 
 
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		return cx18_av_cmd(cx, VIDIOC_S_CROP, arg);
-	}
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
 
 
-	case VIDIOC_G_CROP: {
-		struct v4l2_crop *crop = arg;
+	if (vf->tuner != 0)
+		return -EINVAL;
 
 
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		return cx18_av_cmd(cx, VIDIOC_G_CROP, arg);
-	}
+	cx18_mute(cx);
+	CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+	cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);
+	cx18_unmute(cx);
+	return 0;
+}
 
 
-	case VIDIOC_ENUM_FMT: {
-		static struct v4l2_fmtdesc formats[] = {
-			{ 0, 0, 0,
-			  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
-			  { 0, 0, 0, 0 }
-			},
-			{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
-			  "MPEG", V4L2_PIX_FMT_MPEG,
-			  { 0, 0, 0, 0 }
-			}
-		};
-		struct v4l2_fmtdesc *fmt = arg;
-		enum v4l2_buf_type type = fmt->type;
-
-		switch (type) {
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			break;
-		default:
-			return -EINVAL;
-		}
-		if (fmt->index > 1)
-			return -EINVAL;
-		*fmt = formats[fmt->index];
-		fmt->type = type;
-		return 0;
-	}
+static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-	case VIDIOC_G_INPUT:{
-		*(int *)arg = cx->active_input;
-		break;
-	}
+	*std = cx->std;
+	return 0;
+}
 
 
-	case VIDIOC_S_INPUT:{
-		int inp = *(int *)arg;
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
 
 
-		if (inp < 0 || inp >= cx->nof_inputs)
-			return -EINVAL;
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
 
 
-		if (inp == cx->active_input) {
-			CX18_DEBUG_INFO("Input unchanged\n");
-			break;
-		}
-		CX18_DEBUG_INFO("Changing input from %d to %d\n",
-				cx->active_input, inp);
+	if ((*std & V4L2_STD_ALL) == 0)
+		return -EINVAL;
 
 
-		cx->active_input = inp;
-		/* Set the audio input to whatever is appropriate for the
-		   input type. */
-		cx->audio_input = cx->card->video_inputs[inp].audio_index;
+	if (*std == cx->std)
+		return 0;
 
 
-		/* prevent others from messing with the streams until
-		   we're finished changing inputs. */
-		cx18_mute(cx);
-		cx18_video_set_io(cx);
-		cx18_audio_set_io(cx);
-		cx18_unmute(cx);
-		break;
+	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
+	    atomic_read(&cx->ana_capturing) > 0) {
+		/* Switching standard would turn off the radio or mess
+		   with already running streams, prevent that by
+		   returning EBUSY. */
+		return -EBUSY;
 	}
 	}
 
 
-	case VIDIOC_G_FREQUENCY:{
-		struct v4l2_frequency *vf = arg;
+	cx->std = *std;
+	cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+	cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
+	cx->params.width = 720;
+	cx->params.height = cx->is_50hz ? 576 : 480;
+	cx->vbi.count = cx->is_50hz ? 18 : 12;
+	cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
+	cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
+	cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
+	CX18_DEBUG_INFO("Switching standard to %llx.\n",
+			(unsigned long long) cx->std);
+
+	/* Tuner */
+	cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+	return 0;
+}
 
 
-		if (vf->tuner != 0)
-			return -EINVAL;
-		cx18_call_i2c_clients(cx, cmd, arg);
-		break;
-	}
+static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
 
 
-	case VIDIOC_S_FREQUENCY:{
-		struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
 
 
-		if (vf.tuner != 0)
-			return -EINVAL;
+	if (vt->index != 0)
+		return -EINVAL;
 
 
-		cx18_mute(cx);
-		CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
-		cx18_call_i2c_clients(cx, cmd, &vf);
-		cx18_unmute(cx);
-		break;
-	}
+	/* Setting tuner can only set audio mode */
+	cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
 
 
-	case VIDIOC_ENUMSTD:{
-		struct v4l2_standard *vs = arg;
-		int idx = vs->index;
+	return 0;
+}
 
 
-		if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
-			return -EINVAL;
+static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-		*vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
-				cx18_std_60hz : cx18_std_50hz;
-		vs->index = idx;
-		vs->id = enum_stds[idx].std;
-		strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
-		break;
-	}
+	if (vt->index != 0)
+		return -EINVAL;
 
 
-	case VIDIOC_G_STD:{
-		*(v4l2_std_id *) arg = cx->std;
-		break;
+	cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
+
+	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+		strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+		vt->type = V4L2_TUNER_RADIO;
+	} else {
+		strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
+		vt->type = V4L2_TUNER_ANALOG_TV;
 	}
 	}
 
 
-	case VIDIOC_S_STD: {
-		v4l2_std_id std = *(v4l2_std_id *) arg;
+	return 0;
+}
 
 
-		if ((std & V4L2_STD_ALL) == 0)
-			return -EINVAL;
+static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_sliced_vbi_cap *cap)
+{
+	return -EINVAL;
+}
 
 
-		if (std == cx->std)
-			break;
+static int cx18_g_enc_index(struct file *file, void *fh,
+				struct v4l2_enc_idx *idx)
+{
+	return -EINVAL;
+}
 
 
-		if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
-		    atomic_read(&cx->ana_capturing) > 0) {
-			/* Switching standard would turn off the radio or mess
-			   with already running streams, prevent that by
-			   returning EBUSY. */
-			return -EBUSY;
-		}
+static int cx18_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
 
 
-		cx->std = std;
-		cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
-		cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
-		cx->params.width = 720;
-		cx->params.height = cx->is_50hz ? 576 : 480;
-		cx->vbi.count = cx->is_50hz ? 18 : 12;
-		cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
-		cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
-		cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
-		CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std);
-
-		/* Tuner */
-		cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
+		return cx18_start_capture(id);
+
+	case V4L2_ENC_CMD_STOP:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		cx18_stop_capture(id,
+				  enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
 		break;
 		break;
-	}
-
-	case VIDIOC_S_TUNER: {	/* Setting tuner can only set audio mode */
-		struct v4l2_tuner *vt = arg;
 
 
-		if (vt->index != 0)
-			return -EINVAL;
-
-		cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
+	case V4L2_ENC_CMD_PAUSE:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+		if (!atomic_read(&cx->ana_capturing))
+			return -EPERM;
+		if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+			return 0;
+		cx18_mute(cx);
+		cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
 		break;
 		break;
-	}
-
-	case VIDIOC_G_TUNER: {
-		struct v4l2_tuner *vt = arg;
-
-		if (vt->index != 0)
-			return -EINVAL;
-
-		memset(vt, 0, sizeof(*vt));
-		cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
 
 
-		if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
-			strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
-			vt->type = V4L2_TUNER_RADIO;
-		} else {
-			strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
-			vt->type = V4L2_TUNER_ANALOG_TV;
-		}
+	case V4L2_ENC_CMD_RESUME:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
+		if (!atomic_read(&cx->ana_capturing))
+			return -EPERM;
+		if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+			return 0;
+		cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+		cx18_unmute(cx);
 		break;
 		break;
-	}
 
 
-	case VIDIOC_G_SLICED_VBI_CAP: {
-		struct v4l2_sliced_vbi_cap *cap = arg;
-		int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
-		int f, l;
-		enum v4l2_buf_type type = cap->type;
-
-		memset(cap, 0, sizeof(*cap));
-		cap->type = type;
-		if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-			for (f = 0; f < 2; f++) {
-				for (l = 0; l < 24; l++) {
-					if (valid_service_line(f, l, cx->is_50hz))
-						cap->service_lines[f][l] = set;
-				}
-			}
-			return 0;
-		}
+	default:
+		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
+	return 0;
+}
 
 
-	case VIDIOC_ENCODER_CMD:
-	case VIDIOC_TRY_ENCODER_CMD: {
-		struct v4l2_encoder_cmd *enc = arg;
-		int try = cmd == VIDIOC_TRY_ENCODER_CMD;
-
-		memset(&enc->raw, 0, sizeof(enc->raw));
-		switch (enc->cmd) {
-		case V4L2_ENC_CMD_START:
-			enc->flags = 0;
-			if (try)
-				return 0;
-			return cx18_start_capture(id);
-
-		case V4L2_ENC_CMD_STOP:
-			enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
-			if (try)
-				return 0;
-			cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
-			return 0;
+static int cx18_try_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-		case V4L2_ENC_CMD_PAUSE:
-			enc->flags = 0;
-			if (try)
-				return 0;
-			if (!atomic_read(&cx->ana_capturing))
-				return -EPERM;
-			if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
-				return 0;
-			cx18_mute(cx);
-			cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
-			break;
-
-		case V4L2_ENC_CMD_RESUME:
-			enc->flags = 0;
-			if (try)
-				return 0;
-			if (!atomic_read(&cx->ana_capturing))
-				return -EPERM;
-			if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
-				return 0;
-			cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
-			cx18_unmute(cx);
-			break;
-		default:
-			return -EINVAL;
-		}
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
 		break;
 		break;
-	}
 
 
-	case VIDIOC_LOG_STATUS:
-	{
-		struct v4l2_input vidin;
-		struct v4l2_audio audin;
-		int i;
+	case V4L2_ENC_CMD_STOP:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		break;
 
 
-		CX18_INFO("=================  START STATUS CARD #%d  =================\n", cx->num);
-		if (cx->hw_flags & CX18_HW_TVEEPROM) {
-			struct tveeprom tv;
+	case V4L2_ENC_CMD_PAUSE:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+		break;
 
 
-			cx18_read_eeprom(cx, &tv);
-		}
-		cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
-		cx18_get_input(cx, cx->active_input, &vidin);
-		cx18_get_audio_input(cx, cx->audio_input, &audin);
-		CX18_INFO("Video Input: %s\n", vidin.name);
-		CX18_INFO("Audio Input: %s\n", audin.name);
-		CX18_INFO("Tuner: %s\n",
-			test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?
-			"Radio" : "TV");
-		cx2341x_log_status(&cx->params, cx->name);
-		CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
-		for (i = 0; i < CX18_MAX_STREAMS; i++) {
-			struct cx18_stream *s = &cx->streams[i];
-
-			if (s->v4l2dev == NULL || s->buffers == 0)
-				continue;
-			CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
-				s->name, s->s_flags,
-				(s->buffers - s->q_free.buffers) * 100 / s->buffers,
-				(s->buffers * s->buf_size) / 1024, s->buffers);
-		}
-		CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
-				(long long)cx->mpg_data_received,
-				(long long)cx->vbi_data_inserted);
-		CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
+	case V4L2_ENC_CMD_RESUME:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
 		break;
 		break;
-	}
 
 
 	default:
 	default:
+		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
 
 
-static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
-			      unsigned int cmd, void *arg)
+static int cx18_log_status(struct file *file, void *fh)
 {
 {
-	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
-	struct cx18 *cx = id->cx;
-	int ret;
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+	struct v4l2_input vidin;
+	struct v4l2_audio audin;
+	int i;
+
+	CX18_INFO("=================  START STATUS CARD #%d  =================\n", cx->num);
+	if (cx->hw_flags & CX18_HW_TVEEPROM) {
+		struct tveeprom tv;
+
+		cx18_read_eeprom(cx, &tv);
+	}
+	cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
+	cx18_get_input(cx, cx->active_input, &vidin);
+	cx18_get_audio_input(cx, cx->audio_input, &audin);
+	CX18_INFO("Video Input: %s\n", vidin.name);
+	CX18_INFO("Audio Input: %s\n", audin.name);
+	mutex_lock(&cx->gpio_lock);
+	CX18_INFO("GPIO:  direction 0x%08x, value 0x%08x\n",
+		cx->gpio_dir, cx->gpio_val);
+	mutex_unlock(&cx->gpio_lock);
+	CX18_INFO("Tuner: %s\n",
+		test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
+	cx2341x_log_status(&cx->params, cx->name);
+	CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
+	for (i = 0; i < CX18_MAX_STREAMS; i++) {
+		struct cx18_stream *s = &cx->streams[i];
+
+		if (s->v4l2dev == NULL || s->buffers == 0)
+			continue;
+		CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
+			  s->name, s->s_flags,
+			  (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+			  (s->buffers * s->buf_size) / 1024, s->buffers);
+	}
+	CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
+			(long long)cx->mpg_data_received,
+			(long long)cx->vbi_data_inserted);
+	CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
+	return 0;
+}
+
+static int cx18_default(struct file *file, void *fh, int cmd, void *arg)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 
-	/* check priority */
 	switch (cmd) {
 	switch (cmd) {
-	case VIDIOC_S_CTRL:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_S_FREQUENCY:
-	case VIDIOC_S_FMT:
-	case VIDIOC_S_CROP:
-	case VIDIOC_S_EXT_CTRLS:
-		ret = v4l2_prio_check(&cx->prio, &id->prio);
-		if (ret)
-			return ret;
+	case VIDIOC_INT_S_AUDIO_ROUTING: {
+		struct v4l2_routing *route = arg;
+
+		CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
+			route->input, route->output);
+		cx18_audio_set_route(cx, route);
+		break;
 	}
 	}
 
 
-	switch (cmd) {
-	case VIDIOC_DBG_G_REGISTER:
-	case VIDIOC_DBG_S_REGISTER:
-	case VIDIOC_G_CHIP_IDENT:
-	case VIDIOC_INT_S_AUDIO_ROUTING:
-	case VIDIOC_INT_RESET:
-		if (cx18_debug & CX18_DBGFLG_IOCTL) {
-			printk(KERN_INFO "cx18%d ioctl: ", cx->num);
-			v4l_printk_ioctl(cmd);
-		}
-		return cx18_debug_ioctls(filp, cmd, arg);
-
-	case VIDIOC_G_PRIORITY:
-	case VIDIOC_S_PRIORITY:
-	case VIDIOC_QUERYCAP:
-	case VIDIOC_ENUMINPUT:
-	case VIDIOC_G_INPUT:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_G_FMT:
-	case VIDIOC_S_FMT:
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_ENUM_FMT:
-	case VIDIOC_CROPCAP:
-	case VIDIOC_G_CROP:
-	case VIDIOC_S_CROP:
-	case VIDIOC_G_FREQUENCY:
-	case VIDIOC_S_FREQUENCY:
-	case VIDIOC_ENUMSTD:
-	case VIDIOC_G_STD:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_G_TUNER:
-	case VIDIOC_ENUMAUDIO:
-	case VIDIOC_S_AUDIO:
-	case VIDIOC_G_AUDIO:
-	case VIDIOC_G_SLICED_VBI_CAP:
-	case VIDIOC_LOG_STATUS:
-	case VIDIOC_G_ENC_INDEX:
-	case VIDIOC_ENCODER_CMD:
-	case VIDIOC_TRY_ENCODER_CMD:
-		if (cx18_debug & CX18_DBGFLG_IOCTL) {
-			printk(KERN_INFO "cx18%d ioctl: ", cx->num);
-			v4l_printk_ioctl(cmd);
-		}
-		return cx18_v4l2_ioctls(cx, filp, cmd, arg);
-
-	case VIDIOC_QUERYMENU:
-	case VIDIOC_QUERYCTRL:
-	case VIDIOC_S_CTRL:
-	case VIDIOC_G_CTRL:
-	case VIDIOC_S_EXT_CTRLS:
-	case VIDIOC_G_EXT_CTRLS:
-	case VIDIOC_TRY_EXT_CTRLS:
-		if (cx18_debug & CX18_DBGFLG_IOCTL) {
-			printk(KERN_INFO "cx18%d ioctl: ", cx->num);
-			v4l_printk_ioctl(cmd);
-		}
-		return cx18_control_ioctls(cx, cmd, arg);
+	case VIDIOC_INT_RESET: {
+		u32 val = *(u32 *)arg;
+
+		if ((val == 0) || (val & 0x01))
+			cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]);
+		break;
+	}
 
 
-	case 0x00005401:	/* Handle isatty() calls */
-		return -EINVAL;
 	default:
 	default:
-		return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
-						   cx18_v4l2_do_ioctl);
+		return -EINVAL;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -840,12 +772,65 @@ static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
 int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 		    unsigned long arg)
 		    unsigned long arg)
 {
 {
+	struct video_device *vfd = video_devdata(filp);
 	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
 	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
 	struct cx18 *cx = id->cx;
 	struct cx18 *cx = id->cx;
 	int res;
 	int res;
 
 
 	mutex_lock(&cx->serialize_lock);
 	mutex_lock(&cx->serialize_lock);
-	res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl);
+
+	if (cx18_debug & CX18_DBGFLG_IOCTL)
+		vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+	res = video_ioctl2(inode, filp, cmd, arg);
+	vfd->debug = 0;
 	mutex_unlock(&cx->serialize_lock);
 	mutex_unlock(&cx->serialize_lock);
 	return res;
 	return res;
 }
 }
+
+void cx18_set_funcs(struct video_device *vdev)
+{
+	vdev->vidioc_querycap                = cx18_querycap;
+	vdev->vidioc_g_priority              = cx18_g_priority;
+	vdev->vidioc_s_priority              = cx18_s_priority;
+	vdev->vidioc_s_audio                 = cx18_s_audio;
+	vdev->vidioc_g_audio                 = cx18_g_audio;
+	vdev->vidioc_enumaudio               = cx18_enumaudio;
+	vdev->vidioc_enum_input              = cx18_enum_input;
+	vdev->vidioc_cropcap                 = cx18_cropcap;
+	vdev->vidioc_s_crop                  = cx18_s_crop;
+	vdev->vidioc_g_crop                  = cx18_g_crop;
+	vdev->vidioc_g_input                 = cx18_g_input;
+	vdev->vidioc_s_input                 = cx18_s_input;
+	vdev->vidioc_g_frequency             = cx18_g_frequency;
+	vdev->vidioc_s_frequency             = cx18_s_frequency;
+	vdev->vidioc_s_tuner                 = cx18_s_tuner;
+	vdev->vidioc_g_tuner                 = cx18_g_tuner;
+	vdev->vidioc_g_enc_index             = cx18_g_enc_index;
+	vdev->vidioc_g_std                   = cx18_g_std;
+	vdev->vidioc_s_std                   = cx18_s_std;
+	vdev->vidioc_log_status              = cx18_log_status;
+	vdev->vidioc_enum_fmt_vid_cap        = cx18_enum_fmt_vid_cap;
+	vdev->vidioc_encoder_cmd             = cx18_encoder_cmd;
+	vdev->vidioc_try_encoder_cmd         = cx18_try_encoder_cmd;
+	vdev->vidioc_g_fmt_vid_cap           = cx18_g_fmt_vid_cap;
+	vdev->vidioc_g_fmt_vbi_cap           = cx18_g_fmt_vbi_cap;
+	vdev->vidioc_g_fmt_sliced_vbi_cap    = cx18_g_fmt_sliced_vbi_cap;
+	vdev->vidioc_s_fmt_vid_cap           = cx18_s_fmt_vid_cap;
+	vdev->vidioc_s_fmt_vbi_cap           = cx18_s_fmt_vbi_cap;
+	vdev->vidioc_s_fmt_sliced_vbi_cap    = cx18_s_fmt_sliced_vbi_cap;
+	vdev->vidioc_try_fmt_vid_cap         = cx18_try_fmt_vid_cap;
+	vdev->vidioc_try_fmt_vbi_cap         = cx18_try_fmt_vbi_cap;
+	vdev->vidioc_try_fmt_sliced_vbi_cap  = cx18_try_fmt_sliced_vbi_cap;
+	vdev->vidioc_g_sliced_vbi_cap        = cx18_g_sliced_vbi_cap;
+	vdev->vidioc_g_chip_ident            = cx18_g_chip_ident;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	vdev->vidioc_g_register              = cx18_g_register;
+	vdev->vidioc_s_register              = cx18_s_register;
+#endif
+	vdev->vidioc_default                 = cx18_default;
+	vdev->vidioc_queryctrl               = cx18_queryctrl;
+	vdev->vidioc_querymenu               = cx18_querymenu;
+	vdev->vidioc_g_ext_ctrls             = cx18_g_ext_ctrls;
+	vdev->vidioc_s_ext_ctrls             = cx18_s_ext_ctrls;
+	vdev->vidioc_try_ext_ctrls           = cx18_try_ext_ctrls;
+}

+ 4 - 2
drivers/media/video/cx18/cx18-ioctl.h

@@ -24,7 +24,9 @@
 u16 cx18_service2vbi(int type);
 u16 cx18_service2vbi(int type);
 void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
 void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
 u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
 u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
+void cx18_set_funcs(struct video_device *vdev);
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std);
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int cx18_s_input(struct file *file, void *fh, unsigned int inp);
 int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 		    unsigned long arg);
 		    unsigned long arg);
-int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd,
-		     void *arg);

+ 1 - 0
drivers/media/video/cx18/cx18-mailbox.c

@@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = {
 	API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS,                    0),
 	API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS,                    0),
 	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,			0),
 	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,			0),
 	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,			API_FAST),
 	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,			API_FAST),
+	API_ENTRY(CPU, CX18_APU_RESETAI,			API_FAST),
 	API_ENTRY(0, 0,						0),
 	API_ENTRY(0, 0,						0),
 };
 };
 
 

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff