GIT 8f8569cd11d9e753b985f37719784428f33b0d88 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git#devel commit Author: Joe Perches Date: Mon Nov 19 22:48:15 2007 -0300 V4L/DVB (6618): drivers/media/dvb: Add missing "space" Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab commit bd6457c95a213651795900dc05ef3651591269eb Author: Joe Perches Date: Tue Nov 20 09:00:35 2007 -0300 V4L/DVB (6617): drivers/media/video: Add missing "space" Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab commit 05f212dce0391bc2c9e76bdeadaf92440c8e3960 Author: Joe Perches Date: Mon Nov 19 22:48:16 2007 -0300 V4L/DVB (6616): drivers/media/radio: Add missing "space" Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab commit f5688845560bb2a55f46e2e8717aa1bacf3a4f1c Author: Brandon Philips Date: Mon Nov 19 15:10:48 2007 -0300 V4L/DVB (6615): V4L: Fix VIDIOCGMBUF locking in saa7146 Fallout from videobuf_mmap_setup() locking fixes. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab commit 5673027fddd5bb59943110a72b970ba7b8bef29a Author: Mauro Carvalho Chehab Date: Fri Nov 16 16:28:21 2007 -0300 V4L/DVB (6614): Fix driver for i386 architectures Signed-off-by: Mauro Carvalho Chehab commit 6885767f26c51e6fb9ae7c441dc509c7e6bee53a Author: Mauro Carvalho Chehab Date: Fri Nov 16 09:43:19 2007 -0300 V4L/DVB (6613): Fix: add a missing continue statement Signed-off-by: Mauro Carvalho Chehab commit 7e15cd80a78898916a7f7cae93d2aa11a747e0c7 Author: Michel Ludwig Date: Fri Nov 16 07:49:49 2007 -0300 V4L/DVB (6612): Allow RESET_CLK callback and avoids unneeded loading TM5600/TM6000 needs clock reset during firmware load. This patch adds the capability of caling a callback method for this. Also, avoids uneeded firmware loads. Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab commit 535d9935e499bb8cfa27f8ba3b117ffebff7e977 Author: Michel Ludwig Date: Fri Nov 16 07:46:14 2007 -0300 V4L/DVB (6611): Change xc2028_attach method to make easier for DVB Removes uneeded parameters and adds an structure for passing the parameters This patch is co-authored by Mauro Carvalho Chehab. Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab commit 563138a8759346a7a4164b1a65c85975290d8e18 Author: Michel Ludwig Date: Fri Nov 16 07:19:35 2007 -0300 V4L/DVB (6610): Fix a wrong typecast Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab commit bda6adbc75a1d36aeefb32b6b82e28e07c5dc9f9 Author: Mauro Carvalho Chehab Date: Thu Nov 15 23:09:30 2007 -0300 V4L/DVB (6609): Re-adds lock safe videobuf_read_start videobuf_dvb needs videobuf_read_start. The EXPORT_SYMBOL_GPL() were removed by a previous patch. However, videobuf_dvb needs this. This patch re-adds videobuf_read_start, doing the proper lock. Signed-off-by: Mauro Carvalho Chehab commit 12e507be1a203608e4729fac74479fb943b030de Author: Michael Krufky Date: Thu Nov 15 10:34:33 2007 -0300 V4L/DVB (6607): saa7134: add support for reading Hauppauge eeprom Increased size of dev->eedata from 128 to 256, since the Hauppauge data begins at byte 128. This has been tested on boards with smaller eeproms, and caused no problems. Added comments to distinguish between the various versions of the HVR1110. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit d8a469d802f81990cf76ee267a3223383a40cac7 Author: Michael Krufky Date: Thu Nov 15 10:01:11 2007 -0300 V4L/DVB (6606): saa7134: add autodetection support for alternate subids of Hauppauge HVR1110 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 9fd8414a4ca7d15beb888716c8450991442130f3 Author: Mauro Carvalho Chehab Date: Thu Nov 15 11:58:00 2007 -0300 V4L/DVB (6605): Add a modprobe option to manually select audio standard While there's no public API to define audio standard, adds a hack option for select them. This is needed only for NICAM and A2 firmwares, since AM, BTSC and EAIJ are already properly handled, on firmware version 2.7. Signed-off-by: Mauro Carvalho Chehab commit eadf71faba427a1db9e3c8d73d2c0a806730d66e Author: Brandon Philips Date: Tue Nov 6 20:23:08 2007 -0300 V4L/DVB (6603): V4L: videobuf: convert streaming and reading to bitfields Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab commit 349f9465345360d6a13730f141853c2416e8a3f2 Author: Brandon Philips Date: Tue Nov 13 20:11:26 2007 -0300 V4L/DVB (6602): V4L: Convert videobuf drivers to videobuf_stop Drivers were using cookie cutter code for stopping the read/stream. Use the new videobuf_stop function which is lock safe. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab commit 61f8d0439aeaa2f0bdd279c7db963ba3784ffa3d Author: Brandon Philips Date: Tue Nov 13 20:05:38 2007 -0300 V4L/DVB (6601): V4L: videobuf-core locking fixes and comments - Add comments to functions that require that caller hold q->lock - Add __videobuf_mmap_free that doesn't hold q->lock for use within videobuf - Add locking to videobuf_mmap_free - Fix linux/drivers/media/common/saa7146_video.c which was holding lock around videobuf_read_stop - Add locking to functions that operate on a queue - Add videobuf_stop to take care of stopping in both the read and stream case TODO: bttv still has an unsafe call to videobuf_queue_is_busy Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab commit d29e290d2fa2dd4eb42495078ed929ab07d447a2 Author: Brandon Philips Date: Tue Nov 6 20:02:36 2007 -0300 V4L/DVB (6600): V4L: videobuf: don't chew up namespace STATE_.*, convert to VIDEOBUF_ s/STATE_NEEDS_INIT/VIDEOBUF_NEEDS_INIT/g s/STATE_PREPARED/VIDEOBUF_PREPARED/g s/STATE_QUEUED/VIDEOBUF_QUEUED/g s/STATE_ACTIVE/VIDEOBUF_ACTIVE/g s/STATE_DONE/VIDEOBUF_DONE/g s/STATE_ERROR/VIDEOBUF_ERROR/g s/STATE_IDLE/VIDEOBUF_IDLE/g Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab commit 4e8f0af2520889d9b9ac05a85b54ac3e56ad61f0 Author: Mauro Carvalho Chehab Date: Thu Nov 15 10:45:19 2007 -0300 V4L/DVB (6598): Fix standard name Signed-off-by: Mauro Carvalho Chehab commit 959c1cc4ca96932aa01d9ab681b393183d3aa895 Author: Mauro Carvalho Chehab Date: Thu Nov 15 09:44:30 2007 -0300 V4L/DVB (6595): Corrects printk lines Make the driver less verbose by default. It adds a debug parameter to make the driver more verbose. Also, error messages were using KERN_ERR level, instead of KERN_INFO. A few printk messages were reviewed to make them more clear. Signed-off-by: Mauro Carvalho Chehab commit 33fd0a578f697fbe3aef02eec28e918b4739bcac Author: Mauro Carvalho Chehab Date: Thu Nov 15 09:35:44 2007 -0300 V4L/DVB (6594): Add tuner_err macro Some tuners, like xc3028, need to print error messages. Instead of declaring local macros, create a tuner global macro for printing tuner errors. To preserve CodingStyle on all tuner_macros, a few CodingStyle violations were fixed at the other macros: - lines with more than 80 columns - two statements at the same line The patch also removes the CodingStyle violation of having emacs declarations inside de source code (CodingStyle chapter 18). Signed-off-by: Mauro Carvalho Chehab commit a8d38a4af713d8fa1db72b8827e38d0c1f361089 Author: Mauro Carvalho Chehab Date: Thu Nov 15 08:43:53 2007 -0300 V4L/DVB (6593): Fix scode table loading Xceive 2028/3028 has a concept of scode/dcode. Scode is a table of 16 values (each with 12 bytes i2c sequence). Dcode is the entry of Scode table that should be used, given a certain frequency. The idea is that, depending on what frequency is selected, and according with a country-based (or standard-based?) table, the Xceive should be "hacked" to fine-tune that specific frequency. By default, Scode=0 is used, for undefined frequencies. Also, Scode=0 seems to be the most used value. This patch adds the capability of selecting a scode. However, extra work will be needed to allow auto-selecting the proper scode, for a given set of frequencies. I'm not sure what would be the proper way for implementing the dcode selection. Signed-off-by: Mauro Carvalho Chehab commit eeeff237698b00a4ab53f55e4e88b3878aa3f12d Author: Mauro Carvalho Chehab Date: Wed Nov 14 19:30:28 2007 -0300 V4L/DVB (6592): Add the capability to work with more complete firmwares Firmware version 2.7 has other firmware types. This patch adds the capability for the driver to work with those newer types. Signed-off-by: Mauro Carvalho Chehab commit fb4404b6ae441c9d7a82211948bc957e31a79c6f Author: Luca Risolia Date: Mon Nov 12 11:42:54 2007 -0300 V4L/DVB (6591): Adds support for MT9V111 on sn9c102 Adds a new image sensor to the sn9c102 driver. Signed-off-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab commit 17f0396048c4be837088142a3f501547d5771c52 Author: Olivier DANET Date: Mon Nov 12 10:48:51 2007 -0300 V4L/DVB (6590): Adding support for VHF with MT2266-devices MT2266 : - support for VHF - Minor enhancements Signed-off-by: Olivier DANET Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab commit e8c801b948577e42cb39c283f922d2fb991e2282 Author: dominik Date: Sat Nov 10 19:23:31 2007 -0300 V4L/DVB (6589): Gigabyte u7000 usb dvb-t support Signed-off-by: dominik Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab commit 0a619b4c91d6baa423fad551fb476e818d1b49e4 Author: Jaroslav Barton Date: Sat Nov 10 19:17:45 2007 -0300 V4L/DVB (6588): Leadtek Winfast DTV Dongle remote control Add remote controller support for Leadtek Winfast DTV Dongle based on DiB7700P, MT2060 and using last drivers (6040:6a79c243aecc), firmware dvb-usb-dib0700-03-pre1.fw Signed-off-by: Jaroslav Barton Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab commit 5e07ac7ab6fbf150695dfdc63164f19e4489eab5 Author: Mauro Carvalho Chehab Date: Sun Nov 11 14:15:34 2007 -0300 V4L/DVB (6587): Cleanup at tv norm selection With the conversion to the vidio_ioctl2, tvnorms array is not required anymore. Also, removed some code from V4L1 time (VIDEO_MODE_foo), specied at the non-used video_decoder.h. Signed-off-by: Mauro Carvalho Chehab commit 5ac6896dd883a0847e0638f690113e8c7b3edba0 Author: Mauro Carvalho Chehab Date: Sun Nov 11 13:23:54 2007 -0300 V4L/DVB (6586): Remove some dead code and make drive fully V4L2 compatible There were some vestiges of an old V4L1 I2C driver that were called by em28xx. This patch removes this dead code, and replaces videodev.h to videodev2.h Now, this driver doesn't require V4L1 anymore. Signed-off-by: Mauro Carvalho Chehab commit 8c703bf4c55acb926dff4c98656db18e42b8dcbf Author: Mauro Carvalho Chehab Date: Sun Nov 11 13:17:17 2007 -0300 V4L/DVB (6585): Convert em28xx to video_ioctl2 Uses the newer ioctl handler at videodev. This patch also cleans up some bad logic at the driver and do CodingStyle and other cleanups at the resulting driver. Also, since VIDIOCMBUF were not working, the V4L1 compat code were removed. The compat code will eventually be re-inserted, if we find a clean way for implementing compatibility with the old API. Signed-off-by: Mauro Carvalho Chehab commit e3aa3e1ddcf16fbffb9030ca06daa7786e726023 Author: Mauro Carvalho Chehab Date: Sun Nov 11 01:13:49 2007 -0300 V4L/DVB (6584): Fix read() method Backport read() fixes from Markus Rechberger. Signed-off-by: Mauro Carvalho Chehab commit d5a2b89815b3d657b3027ac548a7e9321e626ca7 Author: Mauro Carvalho Chehab Date: Sun Nov 11 01:08:26 2007 -0300 V4L/DVB (6583): Fix em28xx read stream locking On some situations, closing an streaming application and re-opening were returning -EBUSY. Uses the same locking schema also present on cx88. Signed-off-by: Mauro Carvalho Chehab commit e0ad567927e7c9c0b9eb1d7b9e27b9f27094ad64 Author: Mauro Carvalho Chehab Date: Sat Nov 10 22:21:01 2007 -0300 V4L/DVB (6582): Fix em28xx to allow multiple open Allows shared access support for em28xx. Just one userspace application is allowed to get stream. The other(s) application(s) can change V4L2 controls, set video standards, etc. This patch were splited from Markus Rechberger's tree and backported to 2.6.17 by Pádraig Brady. The original patch were ported to the latest em28xx version and had CodingStyle corrected to solve the issues pointed by scripts/checkpatch.pl. Thanks to Pádraig Brady for pointing this. Signed-off-by: Mauro Carvalho Chehab commit 993077f147c1baf45642ab5fe2ecf8cd965597d4 Author: Mauro Carvalho Chehab Date: Sat Nov 10 10:26:20 2007 -0300 V4L/DVB (6581): Fix: avoids negative vma usage count Signed-off-by: Mauro Carvalho Chehab commit 4454760e2327239133593484af05d3be595c8d26 Author: Sakari Ailus Date: Tue Oct 30 05:52:52 2007 -0300 V4L/DVB (6580): Set slave's master before master's attach call. V4L: Int if: Set slave's master before attach, remove master argument The master also now gets its own pointer from slave's structure. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab commit fca5c82d3b6be74fa4cd9053b386f2373eb71d33 Author: Hartmut Hackmann Date: Thu Nov 8 08:54:53 2007 -0300 V4L/DVB (6579): Fix bug #8824: Correct support for Diseqc on tda10086 This is a modified version of a patch previously posted by Thomas Unverzagt. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab commit 7cd85bdb90156843447b134b57accd88f4e43b16 Author: Adrian Bunk Date: Mon Nov 5 14:07:06 2007 -0300 V4L/DVB (6578): dvb-usb: make some debug vars static This patch makes some needlessly global debug variables static. opera1.h became so small that I removed it. Signed-off-by: Adrian Bunk Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 1c6a4dd77cdee4806584094f2797d8bbd3675438 Author: Adrian Bunk Date: Mon Nov 5 14:07:26 2007 -0300 V4L/DVB (6577): et61x251/: make 5 functions static This patch makes the following needlessly global functions in et61x251_core.c static: - et61x251_read_reg() - et61x251_i2c_try_read() - et61x251_i2c_try_write() - et61x251_i2c_read() - et61x251_i2c_write() Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab commit e8e7d9584b53fa93195372078d7bae336e5392c0 Author: Adrian Bunk Date: Mon Nov 5 14:07:22 2007 -0300 V4L/DVB (6576): cx88-mpeg.c: make 4 functions static This patch makes the following needlessly global functions static: - cx8802_init_common() - cx8802_fini_common() - cx8802_suspend_common() - cx8802_resume_common() Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab commit 52dc69513b8713a1eb91215803c6f2e144ad479d Author: Adrian Bunk Date: Mon Nov 5 14:07:20 2007 -0300 V4L/DVB (6575): cx23885/: cleanups This patch contains the following cleanups: - make the following needlessly global code static: - cx23885-core.c: struct cx23885_sram_channels[] - cx23885-core.c: struct cx23887_sram_channels[] - cx23885-core.c: cx23885_wakeup() - cx23885-core.c: cx23885_sram_channel_setup() - cx23885-core.c: cx23885_sram_channel_dump() - cx23885-core.c: cx23885_risc_disasm() - cx23885-core.c: cx23885_shutdown() - cx23885-core.c: cx23885_reset() - cx23885-core.c: cx23885_dev_unregister() - cx23885-core.c: cx23885_risc_databuffer() - cx23885-core.c: cx23885_risc_stopper() - #if 0 the following unused functions: - cx23885-core.c: cx23885_risc_buffer() - cx23885-core.c: cx23885_cancel_buffers() - remove the following unused EXPORT_SYMBOL's: - cx23885-cards.c: cx23885_boards - cx23885-i2c.c: cx23885_call_i2c_clients Signed-off-by: Adrian Bunk Reviewed-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab commit 9b8ac92f0133b835f6f1cbec87b2509608b2fc3e Author: Adrian Bunk Date: Mon Nov 5 14:07:18 2007 -0300 V4L/DVB (6574): common/ir-functions.c: make a function static ir_rc5_decode() can become static. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab commit 6e5fea56f4ece937e684d7312064e74ee2392922 Author: Adrian Bunk Date: Mon Nov 5 14:06:52 2007 -0300 V4L/DVB (6573): unexport flexcop_reset_block_300 This patch removes the unused EXPORT_SYMBOL(flexcop_reset_block_300). Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab commit 1ccf5adf93de11e1fb6e217e8fc266d8740cbdec Author: Adrian Bunk Date: Mon Nov 5 14:06:47 2007 -0300 V4L/DVB (6572): dvb-usb/vp702x.c: cleanups This patch contains the following cleanups: - make the needlessly global vp702x_usb_out_op() static - #if 0 the unused vp702x_power_ctrl() Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab commit 2141c772e1438d1a976632b5f87edd0a793fac07 Author: Adrian Bunk Date: Mon Nov 5 14:06:41 2007 -0300 V4L/DVB (6571): dvb-usb/gp8psk.c: #if 0 gp8psk_bcm4500_reload() This patch #if 0's the unused gp8psk_bcm4500_reload() Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab commit 6493b555352014b849a04a096a63bf12f262dee8 Author: Adrian Bunk Date: Mon Nov 5 14:06:38 2007 -0300 V4L/DVB (6570): core/dvb_ringbuffer.c: remove unused exports This patch removes the following unused EXPORT_SYMBOL's: - dvb_ringbuffer_flush - dvb_ringbuffer_pkt_write - dvb_ringbuffer_pkt_read - dvb_ringbuffer_pkt_dispose - dvb_ringbuffer_pkt_next Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab commit a32bafc075ca00e0e97bd45c8eaa4fb8b941ddc1 Author: Adrian Bunk Date: Mon Nov 5 14:06:31 2007 -0300 V4L/DVB (6569): bt8xx/dst.c: make code static This patch makes the following needlessly global code static: - dst_gpio_outb() - dst_gpio_inb() - rdc_8820_reset() - dst_pio_enable() - dst_command() - struct tuner_list[] Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab commit b7057879e0863e1070756829c58bd6ee6cc42d95 Author: Roel Kluin <12o3l@tiscali.nl> Date: Tue Nov 6 10:25:16 2007 -0300 V4L/DVB (6564): Move check before lock Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Signed-off-by: Andrew Morton CC: Antti Palosaari CC: Carl Lundqvist CC: Aapo Tahkola Signed-off-by: Mauro Carvalho Chehab commit fe72b3c583c1926396c137772b197d7e2b4e9c97 Author: Michael Krufky Date: Mon Nov 5 09:54:42 2007 -0300 V4L/DVB (6563): tda8290: optimize for loop in tda829x_probe function Thanks to Trent Piepho for pointing this out. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 1bab3fce8d6d451d6c4f02e8281b36e8e03c8470 Author: Mauro Carvalho Chehab Date: Mon Nov 5 09:30:39 2007 -0300 V4L/DVB (6562): Make HVR900 to use also tveeprom Hauppauge firmwares can be decoded using tveeprom. This patch adds HVR-900 as a tveeprom client. It also adds xc3028 tuner entry to tveeprom. Signed-off-by: Mauro Carvalho Chehab commit 70bad35ff4c9473cacbfbb3ed2a262aca0c188e7 Author: Mauro Carvalho Chehab Date: Mon Nov 5 09:07:13 2007 -0300 V4L/DVB (6561): Fix xc2028 get register functions and calls The status registers require a dword for setting register. Fix it on all occurrences, and at xc3028_get_reg. Also, improves the hardware/firmware detection printk. Signed-off-by: Mauro Carvalho Chehab commit 28b77573b2a916961d113e6e5f25231074d1de4f Author: Mauro Carvalho Chehab Date: Mon Nov 5 08:42:55 2007 -0300 V4L/DVB (6560): Fix a bug when setting tuner type Tuner-type were correctly filled only by the hint function. Signed-off-by: Mauro Carvalho Chehab commit f667ac3d982631b2237959b9e14ecd4f2355db8e Author: Mauro Carvalho Chehab Date: Mon Nov 5 08:41:50 2007 -0300 V4L/DVB (6559): Fix a buffer overflow at xc2028_get_reg Signed-off-by: Mauro Carvalho Chehab commit e9b2cf1d3ed36ba9a6e6cfbf20407eed5b0d4eb6 Author: Hans Verkuil Date: Thu Nov 1 06:19:39 2007 -0300 V4L/DVB (6557): tea5767: remove unnecessary warning Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 16cbe11e11033bdeb9934fe50db916960004cf60 Author: Hans Verkuil Date: Sun Nov 4 11:03:36 2007 -0300 V4L/DVB (6556): tuner: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit a944a0eaa5fd9e225cf881fa467abb20e145e67f Author: Hans Verkuil Date: Sun Nov 4 10:53:09 2007 -0300 V4L/DVB (6555): tuner: reorder functions to prepare for i2c conversion Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 7b62818b9957cb8a29fa317f20d24039e5c58513 Author: Hans Verkuil Date: Sun Nov 4 10:42:42 2007 -0300 V4L/DVB (6553): tuner: replace default_mode_mask The default_mode_mask global is replaced by a list of tuner structs. The tuner driver now walks that list to see which radio and/or tv tuner devices are registered to a given i2c adapter. The default_mode_mask global had to go since this is no longer supported with the new bus-based I2C API. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 65806304ab0f9b81c2974adbece73f3e6f1f0090 Author: Michael Krufky Date: Sun Nov 4 11:03:22 2007 -0300 V4L/DVB (6551): tda8290: rule out tda988x before detecting tda8290/tda8295 To ensure prevention of detecting a tda9885/6/7 as a tda8290 or tda8295, we will rule out the tda988x before testing the tda8290 / tda8295 id registers. We read 8 bytes from the chip. If they are all equal, then it is not a tda829x, or some other error has occurred. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 0f91192fce122ec0d2cd19be96f7b5ad37b83998 Author: Michael Krufky Date: Sun Nov 4 10:51:28 2007 -0300 V4L/DVB (6550): tda8290: return -ENODEV on probe failures Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 5e6abe66ad096f5123653b2a99f2bda35652ec74 Author: Mauro Carvalho Chehab Date: Tue Nov 20 11:28:08 2007 -0200 V4L/DVB(6548b) Fix compilation for em28xx From: Mauro Carvalho Chehab In file included from drivers/media/video/em28xx/em28xx-i2c.c:31: drivers/media/video/tuner-xc2028.h:10:26: error: dvb_frontend.h: No such file or directory In file included from drivers/media/video/em28xx/em28xx-i2c.c:31: drivers/media/video/tuner-xc2028.h:32: warning: 'struct dvb_frontend' declared inside parameter list drivers/media/video/tuner-xc2028.h:32: warning: its scope is only this definition or declaration, which is probably not what you want Signed-off-by: Mauro Carvalho Chehab commit c34897763c7b8fc3c1fa778c02d91f9bd8d2cf23 Author: Mauro Carvalho Chehab Date: Tue Nov 20 11:28:08 2007 -0200 V4L/DVB(6548a) Fix compilation for TDA8290 From: Mauro Carvalho Chehab drivers/media/video/tda8290.c:27:21: error: tda827x.h: No such file or directory drivers/media/video/tda8290.c:28:22: error: tda18271.h: No such file or directory drivers/media/video/tda8290.c:52: error: field 'cfg' has incomplete type drivers/media/video/tda8290.c: In function 'tda829x_find_tuner': drivers/media/video/tda8290.c:590: error: implicit declaration of function 'tda18271_attach' drivers/media/video/tda8290.c:598: error: implicit declaration of function 'tda827x_attach' Signed-off-by: Mauro Carvalho Chehab commit 2ca92bfc5d9d530046db3bb5fe73efdd803ba459 Author: Mauro Carvalho Chehab Date: Sun Nov 4 08:32:42 2007 -0300 V4L/DVB (6546): Add comments for the hint methods Signed-off-by: Mauro Carvalho Chehab commit 11630ee0026ee4ba184437f3397937562a3bbdea Author: Sascha Sommer Date: Sun Nov 4 08:06:48 2007 -0300 V4L/DVB (6545): em28xx: autodetect Cinergy 200 USB and VGear PocketTV Adds autodetection support for the Cinergy200 USB and the VGear PocketTV. Whenever a usb device with generic empia em2800 usb ids is detected the device gets scanned for connected i2c devices. If the device list matches an em2800 device in the device list the model id gets changed accordingly. Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab commit 169397f7626fd495ae11722ba9acc3d3fb94a46d Author: Michael Krufky Date: Sat Nov 3 22:14:54 2007 -0300 V4L/DVB (6543): tda8290: enable probing of tda8295 Prevent the tda8295 from falsely being detected as a tda9887 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 2b2e0c97063727159aa3d94b5c56b43a5e633426 Author: Mauro Carvalho Chehab Date: Sat Nov 3 22:40:24 2007 -0300 V4L/DVB (6542): Fix S-video mode on tvp5150 Thanks to Markus Reichberger to point this. Signed-off-by: Mauro Carvalho Chehab commit 81702204773d3a671a5dd25f1e7e9015ffe688c8 Author: Mauro Carvalho Chehab Date: Sat Nov 3 22:04:33 2007 -0300 V4L/DVB (6541): Add V-Gear PocketTV to Cardlist.em28xx Signed-off-by: Mauro Carvalho Chehab commit 5ef0919a95f342362e1d22843fe0e2816542da67 Author: Sascha Sommer Date: Sat Nov 3 16:48:01 2007 -0300 V4L/DVB (6540): em28xx: fix failing autodetection after the reboot The attached patch is required so that the autodetecion code also works after a reboot. Setting the I2C speed does not seem to be supported for em2800. Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab commit 2cfcfb6ad4eb59f61e911163431ea93324a2b4f5 Author: Sascha Sommer Date: Sat Nov 3 15:05:07 2007 -0300 V4L/DVB (6539): em28xx: add support for vgear pockettv attached patch adds support for the vgear pockettv. It seems to require a write to another register for audio to work. I checked my old cinergydrv and we did the same register write there. I therefore enabled it for all em2800 based devices. Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab commit b8419afb7bdd46dd44954685824d9023683c4b75 Author: Sascha Sommer Date: Sat Nov 3 21:22:38 2007 -0300 V4L/DVB (6538): em28xx: fix locking to allow accesses from 2 different threads at the same time The attached patch modifies the em28xx driver so that there can be ioctls from multiple different threads. This is necessary for capture apps like MPlayer that use different threads for capturing and channel tuning. Now the locking is only done for the ioctls that change properties of the device or access the i2c bus. It also removes some locks that look unnecessary: In em28xx_init_dev: the videodevice is not registered yet so nothing can access the hardware meanwhile, the device struct is not assigned to the interface yet so no race with disconnect is possible In em28xx_release_resources: it gets only called when dev->lock is already held Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab commit 34e478d35b2ba88ab7d48986ae071e30b3610f59 Author: Mauro Carvalho Chehab Date: Sat Nov 3 21:21:57 2007 -0300 V4L/DVB (6537): Add entry for Pixelview Prolink PlayTV USB 2.0 Signed-off-by: Mauro Carvalho Chehab commit d12cc0bb82b603a998890b06ac6f4a2d7d20c706 Author: Mauro Carvalho Chehab Date: Sat Nov 3 21:20:59 2007 -0300 V4L/DVB (6536): Add a hint for boards without unique USB ID This patch adds a function to allow trying to detect boards that shares the generic IDs. The current detection method is based at eeprom checksum. Signed-off-by: Mauro Carvalho Chehab commit 7fc8be9da9cfe3d38f77678f55edfeeb15481b92 Author: Mauro Carvalho Chehab Date: Sat Nov 3 08:07:07 2007 -0300 V4L/DVB (6535): Fix: Adds the generic PCI IDs for em28xx Signed-off-by: Mauro Carvalho Chehab commit fb158686954079fa26a01e720e17be8bf80f3ea3 Author: Mauro Carvalho Chehab Date: Thu Nov 1 21:52:58 2007 -0300 V4L/DVB (6519): Fix HVR900/HVR950 entry - Television is now default; - Add HVR950 name at the entry. Signed-off-by: Mauro Carvalho Chehab commit 6bc56c505ef0015376c009b193aa0bf5fd6b307e Author: Mauro Carvalho Chehab Date: Thu Nov 1 17:47:42 2007 -0300 V4L/DVB (6517): CodingStyle fixup Used scripts/Lindent + manual check + scripts/checkpatch.pl Signed-off-by: Mauro Carvalho Chehab commit 001c3b879a2b1eb39581cf3281404ea1decb8532 Author: Mauro Carvalho Chehab Date: Thu Nov 1 16:56:26 2007 -0300 V4L/DVB (6516): Allow faster loading by using 64 bytes block by em28xx i2c write Signed-off-by: Mauro Carvalho Chehab commit 9ed34064d6b1b0af74c5ac2f2b52e36eb1fc1996 Author: Trent Piepho Date: Thu Nov 1 01:16:05 2007 -0300 V4L/DVB (6508): ttpci: Rework Kconfig menus and Makefile The ttpci Kconfig file has bugs that cause it to fail in certain Kconfig situations. The basic problem is that it selects certain drivers, but does not depend on the dependencies of those drivers. See http://article.gmane.org/gmane.comp.video.video4linux/35072 Using the Kconfig file also has some annoyances. For instance one can't turn off AV7110 support unless you go down several options and first turn off budget-patch support. Normally user selectable drivers are not forced on like this. The "AV7110 cards with Budget Patch" option is disabled if "Budget cards" isn't on. Normally a driver appears nested under a driver it depends on, but since drivers that don't depend on "Budget cards" are between the two options, the config programs can't display the tree correctly. The Makefile has an issue too. Some modules, ttpci-eeprom and budget-core, appear in the Makefile under several different config symbols. If more than one of these symbols is on, they will get added the to list of objects multiple times. The normal convention is to have a config symbol just the common object(s) and have the users of the that object either depend on or select that config symbol. This patch fixes all these issues. ttpci-eepom is under a new config symbol, and so is the budget-core module. The four different budget card types appear as sub-drivers under a main "SAA7146 DVB cards" option. Turning on budget-patch doesn't force AV7110. Drivers using SAA7146_VV have the necessary VIDEO_DEV dependency, so that it isn't possible to select SAA7146_VV without V4L being on. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab commit a091cc66107c91af9f0f86ddd31c3012961cc027 Author: Trent Piepho Date: Thu Nov 1 01:16:04 2007 -0300 V4L/DVB (6507): bttv: whitespace cleanup Someone wasn't using the v4l-dvb commit scripts and so didn't run the automatic whitespace cleaner on their code. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab commit 058a3167a72c5e6f8a0fd8a2ad12764b5a667b1b Author: Marco Schluessler Date: Wed Oct 31 01:20:42 2007 -0300 V4L/DVB (6497): saa7146/budget*/dvb-ttpci: Remove V4L1 code Remove V4L1 code. Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab commit 1f8b86ae5dea7ca81e4b629420edb45eb66d5087 Author: Marco Schluessler Date: Wed Oct 31 00:44:22 2007 -0300 V4L/DVB (6496): saa7146_vv.h: remove wrong include remove wrong include Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab commit 86c9d4177c0f18b464aedfb259e4e217e2c9949f Author: Michael Krufky Date: Tue Oct 30 09:46:10 2007 -0300 V4L/DVB (6492): tuner: improve tuner_foo printk macros consistency Alter the tuner_foo printk macros to indicate which module is generating the message. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 38efe4055f735c7ac581232fc4697927587a4314 Author: Michael Krufky Date: Tue Oct 30 09:44:12 2007 -0300 V4L/DVB (6491): tuner: prevent repeated "type set" message unless debug is enabled The tuner sub-module will usually log its type during its _attach() function, then tuner-core reports which type was attached when control is returned. In most cases, we expect to see the same message reported from both locations. We only need to see this second message if debug is enabled. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit de8cea6b3a03209ff95c464db90b34813bab9537 Author: Hans Verkuil Date: Tue Oct 30 06:00:05 2007 -0300 V4L/DVB (6490): Remove EXPERIMENTAL from several i2c drivers Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit fee834f5ca934c8808ba34b4bc19f8be0ed2c571 Author: Hans Verkuil Date: Tue Oct 30 05:55:58 2007 -0300 V4L/DVB (6489): ivtv: add support for AVerMedia PVR-150 Plus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 34fd3eacad7b16713c51d171e36b62f3c33d114a Author: Hans Verkuil Date: Tue Oct 30 05:50:03 2007 -0300 V4L/DVB (6488): ivtv: add ASUS Falcon2 support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit b6394053cf31f3168a41ecd2b1e79a2b93854a12 Author: Hans Verkuil Date: Tue Oct 30 05:41:54 2007 -0300 V4L/DVB (6487): i2c-id: add M52790 driver ID Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 877929bd1675f3eabcfd4c265dcd21c7e8c91865 Author: Hans Verkuil Date: Tue Oct 30 05:41:25 2007 -0300 V4L/DVB (6486): m52790: add new Mitsubishi A/V switch i2c driver This driver is used by the ASUS Falcon2 cx23416-based cards. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit a3bfdefba4602f3fb4bef399e981ac813a2ad917 Author: Hans Verkuil Date: Tue Oct 30 04:16:35 2007 -0300 V4L/DVB (6485): ivtv: fix compile warning Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit e1767ed795f18a4aa2772f15e26bd98afb4e8d55 Author: Douglas Schilling Landgraf Date: Mon Oct 29 00:44:55 2007 -0300 V4L/DVB (6483): ivtv-streams: make file_operations const Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab commit d443aa769f951be481bdde6ee0e0c991e37cf8f6 Author: Douglas Schilling Landgraf Date: Mon Oct 29 00:37:07 2007 -0300 V4L/DVB (6482): zr364: make file_operations const zr364: make file_operations const Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab commit 7cc2f718c23524a0570695e428c8171923476e00 Author: Douglas Schilling Landgraf Date: Sun Oct 28 23:41:19 2007 -0300 V4L/DVB (6481): radio-gemtek: make file_operations const make file_operations const Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab commit 4e564a47fd0b57b23d08f2d9d8aabf649ee5229a Author: Randy Dunlap Date: Mon Oct 29 15:19:45 2007 -0300 V4L/DVB (6480): bttv: uses input functions, should depend on INPUT Several media drivers use input_(*) functions so they need to depend on the INPUT config symbol. drivers/built-in.o: In function `bttv_input_fini': linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:346: undefined reference to `input_unregister_device' drivers/built-in.o: In function `bttv_input_init': linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:204: undefined reference to `input_allocate_device' linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:335: undefined reference to `input_free_device' linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:321: undefined reference to `input_register_device' linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:335: undefined reference to `input_free_device' Signed-off-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab commit d250450735cd39b4c45c0d19086840831676fd43 Author: Mauro Carvalho Chehab Date: Mon Oct 29 23:44:18 2007 -0300 V4L/DVB (6477): Properly fill MODULE_AUTHOR Most of the driver were written by Mauro Carvalho Chehab. DTV parts were added by Michel Ludwig. Reviewed-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab commit 9153e715465276374940211be887c761328d52b5 Author: Mauro Carvalho Chehab Date: Mon Oct 29 23:36:12 2007 -0300 V4L/DVB (6476): Add support for analog tv on HVR-950 This patch adds USB ID for HVR-950. It also adds the callback for handling firmware loading. Thanks to Markus Reichberger for the reset commands. Signed-off-by: Mauro Carvalho Chehab commit 56ad6c009e749fe552c894f9c7c4b13443e56942 Author: Mauro Carvalho Chehab Date: Mon Oct 29 17:38:59 2007 -0300 V4L/DVB (6475): Fix some troubles at list handling - priv->count were wrong. Should be incremented since the first usage; - forgot to use list_del() to remove the driver; - Release memory if an error occurs during _attach Thanks to Aidan Thornton for pointing this. Signed-off-by: Mauro Carvalho Chehab commit dfa8dd24818cbcd4ecf89b5f48ed6d2550a69b57 Author: Mauro Carvalho Chehab Date: Mon Oct 29 11:33:18 2007 -0300 V4L/DVB (6474): Add support for tuner-xc2028 Signed-off-by: Mauro Carvalho Chehab commit 368f7444f1825008e42acd29655f003771103d6a Author: Mauro Carvalho Chehab Date: Mon Oct 29 11:33:18 2007 -0300 V4L/DVB (6473): Prevents double tuner registering Signed-off-by: Mauro Carvalho Chehab commit 605bb54682189951441d699df6d0872b970efb97 Author: Mauro Carvalho Chehab Date: Mon Oct 29 11:33:18 2007 -0300 V4L/DVB (6472): Re-inserts xc2028 attach code, fixing its parameters I2C bus redesign changed i2c parameters. This patch re-adds tuner xc2028 attach function, replacing the parameters to the newer syntax. Signed-off-by: Mauro Carvalho Chehab commit b927e81614e1bb00500f56ca03cacbbda67ef951 Author: Hans Verkuil Date: Fri Sep 14 05:13:54 2007 -0300 V4L/DVB (6471): tuner: i2c_client cannot be part of the tuner struct The bus-based I2C subsystem allocates the i2c_client struct. So if in order to be able to convert the tuner to the bus-based I2C API the embedded i2c_client struct must be removed from the tuner struct and replaced with a pointer. Signed-off-by: Hans Verkuil Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit e02712af1c609e49cb562a24f906e2d598fa5e50 Author: Mauro Carvalho Chehab Date: Mon Oct 29 11:33:18 2007 -0300 V4L/DVB (6470): Avoid breaking compilation The next patchset series will change i2c structs inside tuner. This patch avoids breaking bissect, by commenting the still unused tuner xc2028. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab commit 6bff63ba5767ef53e4c22224c6012fbc86e89c3a Author: Michael Krufky Date: Sat Oct 27 13:09:16 2007 -0300 V4L/DVB (6469): tuner: remove TUNER_PHILIPS_TDA8295 TUNER_PHILIPS_TDA8290 will autodetect a TDA8290 or a TDA8295, so we don't need this separate entry anymore. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 697565ff65b2f2ab8630b08166a1e718065224ec Author: Michael Krufky Date: Sat Oct 27 02:00:57 2007 -0300 V4L/DVB (6468): tda8290: auto-detect tda8290 or tda8295 Consolidate tda8290_attach() and tda8295_attach() into a single function, tda829x_attach(), which will detect chip combinations tda8290 or tda8295 with tda8275, tda8275a or tda18271. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 1b3be543524107626cd69e5a98b3eb212a949148 Author: Hans Verkuil Date: Tue Sep 18 03:22:32 2007 -0300 V4L/DVB (6467): v4l2-common: minor cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 00a9873c486af0fc9528e7753ce489d14612b9df Author: Hans Verkuil Date: Mon Sep 17 05:13:45 2007 -0300 V4L/DVB (6466): v4l2-i2c-drv: first call remove, then detach client The remove driver function expects that the client is still attached to the driver, so do the detach after calling remove(). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 2619567e0e091b228ecda30a27090d94b365cf47 Author: Hans Verkuil Date: Sun Sep 16 10:47:15 2007 -0300 V4L/DVB (6465): Use correct error codes when chip is not recognized If the chip isn't recognized, then the correct errors should be returned. The v4l2_i2c_attach() utility function will return 0 for all errors except -ENOMEM to provide proper compatibility support for the old I2C probing function. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit b6c1900874b0e425df029e8c2d85ac50738ca861 Author: Hans Verkuil Date: Fri Sep 14 05:03:17 2007 -0300 V4L/DVB (6464): tlv320aic23b: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit cb106a8b99fea0c6e869d41f63447b80dca3b70f Author: Hans Verkuil Date: Fri Sep 14 04:58:31 2007 -0300 V4L/DVB (6463): upd64031a: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 5bc257896b8e7227ab6b18d470807bcd494b8e38 Author: Hans Verkuil Date: Fri Sep 14 04:58:06 2007 -0300 V4L/DVB (6462): upd64083: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 6df5afc8b1c4c052a2c33b8b87cd09e45d6d8625 Author: Hans Verkuil Date: Fri Sep 14 04:50:44 2007 -0300 V4L/DVB (6461): tvaudio: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit ae37b879dd46c90c640c48ad367e5054a89d50fe Author: Hans Verkuil Date: Fri Sep 14 04:49:16 2007 -0300 V4L/DVB (6460): v4l2-i2c-drv: add legacy_probe function pointer Some devices do complicated tests whether the device can be probed or not. Add a legacy_probe function pointer to support that. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit abed2da3b13190017f7588cf61fc5d1e5307c7e6 Author: Hans Verkuil Date: Thu Sep 13 11:44:47 2007 -0300 V4L/DVB (6459): cx25840: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 4165392f5f870dfea4ae616519bafbc6bcb16c54 Author: Hans Verkuil Date: Thu Sep 13 11:30:38 2007 -0300 V4L/DVB (6458): cs53l23a: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 2f7b6fd760abe77a7a11a03c7be57b008fa83d2c Author: Hans Verkuil Date: Thu Sep 13 11:28:59 2007 -0300 V4L/DVB (6457): msp3400: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 958aa05b977df21442bc6de85066e0a55b885252 Author: Hans Verkuil Date: Thu Sep 13 11:21:51 2007 -0300 V4L/DVB (6456): saa7127: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 584f54a29f8c0b21877a32f8045045d0bdfe36f0 Author: Hans Verkuil Date: Thu Sep 13 11:19:39 2007 -0300 V4L/DVB (6455): saa7115: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit c16608b91841dd9e1a2eaa6edcdf20f69d4fa044 Author: Hans Verkuil Date: Thu Sep 13 11:11:44 2007 -0300 V4L/DVB (6454): vp27smpx: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 92183dbcc9bb463a2001e60c49ff8cd4012f4d98 Author: Hans Verkuil Date: Thu Sep 13 11:10:07 2007 -0300 V4L/DVB (6453): wm8739: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 33923cebfe9f45867f8d8c25fa2a21dd8aec9e86 Author: Hans Verkuil Date: Thu Sep 13 11:08:25 2007 -0300 V4L/DVB (6452): wm8775: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 9bc2f512cc567d31b5fabcd91cbbfbb1dc5fbae7 Author: Hans Verkuil Date: Wed Sep 12 08:32:50 2007 -0300 V4L/DVB (6451): v4l2: add support for bus-based I2C drivers Two new headers were added: one for I2C drivers that are only used by V4L2 drivers converted to the new bus-based I2C API, and one that can be used by both converted and unconverted drivers (at the expense of some additional overhead). To support the legacy I2C API a helper function was added to v4l2-common.c. These headers take care of all the 'boilerplate' code that all V4L2 I2C drivers have in common and will automatically support the bus-based I2C API introduced in kernel 2.6.22. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 05203488b9f7594a01272cc709a59e33781a68ef Author: Michael Krufky Date: Sat Oct 27 02:17:19 2007 -0300 V4L/DVB (6450): tda9887: add missing module license This module was always GPL, and will remain GPL Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 59557b4c1fd22896fb32997d84c1412689d0bd44 Author: Michael Krufky Date: Wed Oct 24 09:55:54 2007 -0300 V4L/DVB (6449): tda18271: clean up i2c_gate handling Call analog_demod_ops->i2c_gate_ctrl when in analog tuning mode, and frontend_ops.i2c_gate_ctrl when in digital tuning mode. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit d6b85084e2d3c5938ef36e7a67fb95c2d9dd548b Author: Michael Krufky Date: Wed Oct 24 09:30:17 2007 -0300 V4L/DVB (6448): tda8290: fill i2c_gate_ctrl callback Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit e28ebf68506273f1cb40dfa262ce20f55e360927 Author: Michael Krufky Date: Wed Oct 24 09:23:17 2007 -0300 V4L/DVB (6447): tuner: add i2c_gate_ctrl function to struct analog_tuner_ops In some designs, the tuner silicon may be on an i2c bus behind an i2c gate, controlled by the analog demodulator. We already have a method to control such i2c gates when they are controlled by the digital demodulator, but in some hybrid designs, there may be an i2c gate controlled by each demodulator. For example, when in analog tuning mode, one would access the tuner by opening the i2c gate controlled by the analog demodulator, while when in digital tuning mode, one would access the tuner by opening the i2c gate controlled by the digital demodulator. We must add this callback function to analog_tuner_ops in order to handle such configurations. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit ab3f08d07fead9f404286f35071d0dc9d131df39 Author: Michael Krufky Date: Wed Oct 24 01:00:24 2007 -0300 V4L/DVB (6446): tda18271: clean up debug macros Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 7bfd9b07f35f57a9b8907fa8fa02247bf2765b5a Author: Michael Krufky Date: Mon Oct 22 18:15:39 2007 -0300 V4L/DVB (6445): tuner-core: improve comments inside function fe_release() Explain who is responsible for freeing analog_demod_priv Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit a1b8b8b025ab2ff8e28d7bf2dc3b1360bb8fcf77 Author: Michael Krufky Date: Mon Oct 22 18:03:29 2007 -0300 V4L/DVB (6444): tuner-core: remove excessive parenthesis Convert all instances of "if ((ops) && (ops->foo))" to "if (ops && ops->foo)" Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 375b74fb08768f34b4e95214bea1d46486cfdf2d Author: Michael Krufky Date: Sun Oct 21 20:48:48 2007 -0300 V4L/DVB (6443): make tda9887 build selectable via Kconfig Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 2dcd1b6816e2ef511a30abb01f0f5f632f31f355 Author: Michael Krufky Date: Mon Oct 22 01:10:39 2007 -0300 V4L/DVB (6442): move std if setting from tda8290 to tda827x Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 7ac35894b06f0fae38a2206cdd9b42fc677032f8 Author: Michael Krufky Date: Mon Oct 22 01:44:03 2007 -0300 V4L/DVB (6441): tuner: clean up ops checking in tuner_status function Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 2376aea259353c216f6f4a4c2b79361588e5d612 Author: Michael Krufky Date: Sun Oct 21 19:39:50 2007 -0300 V4L/DVB (6440): tuner: convert analog tuner demod sub-modules to dvb_frontend interface Convert tda9887 and tda8290/5 to dvb_frontend interface Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 6b4744e496c0f81d4828303be2f4d9d84941e751 Author: Michael Krufky Date: Mon Oct 22 00:12:16 2007 -0300 V4L/DVB (6439): dvb_frontend: codingstyle cleanups thanks to checkpatch.pl Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit a23fe7adb95c04152e98692c0050cfa0d786289d Author: Michael Krufky Date: Sun Oct 21 15:22:25 2007 -0300 V4L/DVB (6438): tuner: move analog_demod_priv into struct dvb_frontend Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 42714bc7a8dbd066a52e915a527b92a91db64437 Author: Michael Krufky Date: Sun Oct 21 14:35:21 2007 -0300 V4L/DVB (6437): tuner: clear analog_demod_ops on release Clear analog_demod_ops on release. Fix test for analog_demod_ops after tuner attach. Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 31711858ac7da7eaafc548257d33a033f67c5ee9 Author: Michael Krufky Date: Sun Oct 21 13:40:56 2007 -0300 V4L/DVB (6436): tuner: move analog_tuner_ops into dvb_frontend_ops Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 4cf0df84abd30643b4029ca20f8743dda5726893 Author: Michael Krufky Date: Mon Oct 22 09:56:38 2007 -0300 V4L/DVB (6435): tda8290: add support for NXP TDA18271 tuner and TDA8295 analog demod Add basic support for NXP TDA8295 analog demod and TDA18271 tuner silicon. TDA8295 + TDA8275a not yet tested. TDA8290 + TDA18271 not yet supported. Digital mode of TDA18271 not yet tested & needs more work. Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 511ebab6e776f0e320619c821c2e9fd249c491c3 Author: Michael Krufky Date: Mon Oct 22 00:28:50 2007 -0300 V4L/DVB (6434): tda827x: fix GPL export on attach function EXPORT_SYMBOL should have been EXPORT_SYMBOL_GPL Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 7ae195739f913185819f84281f223a96c4b4bf60 Author: Michael Krufky Date: Sat Aug 25 19:08:45 2007 -0300 V4L/DVB (6433): Move all tda8275/8275a tuning code from tda8290 module into tda827x module Add analog tuning support to tda827x dvb_frontend tuner module. Convert tda8290 module back to native tuner interface. The tda8290 analog demodulator will be handled the same way as tda9887. The tuner.ko module (tuner-core) will pass commands to tda8290 via the tuner_operations interface. tda8290 will communicate with tda827x via the dvb_frontend interface, while passing a pointer to a private data structure. Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab commit 8767b209c38f339030e79d094210228f0880dbb4 Author: Mauro Carvalho Chehab Date: Wed Oct 24 09:22:08 2007 -0300 V4L/DVB (6431): Improve firmware format Signed-off-by: Mauro Carvalho Chehab commit 9ef3ca44fe0f17f7ee1a8877c534f8bc07885492 Author: Mauro Carvalho Chehab Date: Tue Oct 23 15:24:06 2007 -0300 V4L/DVB (6430): Convert tuner-xc2028 driver to the newer hybrid approach This changeset converts tuner-xc2028 to the newer hybrid approach. It also prevents creating twice the xc3028 private struct by both DVB and V4L parts. Signed-off-by: Mauro Carvalho Chehab commit a838894f66aaea324248fdb0d12348fd478871cd Author: Mauro Carvalho Chehab Date: Thu Sep 27 18:27:03 2007 -0300 V4L/DVB (6429): Avoid having two tuner commands happening at the same time Signed-off-by: Mauro Carvalho Chehab commit 331a7844f5100ca1faf994715767032c06170d07 Author: Michel Ludwig Date: Fri Jul 27 08:24:39 2007 -0300 V4L/DVB (6428): Make the naming of the DTV firmware files more consistent Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab commit c34b2dac03829f1c863325a5595cb039d8af15f7 Author: Mauro Carvalho Chehab Date: Wed Jul 18 23:14:25 2007 -0300 V4L/DVB (6427): Some cleanups at tuner-xc2028 driver Signed-off-by: Mauro Carvalho Chehab commit 1ae14811b839ec81936dd34686dcede285de18a6 Author: Mauro Carvalho Chehab Date: Wed Jul 18 13:33:23 2007 -0300 V4L/DVB (6426): Some fixes on tuner-xc2028 Signed-off-by: Mauro Carvalho Chehab commit 5a948b03061c263e2b92ce5f5ffbd0253e1a6f50 Author: Michel Ludwig Date: Wed Jul 18 10:29:10 2007 -0300 V4L/DVB (6425): Add experimental DVB frontend tuner interface to xc2028/3028 Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab commit 0a434730646a168d3ca3883a5bab0e6c4cc5cbba Author: Michel Ludwig Date: Wed Jul 18 10:26:38 2007 -0300 V4L/DVB (6424): Improve tuner-xc2028 script Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab commit 8a612cb50071db364034e21cb324e66573855b29 Author: Mauro Carvalho Chehab Date: Tue Oct 2 11:57:03 2007 -0300 V4L/DVB (6423): Add tuner-xc2028 driver Add support for Xceive XC2028/XC3028 tuner driver Signed-off-by: Mauro Carvalho Chehab commit 1db1b20ddf8eeb4f4e872542141275e9edcf39f6 Author: Mauro Carvalho Chehab Date: Wed Oct 24 11:08:20 2007 -0300 V4L/DVB (6422): Add the pending entries for xc2028/3028 based boards Also replaces all occurrences of TUNER_XCEIVE_XC3028 to TUNER_XC2028. Some work is still may be required to make sure that non-tm6000 drivers will be capable of using tuner-xc2028. Signed-off-by: Mauro Carvalho Chehab commit c2ea87f180e86b9d9accb578984bc99a8822acca Author: Mauro Carvalho Chehab Date: Fri Aug 25 16:53:11 2006 -0300 V4L/DVB (6421): Make Kconfig reflect the changes at audio helper modules Signed-off-by: Mauro Carvalho Chehab commit 935287d9b825e704414904d03306021296c03a62 Author: Mauro Carvalho Chehab Date: Fri Aug 25 16:53:10 2006 -0300 V4L/DVB (6420): V4L2 conversion for tda9875 from V4L1 API Signed-off-by: Mauro Carvalho Chehab commit 1b8e64f7d2ce384278c496a761b7b3ed6801bcc8 Author: Mauro Carvalho Chehab Date: Fri Aug 25 16:53:09 2006 -0300 V4L/DVB (6419): V4L2 port of tda7432 from V4L1 api Signed-off-by: Mauro Carvalho Chehab commit 8950cf6bef619c61f7475ac7c17269805617df16 Author: Mauro Carvalho Chehab Date: Fri Aug 25 16:53:08 2006 -0300 V4L/DVB (6418): Converted tvaudio from V4L1 to V4L2 V4L1 ioctls were replaced to V4L2 were applicable. The older ones already implemented were removed. Signed-off-by: Mauro Carvalho Chehab commit 834a017293ae1e77dd955b07d0eec76289ecf074 Author: Nickolay V. Shmyrev Date: Fri Aug 25 16:53:07 2006 -0300 V4L/DVB (6417): Report detected sound carrier into rxsubchans Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab commit ad792b6c62b27a903455fb39ae79a625e940f593 Author: Nickolay V. Shmyrev Date: Fri Aug 25 16:53:04 2006 -0300 V4L/DVB (6416): Split hooks on volume and audio mode and rework their handling Also convert audio_mode_gpio functions from audio_hook Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab commit f91aeb0ffe54ae6ffed7b427c023753b72c41753 Author: Nickolay V. Shmyrev Date: Fri Oct 26 17:21:30 2007 -0300 V4L/DVB (6415): Restructurize volume hook and drop unused mute hook Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab commit 9695b34ba8b5a4c5e3798fca2684fb168c1ff977 Author: Nickolay V. Shmyrev Date: Fri Oct 26 17:15:19 2007 -0300 V4L/DVB (6414): Remove bass, treble and balance from audio hook since they are unused Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab commit da6761e4cfd6bced68fd50e2508935ea4a018bc4 Author: Nickolay V. Shmyrev Date: Fri Aug 25 16:53:02 2006 -0300 V4L/DVB (6413): Forward VIDIOCGAUDIO and VIDIOCSAUDIO through v4l1-compat Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab commit b496136b65c5b9fea7bb907198b28c4f4edae549 Author: Mauro Carvalho Chehab Date: Fri Oct 26 16:54:54 2007 -0300 V4L/DVB (6412): Audio hooks moved to another file Signed-off-by: Mauro Carvalho Chehab commit c14a9f3f71ff8d4c3ca74ceed146c4e6af39d825 Author: Mauro Carvalho Chehab Date: Fri Oct 26 16:51:47 2007 -0300 V4L/DVB (6411): remove V4L1 from being compiled when V4L2 only is selected Signed-off-by: Mauro Carvalho Chehab commit b264595ff73c5294b22e90339ce037254aedb2fa Author: Nickolay V. Shmyrev Date: Fri Oct 26 11:01:08 2007 -0300 V4L/DVB (6410): Partial conversion from V4L1 to V4L2 This is part of the old V4L1->V4L2 bttv patch, ported to current tree by Mauro Carvalho Chehab Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab commit 02a3ef5d4baa11eb645a658af8fe92b5d7ebb6b5 Author: Nickolay V. Shmyrev Date: Fri Oct 26 10:53:21 2007 -0300 V4L/DVB (6409): Cleanup: removed i2c_vidiocschan This is part of the old V4L1->V4L2 bttv patch, ported to current tree by Mauro Carvalho Chehab Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab commit 4ef9f47353e4bcc2330b2d22d745099ab886565d Author: Nickolay V. Shmyrev Date: Fri Aug 25 16:52:54 2006 -0300 V4L/DVB (6408): Cleanup: Removed obsoleted code from bttv-cards This is part of the old V4L1->V4L2 bttv patch, ported to current tree by Mauro Carvalho Chehab Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab commit 32d76b507f518e31a9a7acb230e3973ac54e08d0 Author: Steven Toth Date: Thu Sep 20 01:44:27 2007 -0300 V4L/DVB (6404): cx23885: i2c 16bit reg/val read/write fix Fix i2c reads and writes of 16bit register address / values Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab commit 7b9542411cf4ace8f4138d8c44549d1c0db10c2d Author: Matthias Kaehlcke Date: Wed Oct 24 17:31:15 2007 -0300 V4L/DVB (6400): usbvision: Convert the usbvision->lock semaphore to the mutex API Convert the usbvision->lock semaphore to the mutex API Signed-off-by: Matthias Kaehlcke Reviewed-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab commit d8ae929d1ccafad6f1e631e2d9e3df752ca87c84 Author: Adrian Bunk Date: Wed Oct 24 13:23:14 2007 -0300 V4L/DVB (6399): saa7134/: make 2 functions static saa7134_buffer_requeue() and set_tvnorm() can become static. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab commit 035b75379587a6db22898d565370d802ad7c1645 Author: Mauro Carvalho Chehab Date: Fri Oct 19 06:59:33 2007 -0300 V4L/DVB (6386): Add support for radio on CX88_BOARD_MSI_TVANYWHERE_MASTER This board has some special tea5767 configuration. Basically, radio XTAL uses a different frequency than the other supported radios. It uses a 13 MHz XTAL. This patch adds the proper radio gpio and tea5767 configurations for the board. Also, with PAL/BG, the board requires some special init for tda9887: port1=0 port2=0 qss=1 Thanks to Serge Kolotylo and MIDImaster for their help on identifying the proper needs for this driver. Signed-off-by: Mauro Carvalho Chehab commit 50ba1b037c80a0a800909b4b66e6f7f362ca5c91 Author: Mauro Carvalho Chehab Date: Thu Oct 18 20:10:07 2007 -0300 V4L/DVB (6385): Adds the capability of configuring tea5767 support tea5767 has several possible configurations. Before the patch, the driver were assuming the more common configuration. However, some newer cards, like MSI @nyware Master requires other configurations, like de-activating a gpio port and changing chip Xtal. This patch adds the capability of altering device configuration at runtime. This may also be used later to activate some features like auto-mute when signal is weak. Signed-off-by: Mauro Carvalho Chehab commit 745d88bb1d2359a28a692027a601072b3d2b8fc8 Author: Mauro Carvalho Chehab Date: Thu Oct 18 19:56:47 2007 -0300 V4L/DVB (6384): Replace TDA9887_SET_CONFIG by TUNER_SET_CONFIG Currently, the only tuner-specific device that allows special configurations is tda9887. However, tea5767 also may require some special configurations (for example, to specify a different Xtal freq). This patch replaces TDA9887_SET_CONFIG by a more generic internal ioctl (TUNER_SET_CONFIG). The newer one allows specifying what tuner is appliable to a configuration set, and allows an arbitrary configuration struct. Signed-off-by: Mauro Carvalho Chehab Documentation/video4linux/CARDLIST.em28xx | 8 +- Documentation/video4linux/CARDLIST.saa7134 | 2 +- Documentation/video4linux/CARDLIST.tuner | 4 +- Documentation/video4linux/sn9c102.txt | 1 + drivers/media/Kconfig | 22 +- drivers/media/common/Kconfig | 2 +- drivers/media/common/ir-functions.c | 3 +- drivers/media/common/saa7146_fops.c | 8 +- drivers/media/common/saa7146_vbi.c | 10 +- drivers/media/common/saa7146_video.c | 19 +- drivers/media/dvb/b2c2/flexcop.c | 1 - drivers/media/dvb/bt8xx/dst.c | 19 +- drivers/media/dvb/bt8xx/dst_common.h | 5 - drivers/media/dvb/dvb-core/dvb_frontend.h | 23 +- drivers/media/dvb/dvb-core/dvb_ringbuffer.c | 5 - drivers/media/dvb/dvb-usb/au6610.c | 6 +- drivers/media/dvb/dvb-usb/cxusb.c | 5 +- drivers/media/dvb/dvb-usb/cxusb.h | 5 - drivers/media/dvb/dvb-usb/dib0700_devices.c | 41 +- drivers/media/dvb/dvb-usb/digitv.c | 3 +- drivers/media/dvb/dvb-usb/digitv.h | 3 - drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 7 +- drivers/media/dvb/dvb-usb/gl861.c | 6 +- drivers/media/dvb/dvb-usb/gp8psk.c | 16 - drivers/media/dvb/dvb-usb/gp8psk.h | 1 - drivers/media/dvb/dvb-usb/opera1.c | 6 +- drivers/media/dvb/dvb-usb/opera1.h | 9 - drivers/media/dvb/dvb-usb/vp702x.c | 15 +- drivers/media/dvb/dvb-usb/vp702x.h | 2 - drivers/media/dvb/dvb-usb/vp7045.c | 5 +- drivers/media/dvb/dvb-usb/vp7045.h | 5 - drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 2 + drivers/media/dvb/frontends/mt2266.c | 204 ++- drivers/media/dvb/frontends/tda10086.c | 14 +- drivers/media/dvb/frontends/tda18271.c | 1065 +++++++++++ drivers/media/dvb/frontends/tda18271.h | 40 + drivers/media/dvb/frontends/tda827x.c | 360 ++++- drivers/media/dvb/frontends/tda827x.h | 7 + drivers/media/dvb/frontends/ves1820.c | 4 +- drivers/media/dvb/ttpci/Kconfig | 37 +- drivers/media/dvb/ttpci/Makefile | 12 +- drivers/media/dvb/ttpci/av7110.c | 3 +- drivers/media/dvb/ttpci/av7110.h | 7 +- drivers/media/dvb/ttpci/av7110_av.c | 16 +- drivers/media/dvb/ttpci/av7110_av.h | 3 +- drivers/media/dvb/ttpci/av7110_v4l.c | 4 +- drivers/media/radio/radio-gemtek.c | 6 +- drivers/media/video/Kconfig | 29 +- drivers/media/video/Makefile | 6 +- drivers/media/video/bt8xx/Kconfig | 2 +- drivers/media/video/bt8xx/Makefile | 2 +- drivers/media/video/bt8xx/bttv-audio-hook.c | 382 ++++ drivers/media/video/bt8xx/bttv-audio-hook.h | 23 + drivers/media/video/bt8xx/bttv-cards.c | 444 +---- drivers/media/video/bt8xx/bttv-driver.c | 894 ++-------- drivers/media/video/bt8xx/bttv-risc.c | 14 +- drivers/media/video/bt8xx/bttv-vbi.c | 6 +- drivers/media/video/bt8xx/bttv.h | 5 +- drivers/media/video/bt8xx/bttvp.h | 9 +- drivers/media/video/cs53l32a.c | 72 +- drivers/media/video/cx23885/cx23885-cards.c | 2 - drivers/media/video/cx23885/cx23885-core.c | 113 +- drivers/media/video/cx23885/cx23885-i2c.c | 18 +- drivers/media/video/cx23885/cx23885.h | 4 - drivers/media/video/cx25840/cx25840-core.c | 470 ++--- drivers/media/video/cx25840/cx25840-vbi.c | 2 +- drivers/media/video/cx88/cx88-alsa.c | 2 +- drivers/media/video/cx88/cx88-blackbird.c | 5 +- drivers/media/video/cx88/cx88-cards.c | 22 + drivers/media/video/cx88/cx88-core.c | 4 +- drivers/media/video/cx88/cx88-i2c.c | 10 +- drivers/media/video/cx88/cx88-mpeg.c | 28 +- drivers/media/video/cx88/cx88-vbi.c | 10 +- drivers/media/video/cx88/cx88-video.c | 27 +- drivers/media/video/cx88/cx88.h | 6 - drivers/media/video/em28xx/Kconfig | 2 +- drivers/media/video/em28xx/Makefile | 3 + drivers/media/video/em28xx/em28xx-cards.c | 419 ++++- drivers/media/video/em28xx/em28xx-i2c.c | 81 +- drivers/media/video/em28xx/em28xx-video.c | 2295 ++++++++++++----------- drivers/media/video/em28xx/em28xx.h | 59 +- drivers/media/video/et61x251/et61x251_core.c | 20 +- drivers/media/video/et61x251/et61x251_sensor.h | 8 - drivers/media/video/ivtv/Kconfig | 1 + drivers/media/video/ivtv/ivtv-cards.c | 85 +- drivers/media/video/ivtv/ivtv-cards.h | 8 +- drivers/media/video/ivtv/ivtv-driver.c | 8 +- drivers/media/video/ivtv/ivtv-i2c.c | 3 + drivers/media/video/ivtv/ivtv-routing.c | 25 +- drivers/media/video/ivtv/ivtv-streams.c | 6 +- drivers/media/video/m52790.c | 172 ++ drivers/media/video/meye.c | 2 +- drivers/media/video/msp3400-driver.c | 73 +- drivers/media/video/mt20xx.c | 2 +- drivers/media/video/saa7115.c | 80 +- drivers/media/video/saa7127.c | 89 +- drivers/media/video/saa7134/saa7134-cards.c | 76 +- drivers/media/video/saa7134/saa7134-core.c | 12 +- drivers/media/video/saa7134/saa7134-dvb.c | 19 +- drivers/media/video/saa7134/saa7134-empress.c | 5 +- drivers/media/video/saa7134/saa7134-i2c.c | 13 +- drivers/media/video/saa7134/saa7134-input.c | 2 +- drivers/media/video/saa7134/saa7134-ts.c | 8 +- drivers/media/video/saa7134/saa7134-vbi.c | 8 +- drivers/media/video/saa7134/saa7134-video.c | 31 +- drivers/media/video/saa7134/saa7134.h | 6 +- drivers/media/video/sn9c102/Makefile | 1 + drivers/media/video/sn9c102/sn9c102_core.c | 4 +- drivers/media/video/sn9c102/sn9c102_devtable.h | 2 + drivers/media/video/sn9c102/sn9c102_mt9v111.c | 259 +++ drivers/media/video/tda7432.c | 232 ++-- drivers/media/video/tda8290.c | 927 +++++----- drivers/media/video/tda8290.h | 30 +- drivers/media/video/tda9875.c | 167 ++- drivers/media/video/tda9887.c | 115 +- drivers/media/video/tda9887.h | 33 + drivers/media/video/tea5761.c | 2 +- drivers/media/video/tea5767.c | 92 +- drivers/media/video/tea5767.h | 19 + drivers/media/video/tlv320aic23b.c | 73 +- drivers/media/video/tuner-core.c | 631 ++++--- drivers/media/video/tuner-driver.h | 65 +- drivers/media/video/tuner-i2c.h | 42 +- drivers/media/video/tuner-simple.c | 17 +- drivers/media/video/tuner-types.c | 8 +- drivers/media/video/tuner-xc2028-types.h | 115 ++ drivers/media/video/tuner-xc2028.c | 970 ++++++++++ drivers/media/video/tuner-xc2028.h | 48 + drivers/media/video/tvaudio.c | 504 +++--- drivers/media/video/tveeprom.c | 4 +- drivers/media/video/tvp5150.c | 11 + drivers/media/video/upd64031a.c | 71 +- drivers/media/video/upd64083.c | 70 +- drivers/media/video/usbvision/usbvision-core.c | 8 +- drivers/media/video/usbvision/usbvision-video.c | 54 +- drivers/media/video/usbvision/usbvision.h | 3 +- drivers/media/video/v4l2-common.c | 32 +- drivers/media/video/v4l2-int-device.c | 6 +- drivers/media/video/videobuf-core.c | 309 ++-- drivers/media/video/videobuf-dvb.c | 2 +- drivers/media/video/vivi.c | 25 +- drivers/media/video/vp27smpx.c | 73 +- drivers/media/video/wm8739.c | 71 +- drivers/media/video/wm8775.c | 78 +- drivers/media/video/zr364xx.c | 2 +- include/linux/i2c-id.h | 1 + include/media/ir-common.h | 1 - include/media/m52790.h | 93 + include/media/saa7146_vv.h | 1 - include/media/tuner.h | 2 +- include/media/v4l2-chip-ident.h | 3 + include/media/v4l2-common.h | 18 +- include/media/v4l2-i2c-drv-legacy.h | 140 ++ include/media/v4l2-i2c-drv.h | 62 + include/media/v4l2-int-device.h | 5 +- include/media/videobuf-core.h | 20 +- 157 files changed, 8532 insertions(+), 5279 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 37f0e3c..f809834 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -1,14 +1,16 @@ 0 -> Unknown EM2800 video grabber (em2800) [eb1a:2800] - 1 -> Unknown EM2820/2840 video grabber (em2820/em2840) + 1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2750,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883] 2 -> Terratec Cinergy 250 USB (em2820/em2840) [0ccd:0036] 3 -> Pinnacle PCTV USB 2 (em2820/em2840) [2304:0208] 4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200] - 5 -> MSI VOX USB 2.0 (em2820/em2840) [eb1a:2820] + 5 -> MSI VOX USB 2.0 (em2820/em2840) 6 -> Terratec Cinergy 200 USB (em2800) 7 -> Leadtek Winfast USB II (em2800) 8 -> Kworld USB2800 (em2800) 9 -> Pinnacle Dazzle DVC 90 (em2820/em2840) [2304:0207] - 10 -> Hauppauge WinTV HVR 900 (em2880) + 10 -> Hauppauge WinTV HVR 900/950 (em2880) 11 -> Terratec Hybrid XS (em2880) 12 -> Kworld PVR TV 2800 RF (em2820/em2840) 13 -> Terratec Prodigy XS (em2880) + 14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) + 15 -> V-Gear PocketTV (em2800) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index a145453..29ca16c 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -102,7 +102,7 @@ 101 -> Pinnacle PCTV 310i [11bd:002f] 102 -> Avermedia AVerTV Studio 507 [1461:9715] 103 -> Compro Videomate DVB-T200A -104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid [0070:6701] +104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid [0070:6700,0070:6701,0070:6702,0070:6703,0070:6704,0070:6705] 105 -> Terratec Cinergy HT PCMCIA [153b:1172] 106 -> Encore ENLTV [1131:2342,1131:2341,3016:2344] 107 -> Encore ENLTV-FM [1131:230f] diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index a88c02d..2211c8e 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -52,7 +52,7 @@ tuner=50 - TCL 2002N tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3) tuner=52 - Thomson DTT 7610 (ATSC/NTSC) tuner=53 - Philips FQ1286 -tuner=54 - tda8290+75 +tuner=54 - Philips/NXP TDA 8290/8295 + 8275/8275A/18271 tuner=55 - TCL 2002MB tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4) tuner=57 - Philips FQ1236A MK4 @@ -69,7 +69,7 @@ tuner=67 - Philips TD1316 Hybrid Tuner tuner=68 - Philips TUV1236D ATSC/NTSC dual in tuner=69 - Tena TNF 5335 and similar models tuner=70 - Samsung TCPN 2121P30A -tuner=71 - Xceive xc3028 +tuner=71 - Xceive xc2028/xc3028 tuner tuner=72 - Thomson FE6600 tuner=73 - Samsung TCPG 6121P30A tuner=75 - Philips TEA5761 FM Radio diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt index 1ffad19..b26f519 100644 --- a/Documentation/video4linux/sn9c102.txt +++ b/Documentation/video4linux/sn9c102.txt @@ -568,6 +568,7 @@ the fingerprint is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'. Many thanks to following persons for their contribute (listed in alphabetical order): +- David Anderson for the donation of a webcam; - Luca Capello for the donation of a webcam; - Philippe Coval for having helped testing the PAS202BCA image sensor; - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 1604f04..8f4a453 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -69,11 +69,13 @@ source "drivers/media/common/Kconfig" config VIDEO_TUNER tristate depends on I2C + select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE menuconfig VIDEO_TUNER_CUSTOMIZE bool "Customize analog tuner modules to build" @@ -89,6 +91,13 @@ menuconfig VIDEO_TUNER_CUSTOMIZE if VIDEO_TUNER_CUSTOMIZE +config TUNER_XC2028 + tristate "XCeive xc2028/xc3028 tuners" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the xc2028/xc3028 tuners. + config TUNER_MT20XX tristate "Microtune 2032 / 2050 tuners" depends on I2C @@ -97,8 +106,10 @@ config TUNER_MT20XX Say Y here to include support for the MT2032 / MT2050 tuner. config TUNER_TDA8290 - tristate "TDA 8290+8275(a) tuner combo" + tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" depends on I2C + select DVB_TDA827X + select DVB_TDA18271 default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for Philips TDA8290+8275(a) tuner. @@ -120,10 +131,19 @@ config TUNER_TEA5767 config TUNER_SIMPLE tristate "Simple tuner support" depends on I2C + select TUNER_TDA9887 default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for various simple tuners. +config TUNER_TDA9887 + tristate "TDA 9885/6/7 analog IF demodulator" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA9885/6/7 + analog IF demodulator. + endif # VIDEO_TUNER_CUSTOMIZE config VIDEOBUF_GEN diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index c5092ef..06ca759 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -1,6 +1,6 @@ config VIDEO_SAA7146 tristate - depends on I2C + depends on I2C && PCI config VIDEO_SAA7146_VV tristate diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c index e7c3ab9..bb2a027 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -258,7 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high) * saa7134 */ /* decode raw bit pattern to RC5 code */ -u32 ir_rc5_decode(unsigned int code) +static u32 ir_rc5_decode(unsigned int code) { unsigned int org_code = code; unsigned int pair; @@ -371,7 +371,6 @@ EXPORT_SYMBOL_GPL(ir_dump_samples); EXPORT_SYMBOL_GPL(ir_decode_biphase); EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); -EXPORT_SYMBOL_GPL(ir_rc5_decode); EXPORT_SYMBOL_GPL(ir_rc5_timer_end); EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup); diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 67d1b1b..b40bf23 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -61,7 +61,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } @@ -83,7 +83,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev, buf->activate(dev,buf,NULL); } else { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); } return 0; @@ -174,7 +174,7 @@ void saa7146_buffer_timeout(unsigned long data) spin_lock_irqsave(&dev->slock,flags); if (q->curr) { DEB_D(("timeout on %p\n", q->curr)); - saa7146_buffer_finish(dev,q,STATE_ERROR); + saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); } /* we don't restart the transfer here like other drivers do. when @@ -366,7 +366,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) } poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || buf->state == STATE_ERROR) { + if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { DEB_D(("poll succeeded!\n")); return POLLIN|POLLRDNORM; } diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index 6103484..c32dda9 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -205,7 +205,7 @@ static int buffer_activate(struct saa7146_dev *dev, struct saa7146_buf *next) { struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next)); saa7146_set_vbi_capture(dev,buf,next); @@ -238,7 +238,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e if (buf->vb.size != size) saa7146_dma_free(dev,q,buf); - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -257,7 +257,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e if (0 != err) return err; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; @@ -335,7 +335,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) saa7146_write(dev, MC1, MASK_20); if (vv->vbi_q.curr) { - saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE); + saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); } videobuf_queue_cancel(&fh->vbi_q); @@ -458,7 +458,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) /* this must be += 2, one count for each field */ vv->vbi_fieldcount+=2; vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount; - saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE); + saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); } else { DEB_VBI(("dev:%p\n",dev)); } diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index f245a3b..c31ab48 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1205,13 +1205,10 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int DEB_D(("VIDIOCGMBUF \n")); q = &fh->video_q; - mutex_lock(&q->lock); err = videobuf_mmap_setup(q,gbuffers,gbufsize, V4L2_MEMORY_MMAP); - if (err < 0) { - mutex_unlock(&q->lock); + if (err < 0) return err; - } gbuffers = err; memset(mbuf,0,sizeof(*mbuf)); @@ -1219,7 +1216,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int mbuf->size = gbuffers * gbufsize; for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; - mutex_unlock(&q->lock); return 0; } #endif @@ -1239,7 +1235,7 @@ static int buffer_activate (struct saa7146_dev *dev, { struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; saa7146_set_capture(dev,buf,next); mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT); @@ -1285,7 +1281,7 @@ static int buffer_prepare(struct videobuf_queue *q, saa7146_dma_free(dev,q,buf); } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct saa7146_format *sfmt; buf->vb.bytesperline = fh->video_fmt.bytesperline; @@ -1318,7 +1314,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; @@ -1440,10 +1436,7 @@ static void video_close(struct saa7146_dev *dev, struct file *file) err = saa7146_stop_preview(fh); } - // release all capture buffers - mutex_lock(&q->lock); - videobuf_read_stop(q); - mutex_unlock(&q->lock); + videobuf_stop(q); /* hmm, why is this function declared void? */ /* return err */ @@ -1460,7 +1453,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st) /* only finish the buffer if we have one... */ if( NULL != q->curr ) { - saa7146_buffer_finish(dev,q,STATE_DONE); + saa7146_buffer_finish(dev,q,VIDEOBUF_DONE); } saa7146_buffer_next(dev,q,0); diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 29ec418..2ddafd0 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -212,7 +212,6 @@ void flexcop_reset_block_300(struct flexcop_device *fc) fc->write_ibi_reg(fc,ctrl_208,v208_save); } -EXPORT_SYMBOL(flexcop_reset_block_300); struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) { diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index b7a17e6..307ff35 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -71,6 +71,7 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); } \ } while(0) +static int dst_command(struct dst_state *state, u8 *data, u8 len); static void dst_packsize(struct dst_state *state, int psize) { @@ -80,7 +81,8 @@ static void dst_packsize(struct dst_state *state, int psize) bt878_device_control(state->bt, DST_IG_TS, &bits); } -int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay) +static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, + u32 outhigh, int delay) { union dst_gpio_packet enb; union dst_gpio_packet bits; @@ -109,9 +111,8 @@ int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int return 0; } -EXPORT_SYMBOL(dst_gpio_outb); -int dst_gpio_inb(struct dst_state *state, u8 *result) +static int dst_gpio_inb(struct dst_state *state, u8 *result) { union dst_gpio_packet rd_packet; int err; @@ -125,7 +126,6 @@ int dst_gpio_inb(struct dst_state *state, u8 *result) return 0; } -EXPORT_SYMBOL(dst_gpio_inb); int rdc_reset_state(struct dst_state *state) { @@ -145,7 +145,7 @@ int rdc_reset_state(struct dst_state *state) } EXPORT_SYMBOL(rdc_reset_state); -int rdc_8820_reset(struct dst_state *state) +static int rdc_8820_reset(struct dst_state *state) { dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { @@ -160,9 +160,8 @@ int rdc_8820_reset(struct dst_state *state) return 0; } -EXPORT_SYMBOL(rdc_8820_reset); -int dst_pio_enable(struct dst_state *state) +static int dst_pio_enable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); @@ -172,7 +171,6 @@ int dst_pio_enable(struct dst_state *state) return 0; } -EXPORT_SYMBOL(dst_pio_enable); int dst_pio_disable(struct dst_state *state) { @@ -611,7 +609,7 @@ static int dst_type_print(struct dst_state *state, u8 type) return 0; } -struct tuner_types tuner_list[] = { +static struct tuner_types tuner_list[] = { { .tuner_type = TUNER_TYPE_L64724, .tuner_name = "L 64724", @@ -1224,7 +1222,7 @@ static int dst_probe(struct dst_state *state) return 0; } -int dst_command(struct dst_state *state, u8 *data, u8 len) +static int dst_command(struct dst_state *state, u8 *data, u8 len) { u8 reply; @@ -1287,7 +1285,6 @@ error: return -EIO; } -EXPORT_SYMBOL(dst_command); static int dst_get_signal(struct dst_state *state) { diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index 87623d2..d88cf2a 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -165,10 +165,8 @@ struct dst_config }; int rdc_reset_state(struct dst_state *state); -int rdc_8820_reset(struct dst_state *state); int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); -int dst_pio_enable(struct dst_state *state); int dst_pio_disable(struct dst_state *state); int dst_error_recovery(struct dst_state* state); int dst_error_bailout(struct dst_state *state); @@ -179,9 +177,6 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len); u8 dst_check_sum(u8 * buf, u32 len); struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); -int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay); - -int dst_command(struct dst_state* state, u8 * data, u8 len); #endif // DST_COMMON_H diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index a5262e8..50dc556 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -62,6 +62,8 @@ struct dvb_tuner_info { u32 bandwidth_step; }; +struct analog_tuner_ops; + struct analog_parameters { unsigned int frequency; unsigned int mode; @@ -84,6 +86,9 @@ struct dvb_tuner_ops { /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); + /** This is to allow setting tuner-specific configs */ + int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); + int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); @@ -143,6 +148,7 @@ struct dvb_frontend_ops { int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); struct dvb_tuner_ops tuner_ops; + struct analog_tuner_ops *analog_demod_ops; }; #define MAX_EVENT 8 @@ -159,18 +165,19 @@ struct dvb_fe_events { struct dvb_frontend { struct dvb_frontend_ops ops; struct dvb_adapter *dvb; - void* demodulator_priv; - void* tuner_priv; - void* frontend_priv; - void* sec_priv; + void *demodulator_priv; + void *tuner_priv; + void *frontend_priv; + void *sec_priv; + void *analog_demod_priv; }; -extern int dvb_register_frontend(struct dvb_adapter* dvb, - struct dvb_frontend* fe); +extern int dvb_register_frontend(struct dvb_adapter *dvb, + struct dvb_frontend *fe); -extern int dvb_unregister_frontend(struct dvb_frontend* fe); +extern int dvb_unregister_frontend(struct dvb_frontend *fe); -extern void dvb_frontend_detach(struct dvb_frontend* fe); +extern void dvb_frontend_detach(struct dvb_frontend *fe); extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index 9878183..ac9d93c 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c @@ -261,11 +261,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_init); EXPORT_SYMBOL(dvb_ringbuffer_empty); EXPORT_SYMBOL(dvb_ringbuffer_free); EXPORT_SYMBOL(dvb_ringbuffer_avail); -EXPORT_SYMBOL(dvb_ringbuffer_flush); EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_write); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_write); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_read); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_next); diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index 18e0b16..f3ff813 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c @@ -79,12 +79,12 @@ static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - if (num > 2) return -EINVAL; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + for (i = 0; i < num; i++) { /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 04e31cf..5b6431e 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -32,9 +32,12 @@ #include "zl10353.h" /* debug */ -int dvb_usb_cxusb_debug; +static int dvb_usb_cxusb_debug; module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); +#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) static int cxusb_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h index c8ef775..79ca7ab 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -4,11 +4,6 @@ #define DVB_USB_LOG_PREFIX "cxusb" #include "dvb-usb.h" -extern int dvb_usb_cxusb_debug; -#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) - /* usb commands - some of it are guesses, don't have a reference yet */ #define CMD_I2C_WRITE 0x08 #define CMD_I2C_READ 0x09 diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 58452b5..1aa335d 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -415,6 +415,35 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0x1e, 0x38, KEY_YELLOW }, { 0x1e, 0x3b, KEY_GOTO }, { 0x1e, 0x3d, KEY_POWER }, + + /* Key codes for the Leadtek Winfast DTV Dongle */ + { 0x00, 0x42, KEY_POWER }, + { 0x07, 0x7c, KEY_TUNER }, + { 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */ + { 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/ + { 0x0f, 0x71, KEY_DOT }, /* frequency */ + { 0x07, 0x43, KEY_0 }, + { 0x0c, 0x41, KEY_1 }, + { 0x04, 0x43, KEY_2 }, + { 0x0b, 0x7f, KEY_3 }, + { 0x0e, 0x41, KEY_4 }, + { 0x06, 0x43, KEY_5 }, + { 0x09, 0x7f, KEY_6 }, + { 0x0d, 0x7e, KEY_7 }, + { 0x05, 0x7c, KEY_8 }, + { 0x0a, 0x40, KEY_9 }, + { 0x0e, 0x4e, KEY_CLEAR }, + { 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */ + { 0x0f, 0x41, KEY_LAST }, /* recall */ + { 0x03, 0x42, KEY_MUTE }, + { 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/ + { 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */ + { 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */ + { 0x0b, 0x70, KEY_RECORD }, + { 0x03, 0x7d, KEY_VOLUMEUP }, + { 0x01, 0x7d, KEY_VOLUMEDOWN }, + { 0x02, 0x42, KEY_CHANNELUP }, + { 0x00, 0x7d, KEY_CHANNELDOWN }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ @@ -821,6 +850,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, +/* 21 */{ USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -862,7 +892,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 7, + .num_device_descs = 8, .devices = { { "DiBcom STK7700P reference design", { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, @@ -891,6 +921,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "AVerMedia AVerTV DVB-T Express", { &dib0700_usb_id_table[20] }, { NULL }, + }, + /* dom : pour Gigabyte U7000 */ + { "Gigabyte U7000", + { &dib0700_usb_id_table[21], NULL }, + { NULL }, } }, @@ -961,7 +996,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "DiBcom STK7700D reference design", { &dib0700_usb_id_table[14], NULL }, { NULL }, - }, + } }, .rc_interval = DEFAULT_RC_INTERVAL, @@ -1024,7 +1059,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Pinnacle PCTV Dual DVB-T Diversity Stick", { &dib0700_usb_id_table[18], NULL }, { NULL }, - }, + } } }, }; diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index bca1e09..3acbda4 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -17,9 +17,10 @@ #include "nxt6000.h" /* debug */ -int dvb_usb_digitv_debug; +static int dvb_usb_digitv_debug; module_param_named(debug,dvb_usb_digitv_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); +#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) static int digitv_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h index 8b43e3d..908c09f 100644 --- a/drivers/media/dvb/dvb-usb/digitv.h +++ b/drivers/media/dvb/dvb-usb/digitv.h @@ -8,9 +8,6 @@ struct digitv_state { int is_nxt6000; }; -extern int dvb_usb_digitv_debug; -#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) - /* protocol (from usblogging and the SDK: * * Always 7 bytes bulk message(s) for controlling diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 4fa3e89..d6d9630 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -44,6 +44,9 @@ #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 #define USB_VID_UNIWILL 0x1584 #define USB_VID_WIDEVIEW 0x14aa +/* dom : pour gigabyte u7000 */ +#define USB_VID_GIGABYTE 0x1044 + /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 @@ -69,6 +72,7 @@ #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 #define USB_PID_DIBCOM_STK7700D 0x1ef0 +#define USB_PID_DIBCOM_STK7700_U7000 0x7001 #define USB_PID_DIBCOM_STK7070P 0x1ebc #define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 @@ -170,6 +174,7 @@ #define USB_PID_OPERA1_WARM 0x3829 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 - +/* dom pour gigabyte u7000 */ +#define USB_PID_GIGABYTE_U7000 0x7001 #endif diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index f01d99c..6b99d9f 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c @@ -56,12 +56,12 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - if (num > 2) return -EINVAL; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + for (i = 0; i < num; i++) { /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 92147ee..83e8535 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -171,22 +171,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } -int gp8psk_bcm4500_reload(struct dvb_usb_device *d) -{ - u8 buf; - int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); - /* Turn off 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) - return -EINVAL; - /* Turn On 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) - return -EINVAL; - /* load BCM4500 firmware */ - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (gp8psk_load_bcm4500fw(d)) - return EINVAL; - return 0; -} static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h index e83a575..e5cd814 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -92,6 +92,5 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); #endif diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index d7c0495..21935bf 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -10,7 +10,9 @@ * see Documentation/dvb/README.dvb-usb for more information */ -#include "opera1.h" +#define DVB_USB_LOG_PREFIX "opera" + +#include "dvb-usb.h" #include "stv0299.h" #define OPERA_READ_MSG 0 @@ -38,7 +40,7 @@ struct opera_rc_keys { u32 event; }; -int dvb_usb_opera1_debug; +static int dvb_usb_opera1_debug; module_param_named(debug, dvb_usb_opera1_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." diff --git a/drivers/media/dvb/dvb-usb/opera1.h b/drivers/media/dvb/dvb-usb/opera1.h deleted file mode 100644 index 5317442..0000000 --- a/drivers/media/dvb/dvb-usb/opera1.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _OPERA1_H_ -#define _OPERA1_H_ - -#define DVB_USB_LOG_PREFIX "opera" -#include "dvb-usb.h" - -extern int dvb_usb_opera1_debug; -#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args) -#endif diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c index 16533b3..e553c13 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -56,7 +56,7 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 return ret; } -int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, +static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) { int ret; @@ -204,19 +204,6 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } -int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - struct vp702x_device_state *st = d->priv; - - if (st->power_state == 0 && onoff) - vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); - else if (st->power_state == 1 && onoff == 0) - vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); - - st->power_state = onoff; - - return 0; -} static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) { diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h index 25a9dee..c2f97f9 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.h +++ b/drivers/media/dvb/dvb-usb/vp702x.h @@ -102,7 +102,5 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff); #endif diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 5bbd2d5..c172bab 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -15,9 +15,12 @@ #include "vp7045.h" /* debug */ -int dvb_usb_vp7045_debug; +static int dvb_usb_vp7045_debug; module_param_named(debug,dvb_usb_vp7045_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); +#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec) { diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h index 9ce21a2..969688f 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.h +++ b/drivers/media/dvb/dvb-usb/vp7045.h @@ -17,11 +17,6 @@ #define DVB_USB_LOG_PREFIX "vp7045" #include "dvb-usb.h" -extern int dvb_usb_vp7045_debug; -#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) - /* vp7045 commands */ /* Twinhan Vendor requests */ diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 59b9ed1..57178d6 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -316,6 +316,13 @@ config DVB_TDA827X help A DVB-T silicon tuner module. Say Y when you want to support this tuner. +config DVB_TDA18271 + tristate "NXP TDA18271 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A silicon tuner module. Say Y when you want to support this tuner. + config DVB_TUNER_QT1010 tristate "Quantek QT1010 silicon tuner" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 4b8ad1f..57e5fa8 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -3,6 +3,7 @@ # EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/video/ obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o @@ -39,6 +40,7 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o +obj-$(CONFIG_DVB_TDA18271) += tda18271.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 03fe826..54b18f9 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -38,8 +38,12 @@ struct mt2266_priv { u32 frequency; u32 bandwidth; + u8 band; }; +#define MT2266_VHF 1 +#define MT2266_UHF 0 + /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ static int debug; @@ -90,26 +94,30 @@ static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) } // Initialisation sequences -static u8 mt2266_init1[] = { - REG_TUNE, - 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f }; +static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, + 0x00, 0x52, 0x99, 0x3f }; static u8 mt2266_init2[] = { - 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, - 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d }; + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, + 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, + 0xff, 0x00, 0x77, 0x0f, 0x2d +}; + +static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22 }; -static u8 mt2266_init_8mhz[] = { - REG_BANDWIDTH, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }; +static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32 }; -static u8 mt2266_init_7mhz[] = { - REG_BANDWIDTH, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 }; +static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7 }; -static u8 mt2266_init_6mhz[] = { - REG_BANDWIDTH, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 }; +static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, + 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; + +static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, + 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; #define FREF 30000 // Quartz oscillator 30 MHz @@ -122,35 +130,78 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame u8 lnaband; u8 b[10]; int i; + u8 band; priv = fe->tuner_priv; - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0xff); - freq = params->frequency / 1000; // Hz -> kHz + if (freq < 470000 && freq > 230000) + return -EINVAL; /* Gap between VHF and UHF bands */ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; priv->frequency = freq * 1000; - tune=2 * freq * (8192/16) / (FREF/16); - - if (freq <= 495000) lnaband = 0xEE; else - if (freq <= 525000) lnaband = 0xDD; else - if (freq <= 550000) lnaband = 0xCC; else - if (freq <= 580000) lnaband = 0xBB; else - if (freq <= 605000) lnaband = 0xAA; else - if (freq <= 630000) lnaband = 0x99; else - if (freq <= 655000) lnaband = 0x88; else - if (freq <= 685000) lnaband = 0x77; else - if (freq <= 710000) lnaband = 0x66; else - if (freq <= 735000) lnaband = 0x55; else - if (freq <= 765000) lnaband = 0x44; else - if (freq <= 802000) lnaband = 0x33; else - if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11; - - msleep(100); - mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz: - (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz: - mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + tune = 2 * freq * (8192/16) / (FREF/16); + band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; + if (band == MT2266_VHF) + tune *= 2; + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + mt2266_writeregs(priv, mt2266_init_6mhz, + sizeof(mt2266_init_6mhz)); + break; + case BANDWIDTH_7_MHZ: + mt2266_writeregs(priv, mt2266_init_7mhz, + sizeof(mt2266_init_7mhz)); + break; + case BANDWIDTH_8_MHZ: + default: + mt2266_writeregs(priv, mt2266_init_8mhz, + sizeof(mt2266_init_8mhz)); + break; + } + + if (band == MT2266_VHF && priv->band == MT2266_UHF) { + dprintk("Switch from UHF to VHF"); + mt2266_writereg(priv, 0x05, 0x04); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); + } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { + dprintk("Switch from VHF to UHF"); + mt2266_writereg(priv, 0x05, 0x52); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); + } + msleep(10); + + if (freq <= 495000) + lnaband = 0xEE; + else if (freq <= 525000) + lnaband = 0xDD; + else if (freq <= 550000) + lnaband = 0xCC; + else if (freq <= 580000) + lnaband = 0xBB; + else if (freq <= 605000) + lnaband = 0xAA; + else if (freq <= 630000) + lnaband = 0x99; + else if (freq <= 655000) + lnaband = 0x88; + else if (freq <= 685000) + lnaband = 0x77; + else if (freq <= 710000) + lnaband = 0x66; + else if (freq <= 735000) + lnaband = 0x55; + else if (freq <= 765000) + lnaband = 0x44; + else if (freq <= 802000) + lnaband = 0x33; + else if (freq <= 840000) + lnaband = 0x22; + else + lnaband = 0x11; b[0] = REG_TUNE; b[1] = (tune >> 8) & 0x1F; @@ -158,47 +209,54 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame b[3] = tune >> 13; mt2266_writeregs(priv,b,4); - dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband); - dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); - - b[0] = 0x05; - b[1] = 0x62; - b[2] = lnaband; - mt2266_writeregs(priv,b,3); + dprintk("set_parms: tune=%d band=%d %s", + (int) tune, (int) lnaband, + (band == MT2266_UHF) ? "UHF" : "VHF"); + dprintk("set_parms: [1..3]: %2x %2x %2x", + (int) b[1], (int) b[2], (int)b[3]); + + if (band == MT2266_UHF) { + b[0] = 0x05; + b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; + b[2] = lnaband; + mt2266_writeregs(priv, b, 3); + } - //Waits for pll lock or timeout + /* Wait for pll lock or timeout */ i = 0; do { mt2266_readreg(priv,REG_LOCK,b); - if ((b[0] & 0x40)==0x40) + if (b[0] & 0x40) break; msleep(10); i++; } while (i<10); dprintk("Lock when i=%i",(int)i); + + if (band == MT2266_UHF && priv->band == MT2266_VHF) + mt2266_writereg(priv, 0x05, 0x62); + + priv->band = band; + return ret; } static void mt2266_calibrate(struct mt2266_priv *priv) { - mt2266_writereg(priv,0x11,0x03); - mt2266_writereg(priv,0x11,0x01); - - mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1)); - mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2)); - - mt2266_writereg(priv,0x33,0x5e); - mt2266_writereg(priv,0x10,0x10); - mt2266_writereg(priv,0x10,0x00); - - mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); - + mt2266_writereg(priv, 0x11, 0x03); + mt2266_writereg(priv, 0x11, 0x01); + mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); + mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); + mt2266_writereg(priv, 0x33, 0x5e); + mt2266_writereg(priv, 0x10, 0x10); + mt2266_writereg(priv, 0x10, 0x00); + mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); msleep(25); - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0x00); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); msleep(75); - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0xff); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0xff); } static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) @@ -217,17 +275,22 @@ static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) static int mt2266_init(struct dvb_frontend *fe) { + int ret; struct mt2266_priv *priv = fe->tuner_priv; - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0xff); + ret = mt2266_writereg(priv, 0x17, 0x6d); + if (ret < 0) + return ret; + ret = mt2266_writereg(priv, 0x1c, 0xff); + if (ret < 0) + return ret; return 0; } static int mt2266_sleep(struct dvb_frontend *fe) { struct mt2266_priv *priv = fe->tuner_priv; - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0x00); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); return 0; } @@ -241,8 +304,8 @@ static int mt2266_release(struct dvb_frontend *fe) static const struct dvb_tuner_ops mt2266_tuner_ops = { .info = { .name = "Microtune MT2266", - .frequency_min = 470000000, - .frequency_max = 860000000, + .frequency_min = 174000000, + .frequency_max = 862000000, .frequency_step = 50000, }, .release = mt2266_release, @@ -264,8 +327,9 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter priv->cfg = cfg; priv->i2c = i2c; + priv->band = MT2266_UHF; - if (mt2266_readreg(priv,0,&id) != 0) { + if (mt2266_readreg(priv, 0, &id)) { kfree(priv); return NULL; } diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c index 9a8ddc5..9d26ace 100644 --- a/drivers/media/dvb/frontends/tda10086.c +++ b/drivers/media/dvb/frontends/tda10086.c @@ -158,7 +158,7 @@ static int tda10086_init(struct dvb_frontend* fe) tda10086_write_byte(state, 0x3d, 0x80); // setup SEC - tda10086_write_byte(state, 0x36, 0x00); // all SEC off + tda10086_write_byte(state, 0x36, 0x80); // all SEC off, no 22k tone tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000))); // } tone frequency tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); // } @@ -183,13 +183,13 @@ static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) dprintk ("%s\n", __FUNCTION__); - switch(tone) { + switch (tone) { case SEC_TONE_OFF: - tda10086_write_byte(state, 0x36, 0x00); + tda10086_write_byte(state, 0x36, 0x80); break; case SEC_TONE_ON: - tda10086_write_byte(state, 0x36, 0x01); + tda10086_write_byte(state, 0x36, 0x81); break; } @@ -212,7 +212,7 @@ static int tda10086_send_master_cmd (struct dvb_frontend* fe, for(i=0; i< cmd->msg_len; i++) { tda10086_write_byte(state, 0x48+i, cmd->msg[i]); } - tda10086_write_byte(state, 0x36, 0x08 | ((cmd->msg_len - 1) << 4)); + tda10086_write_byte(state, 0x36, 0x88 | ((cmd->msg_len - 1) << 4)); tda10086_diseqc_wait(state); @@ -230,11 +230,11 @@ static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minic switch(minicmd) { case SEC_MINI_A: - tda10086_write_byte(state, 0x36, 0x04); + tda10086_write_byte(state, 0x36, 0x84); break; case SEC_MINI_B: - tda10086_write_byte(state, 0x36, 0x06); + tda10086_write_byte(state, 0x36, 0x86); break; } diff --git a/drivers/media/dvb/frontends/tda18271.c b/drivers/media/dvb/frontends/tda18271.c new file mode 100644 index 0000000..aaaa2f8 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271.c @@ -0,0 +1,1065 @@ +/* + tda18271.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include "tuner-driver.h" + +#include "tda18271.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +#define dprintk(level, fmt, arg...) do {\ + if (debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ##arg); } while (0) + +#define R_ID 0x00 /* ID byte */ +#define R_TM 0x01 /* Thermo byte */ +#define R_PL 0x02 /* Power level byte */ +#define R_EP1 0x03 /* Easy Prog byte 1 */ +#define R_EP2 0x04 /* Easy Prog byte 2 */ +#define R_EP3 0x05 /* Easy Prog byte 3 */ +#define R_EP4 0x06 /* Easy Prog byte 4 */ +#define R_EP5 0x07 /* Easy Prog byte 5 */ +#define R_CPD 0x08 /* Cal Post-Divider byte */ +#define R_CD1 0x09 /* Cal Divider byte 1 */ +#define R_CD2 0x0a /* Cal Divider byte 2 */ +#define R_CD3 0x0b /* Cal Divider byte 3 */ +#define R_MPD 0x0c /* Main Post-Divider byte */ +#define R_MD1 0x0d /* Main Divider byte 1 */ +#define R_MD2 0x0e /* Main Divider byte 2 */ +#define R_MD3 0x0f /* Main Divider byte 3 */ +#define R_EB1 0x10 /* Extended byte 1 */ +#define R_EB2 0x11 /* Extended byte 2 */ +#define R_EB3 0x12 /* Extended byte 3 */ +#define R_EB4 0x13 /* Extended byte 4 */ +#define R_EB5 0x14 /* Extended byte 5 */ +#define R_EB6 0x15 /* Extended byte 6 */ +#define R_EB7 0x16 /* Extended byte 7 */ +#define R_EB8 0x17 /* Extended byte 8 */ +#define R_EB9 0x18 /* Extended byte 9 */ +#define R_EB10 0x19 /* Extended byte 10 */ +#define R_EB11 0x1a /* Extended byte 11 */ +#define R_EB12 0x1b /* Extended byte 12 */ +#define R_EB13 0x1c /* Extended byte 13 */ +#define R_EB14 0x1d /* Extended byte 14 */ +#define R_EB15 0x1e /* Extended byte 15 */ +#define R_EB16 0x1f /* Extended byte 16 */ +#define R_EB17 0x20 /* Extended byte 17 */ +#define R_EB18 0x21 /* Extended byte 18 */ +#define R_EB19 0x22 /* Extended byte 19 */ +#define R_EB20 0x23 /* Extended byte 20 */ +#define R_EB21 0x24 /* Extended byte 21 */ +#define R_EB22 0x25 /* Extended byte 22 */ +#define R_EB23 0x26 /* Extended byte 23 */ + +struct tda18271_pll_map { + u32 lomax; + u8 pd; /* post div */ + u8 d; /* div */ +}; + +static struct tda18271_pll_map tda18271_main_pll[] = { + { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, + { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, + { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, + { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, + { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, + { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, + { .lomax = 54000, .pd = 0x59, .d = 0x90 }, + { .lomax = 61000, .pd = 0x58, .d = 0x80 }, + { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, + { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, + { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, + { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, + { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, + { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, + { .lomax = 109000, .pd = 0x49, .d = 0x48 }, + { .lomax = 123000, .pd = 0x48, .d = 0x40 }, + { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, + { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, + { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, + { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, + { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, + { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, + { .lomax = 219000, .pd = 0x39, .d = 0x24 }, + { .lomax = 246000, .pd = 0x38, .d = 0x20 }, + { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, + { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, + { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, + { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, + { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, + { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, + { .lomax = 438000, .pd = 0x29, .d = 0x12 }, + { .lomax = 493000, .pd = 0x28, .d = 0x10 }, + { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, + { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, + { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, + { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, + { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, + { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, + { .lomax = 877000, .pd = 0x19, .d = 0x09 }, + { .lomax = 987000, .pd = 0x18, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271_cal_pll[] = { + { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, + { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, + { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, + { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, + { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, + { .lomax = 88000, .pd = 0xca, .d = 0x50 }, + { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, + { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, + { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, + { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, + { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, + { .lomax = 176000, .pd = 0xba, .d = 0x28 }, + { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, + { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, + { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, + { .lomax = 271000, .pd = 0xad, .d = 0x1a }, + { .lomax = 294000, .pd = 0xac, .d = 0x18 }, + { .lomax = 321000, .pd = 0xab, .d = 0x16 }, + { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, + { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, + { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, + { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, + { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 785000, .pd = 0x99, .d = 0x09 }, + { .lomax = 883000, .pd = 0x98, .d = 0x08 }, + { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +struct tda18271_map { + u32 rfmax; + u8 val; +}; + +static struct tda18271_map tda18271_bp_filter[] = { + { .rfmax = 62000, .val = 0x00 }, + { .rfmax = 84000, .val = 0x01 }, + { .rfmax = 100000, .val = 0x02 }, + { .rfmax = 140000, .val = 0x03 }, + { .rfmax = 170000, .val = 0x04 }, + { .rfmax = 180000, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_km[] = { + { .rfmax = 61100, .val = 0x74 }, + { .rfmax = 350000, .val = 0x40 }, + { .rfmax = 720000, .val = 0x30 }, + { .rfmax = 865000, .val = 0x40 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_band[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 61100, .val = 0x01 }, +/* { .rfmax = 152600, .val = 0x02 }, */ + { .rfmax = 121200, .val = 0x02 }, + { .rfmax = 164700, .val = 0x03 }, + { .rfmax = 203500, .val = 0x04 }, + { .rfmax = 457800, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_gain_taper[] = { + { .rfmax = 45400, .val = 0x1f }, + { .rfmax = 45800, .val = 0x1e }, + { .rfmax = 46200, .val = 0x1d }, + { .rfmax = 46700, .val = 0x1c }, + { .rfmax = 47100, .val = 0x1b }, + { .rfmax = 47500, .val = 0x1a }, + { .rfmax = 47900, .val = 0x19 }, + { .rfmax = 49600, .val = 0x17 }, + { .rfmax = 51200, .val = 0x16 }, + { .rfmax = 52900, .val = 0x15 }, + { .rfmax = 54500, .val = 0x14 }, + { .rfmax = 56200, .val = 0x13 }, + { .rfmax = 57800, .val = 0x12 }, + { .rfmax = 59500, .val = 0x11 }, + { .rfmax = 61100, .val = 0x10 }, + { .rfmax = 67600, .val = 0x0d }, + { .rfmax = 74200, .val = 0x0c }, + { .rfmax = 80700, .val = 0x0b }, + { .rfmax = 87200, .val = 0x0a }, + { .rfmax = 93800, .val = 0x09 }, + { .rfmax = 100300, .val = 0x08 }, + { .rfmax = 106900, .val = 0x07 }, + { .rfmax = 113400, .val = 0x06 }, + { .rfmax = 119900, .val = 0x05 }, + { .rfmax = 126500, .val = 0x04 }, + { .rfmax = 133000, .val = 0x03 }, + { .rfmax = 139500, .val = 0x02 }, + { .rfmax = 146100, .val = 0x01 }, + { .rfmax = 152600, .val = 0x00 }, + { .rfmax = 154300, .val = 0x1f }, + { .rfmax = 156100, .val = 0x1e }, + { .rfmax = 157800, .val = 0x1d }, + { .rfmax = 159500, .val = 0x1c }, + { .rfmax = 161200, .val = 0x1b }, + { .rfmax = 163000, .val = 0x1a }, + { .rfmax = 164700, .val = 0x19 }, + { .rfmax = 170200, .val = 0x17 }, + { .rfmax = 175800, .val = 0x16 }, + { .rfmax = 181300, .val = 0x15 }, + { .rfmax = 186900, .val = 0x14 }, + { .rfmax = 192400, .val = 0x13 }, + { .rfmax = 198000, .val = 0x12 }, + { .rfmax = 203500, .val = 0x11 }, + { .rfmax = 216200, .val = 0x14 }, + { .rfmax = 228900, .val = 0x13 }, + { .rfmax = 241600, .val = 0x12 }, + { .rfmax = 254400, .val = 0x11 }, + { .rfmax = 267100, .val = 0x10 }, + { .rfmax = 279800, .val = 0x0f }, + { .rfmax = 292500, .val = 0x0e }, + { .rfmax = 305200, .val = 0x0d }, + { .rfmax = 317900, .val = 0x0c }, + { .rfmax = 330700, .val = 0x0b }, + { .rfmax = 343400, .val = 0x0a }, + { .rfmax = 356100, .val = 0x09 }, + { .rfmax = 368800, .val = 0x08 }, + { .rfmax = 381500, .val = 0x07 }, + { .rfmax = 394200, .val = 0x06 }, + { .rfmax = 406900, .val = 0x05 }, + { .rfmax = 419700, .val = 0x04 }, + { .rfmax = 432400, .val = 0x03 }, + { .rfmax = 445100, .val = 0x02 }, + { .rfmax = 457800, .val = 0x01 }, + { .rfmax = 476300, .val = 0x19 }, + { .rfmax = 494800, .val = 0x18 }, + { .rfmax = 513300, .val = 0x17 }, + { .rfmax = 531800, .val = 0x16 }, + { .rfmax = 550300, .val = 0x15 }, + { .rfmax = 568900, .val = 0x14 }, + { .rfmax = 587400, .val = 0x13 }, + { .rfmax = 605900, .val = 0x12 }, + { .rfmax = 624400, .val = 0x11 }, + { .rfmax = 642900, .val = 0x10 }, + { .rfmax = 661400, .val = 0x0f }, + { .rfmax = 679900, .val = 0x0e }, + { .rfmax = 698400, .val = 0x0d }, + { .rfmax = 716900, .val = 0x0c }, + { .rfmax = 735400, .val = 0x0b }, + { .rfmax = 753900, .val = 0x0a }, + { .rfmax = 772500, .val = 0x09 }, + { .rfmax = 791000, .val = 0x08 }, + { .rfmax = 809500, .val = 0x07 }, + { .rfmax = 828000, .val = 0x06 }, + { .rfmax = 846500, .val = 0x05 }, + { .rfmax = 865000, .val = 0x04 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_cal[] = { + { .rfmax = 41000, .val = 0x1e }, + { .rfmax = 43000, .val = 0x30 }, + { .rfmax = 45000, .val = 0x43 }, + { .rfmax = 46000, .val = 0x4d }, + { .rfmax = 47000, .val = 0x54 }, + { .rfmax = 47900, .val = 0x64 }, + { .rfmax = 49100, .val = 0x20 }, + { .rfmax = 50000, .val = 0x22 }, + { .rfmax = 51000, .val = 0x2a }, + { .rfmax = 53000, .val = 0x32 }, + { .rfmax = 55000, .val = 0x35 }, + { .rfmax = 56000, .val = 0x3c }, + { .rfmax = 57000, .val = 0x3f }, + { .rfmax = 58000, .val = 0x48 }, + { .rfmax = 59000, .val = 0x4d }, + { .rfmax = 60000, .val = 0x58 }, + { .rfmax = 61100, .val = 0x5f }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +/*---------------------------------------------------------------------*/ + +#define TDA18271_NUM_REGS 39 + +#define TDA18271_ANALOG 0 +#define TDA18271_DIGITAL 1 + +struct tda18271_priv { + u8 i2c_addr; + struct i2c_adapter *i2c_adap; + unsigned char tda18271_regs[TDA18271_NUM_REGS]; + int mode; + + u32 frequency; + u32 bandwidth; +}; + +static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; + int ret = 0; + + switch (priv->mode) { + case TDA18271_ANALOG: + if (ops && ops->i2c_gate_ctrl) + ret = ops->i2c_gate_ctrl(fe, enable); + break; + case TDA18271_DIGITAL: + if (fe->ops.i2c_gate_ctrl) + ret = fe->ops.i2c_gate_ctrl(fe, enable); + break; + } + + return ret; +}; + +/*---------------------------------------------------------------------*/ + +static void tda18271_dump_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + dprintk(1, "=== TDA18271 REG DUMP ===\n"); + dprintk(1, "ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); + dprintk(1, "THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); + dprintk(1, "POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); + dprintk(1, "EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); + dprintk(1, "EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); + dprintk(1, "EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); + dprintk(1, "EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); + dprintk(1, "EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); + dprintk(1, "CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); + dprintk(1, "CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); + dprintk(1, "CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); + dprintk(1, "CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); + dprintk(1, "MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); + dprintk(1, "MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); + dprintk(1, "MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); + dprintk(1, "MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); +} + +static void tda18271_read_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf = 0x00; + int ret; + struct i2c_msg msg[] = { + { .addr = priv->i2c_addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = regs, .len = 16 } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + printk("ERROR: %s: i2c_transfer returned: %d\n", + __FUNCTION__, ret); + + if (debug > 1) + tda18271_dump_regs(fe); +} + +static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf[TDA18271_NUM_REGS+1]; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = len+1 }; + int i, ret; + + BUG_ON((len == 0) || (idx+len > sizeof(buf))); + + buf[0] = idx; + for (i = 1; i <= len; i++) { + buf[i] = regs[idx-1+i]; + } + + tda18271_i2c_gate_ctrl(fe, 1); + + /* write registers */ + ret = i2c_transfer(priv->i2c_adap, &msg, 1); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 1) + printk(KERN_WARNING "ERROR: %s: i2c_transfer returned: %d\n", + __FUNCTION__, ret); +} + +/*---------------------------------------------------------------------*/ + +static void tda18271_init_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda18271_read_regs(fe); + + /* test IR_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x08) != 0) + return; + + printk(KERN_INFO "tda18271: initializing registers\n"); + + /* initialize registers */ + regs[R_ID] = 0x83; + regs[R_TM] = 0x08; + regs[R_PL] = 0x80; + regs[R_EP1] = 0xc6; + regs[R_EP2] = 0xdf; + regs[R_EP3] = 0x16; + regs[R_EP4] = 0x60; + regs[R_EP5] = 0x80; + regs[R_CPD] = 0x80; + regs[R_CD1] = 0x00; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x00; + regs[R_MD1] = 0x00; + regs[R_MD2] = 0x00; + regs[R_MD3] = 0x00; + regs[R_EB1] = 0xff; + regs[R_EB2] = 0x01; + regs[R_EB3] = 0x84; + regs[R_EB4] = 0x41; + regs[R_EB5] = 0x01; + regs[R_EB6] = 0x84; + regs[R_EB7] = 0x40; + regs[R_EB8] = 0x07; + regs[R_EB9] = 0x00; + regs[R_EB10] = 0x00; + regs[R_EB11] = 0x96; + regs[R_EB12] = 0x0f; + regs[R_EB13] = 0xc1; + regs[R_EB14] = 0x00; + regs[R_EB15] = 0x8f; + regs[R_EB16] = 0x00; + regs[R_EB17] = 0x00; + regs[R_EB18] = 0x00; + regs[R_EB19] = 0x00; + regs[R_EB20] = 0x20; + regs[R_EB21] = 0x33; + regs[R_EB22] = 0x48; + regs[R_EB23] = 0xb0; + + tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + /* setup AGC1 & AGC2 */ + regs[R_EB17] = 0x00; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x03; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x43; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x4c; + tda18271_write_regs(fe, R_EB17, 1); + + regs[R_EB20] = 0xa0; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xa7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xe7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + + /* image rejection calibration */ + + /* low-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x81; + regs[R_CPD] = 0xcc; + regs[R_CD1] = 0x6c; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xcd; + regs[R_MD1] = 0x77; + regs[R_MD2] = 0x08; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted low measurement */ + + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x85; + regs[R_CPD] = 0xcb; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x70; + regs[R_CD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + regs[R_EP2] = 0xdf; + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image low optimization completion */ + + /* mid-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x82; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xa9; + regs[R_MD1] = 0x73; + regs[R_MD2] = 0x1a; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted mid measurement */ + + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x86; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0xa0; + regs[R_CD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + regs[R_EP2] = 0xdf; + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image mid optimization completion */ + + /* high-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x83; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x99; + regs[R_MD1] = 0x71; + regs[R_MD2] = 0xcd; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted high measurement */ + + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x87; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x50; + regs[R_CD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + regs[R_EP2] = 0xdf; + + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image high optimization completion */ + + regs[R_EP4] = 0x64; + tda18271_write_regs(fe, R_EP4, 1); + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); +} + +static int tda18271_tune(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 div, N = 0; + int i; + + + dprintk(1, "freq = %d, ifc = %d\n", freq, ifc); + + tda18271_init_regs(fe); + /* RF tracking filter calibration */ + + /* calculate BP_Filter */ + i = 0; + while ((tda18271_bp_filter[i].rfmax * 1000) < freq) { + if (tda18271_bp_filter[i + 1].rfmax == 0) + break; + i++; + } + dprintk(2, "bp filter = 0x%x, i = %d\n", tda18271_bp_filter[i].val, i); + + regs[R_EP1] &= ~0x07; /* clear bp filter bits */ + regs[R_EP1] |= tda18271_bp_filter[i].val; + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x60; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x60; + tda18271_write_regs(fe, R_EB7, 1); + + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + regs[R_EB20] = 0xcc; + tda18271_write_regs(fe, R_EB20, 1); + + /* set CAL mode to RF tracking filter calibration */ + regs[R_EB4] |= 0x03; + + /* calculate CAL PLL */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 1250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2; + break; + } + + i = 0; + while ((tda18271_cal_pll[i].lomax * 1000) < N) { + if (tda18271_cal_pll[i + 1].lomax == 0) + break; + i++; + } + dprintk(2, "cal pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_cal_pll[i].pd, tda18271_cal_pll[i].d, i); + + regs[R_CPD] = tda18271_cal_pll[i].pd; + + div = ((tda18271_cal_pll[i].d * (N / 1000)) << 7) / 125; + regs[R_CD1] = 0xff & (div >> 16); + regs[R_CD2] = 0xff & (div >> 8); + regs[R_CD3] = 0xff & div; + + /* calculate MAIN PLL */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2 + 1000000; + break; + } + + i = 0; + while ((tda18271_main_pll[i].lomax * 1000) < N) { + if (tda18271_main_pll[i + 1].lomax == 0) + break; + i++; + } + dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + + regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; + regs[R_MD1] = 0xff & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* RF tracking filter calibration initialization */ + + /* search for K,M,CO for RF Calibration */ + i = 0; + while ((tda18271_km[i].rfmax * 1000) < freq) { + if (tda18271_km[i + 1].rfmax == 0) + break; + i++; + } + dprintk(2, "km = 0x%x, i = %d\n", tda18271_km[i].val, i); + + regs[R_EB13] &= 0x83; + regs[R_EB13] |= tda18271_km[i].val; + tda18271_write_regs(fe, R_EB13, 1); + + /* search for RF_BAND */ + i = 0; + while ((tda18271_rf_band[i].rfmax * 1000) < freq) { + if (tda18271_rf_band[i + 1].rfmax == 0) + break; + i++; + } + dprintk(2, "rf band = 0x%x, i = %d\n", tda18271_rf_band[i].val, i); + + regs[R_EP2] &= ~0xe0; /* clear rf band bits */ + regs[R_EP2] |= (tda18271_rf_band[i].val << 5); + + /* search for Gain_Taper */ + i = 0; + while ((tda18271_gain_taper[i].rfmax * 1000) < freq) { + if (tda18271_gain_taper[i + 1].rfmax == 0) + break; + i++; + } + dprintk(2, "gain taper = 0x%x, i = %d\n", + tda18271_gain_taper[i].val, i); + + regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ + regs[R_EP2] |= tda18271_gain_taper[i].val; + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x40; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x40; + tda18271_write_regs(fe, R_EB7, 1); + msleep(10); + + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + msleep(60); /* RF tracking filter calibration completion */ + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + tda18271_write_regs(fe, R_EP4, 1); + + tda18271_write_regs(fe, R_EP1, 1); + + /* RF tracking filer correction for VHF_Low band */ + i = 0; + while ((tda18271_rf_cal[i].rfmax * 1000) < freq) { + if (tda18271_rf_cal[i].rfmax == 0) + break; + i++; + } + dprintk(2, "rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); + + /* VHF_Low band only */ + if (tda18271_rf_cal[i].rfmax != 0) { + regs[R_EB14] = tda18271_rf_cal[i].val; + tda18271_write_regs(fe, R_EB14, 1); + } + + /* Channel Configuration */ + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_EB22] = 0x2c; + break; + case TDA18271_DIGITAL: + regs[R_EB22] = 0x37; + break; + } + tda18271_write_regs(fe, R_EB22, 1); + + regs[R_EP1] |= 0x40; /* set dis power level on */ + + /* set standard */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + + /* see table 22 */ + regs[R_EP3] |= std; + + /* TO DO: * + * ================ * + * FM radio, 0x18 * + * ATSC 6MHz, 0x1c * + * DVB-T 6MHz, 0x1c * + * DVB-T 7MHz, 0x1d * + * DVB-T 8MHz, 0x1e * + * QAM 6MHz, 0x1d * + * QAM 8MHz, 0x1f */ + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x80; /* IF notch = 0 */ + break; + case TDA18271_DIGITAL: + regs[R_EP4] |= 0x04; + regs[R_MPD] |= 0x80; + break; + } + + regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ + + /* FIXME: image rejection validity EP5[2:0] */ + + /* calculate MAIN PLL */ + N = freq + ifc; + + i = 0; + while ((tda18271_main_pll[i].lomax * 1000) < N) { + if (tda18271_main_pll[i + 1].lomax == 0) + break; + i++; + } + dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + + regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; + regs[R_MD1] = 0xff & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; + + tda18271_write_regs(fe, R_TM, 15); + msleep(5); + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + u8 std; + u32 bw, sgIF = 0; + + u32 freq = params->frequency; + + priv->mode = TDA18271_DIGITAL; + + /* see table 22 */ + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + std = 0x1b; /* device-specific (spec says 0x1c) */ + sgIF = 5380000; + break; + case QAM_64: + case QAM_256: + std = 0x18; /* device-specific (spec says 0x1d) */ + sgIF = 4000000; + break; + default: + printk(KERN_WARNING "%s: modulation not set!\n", + __FUNCTION__); + return -EINVAL; + } + freq += 1750000; /* Adjust to center (+1.75MHZ) */ + bw = 6000000; + } else if (fe->ops.info.type == FE_OFDM) { + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + std = 0x1c; + bw = 6000000; + break; + case BANDWIDTH_7_MHZ: + std = 0x1d; + bw = 7000000; + break; + case BANDWIDTH_8_MHZ: + std = 0x1e; + bw = 8000000; + break; + default: + printk(KERN_WARNING "%s: bandwidth not set!\n", + __FUNCTION__); + return -EINVAL; + } + } else { + printk(KERN_WARNING "%s: modulation type not supported!\n", + __FUNCTION__); + return -EINVAL; + } + + return tda18271_tune(fe, sgIF, freq, bw, std); +} + +static int tda18271_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + u8 std; + unsigned int sgIF; + char *mode; + + priv->mode = TDA18271_ANALOG; + + /* see table 22 */ + if (params->std & V4L2_STD_MN) { + std = 0x0d; + sgIF = 92; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + std = 0x0e; + sgIF = 108; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + std = 0x0f; + sgIF = 124; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + std = 0x0f; + sgIF = 124; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + std = 0x0f; + sgIF = 124; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + std = 0x0f; + sgIF = 124; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + std = 0x0f; + sgIF = 20; + mode = "LC"; + } else { + std = 0x0f; + sgIF = 124; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) + sgIF = 88; /* if frequency is 5.5 MHz */ + + dprintk(1, "setting tda18271 to system %s\n", mode); + + return tda18271_tune(fe, sgIF * 62500, params->frequency * 62500, + 0, std); +} + +static int tda18271_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static struct dvb_tuner_ops tda18271_tuner_ops = { + .info = { + .name = "NXP TDA18271HD", + .frequency_min = 45000000, + .frequency_max = 864000000, + .frequency_step = 62500 + }, + .set_params = tda18271_set_params, + .set_analog_params = tda18271_set_analog_params, + .release = tda18271_release, + .get_frequency = tda18271_get_frequency, + .get_bandwidth = tda18271_get_bandwidth, +}; + +struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c) +{ + struct tda18271_priv *priv = NULL; + + dprintk(1, "@ 0x%x\n", addr); + priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + return fe; +} +EXPORT_SYMBOL_GPL(tda18271_attach); +MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h new file mode 100644 index 0000000..a8a19a7 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271.h @@ -0,0 +1,40 @@ +/* + tda18271.h - header for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA18271_H__ +#define __TDA18271_H__ + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, + u8 addr, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif + +#endif /* __TDA18271_H__ */ diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c index 256fc4b..8329d33 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/dvb/frontends/tda827x.c @@ -19,12 +19,16 @@ */ #include -#include #include +#include +#include #include "tda827x.h" static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + #define dprintk(args...) \ do { \ if (debug) printk(KERN_DEBUG "tda827x: " args); \ @@ -34,10 +38,57 @@ struct tda827x_priv { int i2c_addr; struct i2c_adapter *i2c_adap; struct tda827x_config *cfg; + + unsigned int sgIF; + unsigned char lpsel; + u32 frequency; u32 bandwidth; }; +static void tda827x_set_std(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + char *mode; + + priv->lpsel = 0; + if (params->std & V4L2_STD_MN) { + priv->sgIF = 92; + priv->lpsel = 1; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->sgIF = 108; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->sgIF = 124; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->sgIF = 124; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->sgIF = 124; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->sgIF = 124; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->sgIF = 20; + mode = "LC"; + } else { + priv->sgIF = 124; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) + priv->sgIF = 88; /* if frequency is 5.5 MHz */ + + dprintk("setting tda827x to system %s\n", mode); +} + + +/* ------------------------------------------------------------------ */ + struct tda827x_data { u32 lomax; u8 spd; @@ -48,7 +99,7 @@ struct tda827x_data { u8 div1p5; }; -static const struct tda827x_data tda827x_dvbt[] = { +static const struct tda827x_data tda827x_table[] = { { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, @@ -106,21 +157,22 @@ static int tda827xo_set_params(struct dvb_frontend *fe, tuner_freq = params->frequency + if_freq; i = 0; - while (tda827x_dvbt[i].lomax < tuner_freq) { - if(tda827x_dvbt[i + 1].lomax == 0) + while (tda827x_table[i].lomax < tuner_freq) { + if (tda827x_table[i + 1].lomax == 0) break; i++; } - N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); + N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); buf[0] = 0; buf[1] = (N>>8) | 0x40; buf[2] = N & 0xff; buf[3] = 0; buf[4] = 0x52; - buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + - (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; - buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; + buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + + tda827x_table[i].bp; + buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; buf[7] = 0xbf; buf[8] = 0x2a; buf[9] = 0x05; @@ -140,7 +192,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe, msleep(500); /* correct CP value */ buf[0] = 0x30; - buf[1] = 0x50 + tda827x_dvbt[i].cp; + buf[1] = 0x50 + tda827x_table[i].cp; msg.len = 2; if (fe->ops.i2c_gate_ctrl) @@ -173,6 +225,102 @@ static int tda827xo_sleep(struct dvb_frontend *fe) /* ------------------------------------------------------------------ */ +static int tda827xo_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[8]; + unsigned char reg2[2]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; + unsigned int freq = params->frequency; + + tda827x_set_std(fe, params); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->sgIF; + + i = 0; + while (tda827x_table[i].lomax < N * 62500) { + if (tda827x_table[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827x_table[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0x40; + tuner_reg[4] = 0x52 + (priv->lpsel << 5); + tuner_reg[5] = (tda827x_table[i].spd << 6) + + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + tda827x_table[i].bp; + tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); + tuner_reg[7] = 0x8f; + + msg.buf = tuner_reg; + msg.len = 8; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msg.buf = reg2; + msg.len = 2; + reg2[0] = 0x80; + reg2[1] = 0; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0xbf; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 0x80; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 4; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4]; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(550); + reg2[0] = 0x30; + reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0x3f; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x80; + reg2[1] = 0x08; /* Vsync en */ + i2c_transfer(priv->i2c_adap, &msg, 1); + + priv->frequency = freq * 62500; + + return 0; +} + +static void tda827xo_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = { 0x80, 0x0c }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + + i2c_transfer(priv->i2c_adap, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + struct tda827xa_data { u32 lomax; u8 svco; @@ -212,6 +360,35 @@ static const struct tda827xa_data tda827xa_dvbt[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} }; +static struct tda827xa_data tda827xa_analog[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + static int tda827xa_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { @@ -368,6 +545,158 @@ static int tda827xa_sleep(struct dvb_frontend *fe) return 0; } +/* ------------------------------------------------------------------ */ + +static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char buf[] = {0x22, 0x01}; + int arg; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + if (priv->cfg->config) { + if (high) + dprintk("setting LNA to high gain\n"); + else + dprintk("setting LNA to low gain\n"); + } + switch (*priv->cfg->config) { + case 0: /* no LNA */ + break; + case 1: /* switch is GPIO 0 of tda8290 */ + case 2: + /* turn Vsync on */ + if (params->std & V4L2_STD_MN) + arg = 1; + else + arg = 0; + if (priv->cfg->tuner_callback) + priv->cfg->tuner_callback(priv->i2c_adap->algo_data, + 1, arg); + buf[1] = high ? 0 : 1; + if (*priv->cfg->config == 2) + buf[1] = high ? 1 : 0; + i2c_transfer(priv->i2c_adap, &msg, 1); + break; + case 3: /* switch with GPIO of saa713x */ + if (priv->cfg->tuner_callback) + priv->cfg->tuner_callback(priv->i2c_adap->algo_data, + 0, high); + break; + } +} + +static int tda827xa_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[11]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = tuner_reg, .len = sizeof(tuner_reg) }; + unsigned int freq = params->frequency; + + tda827x_set_std(fe, params); + + tda827xa_lna_gain(fe, 1, params); + msleep(10); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->sgIF; + + i = 0; + while (tda827xa_analog[i].lomax < N * 62500) { + if (tda827xa_analog[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827xa_analog[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0; + tuner_reg[4] = 0x16; + tuner_reg[5] = (tda827xa_analog[i].spd << 5) + + (tda827xa_analog[i].svco << 3) + + tda827xa_analog[i].sbs; + tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); + tuner_reg[7] = 0x1c; + tuner_reg[8] = 4; + tuner_reg[9] = 0x20; + tuner_reg[10] = 0x00; + msg.len = 11; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0x90; + tuner_reg[1] = 0xff; + tuner_reg[2] = 0xe0; + tuner_reg[3] = 0; + tuner_reg[4] = 0x99 + (priv->lpsel << 1); + msg.len = 5; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0xa0; + tuner_reg[1] = 0xc0; + msg.len = 2; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0x30; + tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msg.flags = I2C_M_RD; + i2c_transfer(priv->i2c_adap, &msg, 1); + msg.flags = 0; + tuner_reg[1] >>= 4; + dprintk("AGC2 gain is: %d\n", tuner_reg[1]); + if (tuner_reg[1] < 1) + tda827xa_lna_gain(fe, 0, params); + + msleep(100); + tuner_reg[0] = 0x60; + tuner_reg[1] = 0x3c; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(163); + tuner_reg[0] = 0x50; + tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0x80; + tuner_reg[1] = 0x28; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0xb0; + tuner_reg[1] = 0x01; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0xc0; + tuner_reg[1] = 0x19 + (priv->lpsel << 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + priv->frequency = freq * 62500; + + return 0; +} + +static void tda827xa_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = {0x80, 0x2c}; + struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + i2c_transfer(priv->i2c_adap, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + static int tda827x_release(struct dvb_frontend *fe) { kfree(fe->tuner_priv); @@ -430,6 +759,7 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = { .init = tda827x_initial_init, .sleep = tda827x_initial_sleep, .set_params = tda827xo_set_params, + .set_analog_params = tda827xo_set_analog_params, .get_frequency = tda827x_get_frequency, .get_bandwidth = tda827x_get_bandwidth, }; @@ -445,6 +775,7 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = { .init = tda827x_init, .sleep = tda827xa_sleep, .set_params = tda827xa_set_params, + .set_analog_params = tda827xa_set_analog_params, .get_frequency = tda827x_get_frequency, .get_bandwidth = tda827x_get_bandwidth, }; @@ -465,9 +796,11 @@ static int tda827x_probe_version(struct dvb_frontend *fe) dprintk("tda827x tuner found\n"); fe->ops.tuner_ops.init = tda827x_init; fe->ops.tuner_ops.sleep = tda827xo_sleep; + priv->cfg->agcf = tda827xo_agcf; } else { dprintk("tda827xa tuner found\n"); memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); + priv->cfg->agcf = tda827xa_agcf; } return 0; } @@ -487,16 +820,13 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, priv->i2c_adap = i2c; priv->cfg = cfg; memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; + dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); + return fe; } - -EXPORT_SYMBOL(tda827x_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +EXPORT_SYMBOL_GPL(tda827x_attach); MODULE_DESCRIPTION("DVB TDA827x driver"); MODULE_AUTHOR("Hartmut Hackmann "); diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h index 69e8263..92eb65b 100644 --- a/drivers/media/dvb/frontends/tda827x.h +++ b/drivers/media/dvb/frontends/tda827x.h @@ -29,9 +29,16 @@ struct tda827x_config { + /* saa7134 - provided callbacks */ void (*lna_gain) (struct dvb_frontend *fe, int high); int (*init) (struct dvb_frontend *fe); int (*sleep) (struct dvb_frontend *fe); + + /* interface to tda829x driver */ + unsigned int *config; + int (*tuner_callback) (void *dev, int command, int arg); + + void (*agcf)(struct dvb_frontend *fe); }; diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 60433b5..8791701 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -65,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("ves1820: %s(): writereg error (reg == 0x%02x," + printk("ves1820: %s(): writereg error (reg == 0x%02x, " "val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret); return (ret != 1) ? -EREMOTEIO : 0; @@ -84,7 +84,7 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) - printk("ves1820: %s(): readreg error (reg == 0x%02x," + printk("ves1820: %s(): readreg error (reg == 0x%02x, " "ret == %i)\n", __FUNCTION__, reg, ret); return b1[0]; diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 54b91f2..ae88243 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -1,8 +1,14 @@ +config TTPCI_EEPROM + tristate + default n + config DVB_AV7110 tristate "AV7110 cards" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 + depends on DVB_CORE && PCI && I2C select FW_LOADER if !DVB_AV7110_FIRMWARE + select TTPCI_EEPROM select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_VES1820 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE @@ -57,10 +63,19 @@ config DVB_AV7110_OSD All other people say N. +config DVB_BUDGET_CORE + tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" + depends on DVB_CORE && PCI && I2C + select VIDEO_SAA7146 + select TTPCI_EEPROM + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder. + config DVB_BUDGET tristate "Budget cards" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 - select VIDEO_SAA7146 + depends on DVB_BUDGET_CORE && I2C select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_VES1820 if !DVB_FE_CUSTOMISE @@ -73,9 +88,9 @@ config DVB_BUDGET select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder. + Support for simple SAA7146 based DVB cards (so called Budget- + or Nova-PCI cards) without onboard MPEG2 decoder, and without + analog inputs or an onboard Common Interface connector. Say Y if you own such a card and want to use it. @@ -84,8 +99,7 @@ config DVB_BUDGET config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT - select VIDEO_SAA7146 + depends on DVB_BUDGET_CORE && I2C select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE @@ -106,8 +120,9 @@ config DVB_BUDGET_CI config DVB_BUDGET_AV tristate "Budget cards with analog video inputs" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 + depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE @@ -127,8 +142,8 @@ config DVB_BUDGET_AV config DVB_BUDGET_PATCH tristate "AV7110 cards with Budget Patch" - depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1 - select DVB_AV7110 + depends on DVB_BUDGET_CORE && I2C + depends on DVB_AV7110 select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_TDA8083 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index 2c11452..d7483f1 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -5,11 +5,13 @@ dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o -obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o -obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o +obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o +obj-$(CONFIG_DVB_BUDGET) += budget.o +obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o +obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o +obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o +obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8b8144f..bf6901c 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2595,7 +2595,8 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, mutex_init(&av7110->osd_mutex); /* TV standard */ - av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; + av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC + : AV7110_VIDEO_MODE_PAL; /* ARM "watchdog" */ init_waitqueue_head(&av7110->arm_wait); diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 0cb4395..39fbf7d 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -46,6 +46,11 @@ extern int av7110_debug; enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM}; +enum av7110_video_mode { + AV7110_VIDEO_MODE_PAL = 0, + AV7110_VIDEO_MODE_NTSC = 1 +}; + struct av7110_p2t { u8 pes[TS_SIZE]; u8 counter; @@ -170,7 +175,7 @@ struct av7110 { ca_slot_info_t ci_slot[2]; - int vidmode; + enum av7110_video_mode vidmode; struct dmxdev dmxdev; struct dvb_demux demux; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index d75e7e4..aef6e36 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -329,7 +329,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) return 0; } -int av7110_set_vidmode(struct av7110 *av7110, int mode) +int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) { int ret; dprintk(2, "av7110:%p, \n", av7110); @@ -348,11 +348,15 @@ int av7110_set_vidmode(struct av7110 *av7110, int mode) } -static int sw2mode[16] = { - VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, - VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, - VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, - VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, +static enum av7110_video_mode sw2mode[16] = { + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, }; static int get_video_format(struct av7110 *av7110, u8 *buf, int count) diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h index 45dc144..5f02ef8 100644 --- a/drivers/media/dvb/ttpci/av7110_av.h +++ b/drivers/media/dvb/ttpci/av7110_av.h @@ -3,7 +3,8 @@ struct av7110; -extern int av7110_set_vidmode(struct av7110 *av7110, int mode); +extern int av7110_set_vidmode(struct av7110 *av7110, + enum av7110_video_mode mode); extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 76cca00..e2f066f 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -876,11 +876,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) struct av7110 *av7110 = (struct av7110*) dev->ext_priv; if (std->id & V4L2_STD_PAL) { - av7110->vidmode = VIDEO_MODE_PAL; + av7110->vidmode = AV7110_VIDEO_MODE_PAL; av7110_set_vidmode(av7110, av7110->vidmode); } else if (std->id & V4L2_STD_NTSC) { - av7110->vidmode = VIDEO_MODE_NTSC; + av7110->vidmode = AV7110_VIDEO_MODE_NTSC; av7110_set_vidmode(av7110, av7110->vidmode); } else diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 5e4b9dd..246422b 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -58,10 +58,10 @@ static int initmute = 1; static int radio_nr = -1; module_param(io, int, 0444); -MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic" +MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " "probing is disabled or fails. The most common I/O ports are: 0x20c " "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " - " work for the combined sound/radiocard)."); + "work for the combined sound/radiocard)."); module_param(probe, bool, 0444); MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " @@ -392,7 +392,7 @@ static struct v4l2_queryctrl radio_qctrl[] = { } }; -static struct file_operations gemtek_fops = { +static const struct file_operations gemtek_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c9f14bf..6c78356 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -45,7 +45,7 @@ comment "Audio decoders" config VIDEO_TVAUDIO tristate "Simple audio decoder chips" - depends on VIDEO_V4L1 && I2C + depends on VIDEO_V4L2 && I2C ---help--- Support for several audio decoder chips found on some bt8xx boards: Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, @@ -57,7 +57,7 @@ config VIDEO_TVAUDIO config VIDEO_TDA7432 tristate "Philips TDA7432 audio processor" - depends on VIDEO_V4L1 && I2C + depends on VIDEO_V4L2 && I2C ---help--- Support for tda7432 audio decoder chip found on some bt8xx boards. @@ -75,7 +75,7 @@ config VIDEO_TDA9840 config VIDEO_TDA9875 tristate "Philips TDA9875 audio processor" - depends on VIDEO_V4L1 && I2C + depends on VIDEO_V4L2 && I2C ---help--- Support for tda9875 audio decoder chip found on some bt8xx boards. @@ -111,7 +111,7 @@ config VIDEO_MSP3400 config VIDEO_CS53L32A tristate "Cirrus Logic CS53L32A audio ADC" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Cirrus Logic CS53L32A low voltage stereo A/D converter. @@ -119,6 +119,15 @@ config VIDEO_CS53L32A To compile this driver as a module, choose M here: the module will be called cs53l32a. +config VIDEO_M52790 + tristate "Mitsubishi M52790 A/V switch" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the Mitsubishi M52790 A/V switch. + + To compile this driver as a module, choose M here: the + module will be called m52790. + config VIDEO_TLV320AIC23B tristate "Texas Instruments TLV320AIC23B audio codec" depends on VIDEO_V4L2 && I2C && EXPERIMENTAL @@ -130,7 +139,7 @@ config VIDEO_TLV320AIC23B config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Wolfson Microelectronics WM8775 high performance stereo A/D Converter with a 4 channel input mixer. @@ -140,7 +149,7 @@ config VIDEO_WM8775 config VIDEO_WM8739 tristate "Wolfson Microelectronics WM8739 stereo audio ADC" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Wolfson Microelectronics WM8739 stereo A/D Converter. @@ -244,7 +253,7 @@ config VIDEO_SAA7114 config VIDEO_SAA711X tristate "Philips SAA7113/4/5 video decoders" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Philips SAA7113/4/5 video decoders. @@ -300,7 +309,7 @@ comment "Video encoders" config VIDEO_SAA7127 tristate "Philips SAA7127/9 digital video encoders" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Philips SAA7127/9 digital video encoders. @@ -338,7 +347,7 @@ comment "Video improvement chips" config VIDEO_UPD64031A tristate "NEC Electronics uPD64031A Ghost Reduction" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the NEC Electronics uPD64031A Ghost Reduction video chip. It is most often found in NTSC TV cards made for @@ -350,7 +359,7 @@ config VIDEO_UPD64031A config VIDEO_UPD64083 tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the NEC Electronics uPD64083 3-Dimensional Y/C separation video chip. It is used to improve the quality of diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index b5a0641..a837e1e 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -4,7 +4,7 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o -tuner-objs := tuner-core.o tuner-types.o tda9887.o +tuner-objs := tuner-core.o tuner-types.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o @@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o +obj-$(CONFIG_VIDEO_M52790) += m52790.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o @@ -81,11 +82,13 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o +obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o obj-$(CONFIG_TUNER_TDA8290) += tda8290.o obj-$(CONFIG_TUNER_TEA5767) += tea5767.o obj-$(CONFIG_TUNER_TEA5761) += tea5761.o +obj-$(CONFIG_TUNER_TDA9887) += tda9887.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o @@ -129,3 +132,4 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 2ca162b..cfc822b 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1 + depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index a096a03..924d216 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -4,7 +4,7 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ - bttv-input.o + bttv-input.o bttv-audio-hook.o obj-$(CONFIG_VIDEO_BT848) += bttv.o diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c new file mode 100644 index 0000000..2364d16 --- /dev/null +++ b/drivers/media/video/bt8xx/bttv-audio-hook.c @@ -0,0 +1,382 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +#include "bttv-audio-hook.h" + +#include + +/* ----------------------------------------------------------------------- */ +/* winview */ + +void winview_volume(struct bttv *btv, __u16 volume) +{ + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + int bits_out, loops, vol, data; + + /* 32 levels logarithmic */ + vol = 32 - ((volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; + data = gpio_read(); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<audmode & V4L2_TUNER_MODE_LANG1) + con = 0x000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x300; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x200; +/* if (t->audmode & V4L2_TUNER_MODE_MONO) + * con = 0x100; */ + gpio_bits(0x300, con); + } else { + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val, con; + + if (btv->radio_user) + return; + + val = gpio_read(); + if (set) { + con = 0x000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) { + if (t->audmode & V4L2_TUNER_MODE_LANG1) { + /* LANG1 + LANG2 */ + con = 0x100; + } + else { + /* LANG2 */ + con = 0x300; + } + } + if (con != (val & 0x300)) { + gpio_bits(0x300, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"gvbctv5pci"); + } + } else { + switch (val & 0x70) { + case 0x10: + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + case 0x30: + t->rxsubchans = V4L2_TUNER_SUB_LANG2; + break; + case 0x50: + t->rxsubchans = V4L2_TUNER_SUB_LANG1; + break; + case 0x60: + t->rxsubchans = V4L2_TUNER_SUB_STEREO; + break; + case 0x70: + t->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + default: + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + } + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Mario Medina Nussbaum + * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, + * 0xdde enables mono and 0xccd enables sap + * + * Petr Vandrovec + * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select + * input/output sound connection, so both must be set for output mode. + * + * Looks like it's needed only for the "tvphone", the "tvphone 98" + * handles this with a tda9840 + * + */ + +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x02; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + val = 0x01; + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1; + return; + } +} + + +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x01; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ + val = 0x02; + btaor(val, ~0x03, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + return; + } +} + +/* Lifetec 9415 handling */ + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (gpio_read() & 0x4000) { + t->audmode = V4L2_TUNER_MODE_MONO; + return; + } + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ + val = 0x0080; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ + val = 0x0880; + if ((t->audmode & V4L2_TUNER_MODE_LANG1) || + (t->audmode & V4L2_TUNER_MODE_MONO)) + val = 0; + gpio_bits(0x0880, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"lt9415"); + } else { + /* autodetect doesn't work with this card :-( */ + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + return; + } +} + +/* TDA9821 on TerraTV+ Bt848, Bt878 */ +void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int con = 0; + + if (set) { + gpio_inout(0x180000,0x180000); + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x080000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x180000; + gpio_bits(0x180000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"terratv"); + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + + +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned long val = 0; + + if (set) { + /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ + if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ + val = 0x420000; + if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ + val = 0x420000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x410000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ + val = 0x020000; + if (val) { + gpio_bits(0x430000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"winfast2000"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM + * revision 9B has on-board TDA9874A sound decoder). + * + * Note: There are card variants without tda9874a. Forcing the "stereo sound route" + * will mute this cards. + */ +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val = 0; + + if (btv->radio_user) + return; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { + val = 0x01; + } + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { + val = 0x02; + } + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"pvbt878p9b"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for FlyVideo 2000S (with tda9874 decoder) + * based on pvbt878p9b_audio() - this is not tested, please fix!!! + */ +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val = 0xffff; + + if (btv->radio_user) + return; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { + val = 0x0000; + } + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ + } + if (val != 0xffff) { + gpio_bits(0x1800, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"fv2000s"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * sound control for Canopus WinDVR PCI + * Masaki Suzuki + */ +void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned long val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) + val = 0x040000; + if (t->audmode & V4L2_TUNER_MODE_LANG1) + val = 0; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + val = 0x100000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + val = 0; + if (val) { + gpio_bits(0x140000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"windvr"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * sound control for AD-TVK503 + * Hiroshi Takekawa + */ +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int con = 0xffffff; + + /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ + + if (set) { + /* btor(***, BT848_GPIO_OUT_EN); */ + if (t->audmode & V4L2_TUNER_MODE_LANG1) + con = 0x00000000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x00180000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x00000000; + if (t->audmode & V4L2_TUNER_MODE_MONO) + con = 0x00060000; + if (con != 0xffffff) { + gpio_bits(0x1e0000,con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "adtvk503"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/video/bt8xx/bttv-audio-hook.h new file mode 100644 index 0000000..159d07a --- /dev/null +++ b/drivers/media/video/bt8xx/bttv-audio-hook.h @@ -0,0 +1,23 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +#include "bttvp.h" + +void winview_volume (struct bttv *btv, __u16 volume); + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void terratv_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); + diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 3abd9fa..a233165 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -39,6 +39,7 @@ #include "bttvp.h" #include #include +#include "bttv-audio-hook.h" /* fwd decl */ static void boot_msp34xx(struct bttv *btv, int pin); @@ -50,20 +51,6 @@ static void modtec_eeprom(struct bttv *btv); static void init_PXC200(struct bttv *btv); static void init_RTV24(struct bttv *btv); -static void winview_audio(struct bttv *btv, struct video_audio *v, int set); -static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set); -static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, - int set); -static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, - int set); -static void terratv_audio(struct bttv *btv, struct video_audio *v, int set); -static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); -static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set); -static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); -static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set); -static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); -static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); -static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set); static void rv605_muxsel(struct bttv *btv, unsigned int input); static void eagle_muxsel(struct bttv *btv, unsigned int input); static void xguard_muxsel(struct bttv *btv, unsigned int input); @@ -427,7 +414,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = avermedia_tvphone_audio, + .audio_mode_gpio= avermedia_tvphone_audio, .has_remote = 1, }, [BTTV_BOARD_MATRIX_VISION] = { @@ -539,7 +526,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = avermedia_tv_stereo_audio, + .audio_mode_gpio= avermedia_tv_stereo_audio, .no_gpioirq = 1, }, [BTTV_BOARD_VHX] = { @@ -604,7 +591,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = winview_audio, + .volume_gpio = winview_volume, .has_radio = 1, }, [BTTV_BOARD_AVEC_INTERCAP] = { @@ -728,7 +715,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = terratv_audio, + .audio_mode_gpio= terratv_audio, }, [BTTV_BOARD_HAUPPAUG_WCAM] = { .name = "Hauppauge WinCam newer (bt878)", @@ -776,7 +763,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = terratv_audio, + .audio_mode_gpio= terratv_audio, /* GPIO wiring: External 20 pin connector (for Active Radio Upgrade board) gpio00: i2c-sda @@ -915,7 +902,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */ .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = winfast2000_audio, + .audio_mode_gpio= winfast2000_audio, .has_remote = 1, }, [BTTV_BOARD_CHRONOS_VS2] = { @@ -1035,7 +1022,7 @@ struct tvcard bttv_tvcards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_radio = 1, - .audio_hook = avermedia_tvphone_audio, + .audio_mode_gpio= avermedia_tvphone_audio, }, [BTTV_BOARD_PV951] = { .name = "ProVideo PV951", /* pic16c54 */ @@ -1167,7 +1154,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ALPS_TSHC6_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = gvbctv3pci_audio, + .audio_mode_gpio= gvbctv3pci_audio, }, [BTTV_BOARD_PXELVWPLTVPAK] = { .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", @@ -1472,7 +1459,7 @@ struct tvcard bttv_tvcards[] = { /* -dk-???: set mute=0x1800 for tda9874h daughterboard */ .gpiomux = { 0x0000,0x0800,0x1000,0x1000 }, .gpiomute = 0x1800, - .audio_hook = fv2000s_audio, + .audio_mode_gpio= fv2000s_audio, .no_msp34xx = 1, .no_tda9875 = 1, .needs_tvaudio = 1, @@ -1513,7 +1500,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = gvbctv3pci_audio, + .audio_mode_gpio= gvbctv3pci_audio, }, /* ---- card 0x44 ---------------------------------- */ @@ -1632,7 +1619,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */ + .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */ .has_radio = 1, /* Note: not all cards have radio */ .has_remote = 1, /* GPIO wiring: @@ -1710,7 +1697,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = windvr_audio, + .audio_mode_gpio= windvr_audio, }, [BTTV_BOARD_GRANDTEC_MULTI] = { .name = "GrandTec Multi Capture Card (Bt878)", @@ -1807,7 +1794,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC_M, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = gvbctv5pci_audio, + .audio_mode_gpio= gvbctv5pci_audio, .has_radio = 1, }, [BTTV_BOARD_OSPREY1x0] = { @@ -2106,7 +2093,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = adtvk503_audio, + .audio_mode_gpio= adtvk503_audio, }, /* ---- card 0x64 ---------------------------------- */ @@ -3173,8 +3160,8 @@ static void flyvideo_gpio(struct bttv *btv) /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ - if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio; - /* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */ + if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio; + /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ } static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, @@ -3574,8 +3561,12 @@ void __devinit bttv_init_card2(struct bttv *btv) } if (btv->tda9887_conf) { - bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG, - &btv->tda9887_conf); + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &btv->tda9887_conf; + + bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg); } btv->svhs = bttv_tvcards[btv->c.type].svhs; @@ -3590,8 +3581,10 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->has_remote=1; if (!bttv_tvcards[btv->c.type].no_gpioirq) btv->gpioirq=1; - if (bttv_tvcards[btv->c.type].audio_hook) - btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook; + if (bttv_tvcards[btv->c.type].volume_gpio) + btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio; + if (bttv_tvcards[btv->c.type].audio_mode_gpio) + btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio; if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) { /* detect Bt832 chip for quartzsight digital camera */ @@ -3950,7 +3943,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv) void bttv_tda9880_setnorm(struct bttv *btv, int norm) { /* fix up our card entry */ - if(norm==VIDEO_MODE_NTSC) { + if(norm==V4L2_STD_NTSC) { bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; @@ -4319,387 +4312,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq) tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ } - -/* ----------------------------------------------------------------------- */ -/* winview */ - -static void winview_audio(struct bttv *btv, struct video_audio *v, int set) -{ - /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ - int bits_out, loops, vol, data; - - if (!set) { - /* Fixed by Leandro Lucarella flags |= VIDEO_AUDIO_VOLUME; - return; - } - - /* 32 levels logarithmic */ - vol = 32 - ((v->volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; - data = gpio_read(); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1<mode & VIDEO_SOUND_LANG1) - con = 0x000; - if (v->mode & VIDEO_SOUND_LANG2) - con = 0x300; - if (v->mode & VIDEO_SOUND_STEREO) - con = 0x200; -/* if (v->mode & VIDEO_SOUND_MONO) - * con = 0x100; */ - gpio_bits(0x300, con); - } else { - v->mode = VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -static void -gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int val, con; - - if (btv->radio_user) - return; - - val = gpio_read(); - if (set) { - con = 0x000; - if (v->mode & VIDEO_SOUND_LANG2) { - if (v->mode & VIDEO_SOUND_LANG1) { - /* LANG1 + LANG2 */ - con = 0x100; - } - else { - /* LANG2 */ - con = 0x300; - } - } - if (con != (val & 0x300)) { - gpio_bits(0x300, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"gvbctv5pci"); - } - } else { - switch (val & 0x70) { - case 0x10: - v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - break; - case 0x30: - v->mode = VIDEO_SOUND_LANG2; - break; - case 0x50: - v->mode = VIDEO_SOUND_LANG1; - break; - case 0x60: - v->mode = VIDEO_SOUND_STEREO; - break; - case 0x70: - v->mode = VIDEO_SOUND_MONO; - break; - default: - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } - } -} - -/* - * Mario Medina Nussbaum - * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, - * 0xdde enables mono and 0xccd enables sap - * - * Petr Vandrovec - * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select - * input/output sound connection, so both must be set for output mode. - * - * Looks like it's needed only for the "tvphone", the "tvphone 98" - * handles this with a tda9840 - * - */ -static void -avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) -{ - int val = 0; - - if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ - val = 0x02; - if (v->mode & VIDEO_SOUND_STEREO) - val = 0x01; - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1; - return; - } -} - -static void -avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set) -{ - int val = 0; - - if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ - val = 0x01; - if (v->mode & VIDEO_SOUND_STEREO) /* STEREO */ - val = 0x02; - btaor(val, ~0x03, BT848_GPIO_DATA); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - return; - } -} - -/* Lifetec 9415 handling */ -static void -lt9415_audio(struct bttv *btv, struct video_audio *v, int set) -{ - int val = 0; - - if (gpio_read() & 0x4000) { - v->mode = VIDEO_SOUND_MONO; - return; - } - - if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */ - val = 0x0080; - if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */ - val = 0x0880; - if ((v->mode & VIDEO_SOUND_LANG1) || - (v->mode & VIDEO_SOUND_MONO)) - val = 0; - gpio_bits(0x0880, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"lt9415"); - } else { - /* autodetect doesn't work with this card :-( */ - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - return; - } -} - -/* TDA9821 on TerraTV+ Bt848, Bt878 */ -static void -terratv_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int con = 0; - - if (set) { - gpio_inout(0x180000,0x180000); - if (v->mode & VIDEO_SOUND_LANG2) - con = 0x080000; - if (v->mode & VIDEO_SOUND_STEREO) - con = 0x180000; - gpio_bits(0x180000, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"terratv"); - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -static void -winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned long val = 0; - - if (set) { - /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ - if (v->mode & VIDEO_SOUND_MONO) /* Mono */ - val = 0x420000; - if (v->mode & VIDEO_SOUND_LANG1) /* Mono */ - val = 0x420000; - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ - val = 0x410000; - if (v->mode & VIDEO_SOUND_STEREO) /* Stereo */ - val = 0x020000; - if (val) { - gpio_bits(0x430000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"winfast2000"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM - * revision 9B has on-board TDA9874A sound decoder). - * - * Note: There are card variants without tda9874a. Forcing the "stereo sound route" - * will mute this cards. - */ -static void -pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int val = 0; - - if (btv->radio_user) - return; - - if (set) { - if (v->mode & VIDEO_SOUND_MONO) { - val = 0x01; - } - if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) - || (v->mode & VIDEO_SOUND_STEREO)) { - val = 0x02; - } - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pvbt878p9b"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for FlyVideo 2000S (with tda9874 decoder) - * based on pvbt878p9b_audio() - this is not tested, please fix!!! - */ -static void -fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int val = 0xffff; - - if (btv->radio_user) - return; - if (set) { - if (v->mode & VIDEO_SOUND_MONO) { - val = 0x0000; - } - if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) - || (v->mode & VIDEO_SOUND_STEREO)) { - val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ - } - if (val != 0xffff) { - gpio_bits(0x1800, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"fv2000s"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * sound control for Canopus WinDVR PCI - * Masaki Suzuki - */ -static void -windvr_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned long val = 0; - - if (set) { - if (v->mode & VIDEO_SOUND_MONO) - val = 0x040000; - if (v->mode & VIDEO_SOUND_LANG1) - val = 0; - if (v->mode & VIDEO_SOUND_LANG2) - val = 0x100000; - if (v->mode & VIDEO_SOUND_STEREO) - val = 0; - if (val) { - gpio_bits(0x140000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"windvr"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * sound control for AD-TVK503 - * Hiroshi Takekawa - */ -static void -adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int con = 0xffffff; - - /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ - - if (set) { - /* btor(***, BT848_GPIO_OUT_EN); */ - if (v->mode & VIDEO_SOUND_LANG1) - con = 0x00000000; - if (v->mode & VIDEO_SOUND_LANG2) - con = 0x00180000; - if (v->mode & VIDEO_SOUND_STEREO) - con = 0x00000000; - if (v->mode & VIDEO_SOUND_MONO) - con = 0x00060000; - if (con != 0xffffff) { - gpio_bits(0x1e0000,con); - if (bttv_gpio) - bttv_gpio_tracking(btv, "adtvk503"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] * * This is needed because rv605 don't use a normal multiplex, but a crosspoint diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index a88b56e..03cc833 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -9,6 +9,12 @@ some v4l2 code lines are taken from Justin's bttv2 driver which is (c) 2000 Justin Schoeman + V4L1 removal from: + (c) 2005-2006 Nickolay V. Shmyrev + + Fixes to be fully V4L2 compliant by + (c) 2006 Mauro Carvalho Chehab + Cropping and overscan support Copyright (C) 2005, 2006 Michael H. Schimek Sponsored by OPQ Systems AB @@ -157,7 +163,7 @@ MODULE_LICENSE("GPL"); static ssize_t show_card(struct device *cd, struct device_attribute *attr, char *buf) { - struct video_device *vfd = to_video_device(cd); + struct video_device *vfd = container_of(cd, struct video_device, class_dev); struct bttv *btv = dev_get_drvdata(vfd->dev); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } @@ -473,28 +479,24 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); static const struct bttv_format bttv_formats[] = { { .name = "8 bpp, gray", - .palette = VIDEO_PALETTE_GREY, .fourcc = V4L2_PIX_FMT_GREY, .btformat = BT848_COLOR_FMT_Y8, .depth = 8, .flags = FORMAT_FLAGS_PACKED, },{ .name = "8 bpp, dithered color", - .palette = VIDEO_PALETTE_HI240, .fourcc = V4L2_PIX_FMT_HI240, .btformat = BT848_COLOR_FMT_RGB8, .depth = 8, .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, },{ .name = "15 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB555, .fourcc = V4L2_PIX_FMT_RGB555, .btformat = BT848_COLOR_FMT_RGB15, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "15 bpp RGB, be", - .palette = -1, .fourcc = V4L2_PIX_FMT_RGB555X, .btformat = BT848_COLOR_FMT_RGB15, .btswap = 0x03, /* byteswap */ @@ -502,14 +504,12 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "16 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB565, .fourcc = V4L2_PIX_FMT_RGB565, .btformat = BT848_COLOR_FMT_RGB16, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "16 bpp RGB, be", - .palette = -1, .fourcc = V4L2_PIX_FMT_RGB565X, .btformat = BT848_COLOR_FMT_RGB16, .btswap = 0x03, /* byteswap */ @@ -517,21 +517,18 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "24 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB24, .fourcc = V4L2_PIX_FMT_BGR24, .btformat = BT848_COLOR_FMT_RGB24, .depth = 24, .flags = FORMAT_FLAGS_PACKED, },{ .name = "32 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB32, .fourcc = V4L2_PIX_FMT_BGR32, .btformat = BT848_COLOR_FMT_RGB32, .depth = 32, .flags = FORMAT_FLAGS_PACKED, },{ .name = "32 bpp RGB, be", - .palette = -1, .fourcc = V4L2_PIX_FMT_RGB32, .btformat = BT848_COLOR_FMT_RGB32, .btswap = 0x0f, /* byte+word swap */ @@ -539,21 +536,18 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, YUYV", - .palette = VIDEO_PALETTE_YUV422, .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, YUYV", - .palette = VIDEO_PALETTE_YUYV, .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, UYVY", - .palette = VIDEO_PALETTE_UYVY, .fourcc = V4L2_PIX_FMT_UYVY, .btformat = BT848_COLOR_FMT_YUY2, .btswap = 0x03, /* byteswap */ @@ -561,7 +555,6 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV422P, .fourcc = V4L2_PIX_FMT_YUV422P, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 16, @@ -570,7 +563,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 0, },{ .name = "4:2:0, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV420P, .fourcc = V4L2_PIX_FMT_YUV420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -579,7 +571,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 1, },{ .name = "4:2:0, planar, Y-Cr-Cb", - .palette = -1, .fourcc = V4L2_PIX_FMT_YVU420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -588,7 +579,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 1, },{ .name = "4:1:1, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV411P, .fourcc = V4L2_PIX_FMT_YUV411P, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 12, @@ -597,7 +587,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 0, },{ .name = "4:1:0, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV410P, .fourcc = V4L2_PIX_FMT_YUV410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -606,7 +595,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 2, },{ .name = "4:1:0, planar, Y-Cr-Cb", - .palette = -1, .fourcc = V4L2_PIX_FMT_YVU410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -615,7 +603,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 2, },{ .name = "raw scanlines", - .palette = VIDEO_PALETTE_RAW, .fourcc = -1, .btformat = BT848_COLOR_FMT_RAW, .depth = 8, @@ -1255,16 +1242,6 @@ audio_input(struct bttv *btv, int input) } static void -i2c_vidiocschan(struct bttv *btv) -{ - v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id; - - bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std); - if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200) - bttv_tda9880_setnorm(btv,btv->tvnorm); -} - -static void bttv_crop_calc_limits(struct bttv_crop *c) { /* Scale factor min. 1:1, max. 16:1. Min. image size @@ -1298,6 +1275,7 @@ static int set_tvnorm(struct bttv *btv, unsigned int norm) { const struct bttv_tvnorm *tvnorm; + v4l2_std_id id; if (norm < 0 || norm >= BTTV_TVNORMS) return -EINVAL; @@ -1334,6 +1312,9 @@ set_tvnorm(struct bttv *btv, unsigned int norm) bttv_tda9880_setnorm(btv,norm); break; } + id = tvnorm->v4l2_id; + bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id); + return 0; } @@ -1359,7 +1340,6 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm) audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ? TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN)); set_tvnorm(btv, norm); - i2c_vidiocschan(btv); } static void init_irqreg(struct bttv *btv) @@ -1454,36 +1434,6 @@ static void bttv_reinit_bt848(struct bttv *btv) static int get_control(struct bttv *btv, struct v4l2_control *c) { - struct video_audio va; - int i; - - for (i = 0; i < BTTV_CTLS; i++) - if (bttv_ctls[i].id == c->id) - break; - if (i == BTTV_CTLS) - return -EINVAL; - if (btv->audio_hook && i >= 4 && i <= 8) { - memset(&va,0,sizeof(va)); - btv->audio_hook(btv,&va,0); - switch (c->id) { - case V4L2_CID_AUDIO_MUTE: - c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0; - break; - case V4L2_CID_AUDIO_VOLUME: - c->value = va.volume; - break; - case V4L2_CID_AUDIO_BALANCE: - c->value = va.balance; - break; - case V4L2_CID_AUDIO_BASS: - c->value = va.bass; - break; - case V4L2_CID_AUDIO_TREBLE: - c->value = va.treble; - break; - } - return 0; - } switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = btv->bright; @@ -1547,44 +1497,8 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) static int set_control(struct bttv *btv, struct v4l2_control *c) { - struct video_audio va; - int i,val; - - for (i = 0; i < BTTV_CTLS; i++) - if (bttv_ctls[i].id == c->id) - break; - if (i == BTTV_CTLS) - return -EINVAL; - if (btv->audio_hook && i >= 4 && i <= 8) { - memset(&va,0,sizeof(va)); - btv->audio_hook(btv,&va,0); - switch (c->id) { - case V4L2_CID_AUDIO_MUTE: - if (c->value) { - va.flags |= VIDEO_AUDIO_MUTE; - audio_mute(btv, 1); - } else { - va.flags &= ~VIDEO_AUDIO_MUTE; - audio_mute(btv, 0); - } - break; + int val; - case V4L2_CID_AUDIO_VOLUME: - va.volume = c->value; - break; - case V4L2_CID_AUDIO_BALANCE: - va.balance = c->value; - break; - case V4L2_CID_AUDIO_BASS: - va.bass = c->value; - break; - case V4L2_CID_AUDIO_TREBLE: - va.treble = c->value; - break; - } - btv->audio_hook(btv,&va,1); - return 0; - } switch (c->id) { case V4L2_CID_BRIGHTNESS: bt848_bright(btv,c->value); @@ -1602,6 +1516,11 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) audio_mute(btv, c->value); /* fall through */ case V4L2_CID_AUDIO_VOLUME: + if (btv->volume_gpio) { + btv->volume_gpio (btv, c->value); + } + bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c); + break; case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: @@ -1693,20 +1612,6 @@ static void bttv_field_count(struct bttv *btv) } static const struct bttv_format* -format_by_palette(int palette) -{ - unsigned int i; - - for (i = 0; i < BTTV_FORMATS; i++) { - if (-1 == bttv_formats[i].palette) - continue; - if (bttv_formats[i].palette == palette) - return bttv_formats+i; - } - return NULL; -} - -static const struct bttv_format* format_by_fourcc(int fourcc) { unsigned int i; @@ -1733,7 +1638,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, dprintk("switch_overlay: enter [new=%p]\n",new); if (new) - new->vb.state = STATE_DONE; + new->vb.state = VIDEOBUF_DONE; spin_lock_irqsave(&btv->s_lock,flags); old = btv->screen; btv->screen = new; @@ -1844,7 +1749,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, } /* alloc risc memory */ - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf))) goto fail; @@ -1854,7 +1759,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, if (0 != (rc = bttv_buffer_risc(btv,buf))) goto fail; - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -1893,7 +1798,7 @@ buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct bttv_fh *fh = q->priv_data; struct bttv *btv = fh->btv; - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; list_add_tail(&buf->vb.queue,&btv->capture); if (!btv->curr.frame_irq) { btv->loop_irq |= 1; @@ -1919,151 +1824,6 @@ static struct videobuf_queue_ops bttv_video_qops = { static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) { switch (cmd) { - case BTTV_VERSION: - return BTTV_VERSION_CODE; - - /* *** v4l1 *** ************************************************ */ - case VIDIOCGFREQ: - { - unsigned long *freq = arg; - *freq = btv->freq; - return 0; - } - case VIDIOCSFREQ: - { - struct v4l2_frequency freq; - - memset(&freq, 0, sizeof(freq)); - freq.frequency = *(unsigned long *)arg; - mutex_lock(&btv->lock); - freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - btv->freq = *(unsigned long *)arg; - bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq); - if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv,*(unsigned long *)arg); - mutex_unlock(&btv->lock); - return 0; - } - - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; - - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (v->tuner) /* Only tuner 0 */ - return -EINVAL; - strcpy(v->name, "Television"); - v->rangelow = 0; - v->rangehigh = 0x7FFFFFFF; - v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; - v->mode = btv->tvnorm; - v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; - bttv_call_i2c_clients(btv,cmd,v); - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; - - if (v->tuner) /* Only tuner 0 */ - return -EINVAL; - if (v->mode >= BTTV_TVNORMS) - return -EINVAL; - - mutex_lock(&btv->lock); - set_tvnorm(btv,v->mode); - bttv_call_i2c_clients(btv,cmd,v); - mutex_unlock(&btv->lock); - return 0; - } - - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - unsigned int channel = v->channel; - - if (channel >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - v->tuners=0; - v->flags = VIDEO_VC_AUDIO; - v->type = VIDEO_TYPE_CAMERA; - v->norm = btv->tvnorm; - if (channel == bttv_tvcards[btv->c.type].tuner) { - strcpy(v->name,"Television"); - v->flags|=VIDEO_VC_TUNER; - v->type=VIDEO_TYPE_TV; - v->tuners=1; - } else if (channel == btv->svhs) { - strcpy(v->name,"S-Video"); - } else { - sprintf(v->name,"Composite%d",channel); - } - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - unsigned int channel = v->channel; - - if (channel >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - if (v->norm >= BTTV_TVNORMS) - return -EINVAL; - - mutex_lock(&btv->lock); - if (channel == btv->input && - v->norm == btv->tvnorm) { - /* nothing to do */ - mutex_unlock(&btv->lock); - return 0; - } - - set_input(btv, v->channel, v->norm); - mutex_unlock(&btv->lock); - return 0; - } - - case VIDIOCGAUDIO: - { - struct video_audio *v = arg; - - memset(v,0,sizeof(*v)); - strcpy(v->name,"Television"); - v->flags |= VIDEO_AUDIO_MUTABLE; - v->mode = VIDEO_SOUND_MONO; - - mutex_lock(&btv->lock); - bttv_call_i2c_clients(btv,cmd,v); - - /* card specific hooks */ - if (btv->audio_hook) - btv->audio_hook(btv,v,0); - - mutex_unlock(&btv->lock); - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio *v = arg; - unsigned int audio = v->audio; - - if (audio >= bttv_tvcards[btv->c.type].audio_inputs) - return -EINVAL; - - mutex_lock(&btv->lock); - audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0); - bttv_call_i2c_clients(btv,cmd,v); - - /* card specific hooks */ - if (btv->audio_hook) - btv->audio_hook(btv,v,1); - - mutex_unlock(&btv->lock); - return 0; - } - - /* *** v4l2 *** ************************************************ */ case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; @@ -2095,7 +1855,6 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) mutex_lock(&btv->lock); set_tvnorm(btv,i); - i2c_vidiocschan(btv); mutex_unlock(&btv->lock); return 0; } @@ -2160,45 +1919,6 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) return 0; } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - mutex_lock(&btv->lock); - memset(t,0,sizeof(*t)); - t->rxsubchans = V4L2_TUNER_SUB_MONO; - bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); - strcpy(t->name, "Television"); - t->capability = V4L2_TUNER_CAP_NORM; - t->type = V4L2_TUNER_ANALOG_TV; - if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) - t->signal = 0xffff; - - if (btv->audio_hook) { - /* Hmmm ... */ - struct video_audio va; - memset(&va, 0, sizeof(struct video_audio)); - btv->audio_hook(btv,&va,0); - t->audmode = V4L2_TUNER_MODE_MONO; - t->rxsubchans = V4L2_TUNER_SUB_MONO; - if(va.mode & VIDEO_SOUND_STEREO) { - t->audmode = V4L2_TUNER_MODE_STEREO; - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - } - if(va.mode & VIDEO_SOUND_LANG2) { - t->audmode = V4L2_TUNER_MODE_LANG1; - t->rxsubchans = V4L2_TUNER_SUB_LANG1 - | V4L2_TUNER_SUB_LANG2; - } - } - /* FIXME: fill capability+audmode */ - mutex_unlock(&btv->lock); - return 0; - } case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; @@ -2209,19 +1929,9 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) return -EINVAL; mutex_lock(&btv->lock); bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); - if (btv->audio_hook) { - struct video_audio va; - memset(&va, 0, sizeof(struct video_audio)); - if (t->audmode == V4L2_TUNER_MODE_MONO) - va.mode = VIDEO_SOUND_MONO; - else if (t->audmode == V4L2_TUNER_MODE_STEREO || - t->audmode == V4L2_TUNER_MODE_LANG1_LANG2) - va.mode = VIDEO_SOUND_STEREO; - else if (t->audmode == V4L2_TUNER_MODE_LANG1) - va.mode = VIDEO_SOUND_LANG1; - else if (t->audmode == V4L2_TUNER_MODE_LANG2) - va.mode = VIDEO_SOUND_LANG2; - btv->audio_hook(btv,&va,1); + + if (btv->audio_mode_gpio) { + btv->audio_mode_gpio (btv,t,1); } mutex_unlock(&btv->lock); return 0; @@ -2259,6 +1969,10 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr); return 0; } + case VIDIOC_G_CTRL: + return get_control(btv,arg); + case VIDIOC_S_CTRL: + return set_control(btv,arg); #ifdef CONFIG_VIDEO_ADV_DEBUG case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_S_REGISTER: @@ -2803,7 +2517,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, { struct bttv_fh *fh = file->private_data; struct bttv *btv = fh->btv; - unsigned long flags; int retval = 0; if (bttv_debug > 1) @@ -2813,9 +2526,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, bttv_reinit_bt848(btv); switch (cmd) { - case VIDIOCSFREQ: - case VIDIOCSTUNER: - case VIDIOCSCHAN: case VIDIOC_S_CTRL: case VIDIOC_S_STD: case VIDIOC_S_INPUT: @@ -2827,237 +2537,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, }; switch (cmd) { - - /* *** v4l1 *** ************************************************ */ - case VIDIOCGCAP: - { - struct video_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->name,btv->video_dev->name); - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - /* vbi */ - cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT; - } else { - /* others */ - cap->type = VID_TYPE_CAPTURE| - VID_TYPE_TUNER| - VID_TYPE_CLIPPING| - VID_TYPE_SCALES; - if (no_overlay <= 0) - cap->type |= VID_TYPE_OVERLAY; - - cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; - cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; - cap->minwidth = 48; - cap->minheight = 32; - } - cap->channels = bttv_tvcards[btv->c.type].video_inputs; - cap->audios = bttv_tvcards[btv->c.type].audio_inputs; - return 0; - } - - case VIDIOCGPICT: - { - struct video_picture *pic = arg; - - memset(pic,0,sizeof(*pic)); - pic->brightness = btv->bright; - pic->contrast = btv->contrast; - pic->hue = btv->hue; - pic->colour = btv->saturation; - if (fh->fmt) { - pic->depth = fh->fmt->depth; - pic->palette = fh->fmt->palette; - } - return 0; - } - case VIDIOCSPICT: - { - struct video_picture *pic = arg; - const struct bttv_format *fmt; - - fmt = format_by_palette(pic->palette); - if (NULL == fmt) - return -EINVAL; - mutex_lock(&fh->cap.lock); - if (fmt->flags & FORMAT_FLAGS_RAW) { - /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL * - RAW_LINES * 2. F1 is stored at offset 0, F2 - at buffer size / 2. */ - fh->width = RAW_BPL; - fh->height = gbufsize / RAW_BPL; - btv->init.width = RAW_BPL; - btv->init.height = gbufsize / RAW_BPL; - } - fh->ovfmt = fmt; - fh->fmt = fmt; - btv->init.ovfmt = fmt; - btv->init.fmt = fmt; - if (bigendian) { - /* dirty hack time: swap bytes for overlay if the - display adaptor is big endian (insmod option) */ - if (fmt->palette == VIDEO_PALETTE_RGB555 || - fmt->palette == VIDEO_PALETTE_RGB565 || - fmt->palette == VIDEO_PALETTE_RGB32) { - fh->ovfmt = fmt+1; - } - } - bt848_bright(btv,pic->brightness); - bt848_contrast(btv,pic->contrast); - bt848_hue(btv,pic->hue); - bt848_sat(btv,pic->colour); - mutex_unlock(&fh->cap.lock); - return 0; - } - - case VIDIOCGWIN: - { - struct video_window *win = arg; - - memset(win,0,sizeof(*win)); - win->x = fh->ov.w.left; - win->y = fh->ov.w.top; - win->width = fh->ov.w.width; - win->height = fh->ov.w.height; - return 0; - } - case VIDIOCSWIN: - { - struct video_window *win = arg; - struct v4l2_window w2; - - if (no_overlay > 0) { - printk ("VIDIOCSWIN: no_overlay\n"); - return -EINVAL; - } - - w2.field = V4L2_FIELD_ANY; - w2.w.left = win->x; - w2.w.top = win->y; - w2.w.width = win->width; - w2.w.height = win->height; - w2.clipcount = win->clipcount; - w2.clips = (struct v4l2_clip __user *)win->clips; - retval = setup_window(fh, btv, &w2, 0); - if (0 == retval) { - /* on v4l1 this ioctl affects the read() size too */ - fh->width = fh->ov.w.width; - fh->height = fh->ov.w.height; - btv->init.width = fh->ov.w.width; - btv->init.height = fh->ov.w.height; - } - return retval; - } - - case VIDIOCGFBUF: - { - struct video_buffer *fbuf = arg; - - fbuf->base = btv->fbuf.base; - fbuf->width = btv->fbuf.fmt.width; - fbuf->height = btv->fbuf.fmt.height; - fbuf->bytesperline = btv->fbuf.fmt.bytesperline; - if (fh->ovfmt) - fbuf->depth = fh->ovfmt->depth; - else { - if (fbuf->width) - fbuf->depth = ((fbuf->bytesperline<<3) - + (fbuf->width-1) ) - /fbuf->width; - else - fbuf->depth = 0; - } - return 0; - } - case VIDIOCSFBUF: - { - struct video_buffer *fbuf = arg; - const struct bttv_format *fmt; - unsigned long end; - - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; - end = (unsigned long)fbuf->base + - fbuf->height * fbuf->bytesperline; - mutex_lock(&fh->cap.lock); - retval = -EINVAL; - - switch (fbuf->depth) { - case 8: - fmt = format_by_palette(VIDEO_PALETTE_HI240); - break; - case 16: - fmt = format_by_palette(VIDEO_PALETTE_RGB565); - break; - case 24: - fmt = format_by_palette(VIDEO_PALETTE_RGB24); - break; - case 32: - fmt = format_by_palette(VIDEO_PALETTE_RGB32); - break; - case 15: - fbuf->depth = 16; - fmt = format_by_palette(VIDEO_PALETTE_RGB555); - break; - default: - fmt = NULL; - break; - } - if (NULL == fmt) - goto fh_unlock_and_return; - - fh->ovfmt = fmt; - fh->fmt = fmt; - btv->init.ovfmt = fmt; - btv->init.fmt = fmt; - btv->fbuf.base = fbuf->base; - btv->fbuf.fmt.width = fbuf->width; - btv->fbuf.fmt.height = fbuf->height; - if (fbuf->bytesperline) - btv->fbuf.fmt.bytesperline = fbuf->bytesperline; - else - btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8; - mutex_unlock(&fh->cap.lock); - return 0; - } - - case VIDIOCCAPTURE: - case VIDIOC_OVERLAY: - { - struct bttv_buffer *new; - int *on = arg; - - if (*on) { - /* verify args */ - if (NULL == btv->fbuf.base) - return -EINVAL; - if (!fh->ov.setup_ok) { - dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr); - return -EINVAL; - } - } - - if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) - return -EBUSY; - - mutex_lock(&fh->cap.lock); - if (*on) { - fh->ov.tvnorm = btv->tvnorm; - new = videobuf_pci_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - } else { - new = NULL; - } - - /* switch over */ - retval = bttv_switch_overlay(btv,fh,new); - mutex_unlock(&fh->cap.lock); - return retval; - } - +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; @@ -3078,107 +2558,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&fh->cap.lock); return 0; } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - struct bttv_buffer *buf; - enum v4l2_field field; - __s32 height2; - int res; - - if (vm->frame >= VIDEO_MAX_FRAME) - return -EINVAL; - - res = bttv_resource(fh); - if (!check_alloc_btres(btv, fh, res)) - return -EBUSY; - - mutex_lock(&fh->cap.lock); - retval = -EINVAL; - buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame]; - if (NULL == buf) - goto fh_unlock_and_return; - if (0 == buf->vb.baddr) - goto fh_unlock_and_return; - if (buf->vb.state == STATE_QUEUED || - buf->vb.state == STATE_ACTIVE) - goto fh_unlock_and_return; - - height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - field = (vm->height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - retval = bttv_prepare_buffer(&fh->cap,btv,buf, - format_by_palette(vm->format), - vm->width,vm->height,field); - if (0 != retval) - goto fh_unlock_and_return; - btv->init.width = vm->width; - btv->init.height = vm->height; - spin_lock_irqsave(&btv->s_lock,flags); - buffer_queue(&fh->cap,&buf->vb); - spin_unlock_irqrestore(&btv->s_lock,flags); - mutex_unlock(&fh->cap.lock); - return 0; - } - case VIDIOCSYNC: - { - int *frame = arg; - struct bttv_buffer *buf; - - if (*frame >= VIDEO_MAX_FRAME) - return -EINVAL; - - mutex_lock(&fh->cap.lock); - retval = -EINVAL; - buf = (struct bttv_buffer *)fh->cap.bufs[*frame]; - if (NULL == buf) - goto fh_unlock_and_return; - retval = videobuf_waiton(&buf->vb,0,1); - if (0 != retval) - goto fh_unlock_and_return; - switch (buf->vb.state) { - case STATE_ERROR: - retval = -EIO; - /* fall through */ - case STATE_DONE: - { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - videobuf_dma_sync(&fh->cap,dma); - bttv_dma_free(&fh->cap,btv,buf); - break; - } - default: - retval = -EINVAL; - break; - } - mutex_unlock(&fh->cap.lock); - return retval; - } - - case VIDIOCGVBIFMT: - if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) { - retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); - if (0 != retval) - return retval; - } - - /* fall through */ - - case VIDIOCSVBIFMT: - return v4l_compat_translate_ioctl(inode, file, cmd, - arg, bttv_do_ioctl); - - case BTTV_VERSION: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGCHAN: - case VIDIOCSCHAN: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return bttv_common_ioctls(btv,cmd,arg); +#endif /* *** v4l2 *** ************************************************ */ case VIDIOC_QUERYCAP: @@ -3206,7 +2586,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, cap->capabilities |= V4L2_CAP_TUNER; return 0; } - case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; @@ -3256,7 +2635,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, strlcpy(f->description,bttv_formats[i].name,sizeof(f->description)); return 0; } - case VIDIOC_TRY_FMT: { struct v4l2_format *f = arg; @@ -3283,6 +2661,38 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, fb->fmt.pixelformat = fh->ovfmt->fourcc; return 0; } + case VIDIOC_OVERLAY: + { + struct bttv_buffer *new; + int *on = arg; + + if (*on) { + /* verify args */ + if (NULL == btv->fbuf.base) + return -EINVAL; + if (!fh->ov.setup_ok) { + dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr); + return -EINVAL; + } + } + + if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) + return -EBUSY; + + mutex_lock(&fh->cap.lock); + if (*on) { + fh->ov.tvnorm = btv->tvnorm; + new = videobuf_pci_alloc(sizeof(*new)); + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + } else { + new = NULL; + } + + /* switch over */ + retval = bttv_switch_overlay(btv,fh,new); + mutex_unlock(&fh->cap.lock); + return retval; + } case VIDIOC_S_FBUF: { struct v4l2_framebuffer *fb = arg; @@ -3350,13 +2760,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&fh->cap.lock); return retval; } - case VIDIOC_REQBUFS: return videobuf_reqbufs(bttv_queue(fh),arg); - case VIDIOC_QUERYBUF: return videobuf_querybuf(bttv_queue(fh),arg); - case VIDIOC_QBUF: { int res = bttv_resource(fh); @@ -3365,11 +2772,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, return -EBUSY; return videobuf_qbuf(bttv_queue(fh),arg); } - case VIDIOC_DQBUF: return videobuf_dqbuf(bttv_queue(fh),arg, file->f_flags & O_NONBLOCK); - case VIDIOC_STREAMON: { int res = bttv_resource(fh); @@ -3407,35 +2812,13 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, return 0; } *c = bttv_ctls[i]; - if (btv->audio_hook && i >= 4 && i <= 8) { - struct video_audio va; - memset(&va,0,sizeof(va)); - btv->audio_hook(btv,&va,0); - switch (bttv_ctls[i].id) { - case V4L2_CID_AUDIO_VOLUME: - if (!(va.flags & VIDEO_AUDIO_VOLUME)) - *c = no_ctl; - break; - case V4L2_CID_AUDIO_BALANCE: - if (!(va.flags & VIDEO_AUDIO_BALANCE)) - *c = no_ctl; - break; - case V4L2_CID_AUDIO_BASS: - if (!(va.flags & VIDEO_AUDIO_BASS)) - *c = no_ctl; - break; - case V4L2_CID_AUDIO_TREBLE: - if (!(va.flags & VIDEO_AUDIO_TREBLE)) - *c = no_ctl; - break; - } - } + + if (!btv->volume_gpio && + (bttv_ctls[i].id == V4L2_CID_AUDIO_VOLUME)) + *c = no_ctl; + return 0; } - case VIDIOC_G_CTRL: - return get_control(btv,arg); - case VIDIOC_S_CTRL: - return set_control(btv,arg); case VIDIOC_G_PARM: { struct v4l2_streamparm *parm = arg; @@ -3448,6 +2831,31 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, parm->parm.capture.timeperframe = s.frameperiod; return 0; } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; + + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + mutex_lock(&btv->lock); + memset(t,0,sizeof(*t)); + t->rxsubchans = V4L2_TUNER_SUB_MONO; + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + strcpy(t->name, "Television"); + t->capability = V4L2_TUNER_CAP_NORM; + t->type = V4L2_TUNER_ANALOG_TV; + if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) + t->signal = 0xffff; + + if (btv->audio_mode_gpio) { + btv->audio_mode_gpio (btv,t,0); + } + + mutex_unlock(&btv->lock); + return 0; + } case VIDIOC_G_PRIORITY: { @@ -3585,17 +2993,18 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_ENUMINPUT: case VIDIOC_G_INPUT: case VIDIOC_S_INPUT: - case VIDIOC_G_TUNER: case VIDIOC_S_TUNER: case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: case VIDIOC_LOG_STATUS: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_S_REGISTER: return bttv_common_ioctls(btv,cmd,arg); - default: - return -ENOIOCTLCMD; + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + bttv_do_ioctl); } return 0; @@ -3611,33 +3020,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, static int bttv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct bttv_fh *fh = file->private_data; - - switch (cmd) { - case BTTV_VBISIZE: - { - const struct bttv_tvnorm *tvnorm; - - tvnorm = fh->vbi_fmt.tvnorm; - - if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] || - fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] || - fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) { - /* BTTV_VBISIZE cannot express these parameters, - however open() resets the paramters to defaults - and apps shouldn't call BTTV_VBISIZE after - VIDIOC_S_FMT. */ - return -EINVAL; - } - - bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); - return (fh->vbi_fmt.fmt.count[0] * 2 - * fh->vbi_fmt.fmt.samples_per_line); - } - - default: - return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl); - } + return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl); } static ssize_t bttv_read(struct file *file, char __user *data, @@ -3721,8 +3104,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) } poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == STATE_DONE || - buf->vb.state == STATE_ERROR) + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -3779,7 +3162,7 @@ static int bttv_open(struct inode *inode, struct file *file) V4L2_FIELD_SEQ_TB, sizeof(struct bttv_buffer), fh); - i2c_vidiocschan(btv); + set_tvnorm(btv,btv->tvnorm); btv->users++; @@ -3827,10 +3210,7 @@ static int bttv_release(struct inode *inode, struct file *file) /* stop vbi capture */ if (check_btres(fh, RESOURCE_VBI)) { - if (fh->vbi.streaming) - videobuf_streamoff(&fh->vbi); - if (fh->vbi.reading) - videobuf_read_stop(&fh->vbi); + videobuf_stop(&fh->vbi); free_btres(btv,fh,RESOURCE_VBI); } @@ -3939,45 +3319,53 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, struct bttv *btv = file->private_data; switch (cmd) { - case VIDIOCGCAP: + case VIDIOC_QUERYCAP: { - struct video_capability *cap = arg; + struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); - strcpy(cap->name,btv->radio_dev->name); - cap->type = VID_TYPE_TUNER; - cap->channels = 1; - cap->audios = 1; + strcpy(cap->driver, "bttv"); + strlcpy(cap->card, btv->radio_dev->name,sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci)); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; return 0; } - - case VIDIOCGTUNER: + case VIDIOC_G_TUNER: { - struct video_tuner *v = arg; + struct v4l2_tuner *t = arg; - if(v->tuner) + if (UNSET == bttv_tvcards[btv->c.type].tuner) return -EINVAL; - memset(v,0,sizeof(*v)); - strcpy(v->name, "Radio"); - bttv_call_i2c_clients(btv,cmd,v); + if (0 != t->index) + return -EINVAL; + mutex_lock(&btv->lock); + memset(t,0,sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + + if (btv->audio_mode_gpio) { + btv->audio_mode_gpio (btv,t,0); + } + + mutex_unlock(&btv->lock); + return 0; } - case VIDIOCSTUNER: - /* nothing to do */ - return 0; - - case BTTV_VERSION: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: + case VIDIOC_S_TUNER: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: case VIDIOC_LOG_STATUS: case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_S_REGISTER: return bttv_common_ioctls(btv,cmd,arg); - default: - return -ENOIOCTLCMD; + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + radio_do_ioctl); } return 0; } @@ -4313,20 +3701,20 @@ static void bttv_irq_timeout(unsigned long data) bttv_set_dma(btv, 0); /* wake up */ - bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR); - bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR); + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR); + bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR); /* cancel all outstanding capture / vbi requests */ while (!list_empty(&btv->capture)) { item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); list_del(&item->vb.queue); - item->vb.state = STATE_ERROR; + item->vb.state = VIDEOBUF_ERROR; wake_up(&item->vb.done); } while (!list_empty(&btv->vcapture)) { item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); list_del(&item->vb.queue); - item->vb.state = STATE_ERROR; + item->vb.state = VIDEOBUF_ERROR; wake_up(&item->vb.done); } @@ -4349,7 +3737,7 @@ bttv_irq_wakeup_top(struct bttv *btv) do_gettimeofday(&wakeup->vb.ts); wakeup->vb.field_count = btv->field_count; - wakeup->vb.state = STATE_DONE; + wakeup->vb.state = VIDEOBUF_DONE; wake_up(&wakeup->vb.done); spin_unlock(&btv->s_lock); } @@ -4398,7 +3786,7 @@ bttv_irq_switch_video(struct bttv *btv) } /* wake up finished buffers */ - bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE); + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE); spin_unlock(&btv->s_lock); } @@ -4431,7 +3819,7 @@ bttv_irq_switch_vbi(struct bttv *btv) bttv_buffer_activate_vbi(btv, new); bttv_set_dma(btv, 0); - bttv_irq_wakeup_vbi(btv, old, STATE_DONE); + bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE); spin_unlock(&btv->s_lock); } @@ -4773,7 +4161,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->init.btv = btv; btv->init.ov.w.width = 320; btv->init.ov.w.height = 240; - btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24); + btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); btv->init.width = 320; btv->init.height = 240; btv->input = 0; diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index 58986f1..e5979f7 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf videobuf_dma_free(dma); btcx_riscmem_free(btv->c.pci,&buf->bottom); btcx_riscmem_free(btv->c.pci,&buf->top); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } int @@ -602,7 +602,7 @@ bttv_buffer_activate_vbi(struct bttv *btv, if (vbi) { unsigned int crop, vdelay; - vbi->vb.state = STATE_ACTIVE; + vbi->vb.state = VIDEOBUF_ACTIVE; list_del(&vbi->vb.queue); /* VDELAY is start of video, end of VBI capturing. */ @@ -644,12 +644,12 @@ bttv_buffer_activate_video(struct bttv *btv, /* video capture */ if (NULL != set->top && NULL != set->bottom) { if (set->top == set->bottom) { - set->top->vb.state = STATE_ACTIVE; + set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); } else { - set->top->vb.state = STATE_ACTIVE; - set->bottom->vb.state = STATE_ACTIVE; + set->top->vb.state = VIDEOBUF_ACTIVE; + set->bottom->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); if (set->bottom->vb.queue.next) @@ -666,7 +666,7 @@ bttv_buffer_activate_video(struct bttv *btv, btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->top) { - set->top->vb.state = STATE_ACTIVE; + set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); bttv_apply_geo(btv, &set->top->geo,1); @@ -677,7 +677,7 @@ bttv_buffer_activate_video(struct bttv *btv, btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->bottom) { - set->bottom->vb.state = STATE_ACTIVE; + set->bottom->vb.state = VIDEOBUF_ACTIVE; if (set->bottom->vb.queue.next) list_del(&set->bottom->vb.queue); bttv_apply_geo(btv, &set->bottom->geo,1); diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 346ce01..b924f05 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -142,7 +142,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, redo_dma_risc = 1; } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; @@ -189,7 +189,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, /* For bttv_buffer_activate_vbi(). */ buf->geo.vdelay = min_vdelay; - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->vb.field = field; dprintk("buf prepare %p: top=%p bottom=%p field=%s\n", vb, &buf->top, &buf->bottom, @@ -209,7 +209,7 @@ vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); dprintk("queue %p\n",vb); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; list_add_tail(&buf->vb.queue,&btv->vcapture); if (NULL == btv->cvbi) { fh->btv->loop_irq |= 4; diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index 19e75d5..bf4c339 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -241,7 +241,10 @@ struct tvcard unsigned int radio_addr; unsigned int has_radio; - void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); }; diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index d4ac4c4..4a02f0a 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -112,7 +112,6 @@ extern const struct bttv_tvnorm bttv_tvnorms[]; struct bttv_format { char *name; - int palette; /* video4linux 1 */ int fourcc; /* video4linux 2 */ int btformat; /* BT848_COLOR_FMT_* */ int btswap; /* BT848_COLOR_CTL_* */ @@ -337,7 +336,9 @@ struct bttv { /* old gpio interface */ wait_queue_head_t gpioq; int shutdown; - void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); /* new gpio interface */ spinlock_t gpio_lock; @@ -458,10 +459,6 @@ struct bttv { extern unsigned int bttv_num; extern struct bttv bttvs[BTTV_MAX]; -/* private ioctls */ -#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) -#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) - #endif #define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index a73e285..65bb6af 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -29,6 +29,7 @@ #include #include #include +#include MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_AUTHOR("Martin Vaughan"); @@ -57,8 +58,7 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_routing *route = arg; struct v4l2_control *ctrl = arg; @@ -134,27 +134,17 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) +static int cs53l32a_probe(struct i2c_client *client) { - struct i2c_client *client; int i; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); for (i = 1; i <= 7; i++) { u8 v = cs53l32a_read(client, i); @@ -179,55 +169,13 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v); } - - i2c_attach_client(client); - return 0; } -static int cs53l32a_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, cs53l32a_attach); - return 0; -} - -static int cs53l32a_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(client); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "cs53l32a", - }, - .id = I2C_DRIVERID_CS53L32A, - .attach_adapter = cs53l32a_probe, - .detach_client = cs53l32a_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "cs53l32a", + .driverid = I2C_DRIVERID_CS53L32A, .command = cs53l32a_command, + .probe = cs53l32a_probe, }; - -static int __init cs53l32a_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit cs53l32a_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(cs53l32a_init_module); -module_exit(cs53l32a_cleanup_module); diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index b9012ac..134b931 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -270,8 +270,6 @@ void cx23885_card_setup(struct cx23885_dev *dev) /* ------------------------------------------------------------------ */ -EXPORT_SYMBOL(cx23885_boards); - /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 3cdd136..f205ad6 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -73,7 +73,7 @@ static LIST_HEAD(cx23885_devlist); * 0x00010ea0 0x00010xxx Free */ -struct sram_channel cx23885_sram_channels[] = { +static struct sram_channel cx23885_sram_channels[] = { [SRAM_CH01] = { .name = "test ch1", .cmds_start = 0x10000, @@ -205,7 +205,7 @@ struct sram_channel cx23885_sram_channels[] = { * 0x00010ea0 0x00010xxx Free */ -struct sram_channel cx23887_sram_channels[] = { +static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH01] = { .name = "test ch1", .cmds_start = 0x0, @@ -356,8 +356,8 @@ static int cx23885_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } -void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count) +static void cx23885_wakeup(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; @@ -378,7 +378,7 @@ void cx23885_wakeup(struct cx23885_tsport *port, do_gettimeofday(&buf->vb.ts); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); - buf->vb.state = STATE_DONE; + buf->vb.state = VIDEOBUF_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } @@ -391,12 +391,10 @@ void cx23885_wakeup(struct cx23885_tsport *port, printk("%s: %d buffers handled (should be 1)\n", __FUNCTION__, bc); } -void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch); -int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) +static int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) { unsigned int i, lines; u32 cdt; @@ -467,8 +465,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, return 0; } -void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch) +static void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch) { static char *name[] = { "init risc lo", @@ -529,8 +527,8 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, dev->name, cx_read(ch->cnt2_reg)); } -void cx23885_risc_disasm(struct cx23885_tsport *port, - struct btcx_riscmem *risc) +static void cx23885_risc_disasm(struct cx23885_tsport *port, + struct btcx_riscmem *risc) { struct cx23885_dev *dev = port->dev; unsigned int i, j, n; @@ -548,7 +546,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port, } } -void cx23885_shutdown(struct cx23885_dev *dev) +static void cx23885_shutdown(struct cx23885_dev *dev) { /* disable RISC controller */ cx_write(DEV_CNTRL2, 0); @@ -578,7 +576,7 @@ void cx23885_shutdown(struct cx23885_dev *dev) } -void cx23885_reset(struct cx23885_dev *dev) +static void cx23885_reset(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); @@ -636,8 +634,8 @@ static int get_resources(struct cx23885_dev *dev) } static void cx23885_timeout(unsigned long data); -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); +static int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { @@ -837,7 +835,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) return 0; } -void cx23885_dev_unregister(struct cx23885_dev *dev) +static void cx23885_dev_unregister(struct cx23885_dev *dev) { release_mem_region(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0)); @@ -912,49 +910,12 @@ static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, return rp; } -int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int top_offset, - unsigned int bottom_offset, unsigned int bpl, - unsigned int padding, unsigned int lines) -{ - u32 instructions, fields; - u32 *rp; - int rc; - - fields = 0; - if (UNSET != top_offset) - fields++; - if (UNSET != bottom_offset) - fields++; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Padding - can cause next bpl to start close to a page border. First DMA - region may be smaller than PAGE_SIZE */ - /* write and jump need and extra dword */ - instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; - if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - if (UNSET != top_offset) - rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); - if (UNSET != bottom_offset) - rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); - return 0; -} -int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) +static int cx23885_risc_databuffer(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int bpl, + unsigned int lines) { u32 instructions; u32 *rp; @@ -981,8 +942,8 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, return 0; } -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) +static int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value) { u32 *rp; int rc; @@ -1011,7 +972,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } static int cx23885_start_dma(struct cx23885_tsport *port, @@ -1114,7 +1075,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); cx23885_start_dma(port, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(5, "[%p/%d] restart_queue - first active\n", @@ -1125,7 +1086,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ @@ -1162,7 +1123,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { buf->vb.width = port->ts_packet_size; buf->vb.height = port->ts_packet_count; buf->vb.size = size; @@ -1174,7 +1135,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, videobuf_to_dma(&buf->vb)->sglist, buf->vb.width, buf->vb.height); } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -1197,7 +1158,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->vb.queue, &cx88q->active); cx23885_start_dma(port, cx88q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); dprintk(1, "[%p/%d] %s - first active\n", @@ -1207,7 +1168,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); list_add_tail(&buf->vb.queue, &cx88q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ @@ -1231,7 +1192,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); @@ -1243,16 +1204,6 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, spin_unlock_irqrestore(&port->slock, flags); } -void cx23885_cancel_buffers(struct cx23885_tsport *port) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_dmaqueue *q = &port->mpegq; - - dprintk(1, "%s()\n", __FUNCTION__); - del_timer_sync(&q->timeout); - cx23885_stop_dma(port); - do_cancel_buffers(port, "cancel", 0); -} static void cx23885_timeout(unsigned long data) { diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 71da528..08e92df 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -84,7 +84,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, u32 wdata, addr, ctrl; int retval, cnt; - dprintk(1, "%s()\n", __FUNCTION__); + dprintk(1, "%s(msg->len=%d, last=%d)\n", __FUNCTION__, msg->len, last); + /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { cx_write(bus->reg_addr, msg->addr << 25); @@ -127,7 +128,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, wdata = msg->buf[cnt]; ctrl = bus->i2c_period | (1 << 12) | (1 << 2); - if (cnt < msg->len-1 || !last) + if (cnt < msg->len - 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; cx_write(bus->reg_addr, addr); @@ -162,7 +163,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, u32 ctrl, cnt; int retval; - dprintk(1, "%s()\n", __FUNCTION__); + dprintk(1, "%s(msg->len=%d, last=%d)\n", __FUNCTION__, msg->len, last); /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { @@ -178,11 +179,14 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, return 0; } + if (i2c_debug) + printk(" addr << 1) + 1); + for(cnt = 0; cnt < msg->len; cnt++) { ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; - if (cnt < msg->len-1 || !last) + if (cnt < msg->len - 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; cx_write(bus->reg_addr, msg->addr << 25); @@ -195,9 +199,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, goto eio; msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; if (i2c_debug) { - if (!(ctrl & I2C_NOSTOP)) - printk(" addr << 1) +1); - printk(" =%02x", msg->buf[cnt]); + printk(" %02x", msg->buf[cnt]); if (!(ctrl & I2C_NOSTOP)) printk(" >\n"); } @@ -366,8 +368,6 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus) /* ----------------------------------------------------------------------- */ -EXPORT_SYMBOL(cx23885_call_i2c_clients); - /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index dec4dc2..205640c 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -254,10 +254,6 @@ struct sram_channel { #define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) #define cx_clear(reg,bit) cx_andor((reg),(bit),0) -extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc); - /* ----------------------------------------------------------- */ /* cx23885-cards.c */ diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 15f191e..6d2ca82 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "cx25840-core.h" @@ -122,8 +123,6 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, enum cx25840_audio_input aud_input); -static void log_audio_status(struct i2c_client *client); -static void log_video_status(struct i2c_client *client); /* ----------------------------------------------------------------------- */ @@ -641,6 +640,200 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) /* ----------------------------------------------------------------------- */ +static void log_video_status(struct i2c_client *client) +{ + static const char *const fmt_strs[] = { + "0x0", + "NTSC-M", "NTSC-J", "NTSC-4.43", + "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", + "0x9", "0xA", "0xB", + "SECAM", + "0xD", "0xE", "0xF" + }; + + struct cx25840_state *state = i2c_get_clientdata(client); + u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; + u8 gen_stat1 = cx25840_read(client, 0x40d); + u8 gen_stat2 = cx25840_read(client, 0x40e); + int vid_input = state->vid_input; + + v4l_info(client, "Video signal: %spresent\n", + (gen_stat2 & 0x20) ? "" : "not "); + v4l_info(client, "Detected format: %s\n", + fmt_strs[gen_stat1 & 0xf]); + + v4l_info(client, "Specified standard: %s\n", + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + + if (vid_input >= CX25840_COMPOSITE1 && + vid_input <= CX25840_COMPOSITE8) { + v4l_info(client, "Specified video input: Composite %d\n", + vid_input - CX25840_COMPOSITE1 + 1); + } else { + v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + } + + v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); +} + +/* ----------------------------------------------------------------------- */ + +static void log_audio_status(struct i2c_client *client) +{ + struct cx25840_state *state = i2c_get_clientdata(client); + u8 download_ctl = cx25840_read(client, 0x803); + u8 mod_det_stat0 = cx25840_read(client, 0x804); + u8 mod_det_stat1 = cx25840_read(client, 0x805); + u8 audio_config = cx25840_read(client, 0x808); + u8 pref_mode = cx25840_read(client, 0x809); + u8 afc0 = cx25840_read(client, 0x80b); + u8 mute_ctl = cx25840_read(client, 0x8d3); + int aud_input = state->aud_input; + char *p; + + switch (mod_det_stat0) { + case 0x00: p = "mono"; break; + case 0x01: p = "stereo"; break; + case 0x02: p = "dual"; break; + case 0x04: p = "tri"; break; + case 0x10: p = "mono with SAP"; break; + case 0x11: p = "stereo with SAP"; break; + case 0x12: p = "dual with SAP"; break; + case 0x14: p = "tri with SAP"; break; + case 0xfe: p = "forced mode"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio mode: %s\n", p); + + switch (mod_det_stat1) { + case 0x00: p = "not defined"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; + case 0x0e: p = "IF FM Radio"; break; + case 0x0f: p = "BTSC"; break; + case 0x10: p = "high-deviation FM"; break; + case 0x11: p = "very high-deviation FM"; break; + case 0xfd: p = "unknown audio standard"; break; + case 0xfe: p = "forced audio standard"; break; + case 0xff: p = "no detected audio standard"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio standard: %s\n", p); + v4l_info(client, "Audio muted: %s\n", + (state->unmute_volume >= 0) ? "yes" : "no"); + v4l_info(client, "Audio microcontroller: %s\n", + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); + + switch (audio_config >> 4) { + case 0x00: p = "undefined"; break; + case 0x01: p = "BTSC"; break; + case 0x02: p = "EIAJ"; break; + case 0x03: p = "A2-M"; break; + case 0x04: p = "A2-BG"; break; + case 0x05: p = "A2-DK1"; break; + case 0x06: p = "A2-DK2"; break; + case 0x07: p = "A2-DK3"; break; + case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x09: p = "AM-L"; break; + case 0x0a: p = "NICAM-BG"; break; + case 0x0b: p = "NICAM-DK"; break; + case 0x0c: p = "NICAM-I"; break; + case 0x0d: p = "NICAM-L"; break; + case 0x0e: p = "FM radio"; break; + case 0x0f: p = "automatic detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio standard: %s\n", p); + + if ((audio_config >> 4) < 0xF) { + switch (audio_config & 0xF) { + case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; + case 0x01: p = "MONO2 (LANGUAGE B)"; break; + case 0x02: p = "MONO3 (STEREO forced MONO)"; break; + case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; + case 0x04: p = "STEREO"; break; + case 0x05: p = "DUAL1 (AB)"; break; + case 0x06: p = "DUAL2 (AC) (FM)"; break; + case 0x07: p = "DUAL3 (BC) (FM)"; break; + case 0x08: p = "DUAL4 (AC) (AM)"; break; + case 0x09: p = "DUAL5 (BC) (AM)"; break; + case 0x0a: p = "SAP"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio mode: %s\n", p); + } else { + switch (audio_config & 0xF) { + case 0x00: p = "BG"; break; + case 0x01: p = "DK1"; break; + case 0x02: p = "DK2"; break; + case 0x03: p = "DK3"; break; + case 0x04: p = "I"; break; + case 0x05: p = "L"; break; + case 0x06: p = "BTSC"; break; + case 0x07: p = "EIAJ"; break; + case 0x08: p = "A2-M"; break; + case 0x09: p = "FM Radio"; break; + case 0x0f: p = "automatic standard and mode detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio system: %s\n", p); + } + + if (aud_input) { + v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); + } else { + v4l_info(client, "Specified audio input: External\n"); + } + + switch (pref_mode & 0xf) { + case 0: p = "mono/language A"; break; + case 1: p = "language B"; break; + case 2: p = "language C"; break; + case 3: p = "analog fallback"; break; + case 4: p = "stereo"; break; + case 5: p = "language AC"; break; + case 6: p = "language BC"; break; + case 7: p = "language AB"; break; + default: p = "undefined"; + } + v4l_info(client, "Preferred audio mode: %s\n", p); + + if ((audio_config & 0xf) == 0xf) { + switch ((afc0 >> 3) & 0x3) { + case 0: p = "system DK"; break; + case 1: p = "system L"; break; + case 2: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 65 MHz format: %s\n", p); + + switch (afc0 & 0x7) { + case 0: p = "chroma"; break; + case 1: p = "BTSC"; break; + case 2: p = "EIAJ"; break; + case 3: p = "A2-M"; break; + case 4: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 45 MHz format: %s\n", p); + } +} + +/* ----------------------------------------------------------------------- */ + static int cx25840_command(struct i2c_client *client, unsigned int cmd, void *arg) { @@ -879,30 +1072,15 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_cx25840; - -static int cx25840_detect_client(struct i2c_adapter *adapter, int address, - int kind) +static int cx25840_probe(struct i2c_client *client) { - struct i2c_client *client; struct cx25840_state *state; u32 id; u16 device_id; - /* Check if the adapter supports the needed features - * Not until kernel version 2.6.11 did the bit-algo - * correctly report that it would do an I2C-level xfer */ - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_cx25840; - snprintf(client->name, sizeof(client->name) - 1, "cx25840"); + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); @@ -919,13 +1097,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); - kfree(client); - return 0; + return -ENODEV; } state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } @@ -948,251 +1124,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->vbi_line_offset = 8; state->id = id; state->rev = device_id; - - i2c_attach_client(client); - return 0; } -static int cx25840_attach_adapter(struct i2c_adapter *adapter) +static int cx25840_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, &cx25840_detect_client); + kfree(i2c_get_clientdata(client)); return 0; } -static int cx25840_detach_client(struct i2c_client *client) -{ - struct cx25840_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - - kfree(state); - kfree(client); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct i2c_driver i2c_driver_cx25840 = { - .driver = { - .name = "cx25840", - }, - .id = I2C_DRIVERID_CX25840, - .attach_adapter = cx25840_attach_adapter, - .detach_client = cx25840_detach_client, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "cx25840", + .driverid = I2C_DRIVERID_CX25840, .command = cx25840_command, + .probe = cx25840_probe, + .remove = cx25840_remove, }; - - -static int __init m__init(void) -{ - return i2c_add_driver(&i2c_driver_cx25840); -} - -static void __exit m__exit(void) -{ - i2c_del_driver(&i2c_driver_cx25840); -} - -module_init(m__init); -module_exit(m__exit); - -/* ----------------------------------------------------------------------- */ - -static void log_video_status(struct i2c_client *client) -{ - static const char *const fmt_strs[] = { - "0x0", - "NTSC-M", "NTSC-J", "NTSC-4.43", - "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", - "0x9", "0xA", "0xB", - "SECAM", - "0xD", "0xE", "0xF" - }; - - struct cx25840_state *state = i2c_get_clientdata(client); - u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; - u8 gen_stat1 = cx25840_read(client, 0x40d); - u8 gen_stat2 = cx25840_read(client, 0x40e); - int vid_input = state->vid_input; - - v4l_info(client, "Video signal: %spresent\n", - (gen_stat2 & 0x20) ? "" : "not "); - v4l_info(client, "Detected format: %s\n", - fmt_strs[gen_stat1 & 0xf]); - - v4l_info(client, "Specified standard: %s\n", - vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); - - if (vid_input >= CX25840_COMPOSITE1 && - vid_input <= CX25840_COMPOSITE8) { - v4l_info(client, "Specified video input: Composite %d\n", - vid_input - CX25840_COMPOSITE1 + 1); - } else { - v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", - (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); - } - - v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); -} - -/* ----------------------------------------------------------------------- */ - -static void log_audio_status(struct i2c_client *client) -{ - struct cx25840_state *state = i2c_get_clientdata(client); - u8 download_ctl = cx25840_read(client, 0x803); - u8 mod_det_stat0 = cx25840_read(client, 0x804); - u8 mod_det_stat1 = cx25840_read(client, 0x805); - u8 audio_config = cx25840_read(client, 0x808); - u8 pref_mode = cx25840_read(client, 0x809); - u8 afc0 = cx25840_read(client, 0x80b); - u8 mute_ctl = cx25840_read(client, 0x8d3); - int aud_input = state->aud_input; - char *p; - - switch (mod_det_stat0) { - case 0x00: p = "mono"; break; - case 0x01: p = "stereo"; break; - case 0x02: p = "dual"; break; - case 0x04: p = "tri"; break; - case 0x10: p = "mono with SAP"; break; - case 0x11: p = "stereo with SAP"; break; - case 0x12: p = "dual with SAP"; break; - case 0x14: p = "tri with SAP"; break; - case 0xfe: p = "forced mode"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio mode: %s\n", p); - - switch (mod_det_stat1) { - case 0x00: p = "not defined"; break; - case 0x01: p = "EIAJ"; break; - case 0x02: p = "A2-M"; break; - case 0x03: p = "A2-BG"; break; - case 0x04: p = "A2-DK1"; break; - case 0x05: p = "A2-DK2"; break; - case 0x06: p = "A2-DK3"; break; - case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x08: p = "AM-L"; break; - case 0x09: p = "NICAM-BG"; break; - case 0x0a: p = "NICAM-DK"; break; - case 0x0b: p = "NICAM-I"; break; - case 0x0c: p = "NICAM-L"; break; - case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; - case 0x0e: p = "IF FM Radio"; break; - case 0x0f: p = "BTSC"; break; - case 0x10: p = "high-deviation FM"; break; - case 0x11: p = "very high-deviation FM"; break; - case 0xfd: p = "unknown audio standard"; break; - case 0xfe: p = "forced audio standard"; break; - case 0xff: p = "no detected audio standard"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio standard: %s\n", p); - v4l_info(client, "Audio muted: %s\n", - (state->unmute_volume >= 0) ? "yes" : "no"); - v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? - ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); - - switch (audio_config >> 4) { - case 0x00: p = "undefined"; break; - case 0x01: p = "BTSC"; break; - case 0x02: p = "EIAJ"; break; - case 0x03: p = "A2-M"; break; - case 0x04: p = "A2-BG"; break; - case 0x05: p = "A2-DK1"; break; - case 0x06: p = "A2-DK2"; break; - case 0x07: p = "A2-DK3"; break; - case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x09: p = "AM-L"; break; - case 0x0a: p = "NICAM-BG"; break; - case 0x0b: p = "NICAM-DK"; break; - case 0x0c: p = "NICAM-I"; break; - case 0x0d: p = "NICAM-L"; break; - case 0x0e: p = "FM radio"; break; - case 0x0f: p = "automatic detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio standard: %s\n", p); - - if ((audio_config >> 4) < 0xF) { - switch (audio_config & 0xF) { - case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; - case 0x01: p = "MONO2 (LANGUAGE B)"; break; - case 0x02: p = "MONO3 (STEREO forced MONO)"; break; - case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; - case 0x04: p = "STEREO"; break; - case 0x05: p = "DUAL1 (AB)"; break; - case 0x06: p = "DUAL2 (AC) (FM)"; break; - case 0x07: p = "DUAL3 (BC) (FM)"; break; - case 0x08: p = "DUAL4 (AC) (AM)"; break; - case 0x09: p = "DUAL5 (BC) (AM)"; break; - case 0x0a: p = "SAP"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio mode: %s\n", p); - } else { - switch (audio_config & 0xF) { - case 0x00: p = "BG"; break; - case 0x01: p = "DK1"; break; - case 0x02: p = "DK2"; break; - case 0x03: p = "DK3"; break; - case 0x04: p = "I"; break; - case 0x05: p = "L"; break; - case 0x06: p = "BTSC"; break; - case 0x07: p = "EIAJ"; break; - case 0x08: p = "A2-M"; break; - case 0x09: p = "FM Radio"; break; - case 0x0f: p = "automatic standard and mode detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio system: %s\n", p); - } - - if (aud_input) { - v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); - } else { - v4l_info(client, "Specified audio input: External\n"); - } - - switch (pref_mode & 0xf) { - case 0: p = "mono/language A"; break; - case 1: p = "language B"; break; - case 2: p = "language C"; break; - case 3: p = "analog fallback"; break; - case 4: p = "stereo"; break; - case 5: p = "language AC"; break; - case 6: p = "language BC"; break; - case 7: p = "language AB"; break; - default: p = "undefined"; - } - v4l_info(client, "Preferred audio mode: %s\n", p); - - if ((audio_config & 0xf) == 0xf) { - switch ((afc0 >> 3) & 0x3) { - case 0: p = "system DK"; break; - case 1: p = "system L"; break; - case 2: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 65 MHz format: %s\n", p); - - switch (afc0 & 0x7) { - case 0: p = "chroma"; break; - case 1: p = "BTSC"; break; - case 2: p = "EIAJ"; break; - case 3: p = "A2-M"; break; - case 4: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 45 MHz format: %s\n", p); - } -} diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index ced13fe..6828f59 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -180,7 +180,7 @@ void cx25840_vbi_setup(struct i2c_client *client) fsc/1000000,fsc%1000000); v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " - "vblank %i , vactive %i, vblank656 %i, src_dec %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, diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 40ffd7a..8735227 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -417,7 +417,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; chip->buf = buf; chip->dma_risc = dma; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index f33f0b4..f802b56 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1085,10 +1085,7 @@ static int mpeg_release(struct inode *inode, struct file *file) cx8802_cancel_buffers(fh->dev); /* stop mpeg capture */ - if (fh->mpegq.streaming) - videobuf_streamoff(&fh->mpegq); - if (fh->mpegq.reading) - videobuf_read_stop(&fh->mpegq); + videobuf_stop(&fh->mpegq); videobuf_mmap_free(&fh->mpegq); file->private_data = NULL; diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index a4eb6a8..f8a786a 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -26,6 +26,7 @@ #include #include "cx88.h" +#include "tea5767.h" static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; @@ -245,6 +246,10 @@ static const struct cx88_board cx88_boards[] = { }}, .radio = { .type = CX88_RADIO, + .vmux = 3, + .gpio0 = 0x000040bf, + .gpio1 = 0x000080c0, + .gpio2 = 0x0000ff20, }, }, [CX88_BOARD_WINFAST_DV2000] = { @@ -1979,6 +1984,23 @@ static void cx88_card_setup(struct cx88_core *core) core->name, i); } break; + case CX88_BOARD_MSI_TVANYWHERE_MASTER: + { + struct v4l2_priv_tun_config tea5767_cfg; + struct tea5767_ctrl ctl; + + memset(&ctl, 0, sizeof(ctl)); + + ctl.high_cut = 1; + ctl.st_noise = 1; + ctl.deemph_75 = 1; + ctl.xtal_freq = TEA5767_HIGH_LO_13MHz; + + tea5767_cfg.tuner = TUNER_TEA5767; + tea5767_cfg.priv = &ctl; + + cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg); + } } } diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 62e8dd2..01e2ac9 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -220,7 +220,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } /* ------------------------------------------------------------------ */ @@ -538,7 +538,7 @@ void cx88_wakeup(struct cx88_core *core, do_gettimeofday(&buf->vb.ts); dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, count, buf->count); - buf->vb.state = STATE_DONE; + buf->vb.state = VIDEOBUF_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index c8b1c50..937497c 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -127,8 +127,14 @@ static int attach_inform(struct i2c_client *client) } } - if (core->board.tda9887_conf) - client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf); + if (core->board.tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &core->board.tda9887_conf; + + client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg); + } return 0; } diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 448c673..339a88a 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -195,7 +195,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&q->active); cx8802_start_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(1,"[%p/%d] restart_queue - first active\n", @@ -206,7 +206,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(1,"[%p/%d] restart_queue - move to active\n", @@ -242,7 +242,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { buf->vb.width = dev->ts_packet_size; buf->vb.height = dev->ts_packet_count; buf->vb.size = size; @@ -254,7 +254,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, dma->sglist, buf->vb.width, buf->vb.height, 0); } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -276,7 +276,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->vb.queue,&cx88q->active); cx8802_start_dma(dev, cx88q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(1,"[%p/%d] %s - first active\n", @@ -286,7 +286,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is not empty - append to active\n" ); prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue); list_add_tail(&buf->vb.queue,&cx88q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk( 1, "[%p/%d] %s - append to active\n", @@ -306,7 +306,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); @@ -437,10 +437,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) return IRQ_RETVAL(handled); } -/* ----------------------------------------------------------- */ -/* exported stuff */ - -int cx8802_init_common(struct cx8802_dev *dev) +static int cx8802_init_common(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; int err; @@ -488,7 +485,7 @@ int cx8802_init_common(struct cx8802_dev *dev) return 0; } -void cx8802_fini_common(struct cx8802_dev *dev) +static void cx8802_fini_common(struct cx8802_dev *dev) { dprintk( 2, "cx8802_fini_common\n" ); cx8802_stop_dma(dev); @@ -504,7 +501,7 @@ void cx8802_fini_common(struct cx8802_dev *dev) /* ----------------------------------------------------------- */ -int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) +static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -530,7 +527,7 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) return 0; } -int cx8802_resume_common(struct pci_dev *pci_dev) +static int cx8802_resume_common(struct pci_dev *pci_dev) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -874,9 +871,6 @@ EXPORT_SYMBOL(cx8802_buf_prepare); EXPORT_SYMBOL(cx8802_buf_queue); EXPORT_SYMBOL(cx8802_cancel_buffers); -EXPORT_SYMBOL(cx8802_init_common); -EXPORT_SYMBOL(cx8802_fini_common); - EXPORT_SYMBOL(cx8802_register_driver); EXPORT_SYMBOL(cx8802_unregister_driver); EXPORT_SYMBOL(cx8802_get_driver); diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index babb085..d96ecfc 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -130,7 +130,7 @@ void cx8800_vbi_timeout(unsigned long data) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); @@ -168,7 +168,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = VBI_LINE_LENGTH; buf->vb.height = VBI_LINE_COUNT; @@ -183,7 +183,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, buf->vb.width, 0, buf->vb.height); } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -207,7 +207,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue,&q->active); cx8800_start_vbi_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] vbi_queue - first active\n", @@ -216,7 +216,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } else { prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 5ee05f8..6d5ea8c 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -486,7 +486,7 @@ static int restart_video_queue(struct cx8800_dev *dev, if (NULL == prev) { list_move_tail(&buf->vb.queue, &q->active); start_video_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] restart_queue - first active\n", @@ -496,7 +496,7 @@ static int restart_video_queue(struct cx8800_dev *dev, prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] restart_queue - move to active\n", @@ -553,7 +553,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, init_buffer = 1; } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { init_buffer = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; @@ -601,7 +601,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, fh->width, fh->height, fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -625,14 +625,14 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (!list_empty(&q->queued)) { list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue,&q->active); start_video_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] buffer_queue - first active\n", @@ -644,7 +644,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", @@ -652,7 +652,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } else { list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } @@ -822,8 +822,8 @@ video_poll(struct file *file, struct poll_table_struct *wait) return POLLERR; } poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == STATE_DONE || - buf->vb.state == STATE_ERROR) + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -851,10 +851,7 @@ static int video_release(struct inode *inode, struct file *file) /* stop vbi capture */ if (res_check(fh, RESOURCE_VBI)) { - if (fh->vbiq.streaming) - videobuf_streamoff(&fh->vbiq); - if (fh->vbiq.reading) - videobuf_read_stop(&fh->vbiq); + videobuf_stop(&fh->vbiq); res_free(dev,fh,RESOURCE_VBI); } @@ -1499,7 +1496,7 @@ static void cx8800_vid_timeout(unsigned long data) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index eb296bd..bb1036a 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -633,12 +633,6 @@ int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev, void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf); void cx8802_cancel_buffers(struct cx8802_dev *dev); -int cx8802_init_common(struct cx8802_dev *dev); -void cx8802_fini_common(struct cx8802_dev *dev); - -int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state); -int cx8802_resume_common(struct pci_dev *pci_dev); - /* ----------------------------------------------------------- */ /* cx88-video.c*/ extern const u32 cx88_user_ctrls[]; diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index c112780..813077b 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_EM28XX tristate "Empia EM2800/2820/2840 USB video capture support" - depends on VIDEO_V4L1 && I2C && INPUT + depends on VIDEO_DEV && I2C && INPUT select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index 826d0e3..7e7a93d 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -4,3 +4,6 @@ em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 418ea8b..fd64058 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -35,13 +35,23 @@ #include #include "em28xx.h" +#include "tuner-xc2028.h" + +static int tuner = -1; +module_param(tuner, int, 0444); +MODULE_PARM_DESC(tuner, "tuner type"); + +struct em28xx_hash_table { + unsigned long hash; + unsigned int model; + unsigned int tuner; +}; struct em28xx_board em28xx_boards[] = { [EM2800_BOARD_UNKNOWN] = { .name = "Unknown EM2800 video grabber", .is_em2800 = 1, .vchannels = 2, - .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, @@ -56,28 +66,13 @@ struct em28xx_board em28xx_boards[] = { }}, }, [EM2820_BOARD_UNKNOWN] = { - .name = "Unknown EM2820/2840 video grabber", + .name = "Unknown EM2750/28xx video grabber", .is_em2800 = 0, - .vchannels = 2, - .norm = VIDEO_MODE_PAL, - .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, - .decoder = EM28XX_SAA7113, - .input = {{ - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - },{ - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - }}, }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { .name = "Kworld PVR TV 2800 RF", .is_em2800 = 0, .vchannels = 2, - .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, @@ -94,7 +89,6 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_TERRATEC_CINERGY_250] = { .name = "Terratec Cinergy 250 USB", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -116,7 +110,6 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_PINNACLE_USB_2] = { .name = "Pinnacle PCTV USB 2", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -138,7 +131,6 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = { .name = "Hauppauge WinTV USB 2", .vchannels = 3, - .norm = VIDEO_MODE_NTSC, .tuner_type = TUNER_PHILIPS_FM1236_MK3, .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, .has_tuner = 1, @@ -156,10 +148,74 @@ struct em28xx_board em28xx_boards[] = { MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), }}, }, + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { + .name = "Hauppauge WinTV HVR 900/950", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .has_tuner = 1, + .decoder = EM28XX_TVP5150, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + }}, + }, + [EM2880_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Hybrid XS", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + }}, + }, + /* maybe there's a reason behind it why Terratec sells the Hybrid XS as Prodigy XS with a + * different PID, let's keep it separated for now maybe we'll need it lateron */ + [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { + .name = "Terratec Prodigy XS", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + }}, + }, [EM2820_BOARD_MSI_VOX_USB_2] = { .name = "MSI VOX USB 2.0", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, .has_tuner = 1, @@ -182,7 +238,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Cinergy 200 USB", .is_em2800 = 1, .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -205,7 +260,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Leadtek Winfast USB II", .is_em2800 = 1, .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -228,7 +282,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Kworld USB2800", .is_em2800 = 1, .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_PHILIPS_ATSC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -250,7 +303,6 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_PINNACLE_DVC_90] = { .name = "Pinnacle Dazzle DVC 90", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .has_tuner = 0, .decoder = EM28XX_SAA7113, .input = {{ @@ -263,66 +315,313 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, }}, }, + [EM2800_BOARD_VGEAR_POCKETTV] = { + .name = "V-Gear PocketTV", + .is_em2800 = 1, + .vchannels = 3, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .decoder = EM28XX_SAA7113, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + }}, + }, + [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { + .name = "Pixelview Prolink PlayTV USB 2.0", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .decoder = EM28XX_SAA7113, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + }}, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); /* table of devices that work with this driver */ struct usb_device_id em28xx_id_table [] = { + { USB_DEVICE(0xeb1a, 0x2750), .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 }, + { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2821), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2860), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2861), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2870), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2881), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2883), .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + { USB_DEVICE(0x2040, 0x6513), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { }, }; +MODULE_DEVICE_TABLE (usb, em28xx_id_table); + +/* EEPROM hash table for devices with generic USB IDs */ +static struct em28xx_hash_table em28xx_eeprom_hash [] = { + /* P/N: SA 60002070465 Tuner: TVF7533-MF */ + { 0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF }, +}; + +/* I2C devicelist hash table for devices with generic USB IDs */ +static struct em28xx_hash_table em28xx_i2c_hash[] = { + { 0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC }, + { 0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC }, +}; +/* Since em28xx_pre_card_setup() requires a proper dev->model, + * this won't work for boards with generic PCI IDs + */ void em28xx_pre_card_setup(struct em28xx *dev) { /* request some modules */ switch(dev->model){ - case EM2880_BOARD_TERRATEC_PRODIGY_XS: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_TERRATEC_HYBRID_XS: - { - em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO? - break; - } + case EM2880_BOARD_TERRATEC_PRODIGY_XS: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_TERRATEC_HYBRID_XS: + /* reset through GPIO? */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); + break; } } +static int em28xx_tuner_callback(void *ptr, int command, int arg) +{ + int rc = 0; + struct em28xx *dev = ptr; + + if (dev->tuner_type != TUNER_XC2028) + return 0; + + switch (command) { + case XC2028_TUNER_RESET: + /* FIXME: This is device-dependent */ + dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); + dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); + + msleep(140); + break; + } + return rc; +} + +static void em28xx_config_tuner (struct em28xx *dev) +{ + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + struct tuner_setup tun_setup; + struct v4l2_frequency f; + + if (!dev->has_tuner) + return; + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + tun_setup.tuner_callback = em28xx_tuner_callback; + + em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + + if (dev->tuner_type == TUNER_XC2028) { + memset (&ctl, 0, sizeof(ctl)); + + ctl.fname = XC2028_DEFAULT_FIRMWARE; + ctl.max_len = 64; + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + + em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + } + + /* configure tuner */ + f.tuner = 0; + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = 9076; /* just a magic number */ + dev->ctl_freq = f.frequency; + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); +} + +static int em28xx_hint_board(struct em28xx *dev) +{ + int i; + + /* HINT method: EEPROM + * + * This method works only for boards with eeprom. + * Uses a hash of all eeprom bytes. The hash should be + * unique for a vendor/tuner pair. + * There are a high chance that tuners for different + * video standards produce different hashes. + */ + for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) { + if (dev->hash == em28xx_eeprom_hash[i].hash) { + dev->model = em28xx_eeprom_hash[i].model; + dev->tuner_type = em28xx_eeprom_hash[i].tuner; + + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on eeprom hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " \n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); + + return 0; + } + } + + /* HINT method: I2C attached devices + * + * This method works for all boards. + * Uses a hash of i2c scanned devices. + * Devices with the same i2c attached chips will + * be considered equal. + * This method is less precise than the eeprom one. + */ + + /* user did not request i2c scanning => do it now */ + if (!dev->i2c_hash) + em28xx_do_i2c_scan(dev); + + for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) { + if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { + dev->model = em28xx_i2c_hash[i].model; + dev->tuner_type = em28xx_i2c_hash[i].tuner; + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on i2c devicelist hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " \n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); + + return 0; + } + } + + em28xx_errdev("Your board has no unique USB ID and thus need a " + "hint to be detected.\n"); + em28xx_errdev("You may try to use card= insmod option to " + "workaround that.\n"); + em28xx_errdev("Please send an email with this log to:\n"); + em28xx_errdev("\tV4L Mailing List \n"); + em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); + em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); + + em28xx_errdev("Here is a list of valid choices for the card=" + " insmod option:\n"); + for (i = 0; i < em28xx_bcount; i++) { + em28xx_errdev(" card=%d -> %s\n", + i, em28xx_boards[i].name); + } + return -1; +} + + +static void em28xx_set_model(struct em28xx *dev) +{ + dev->is_em2800 = em28xx_boards[dev->model].is_em2800; + dev->has_tuner = em28xx_boards[dev->model].has_tuner; + dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; + dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; + dev->decoder = em28xx_boards[dev->model].decoder; + dev->video_inputs = em28xx_boards[dev->model].vchannels; + + if (!em28xx_boards[dev->model].has_tuner) + dev->tuner_type = UNSET; +} + void em28xx_card_setup(struct em28xx *dev) { + em28xx_set_model(dev); + + dev->tuner_type = em28xx_boards[dev->model].tuner_type; + /* request some modules */ - switch(dev->model){ - case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - { - struct tveeprom tv; + switch (dev->model) { + case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + { + struct tveeprom tv; +#ifdef CONFIG_MODULES + request_module("tveeprom"); +#endif + /* Call first TVeeprom */ + + dev->i2c_client.addr = 0xa0 >> 1; + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); + + dev->tuner_type = tv.tuner_type; + if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { + dev->i2s_speed = 2048000; + dev->has_msp34xx = 1; + } #ifdef CONFIG_MODULES - request_module("tveeprom"); - request_module("ir-kbd-i2c"); - request_module("msp3400"); + if (tv.has_ir) + request_module("ir-kbd-i2c"); #endif - /* Call first TVeeprom */ - - dev->i2c_client.addr = 0xa0 >> 1; - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); - - dev->tuner_type= tv.tuner_type; - if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { - dev->i2s_speed=2048000; - dev->has_msp34xx=1; - } else - dev->has_msp34xx=0; - break; - } - case EM2820_BOARD_KWORLD_PVRTV2800RF: - { - em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF - break; - } + /* FIXME: Should also retrieve decoder processor type */ + break; + } + case EM2820_BOARD_KWORLD_PVRTV2800RF: + /* GPIO enables sound on KWORLD PVR TV 2800RF */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1); + break; + case EM2820_BOARD_UNKNOWN: + case EM2800_BOARD_UNKNOWN: + if (!em28xx_hint_board(dev)) + em28xx_set_model(dev); } -} -MODULE_DEVICE_TABLE (usb, em28xx_id_table); + /* Allow override tuner type by a module parameter */ + if (tuner >= 0) + dev->tuner_type = tuner; + +#ifdef CONFIG_MODULES + /* request some modules */ + if (dev->has_msp34xx) + request_module("msp3400"); + if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) + request_module("saa7115"); + if (dev->decoder == EM28XX_TVP5150) + request_module("tvp5150"); + if (dev->has_tuner) + request_module("tuner"); +#endif + + em28xx_config_tuner (dev); +} diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index e3a4aa7..cacd04d 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -25,9 +25,9 @@ #include #include #include -#include #include "em28xx.h" +#include "tuner-xc2028.h" #include #include @@ -291,6 +291,31 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, return rc; } +/* based on linux/sunrpc/svcauth.h and linux/hash.h + * The original hash function returns a different value, if arch is x86_64 + * or i386. + */ +static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) +{ + unsigned long hash = 0; + unsigned long l = 0; + int len = 0; + unsigned char c; + do { + if (len == length) { + c = (char)len; + len = -1; + } else + c = *buf++; + l = (l << 8) | c; + len++; + if ((len & (32 / 8 - 1)) == 0) + hash = ((hash^l) * 0x9e370001UL); + } while (len); + + return (hash >> (32 - bits)) & 0xffffffffUL; +} + static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) { unsigned char buf, *p = eedata; @@ -334,7 +359,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) printk("\n"); } - printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id); + if (em_eeprom->id == 0x9567eb1a) + dev->hash = em28xx_hash_mem(eedata, len, 32); + + printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n", + em_eeprom->id, dev->hash); printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID, em_eeprom->product_ID); @@ -391,21 +420,6 @@ static u32 functionality(struct i2c_adapter *adap) } -static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client) -{ - struct em28xx *dev = client->adapter->algo_data; - struct tuner_setup tun_setup; - - if (dev->has_tuner) { - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - } - - return (0); -} - /* * attach_inform() * gets called when a device attaches to the i2c bus @@ -421,6 +435,8 @@ static int attach_inform(struct i2c_client *client) case 0x96: case 0x94: { + struct v4l2_priv_tun_config tda9887_cfg; + struct tuner_setup tun_setup; tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; @@ -428,7 +444,11 @@ static int attach_inform(struct i2c_client *client) tun_setup.addr = client->addr; em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf); + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); break; } case 0x42: @@ -458,9 +478,11 @@ static int attach_inform(struct i2c_client *client) break; default: + if (!dev->tuner_addr) + dev->tuner_addr = client->addr; + dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1); - dev->tuner_addr = client->addr; - em28xx_set_tuner(-1, client); + } return 0; @@ -510,19 +532,26 @@ static char *i2c_devs[128] = { * do_i2c_scan() * check i2c address range for devices */ -static void do_i2c_scan(char *name, struct i2c_client *c) +void em28xx_do_i2c_scan(struct em28xx *dev) { + u8 i2c_devicelist[128]; unsigned char buf; int i, rc; + memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - c->addr = i; - rc = i2c_master_recv(c, &buf, 0); + dev->i2c_client.addr = i; + rc = i2c_master_recv(&dev->i2c_client, &buf, 0); if (rc < 0) continue; - printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name, - i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + i2c_devicelist[i] = i; + printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", + dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } + + dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, + ARRAY_SIZE(i2c_devicelist), 32); } /* @@ -555,7 +584,7 @@ int em28xx_i2c_register(struct em28xx *dev) em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); if (i2c_scan) - do_i2c_scan(dev->name, &dev->i2c_client); + em28xx_do_i2c_scan(dev); return 0; } diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 2529c29..c2901f1 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -33,11 +33,9 @@ #include #include #include -#include #include #include "em28xx.h" -#include #include #include @@ -48,7 +46,7 @@ #define DRIVER_NAME "em28xx" #define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 0, 1) +#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 0) #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ @@ -71,10 +69,6 @@ MODULE_PARM_DESC(card,"card type"); MODULE_PARM_DESC(video_nr,"video device numbers"); MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); -static int tuner = -1; -module_param(tuner, int, 0444); -MODULE_PARM_DESC(tuner, "tuner type"); - static unsigned int video_debug = 0; module_param(video_debug,int,0644); MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); @@ -82,29 +76,6 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ static unsigned long em28xx_devused; -/* supported tv norms */ -static struct em28xx_tvnorm tvnorms[] = { - { - .name = "PAL", - .id = V4L2_STD_PAL, - .mode = VIDEO_MODE_PAL, - }, { - .name = "NTSC", - .id = V4L2_STD_NTSC, - .mode = VIDEO_MODE_NTSC, - }, { - .name = "SECAM", - .id = V4L2_STD_SECAM, - .mode = VIDEO_MODE_SECAM, - }, { - .name = "PAL-M", - .id = V4L2_STD_PAL_M, - .mode = VIDEO_MODE_PAL, - } -}; - -#define TVNORMS ARRAY_SIZE(tvnorms) - /* supported controls */ /* Common to all boards */ static struct v4l2_queryctrl em28xx_qctrl[] = { @@ -131,8 +102,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { static struct usb_driver em28xx_usb_driver; -static DEFINE_MUTEX(em28xx_sysfs_lock); -static DECLARE_RWSEM(em28xx_disconnect); /********************* v4l2 interface ******************************************/ @@ -144,7 +113,8 @@ static int em28xx_config(struct em28xx *dev) { /* Sets I2C speed to 100 KHz */ - em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1); + if (!dev->is_em2800) + em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1); /* enable vbi capturing */ @@ -170,7 +140,6 @@ static int em28xx_config(struct em28xx *dev) */ static void em28xx_config_i2c(struct em28xx *dev) { - struct v4l2_frequency f; struct v4l2_routing route; route.input = INPUT(dev->ctl_input)->vmux; @@ -178,18 +147,6 @@ static void em28xx_config_i2c(struct em28xx *dev) em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); - - /* configure tuner */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 9076; /* FIXME:remove magic number */ - dev->ctl_freq = f.frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); - - /* configure tda9887 */ - - -/* em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */ } /* @@ -221,8 +178,6 @@ static void video_mux(struct em28xx *dev, int index) em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); - em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput); - if (dev->has_msp34xx) { if (dev->i2s_speed) em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed); @@ -244,314 +199,42 @@ static void video_mux(struct em28xx *dev, int index) } } -/* - * em28xx_v4l2_open() - * inits the device and starts isoc transfer - */ -static int em28xx_v4l2_open(struct inode *inode, struct file *filp) +/* Usage lock check functions */ +static int res_get(struct em28xx_fh *fh) { - int minor = iminor(inode); - int errCode = 0; - struct em28xx *h,*dev = NULL; - - list_for_each_entry(h, &em28xx_devlist, devlist) { - if (h->vdev->minor == minor) { - dev = h; - dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - if (h->vbi_dev->minor == minor) { - dev = h; - dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - } - if (NULL == dev) - return -ENODEV; - - em28xx_videodbg("open minor=%d type=%s users=%d\n", - minor,v4l2_type_names[dev->type],dev->users); + struct em28xx *dev = fh->dev; + int rc = 0; - if (!down_read_trylock(&em28xx_disconnect)) - return -ERESTARTSYS; - - if (dev->users) { - em28xx_warn("this driver can be opened only once\n"); - up_read(&em28xx_disconnect); - return -EBUSY; - } - - mutex_init(&dev->fileop_lock); /* to 1 == available */ - spin_lock_init(&dev->queue_lock); - init_waitqueue_head(&dev->wait_frame); - init_waitqueue_head(&dev->wait_stream); + /* This instance already has stream_on */ + if (fh->stream_on) + return rc; mutex_lock(&dev->lock); - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - em28xx_set_alternate(dev); - - dev->width = norm_maxw(dev); - dev->height = norm_maxh(dev); - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ - dev->bytesperline = dev->width * 2; - dev->hscale = 0; - dev->vscale = 0; - - em28xx_capture_start(dev, 1); - em28xx_resolution_set(dev); - - /* device needs to be initialized before isoc transfer */ - video_mux(dev, 0); - - /* start the transfer */ - errCode = em28xx_init_isoc(dev); - if (errCode) - goto err; - + if (dev->stream_on) + rc = -EINVAL; + else { + dev->stream_on = 1; + fh->stream_on = 1; } - dev->users++; - filp->private_data = dev; - dev->io = IO_NONE; - dev->stream = STREAM_OFF; - dev->num_frames = 0; - - /* prepare queues */ - em28xx_empty_framequeues(dev); - - dev->state |= DEV_INITIALIZED; - -err: mutex_unlock(&dev->lock); - up_read(&em28xx_disconnect); - return errCode; + return rc; } -/* - * em28xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -static void em28xx_release_resources(struct em28xx *dev) +static int res_check(struct em28xx_fh *fh) { - mutex_lock(&em28xx_sysfs_lock); - - /*FIXME: I2C IR should be disconnected */ - - em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, - dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); - list_del(&dev->devlist); - video_unregister_device(dev->vdev); - video_unregister_device(dev->vbi_dev); - em28xx_i2c_unregister(dev); - usb_put_dev(dev->udev); - mutex_unlock(&em28xx_sysfs_lock); - - - /* Mark device as unused */ - em28xx_devused&=~(1<devno); + return (fh->stream_on); } -/* - * em28xx_v4l2_close() - * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls - */ -static int em28xx_v4l2_close(struct inode *inode, struct file *filp) +static void res_free(struct em28xx_fh *fh) { - int errCode; - struct em28xx *dev=filp->private_data; - - em28xx_videodbg("users=%d\n", dev->users); + struct em28xx *dev = fh->dev; mutex_lock(&dev->lock); - - em28xx_uninit_isoc(dev); - - em28xx_release_buffers(dev); - - /* the device is already disconnect, free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - em28xx_release_resources(dev); - mutex_unlock(&dev->lock); - kfree(dev); - return 0; - } - - /* set alternate 0 */ - dev->alt = 0; - em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(dev->udev, 0, 0); - if (errCode < 0) { - em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n", - errCode); - } - - dev->users--; - wake_up_interruptible_nr(&dev->open, 1); + fh->stream_on = 0; + dev->stream_on = 0; mutex_unlock(&dev->lock); - return 0; -} - -/* - * em28xx_v4l2_read() - * will allocate buffers when called for the first time - */ -static ssize_t -em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, - loff_t * f_pos) -{ - struct em28xx_frame_t *f, *i; - unsigned long lock_flags; - int ret = 0; - struct em28xx *dev = filp->private_data; - - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); - } - if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); - em28xx_videodbg("not supported yet! ...\n"); - if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->fileop_lock); - return -EFAULT; - } - return (1); - } - if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); - em28xx_videodbg("not supported yet! ...\n"); - if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->fileop_lock); - return -EFAULT; - } - return (1); - } - - if (mutex_lock_interruptible(&dev->fileop_lock)) - return -ERESTARTSYS; - - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("device not present\n"); - mutex_unlock(&dev->fileop_lock); - return -ENODEV; - } - - if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg("device misconfigured; close and open it again\n"); - mutex_unlock(&dev->fileop_lock); - return -EIO; - } - - if (dev->io == IO_MMAP) { - em28xx_videodbg ("IO method is set to mmap; close and open" - " the device again to choose the read method\n"); - mutex_unlock(&dev->fileop_lock); - return -EINVAL; - } - - if (dev->io == IO_NONE) { - if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { - em28xx_errdev("read failed, not enough memory\n"); - mutex_unlock(&dev->fileop_lock); - return -ENOMEM; - } - dev->io = IO_READ; - dev->stream = STREAM_ON; - em28xx_queue_unusedframes(dev); - } - - if (!count) { - mutex_unlock(&dev->fileop_lock); - return 0; - } - - if (list_empty(&dev->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&dev->fileop_lock); - return -EAGAIN; - } - ret = wait_event_interruptible - (dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (ret) { - mutex_unlock(&dev->fileop_lock); - return ret; - } - if (dev->state & DEV_DISCONNECTED) { - mutex_unlock(&dev->fileop_lock); - return -ENODEV; - } - } - - f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame); - - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_for_each_entry(i, &dev->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&dev->outqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - - em28xx_queue_unusedframes(dev); - - if (count > f->buf.length) - count = f->buf.length; - - if (copy_to_user(buf, f->bufmem, count)) { - mutex_unlock(&dev->fileop_lock); - return -EFAULT; - } - *f_pos += count; - - mutex_unlock(&dev->fileop_lock); - - return count; -} - -/* - * em28xx_v4l2_poll() - * will allocate buffers when called for the first time - */ -static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) -{ - unsigned int mask = 0; - struct em28xx *dev = filp->private_data; - - if (mutex_lock_interruptible(&dev->fileop_lock)) - return POLLERR; - - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("device not present\n"); - } else if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg("device is misconfigured; close and open it again\n"); - } else { - if (dev->io == IO_NONE) { - if (!em28xx_request_buffers - (dev, EM28XX_NUM_READ_FRAMES)) { - em28xx_warn - ("poll() failed, not enough memory\n"); - } else { - dev->io = IO_READ; - dev->stream = STREAM_ON; - } - } - - if (dev->io == IO_READ) { - em28xx_queue_unusedframes(dev); - poll_wait(filp, &dev->wait_frame, wait); - - if (!list_empty(&dev->outqueue)) - mask |= POLLIN | POLLRDNORM; - - mutex_unlock(&dev->fileop_lock); - - return mask; - } - } - - mutex_unlock(&dev->fileop_lock); - return POLLERR; } /* @@ -570,7 +253,9 @@ static void em28xx_vm_close(struct vm_area_struct *vma) { /* NOTE: buffers are not freed here */ struct em28xx_frame_t *f = vma->vm_private_data; - f->vma_use_count--; + + if (f->vma_use_count) + f->vma_use_count--; } static struct vm_operations_struct em28xx_vm_ops = { @@ -578,73 +263,6 @@ static struct vm_operations_struct em28xx_vm_ops = { .close = em28xx_vm_close, }; -/* - * em28xx_v4l2_mmap() - */ -static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) -{ - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - struct em28xx *dev = filp->private_data; - - if (mutex_lock_interruptible(&dev->fileop_lock)) - return -ERESTARTSYS; - - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("mmap: device not present\n"); - mutex_unlock(&dev->fileop_lock); - return -ENODEV; - } - - if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg ("mmap: Device is misconfigured; close and " - "open it again\n"); - mutex_unlock(&dev->fileop_lock); - return -EIO; - } - - if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(dev->frame[0].buf.length)) { - mutex_unlock(&dev->fileop_lock); - return -EINVAL; - } - - for (i = 0; i < dev->num_frames; i++) { - if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == dev->num_frames) { - em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); - mutex_unlock(&dev->fileop_lock); - return -EINVAL; - } - - /* VM_IO is eventually going to replace PageReserved altogether */ - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ - - pos = dev->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - em28xx_videodbg("mmap: vm_insert_page failed\n"); - mutex_unlock(&dev->fileop_lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &em28xx_vm_ops; - vma->vm_private_data = &dev->frame[i]; - - em28xx_vm_open(vma); - mutex_unlock(&dev->fileop_lock); - return 0; -} /* * em28xx_get_ctrl() @@ -692,159 +310,99 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) */ static int em28xx_stream_interrupt(struct em28xx *dev) { - int ret = 0; + int rc = 0; /* stop reading from the device */ dev->stream = STREAM_INTERRUPT; - ret = wait_event_timeout(dev->wait_stream, - (dev->stream == STREAM_OFF) || - (dev->state & DEV_DISCONNECTED), - EM28XX_URB_TIMEOUT); - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - else if (ret) { + rc = wait_event_timeout(dev->wait_stream, + (dev->stream == STREAM_OFF) || + (dev->state & DEV_DISCONNECTED), + EM28XX_URB_TIMEOUT); + + if (rc) { dev->state |= DEV_MISCONFIGURED; em28xx_videodbg("device is misconfigured; close and " "open /dev/video%d again\n", dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); - return ret; + return rc; } return 0; } -static int em28xx_set_norm(struct em28xx *dev, int width, int height) -{ - unsigned int hscale, vscale; - unsigned int maxh, maxw; - - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); - - /* width must even because of the YUYV format */ - /* height must be even because of interlacing */ - height &= 0xfffe; - width &= 0xfffe; - - if (height < 32) - height = 32; - if (height > maxh) - height = maxh; - if (width < 48) - width = 48; - if (width > maxw) - width = maxw; - - if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) - hscale = 0x3fff; - width = (((unsigned long)maxw) << 12) / (hscale + 4096L); - - if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) - vscale = 0x3fff; - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - /* set new image size */ - dev->width = width; - dev->height = height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ - dev->bytesperline = dev->width * 2; - dev->hscale = hscale; - dev->vscale = vscale; - - em28xx_resolution_set(dev); - - return 0; -} - -static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format) +static int check_dev(struct em28xx *dev) { - em28xx_videodbg("VIDIOC_G_FMT: type=%s\n", - (format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ? - "V4L2_BUF_TYPE_VIDEO_CAPTURE" : - (format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ? - "V4L2_BUF_TYPE_VBI_CAPTURE" : - (format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ? - "V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " : - "not supported"); - - switch (format->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - format->fmt.pix.width = dev->width; - format->fmt.pix.height = dev->height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - format->fmt.pix.bytesperline = dev->bytesperline; - format->fmt.pix.sizeimage = dev->frame_size; - format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ - - em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width, - dev->height); - break; - } - - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - { - format->fmt.sliced.service_set=0; - - em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); - - if (format->fmt.sliced.service_set==0) - return -EINVAL; - - break; + if (dev->state & DEV_DISCONNECTED) { + em28xx_errdev("v4l2 ioctl: device not present\n"); + return -ENODEV; } - default: - return -EINVAL; + if (dev->state & DEV_MISCONFIGURED) { + em28xx_errdev("v4l2 ioctl: device is misconfigured; " + "close and open it again\n"); + return -EIO; } - return (0); + return 0; } -static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format) +static void get_scale(struct em28xx *dev, + unsigned int width, unsigned int height, + unsigned int *hscale, unsigned int *vscale) { - u32 i; - int ret = 0; - int width = format->fmt.pix.width; - int height = format->fmt.pix.height; - unsigned int hscale, vscale; - unsigned int maxh, maxw; + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); + *hscale = (((unsigned long)maxw) << 12) / width - 4096L; + if (*hscale >= 0x4000) + *hscale = 0x3fff; - em28xx_videodbg("%s: type=%s\n", - cmd == VIDIOC_TRY_FMT ? - "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", - format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? - "V4L2_BUF_TYPE_VIDEO_CAPTURE" : - format->type == V4L2_BUF_TYPE_VBI_CAPTURE ? - "V4L2_BUF_TYPE_VBI_CAPTURE " : - "not supported"); + *vscale = (((unsigned long)maxh) << 12) / height - 4096L; + if (*vscale >= 0x4000) + *vscale = 0x3fff; +} - if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); +/* ------------------------------------------------------------------ + IOCTL vidioc handling + ------------------------------------------------------------------*/ - if (format->fmt.sliced.service_set==0) - return -EINVAL; +static int vidioc_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; - return 0; - } + mutex_lock(&dev->lock); + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + f->fmt.pix.bytesperline = dev->bytesperline; + f->fmt.pix.sizeimage = dev->frame_size; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ + f->fmt.pix.field = dev->interlaced ? + V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; - em28xx_videodbg("%s: requested %dx%d\n", - cmd == VIDIOC_TRY_FMT ? - "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", - format->fmt.pix.width, format->fmt.pix.height); + mutex_unlock(&dev->lock); + return 0; +} - /* FIXME: Move some code away from here */ - /* width must even because of the YUYV format */ - /* height must be even because of interlacing */ +static int vidioc_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int width = f->fmt.pix.width; + int height = f->fmt.pix.height; + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + unsigned int hscale, vscale; + + /* width must even because of the YUYV format + height must be even because of interlacing */ height &= 0xfffe; width &= 0xfffe; @@ -857,639 +415,1200 @@ static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_form if (width > maxw) width = maxw; - if(dev->is_em2800){ + mutex_lock(&dev->lock); + + if (dev->is_em2800) { /* the em2800 can only scale down to 50% */ - if(height % (maxh / 2)) - height=maxh; - if(width % (maxw / 2)) - width=maxw; + if (height % (maxh / 2)) + height = maxh; + if (width % (maxw / 2)) + width = maxw; /* according to empiatech support */ /* the MaxPacketSize is to small to support */ /* framesizes larger than 640x480 @ 30 fps */ /* or 640x576 @ 25 fps. As this would cut */ /* of a part of the image we prefer */ /* 360x576 or 360x480 for now */ - if(width == maxw && height == maxh) + if (width == maxw && height == maxh) width /= 2; } - if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) - hscale = 0x3fff; + get_scale(dev, width, height, &hscale, &vscale); width = (((unsigned long)maxw) << 12) / (hscale + 4096L); + height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) - vscale = 0x3fff; + f->fmt.pix.width = width; + f->fmt.pix.height = height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + f->fmt.pix.bytesperline = width * 2; + f->fmt.pix.sizeimage = width * 2 * height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc, i; - format->fmt.pix.width = width; - format->fmt.pix.height = height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - format->fmt.pix.bytesperline = width * 2; - format->fmt.pix.sizeimage = width * 2 * height; - format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - format->fmt.pix.field = V4L2_FIELD_INTERLACED; + rc = check_dev(dev); + if (rc < 0) + return rc; - em28xx_videodbg("%s: returned %dx%d (%d, %d)\n", - cmd == VIDIOC_TRY_FMT ? - "VIDIOC_TRY_FMT" :"VIDIOC_S_FMT", - format->fmt.pix.width, format->fmt.pix.height, hscale, vscale); + vidioc_try_fmt_cap(file, priv, f); - if (cmd == VIDIOC_TRY_FMT) - return 0; + mutex_lock(&dev->lock); for (i = 0; i < dev->num_frames; i++) if (dev->frame[i].vma_use_count) { em28xx_videodbg("VIDIOC_S_FMT failed. " - "Unmap the buffers first.\n"); - return -EINVAL; + "Unmap the buffers first.\n"); + rc = -EINVAL; + goto err; } /* stop io in case it is already in progress */ if (dev->stream == STREAM_ON) { em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; + rc = em28xx_stream_interrupt(dev); + if (rc < 0) + goto err; } em28xx_release_buffers(dev); dev->io = IO_NONE; /* set new image size */ - dev->width = width; - dev->height = height; + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; dev->frame_size = dev->width * dev->height * 2; dev->field_size = dev->frame_size >> 1; dev->bytesperline = dev->width * 2; - dev->hscale = hscale; - dev->vscale = vscale; + get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + + /* FIXME: This is really weird! Why capture is starting with + this ioctl ??? + */ em28xx_uninit_isoc(dev); em28xx_set_alternate(dev); em28xx_capture_start(dev, 1); em28xx_resolution_set(dev); em28xx_init_isoc(dev); + rc = 0; + +err: + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct v4l2_format f; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + dev->norm = *norm; + mutex_unlock(&dev->lock); + /* Adjusts width/height, if needed */ + f.fmt.pix.width = dev->width; + f.fmt.pix.height = dev->height; + vidioc_try_fmt_cap(file, priv, &f); + + mutex_lock(&dev->lock); + + /* set new image size */ + dev->width = f.fmt.pix.width; + dev->height = f.fmt.pix.height; + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; + dev->bytesperline = dev->width * 2; + get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + + em28xx_resolution_set(dev); + em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm); + + mutex_unlock(&dev->lock); return 0; } -/* - * em28xx_v4l2_do_ioctl() - * This function is _not_ called directly, but from - * em28xx_v4l2_ioctl. Userspace - * copying is done already, arg is a kernel pointer. - */ -static int em28xx_do_ioctl(struct inode *inode, struct file *filp, - struct em28xx *dev, unsigned int cmd, void *arg, - v4l2_kioctl driver_ioctl) +static const char *iname[] = { + [EM28XX_VMUX_COMPOSITE1] = "Composite1", + [EM28XX_VMUX_COMPOSITE2] = "Composite2", + [EM28XX_VMUX_COMPOSITE3] = "Composite3", + [EM28XX_VMUX_COMPOSITE4] = "Composite4", + [EM28XX_VMUX_SVIDEO] = "S-Video", + [EM28XX_VMUX_TELEVISION] = "Television", + [EM28XX_VMUX_CABLE] = "Cable TV", + [EM28XX_VMUX_DVB] = "DVB", + [EM28XX_VMUX_DEBUG] = "for debug only", +}; + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) { - int ret; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned int n; - switch (cmd) { - /* ---------- tv norms ---------- */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; + n = i->index; + if (n >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(n)->type) + return -EINVAL; - i = e->index; - if (i >= TVNORMS) - return -EINVAL; - ret = v4l2_video_std_construct(e, tvnorms[e->index].id, - tvnorms[e->index].name); - e->index = i; - if (ret < 0) - return ret; - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; - *id = dev->tvnorm->id; - return 0; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; + strcpy(i->name, iname[INPUT(n)->type]); - for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) - break; - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) - break; - if (i == TVNORMS) - return -EINVAL; + if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || + (EM28XX_VMUX_CABLE == INPUT(n)->type)) + i->type = V4L2_INPUT_TYPE_TUNER; - mutex_lock(&dev->lock); - dev->tvnorm = &tvnorms[i]; + i->std = dev->vdev->tvnorms; - em28xx_set_norm(dev, dev->width, dev->height); + return 0; +} - em28xx_i2c_call_clients(dev, VIDIOC_S_STD, - &dev->tvnorm->id); +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; - mutex_unlock(&dev->lock); + *i = dev->ctl_input; - return 0; - } + return 0; +} - /* ------ input switching ---------- */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - unsigned int n; - static const char *iname[] = { - [EM28XX_VMUX_COMPOSITE1] = "Composite1", - [EM28XX_VMUX_COMPOSITE2] = "Composite2", - [EM28XX_VMUX_COMPOSITE3] = "Composite3", - [EM28XX_VMUX_COMPOSITE4] = "Composite4", - [EM28XX_VMUX_SVIDEO] = "S-Video", - [EM28XX_VMUX_TELEVISION] = "Television", - [EM28XX_VMUX_CABLE] = "Cable TV", - [EM28XX_VMUX_DVB] = "DVB", - [EM28XX_VMUX_DEBUG] = "for debug only", - }; - - n = i->index; - if (n >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(n)->type) - return -EINVAL; - memset(i, 0, sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, iname[INPUT(n)->type]); - if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || - (EM28XX_VMUX_CABLE == INPUT(n)->type)) - i->type = V4L2_INPUT_TYPE_TUNER; - for (n = 0; n < ARRAY_SIZE(tvnorms); n++) - i->std |= tvnorms[n].id; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = dev->ctl_input; +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; - return 0; - } - case VIDIOC_S_INPUT: - { - int *index = arg; + rc = check_dev(dev); + if (rc < 0) + return rc; - if (*index >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(*index)->type) - return -EINVAL; + if (i >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(i)->type) + return -EINVAL; - mutex_lock(&dev->lock); - video_mux(dev, *index); - mutex_unlock(&dev->lock); + mutex_lock(&dev->lock); - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - unsigned int index = a->index; + video_mux(dev, i); - if (a->index > 1) - return -EINVAL; - memset(a, 0, sizeof(*a)); - index = dev->ctl_ainput; + mutex_unlock(&dev->lock); + return 0; +} - if (index == 0) { - strcpy(a->name, "Television"); - } else { - strcpy(a->name, "Line In"); - } - a->capability = V4L2_AUDCAP_STEREO; - a->index = index; - return 0; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *a = arg; +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned int index = a->index; - if (a->index != dev->ctl_ainput) - return -EINVAL; + if (a->index > 1) + return -EINVAL; - return 0; + index = dev->ctl_ainput; + + if (index == 0) { + strcpy(a->name, "Television"); + } else { + strcpy(a->name, "Line In"); } + a->capability = V4L2_AUDCAP_STEREO; + a->index = index; - /* --- controls ---------------------------------------------- */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i, id=qc->id; - - memset(qc,0,sizeof(*qc)); - qc->id=id; - - if (!dev->has_msp34xx) { - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (qc->id && qc->id == em28xx_qctrl[i].id) { - memcpy(qc, &(em28xx_qctrl[i]), - sizeof(*qc)); - return 0; - } + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (a->index != dev->ctl_ainput) + return -EINVAL; + + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int id = qc->id; + int i; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + memset(qc, 0, sizeof(*qc)); + + qc->id = id; + + if (!dev->has_msp34xx) { + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (qc->id && qc->id == em28xx_qctrl[i].id) { + memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); + return 0; } } - em28xx_i2c_call_clients(dev,cmd,qc); - if (qc->type) - return 0; - else - return -EINVAL; } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - int retval=-EINVAL; + mutex_lock(&dev->lock); + em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc); + mutex_unlock(&dev->lock); - if (!dev->has_msp34xx) - retval=em28xx_get_ctrl(dev, ctrl); - if (retval==-EINVAL) { - em28xx_i2c_call_clients(dev,cmd,arg); - return 0; - } else return retval; + if (qc->type) + return 0; + else + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + mutex_lock(&dev->lock); + + if (!dev->has_msp34xx) + rc = em28xx_get_ctrl(dev, ctrl); + else + rc = -EINVAL; + + if (rc == -EINVAL) { + em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl); + rc = 0; } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - u8 i; - - if (!dev->has_msp34xx){ - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (ctrl->id == em28xx_qctrl[i].id) { - if (ctrl->value < - em28xx_qctrl[i].minimum - || ctrl->value > - em28xx_qctrl[i].maximum) - return -ERANGE; - return em28xx_set_ctrl(dev, ctrl); + + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + u8 i; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + + if (dev->has_msp34xx) + em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); + else { + rc = 1; + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (ctrl->id == em28xx_qctrl[i].id) { + if (ctrl->value < em28xx_qctrl[i].minimum || + ctrl->value > em28xx_qctrl[i].maximum) { + rc = -ERANGE; + break; } + + rc = em28xx_set_ctrl(dev, ctrl); + break; } } + } - em28xx_i2c_call_clients(dev,cmd,arg); - return 0; + /* Control not found - try to send it to the attached devices */ + if (rc == 1) { + em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); + rc = 0; } - /* --- tuner ioctls ------------------------------------------ */ - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - if (0 != t->index) - return -EINVAL; + mutex_unlock(&dev->lock); + return rc; +} - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Tuner"); - mutex_lock(&dev->lock); - /* let clients fill in the remainder of this struct */ - em28xx_i2c_call_clients(dev, cmd, t); - mutex_unlock(&dev->lock); - em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal, - t->afc); - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; - if (0 != t->index) - return -EINVAL; - mutex_lock(&dev->lock); - /* let clients handle this */ - em28xx_i2c_call_clients(dev, cmd, t); + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Tuner"); + + mutex_lock(&dev->lock); + + em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) + return -EINVAL; + + mutex_lock(&dev->lock); + + em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != f->tuner) + return -EINVAL; + + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + + mutex_lock(&dev->lock); + + dev->ctl_freq = f->frequency; + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cc) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + cc->bounds.left = 0; + cc->bounds.top = 0; + cc->bounds.width = dev->width; + cc->bounds.height = dev->height; + cc->defrect = cc->bounds; + cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ + cc->pixelaspect.denominator = 59; + + return 0; +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + return -EINVAL; + + if (list_empty(&dev->inqueue)) + return -EINVAL; + + mutex_lock(&dev->lock); + + if (unlikely(res_get(fh) < 0)) { mutex_unlock(&dev->lock); - return 0; + return -EBUSY; } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; - memset(f, 0, sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; + dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ - return 0; + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + return -EINVAL; + + mutex_lock(&dev->lock); + + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n"); + rc = em28xx_stream_interrupt(dev); + if (rc < 0) { + mutex_unlock(&dev->lock); + return rc; + } } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - if (0 != f->tuner) - return -EINVAL; + em28xx_empty_framequeues(dev); - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; + mutex_unlock(&dev->lock); + return 0; +} - mutex_lock(&dev->lock); - dev->ctl_freq = f->frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); - mutex_unlock(&dev->lock); - return 0; +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); + strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); + strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); + + cap->version = EM28XX_VERSION_CODE; + + cap->capabilities = + V4L2_CAP_SLICED_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + + if (dev->has_tuner) + cap->capabilities |= V4L2_CAP_TUNER; + + return 0; +} + +static int vidioc_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *fmtd) +{ + if (fmtd->index != 0) + return -EINVAL; + + fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(fmtd->description, "Packed YUY2"); + fmtd->pixelformat = V4L2_PIX_FMT_YUYV; + memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); + + return 0; +} + +/* Sliced VBI ioctls */ +static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + + f->fmt.sliced.service_set = 0; + + em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); + + if (f->fmt.sliced.service_set == 0) + rc = -EINVAL; + + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_try_set_vbi_capture(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); + mutex_unlock(&dev->lock); + + if (f->fmt.sliced.service_set == 0) + return -EINVAL; + + return 0; +} + + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + u32 i; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + rb->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + if (dev->io == IO_READ) { + em28xx_videodbg("method is set to read;" + " close and open the device again to" + " choose the mmap I/O method\n"); + return -EINVAL; } - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *cc = arg; - if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + for (i = 0; i < dev->num_frames; i++) + if (dev->frame[i].vma_use_count) { + em28xx_videodbg("VIDIOC_REQBUFS failed; " + "previous buffers are still mapped\n"); return -EINVAL; - cc->bounds.left = 0; - cc->bounds.top = 0; - cc->bounds.width = dev->width; - cc->bounds.height = dev->height; - cc->defrect = cc->bounds; - cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ - cc->pixelaspect.denominator = 59; - return 0; + } + + mutex_lock(&dev->lock); + + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); + rc = em28xx_stream_interrupt(dev); + if (rc < 0) { + mutex_unlock(&dev->lock); + return rc; + } } - case VIDIOC_STREAMON: - { - int *type = arg; - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; + em28xx_empty_framequeues(dev); - if (list_empty(&dev->inqueue)) - return -EINVAL; + em28xx_release_buffers(dev); + if (rb->count) + rb->count = em28xx_request_buffers(dev, rb->count); - dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ + dev->frame_current = NULL; + dev->io = rb->count ? IO_MMAP : IO_NONE; - em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); + mutex_unlock(&dev->lock); + return 0; +} - return 0; - } - case VIDIOC_STREAMOFF: - { - int *type = arg; - int ret; +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b->index >= dev->num_frames || dev->io != IO_MMAP) + return -EINVAL; + + mutex_lock(&dev->lock); + + memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); + + if (dev->frame[b->index].vma_use_count) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + if (dev->frame[b->index].state == F_DONE) + b->flags |= V4L2_BUF_FLAG_DONE; + else if (dev->frame[b->index].state != F_UNUSED) + b->flags |= V4L2_BUF_FLAG_QUEUED; + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned long lock_flags; + int rc; - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP || + b->index >= dev->num_frames) + return -EINVAL; + + if (dev->frame[b->index].state != F_UNUSED) + return -EAGAIN; + + dev->frame[b->index].state = F_QUEUED; + + /* add frame to fifo */ + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_add_tail(&dev->frame[b->index].frame, &dev->inqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + + return 0; +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + struct em28xx_frame_t *f; + unsigned long lock_flags; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + return -EINVAL; + + if (list_empty(&dev->outqueue)) { + if (dev->stream == STREAM_OFF) return -EINVAL; - if (dev->stream == STREAM_ON) { - em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; - } - em28xx_empty_framequeues(dev); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; - return 0; - } - default: - return v4l_compat_translate_ioctl(inode, filp, cmd, arg, - driver_ioctl); + rc = wait_event_interruptible(dev->wait_frame, + (!list_empty(&dev->outqueue)) || + (dev->state & DEV_DISCONNECTED)); + if (rc) + return rc; + + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; } + + spin_lock_irqsave(&dev->queue_lock, lock_flags); + f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame); + list_del(dev->outqueue.next); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + + f->state = F_UNUSED; + memcpy(b, &f->buf, sizeof(*b)); + + if (f->vma_use_count) + b->flags |= V4L2_BUF_FLAG_MAPPED; + return 0; } /* - * em28xx_v4l2_do_ioctl() - * This function is _not_ called directly, but from - * em28xx_v4l2_ioctl. Userspace - * copying is done already, arg is a kernel pointer. + * em28xx_v4l2_open() + * inits the device and starts isoc transfer */ -static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, void *arg) +static int em28xx_v4l2_open(struct inode *inode, struct file *filp) { - struct em28xx *dev = filp->private_data; + int minor = iminor(inode); + int errCode = 0; + struct em28xx *h,*dev = NULL; + struct em28xx_fh *fh; - if (!dev) + list_for_each_entry(h, &em28xx_devlist, devlist) { + if (h->vdev->minor == minor) { + dev = h; + dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + if (h->vbi_dev->minor == minor) { + dev = h; + dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; + } + } + if (NULL == dev) return -ENODEV; - if (video_debug > 1) - v4l_print_ioctl(dev->name,cmd); - - switch (cmd) { - - /* --- capabilities ------------------------------------------ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap, 0, sizeof(*cap)); - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, - sizeof(cap->card)); - strlcpy(cap->bus_info, dev->udev->dev.bus_id, - sizeof(cap->bus_info)); - cap->version = EM28XX_VERSION_CODE; - cap->capabilities = - V4L2_CAP_SLICED_VBI_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (dev->has_tuner) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; + em28xx_videodbg("open minor=%d type=%s users=%d\n", + minor,v4l2_type_names[dev->type],dev->users); + + fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); + + if (!fh) { + em28xx_errdev("em28xx-video.c: Out of memory?!\n"); + return -ENOMEM; } - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *fmtd = arg; + mutex_lock(&dev->lock); + fh->dev = dev; + filp->private_data = fh; - if (fmtd->index != 0) - return -EINVAL; - memset(fmtd, 0, sizeof(*fmtd)); - fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(fmtd->description, "Packed YUY2"); - fmtd->pixelformat = V4L2_PIX_FMT_YUYV; - memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); - return 0; + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { + em28xx_set_alternate(dev); + + dev->width = norm_maxw(dev); + dev->height = norm_maxh(dev); + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ + dev->bytesperline = dev->width * 2; + dev->hscale = 0; + dev->vscale = 0; + + em28xx_capture_start(dev, 1); + em28xx_resolution_set(dev); + + + /* start the transfer */ + errCode = em28xx_init_isoc(dev); + if (errCode) + goto err; + + em28xx_empty_framequeues(dev); } - case VIDIOC_G_FMT: - return em28xx_get_fmt(dev, (struct v4l2_format *) arg); - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); + dev->users++; - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *rb = arg; - u32 i; - int ret; +err: + mutex_unlock(&dev->lock); + return errCode; +} - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; +/* + * em28xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +static void em28xx_release_resources(struct em28xx *dev) +{ - if (dev->io == IO_READ) { - em28xx_videodbg ("method is set to read;" - " close and open the device again to" - " choose the mmap I/O method\n"); - return -EINVAL; - } + /*FIXME: I2C IR should be disconnected */ - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n"); - return -EINVAL; - } + em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", + dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, + dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); + list_del(&dev->devlist); + video_unregister_device(dev->vdev); + video_unregister_device(dev->vbi_dev); + em28xx_i2c_unregister(dev); + usb_put_dev(dev->udev); - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; - } - em28xx_empty_framequeues(dev); + /* Mark device as unused */ + em28xx_devused&=~(1<devno); +} + +/* + * em28xx_v4l2_close() + * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls + */ +static int em28xx_v4l2_close(struct inode *inode, struct file *filp) +{ + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + int errCode; + + em28xx_videodbg("users=%d\n", dev->users); + + if (res_check(fh)) + res_free(fh); + + mutex_lock(&dev->lock); + + if (dev->users == 1) { + em28xx_uninit_isoc(dev); em28xx_release_buffers(dev); - if (rb->count) - rb->count = - em28xx_request_buffers(dev, rb->count); + dev->io = IO_NONE; - dev->frame_current = NULL; + /* the device is already disconnect, + free the remaining resources */ + if (dev->state & DEV_DISCONNECTED) { + em28xx_release_resources(dev); + mutex_unlock(&dev->lock); + kfree(dev); + return 0; + } - em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n", - rb->count); - dev->io = rb->count ? IO_MMAP : IO_NONE; - return 0; + /* set alternate 0 */ + dev->alt = 0; + em28xx_videodbg("setting alternate 0\n"); + errCode = usb_set_interface(dev->udev, 0, 0); + if (errCode < 0) { + em28xx_errdev("cannot change alternate number to " + "0 (error=%i)\n", errCode); + } } - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *b = arg; + kfree(fh); + dev->users--; + wake_up_interruptible_nr(&dev->open, 1); + mutex_unlock(&dev->lock); + return 0; +} - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) - return -EINVAL; +/* + * em28xx_v4l2_read() + * will allocate buffers when called for the first time + */ +static ssize_t +em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, + loff_t * f_pos) +{ + struct em28xx_frame_t *f, *i; + unsigned long lock_flags; + int ret = 0; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + + /* FIXME: read() is not prepared to allow changing the video + resolution while streaming. Seems a bug at em28xx_set_fmt + */ - memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); + if (unlikely(res_get(fh) < 0)) + return -EBUSY; + + mutex_lock(&dev->lock); - if (dev->frame[b->index].vma_use_count) { - b->flags |= V4L2_BUF_FLAG_MAPPED; + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); + + if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); + em28xx_videodbg("not supported yet! ...\n"); + if (copy_to_user(buf, "", 1)) { + mutex_unlock(&dev->lock); + return -EFAULT; } - if (dev->frame[b->index].state == F_DONE) - b->flags |= V4L2_BUF_FLAG_DONE; - else if (dev->frame[b->index].state != F_UNUSED) - b->flags |= V4L2_BUF_FLAG_QUEUED; - return 0; + mutex_unlock(&dev->lock); + return (1); + } + if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); + em28xx_videodbg("not supported yet! ...\n"); + if (copy_to_user(buf, "", 1)) { + mutex_unlock(&dev->lock); + return -EFAULT; + } + mutex_unlock(&dev->lock); + return (1); } - case VIDIOC_QBUF: - { - struct v4l2_buffer *b = arg; - unsigned long lock_flags; - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) { - return -EINVAL; + if (dev->state & DEV_DISCONNECTED) { + em28xx_videodbg("device not present\n"); + mutex_unlock(&dev->lock); + return -ENODEV; + } + + if (dev->state & DEV_MISCONFIGURED) { + em28xx_videodbg("device misconfigured; close and open it again\n"); + mutex_unlock(&dev->lock); + return -EIO; + } + + if (dev->io == IO_MMAP) { + em28xx_videodbg ("IO method is set to mmap; close and open" + " the device again to choose the read method\n"); + mutex_unlock(&dev->lock); + return -EINVAL; + } + + if (dev->io == IO_NONE) { + if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { + em28xx_errdev("read failed, not enough memory\n"); + mutex_unlock(&dev->lock); + return -ENOMEM; } + dev->io = IO_READ; + dev->stream = STREAM_ON; + em28xx_queue_unusedframes(dev); + } - if (dev->frame[b->index].state != F_UNUSED) { + if (!count) { + mutex_unlock(&dev->lock); + return 0; + } + + if (list_empty(&dev->outqueue)) { + if (filp->f_flags & O_NONBLOCK) { + mutex_unlock(&dev->lock); return -EAGAIN; } - dev->frame[b->index].state = F_QUEUED; + ret = wait_event_interruptible + (dev->wait_frame, + (!list_empty(&dev->outqueue)) || + (dev->state & DEV_DISCONNECTED)); + if (ret) { + mutex_unlock(&dev->lock); + return ret; + } + if (dev->state & DEV_DISCONNECTED) { + mutex_unlock(&dev->lock); + return -ENODEV; + } + dev->video_bytesread = 0; + } + + f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame); + + em28xx_queue_unusedframes(dev); + + if (count > f->buf.length) + count = f->buf.length; + + if ((dev->video_bytesread + count) > dev->frame_size) + count = dev->frame_size - dev->video_bytesread; - /* add frame to fifo */ + if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) { + em28xx_err("Error while copying to user\n"); + return -EFAULT; + } + dev->video_bytesread += count; + + if (dev->video_bytesread == dev->frame_size) { spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_add_tail(&dev->frame[b->index].frame, - &dev->inqueue); + list_for_each_entry(i, &dev->outqueue, frame) + i->state = F_UNUSED; + INIT_LIST_HEAD(&dev->outqueue); spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - return 0; + em28xx_queue_unusedframes(dev); + dev->video_bytesread = 0; } - case VIDIOC_DQBUF: - { - struct v4l2_buffer *b = arg; - struct em28xx_frame_t *f; - unsigned long lock_flags; - int ret = 0; - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; + *f_pos += count; + + mutex_unlock(&dev->lock); + + return count; +} + +/* + * em28xx_v4l2_poll() + * will allocate buffers when called for the first time + */ +static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) +{ + unsigned int mask = 0; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; - if (list_empty(&dev->outqueue)) { - if (dev->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - ret = wait_event_interruptible - (dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (ret) - return ret; - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; + if (unlikely(res_get(fh) < 0)) + return POLLERR; + + mutex_lock(&dev->lock); + + if (dev->state & DEV_DISCONNECTED) { + em28xx_videodbg("device not present\n"); + } else if (dev->state & DEV_MISCONFIGURED) { + em28xx_videodbg("device is misconfigured; close and open it again\n"); + } else { + if (dev->io == IO_NONE) { + if (!em28xx_request_buffers + (dev, EM28XX_NUM_READ_FRAMES)) { + em28xx_warn + ("poll() failed, not enough memory\n"); + } else { + dev->io = IO_READ; + dev->stream = STREAM_ON; + } } - spin_lock_irqsave(&dev->queue_lock, lock_flags); - f = list_entry(dev->outqueue.next, - struct em28xx_frame_t, frame); - list_del(dev->outqueue.next); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + if (dev->io == IO_READ) { + em28xx_queue_unusedframes(dev); + poll_wait(filp, &dev->wait_frame, wait); - f->state = F_UNUSED; - memcpy(b, &f->buf, sizeof(*b)); + if (!list_empty(&dev->outqueue)) + mask |= POLLIN | POLLRDNORM; - if (f->vma_use_count) - b->flags |= V4L2_BUF_FLAG_MAPPED; + mutex_unlock(&dev->lock); - return 0; - } - default: - return em28xx_do_ioctl(inode, filp, dev, cmd, arg, - em28xx_video_do_ioctl); + return mask; + } } - return 0; + + mutex_unlock(&dev->lock); + return POLLERR; } /* - * em28xx_v4l2_ioctl() - * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl() + * em28xx_v4l2_mmap() */ -static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) { - int ret = 0; - struct em28xx *dev = filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long start = vma->vm_start; + void *pos; + u32 i; + + if (unlikely(res_get(fh) < 0)) + return -EBUSY; - if (mutex_lock_interruptible(&dev->fileop_lock)) - return -ERESTARTSYS; + mutex_lock(&dev->lock); if (dev->state & DEV_DISCONNECTED) { - em28xx_errdev("v4l2 ioctl: device not present\n"); - mutex_unlock(&dev->fileop_lock); + em28xx_videodbg("mmap: device not present\n"); + mutex_unlock(&dev->lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { - em28xx_errdev - ("v4l2 ioctl: device is misconfigured; close and open it again\n"); - mutex_unlock(&dev->fileop_lock); + em28xx_videodbg ("mmap: Device is misconfigured; close and " + "open it again\n"); + mutex_unlock(&dev->lock); return -EIO; } - ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl); + if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) { + mutex_unlock(&dev->lock); + return -EINVAL; + } + + if (size > PAGE_ALIGN(dev->frame[0].buf.length)) + size = PAGE_ALIGN(dev->frame[0].buf.length); + + for (i = 0; i < dev->num_frames; i++) { + if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) + break; + } + if (i == dev->num_frames) { + em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); + mutex_unlock(&dev->lock); + return -EINVAL; + } + + /* VM_IO is eventually going to replace PageReserved altogether */ + vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + + pos = dev->frame[i].bufmem; + while (size > 0) { /* size is page-aligned */ + if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { + em28xx_videodbg("mmap: vm_insert_page failed\n"); + mutex_unlock(&dev->lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } - mutex_unlock(&dev->fileop_lock); + vma->vm_ops = &em28xx_vm_ops; + vma->vm_private_data = &dev->frame[i]; - return ret; + em28xx_vm_open(vma); + mutex_unlock(&dev->lock); + return 0; } static const struct file_operations em28xx_v4l_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .ioctl = em28xx_v4l2_ioctl, - .read = em28xx_v4l2_read, - .poll = em28xx_v4l2_poll, - .mmap = em28xx_v4l2_mmap, - .llseek = no_llseek, - .compat_ioctl = v4l_compat_ioctl32, + .owner = THIS_MODULE, + .open = em28xx_v4l2_open, + .release = em28xx_v4l2_close, + .read = em28xx_v4l2_read, + .poll = em28xx_v4l2_poll, + .mmap = em28xx_v4l2_mmap, + .ioctl = video_ioctl2, + .llseek = no_llseek, + .compat_ioctl = v4l_compat_ioctl32, +}; +static const struct video_device em28xx_video_template = { + .fops = &em28xx_v4l_fops, + .release = video_device_release, + + .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, + .vidioc_g_fmt_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_cropcap = vidioc_cropcap, + + .vidioc_g_fmt_vbi_capture = vidioc_g_fmt_vbi_capture, + .vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture, + .vidioc_s_fmt_vbi_capture = vidioc_try_set_vbi_capture, + + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + + .tvnorms = V4L2_STD_ALL, + .current_norm = V4L2_STD_PAL, }; + /******************************** usb interface *****************************************/ /* @@ -1497,45 +1616,48 @@ static const struct file_operations em28xx_v4l_fops = { * allocates and inits the device structs, registers i2c bus and v4l device */ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, - int minor, int model) + int minor) { struct em28xx *dev = *devhandle; int retval = -ENOMEM; - int errCode, i; + int errCode; unsigned int maxh, maxw; dev->udev = udev; - dev->model = model; mutex_init(&dev->lock); + spin_lock_init(&dev->queue_lock); init_waitqueue_head(&dev->open); + init_waitqueue_head(&dev->wait_frame); + init_waitqueue_head(&dev->wait_stream); dev->em28xx_write_regs = em28xx_write_regs; dev->em28xx_read_reg = em28xx_read_reg; dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; dev->em28xx_write_regs_req = em28xx_write_regs_req; dev->em28xx_read_reg_req = em28xx_read_reg_req; - dev->is_em2800 = em28xx_boards[model].is_em2800; - dev->has_tuner = em28xx_boards[model].has_tuner; - dev->has_msp34xx = em28xx_boards[model].has_msp34xx; - dev->tda9887_conf = em28xx_boards[model].tda9887_conf; - dev->decoder = em28xx_boards[model].decoder; - - if (tuner >= 0) - dev->tuner_type = tuner; - else - dev->tuner_type = em28xx_boards[model].tuner_type; + dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - dev->video_inputs = em28xx_boards[model].vchannels; + em28xx_pre_card_setup(dev); - for (i = 0; i < TVNORMS; i++) - if (em28xx_boards[model].norm == tvnorms[i].mode) - break; - if (i == TVNORMS) - i = 0; + errCode = em28xx_config(dev); + if (errCode) { + em28xx_errdev("error configuring device\n"); + em28xx_devused &= ~(1<devno); + kfree(dev); + return -ENOMEM; + } + + /* register i2c bus */ + em28xx_i2c_register(dev); - dev->tvnorm = &tvnorms[i]; /* set default norm */ + /* Do board specific init and eeprom reading */ + em28xx_card_setup(dev); - em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name); + /* configure the device */ + em28xx_config_i2c(dev); + + /* set default norm */ + dev->norm = em28xx_video_template.current_norm; maxw = norm_maxw(dev); maxh = norm_maxh(dev); @@ -1552,53 +1674,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vscale = 0; dev->ctl_input = 2; - /* setup video picture settings for saa7113h */ - memset(&dev->vpic, 0, sizeof(dev->vpic)); - dev->vpic.colour = 128 << 8; - dev->vpic.hue = 128 << 8; - dev->vpic.brightness = 128 << 8; - dev->vpic.contrast = 192 << 8; - dev->vpic.whiteness = 128 << 8; /* This one isn't used */ - dev->vpic.depth = 16; - dev->vpic.palette = VIDEO_PALETTE_YUV422; - - em28xx_pre_card_setup(dev); -#ifdef CONFIG_MODULES - /* request some modules */ - if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) - request_module("saa7115"); - if (dev->decoder == EM28XX_TVP5150) - request_module("tvp5150"); - if (dev->has_tuner) - request_module("tuner"); -#endif errCode = em28xx_config(dev); - if (errCode) { - em28xx_errdev("error configuring device\n"); - em28xx_devused&=~(1<devno); - kfree(dev); - return -ENOMEM; - } - - mutex_lock(&dev->lock); - /* register i2c bus */ - em28xx_i2c_register(dev); - - /* Do board specific init and eeprom reading */ - em28xx_card_setup(dev); - /* configure the device */ - em28xx_config_i2c(dev); - - mutex_unlock(&dev->lock); - - errCode = em28xx_config(dev); - -#ifdef CONFIG_MODULES - if (dev->has_msp34xx) - request_module("msp3400"); -#endif - /* allocate and fill v4l2 device struct */ + /* allocate and fill video video_device struct */ dev->vdev = video_device_alloc(); if (NULL == dev->vdev) { em28xx_errdev("cannot allocate video_device.\n"); @@ -1606,7 +1684,16 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, kfree(dev); return -ENOMEM; } + memcpy(dev->vdev, &em28xx_video_template, + sizeof(em28xx_video_template)); + dev->vdev->type = VID_TYPE_CAPTURE; + if (dev->has_tuner) + dev->vdev->type |= VID_TYPE_TUNER; + dev->vdev->dev = &dev->udev->dev; + snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), + "%s#%d %s", "em28xx", dev->devno, "video"); + /* Allocate and fill vbi video_device struct */ dev->vbi_dev = video_device_alloc(); if (NULL == dev->vbi_dev) { em28xx_errdev("cannot allocate video_device.\n"); @@ -1615,31 +1702,26 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, kfree(dev); return -ENOMEM; } - - /* Fills VBI device info */ + memcpy(dev->vbi_dev, &em28xx_video_template, + sizeof(em28xx_video_template)); dev->vbi_dev->type = VFL_TYPE_VBI; - dev->vbi_dev->fops = &em28xx_v4l_fops; - dev->vbi_dev->minor = -1; dev->vbi_dev->dev = &dev->udev->dev; - dev->vbi_dev->release = video_device_release; - snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", - "em28xx",dev->devno,"vbi"); - - /* Fills CAPTURE device info */ - dev->vdev->type = VID_TYPE_CAPTURE; - if (dev->has_tuner) - dev->vdev->type |= VID_TYPE_TUNER; - dev->vdev->fops = &em28xx_v4l_fops; - dev->vdev->minor = -1; - dev->vdev->dev = &dev->udev->dev; - dev->vdev->release = video_device_release; - snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", - "em28xx",dev->devno,"video"); + snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), + "%s#%d %s", "em28xx", dev->devno, "vbi"); list_add_tail(&dev->devlist,&em28xx_devlist); - /* register v4l2 device */ - mutex_lock(&dev->lock); + if (dev->has_msp34xx) { + /* Send a reset to other chips via gpio */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); + msleep(3); + em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); + msleep(3); + } + + video_mux(dev, 0); + + /* register v4l2 video video_device */ if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]))) { em28xx_errdev("unable to register video device (error=%i).\n", @@ -1652,6 +1734,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return -ENODEV; } + /* register v4l2 vbi video_device */ if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]) < 0) { printk("unable to register vbi device\n"); @@ -1662,21 +1745,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, em28xx_devused&=~(1<devno); kfree(dev); return -ENODEV; - } else { - printk("registered VBI\n"); - } - - if (dev->has_msp34xx) { - /* Send a reset to other chips via gpio */ - em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); - msleep(3); - em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); - msleep(3); - } - video_mux(dev, 0); - - mutex_unlock(&dev->lock); em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, @@ -1697,7 +1766,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, struct usb_interface *uif; struct em28xx *dev = NULL; int retval = -ENODEV; - int model,i,nr,ifnum; + int i, nr, ifnum; udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; @@ -1737,8 +1806,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, return -ENODEV; } - model=id->driver_info; - if (nr >= EM28XX_MAXBOARDS) { printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); em28xx_devused&=~(1<name, 29, "em28xx #%d", nr); - dev->devno=nr; + dev->devno = nr; + dev->model = id->driver_info; /* compute alternate max packet sizes */ uif = udev->actconfig->interface[0]; @@ -1781,30 +1849,14 @@ static int em28xx_usb_probe(struct usb_interface *interface, } if ((card[nr]>=0)&&(card[nr] insmod option to\n" - "%s: workaround that. Redirect complaints to the vendor of\n" - "%s: the TV card. Generic type will be used." - "%s: Best regards,\n" - "%s: -- tux\n", - dev->name,dev->name,dev->name,dev->name,dev->name); - em28xx_errdev("%s: Here is a list of valid choices for the card= insmod option:\n", - dev->name); - for (i = 0; i < em28xx_bcount; i++) { - em28xx_errdev(" card=%d -> %s\n", i, - em28xx_boards[i].name); - } - } + dev->model = card[nr]; /* allocate device struct */ - retval = em28xx_init_dev(&dev, udev, nr, model); + retval = em28xx_init_dev(&dev, udev, nr); if (retval) return retval; - em28xx_info("Found %s\n", em28xx_boards[model].name); + em28xx_info("Found %s\n", em28xx_boards[dev->model].name); /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); @@ -1818,18 +1870,19 @@ static int em28xx_usb_probe(struct usb_interface *interface, */ static void em28xx_usb_disconnect(struct usb_interface *interface) { - struct em28xx *dev = usb_get_intfdata(interface); + struct em28xx *dev; + + dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!dev) return; - down_write(&em28xx_disconnect); + em28xx_info("disconnecting %s\n", dev->vdev->name); + /* wait until all current v4l2 io is finished then deallocate resources */ mutex_lock(&dev->lock); - em28xx_info("disconnecting %s\n", dev->vdev->name); - wake_up_interruptible_all(&dev->open); if (dev->users) { @@ -1848,6 +1901,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) em28xx_release_resources(dev); } + mutex_unlock(&dev->lock); if (!dev->users) { @@ -1855,7 +1909,6 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) kfree(dev); } - up_write(&em28xx_disconnect); } static struct usb_driver em28xx_usb_driver = { diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index d8fcc9e..8d04586 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -25,7 +25,7 @@ #ifndef _EM28XX_H #define _EM28XX_H -#include +#include #include #include #include @@ -46,6 +46,8 @@ #define EM2880_BOARD_TERRATEC_HYBRID_XS 11 #define EM2820_BOARD_KWORLD_PVRTV2800RF 12 #define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 +#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 +#define EM2800_BOARD_VGEAR_POCKETTV 15 #define UNSET -1 @@ -165,7 +167,6 @@ enum em28xx_decoder { struct em28xx_board { char *name; int vchannels; - int norm; int tuner_type; /* i2c flags */ @@ -201,14 +202,6 @@ enum em28xx_dev_state { DEV_MISCONFIGURED = 0x04, }; -/* tvnorms */ -struct em28xx_tvnorm { - char *name; - v4l2_std_id id; - /* mode for saa7113h */ - int mode; -}; - /* main device struct */ struct em28xx { /* generic device properties */ @@ -222,6 +215,8 @@ struct em28xx { unsigned int has_msp34xx:1; unsigned int has_tda9887:1; + unsigned int stream_on:1; /* Locks streams */ + u32 i2s_speed; /* I2S speed for audio digital stream */ enum em28xx_decoder decoder; @@ -235,8 +230,7 @@ struct em28xx { /* video for linux */ int users; /* user count for exclusive use */ struct video_device *vdev; /* video for linux device struct */ - struct video_picture vpic; /* picture settings only used to init saa7113h */ - struct em28xx_tvnorm *tvnorm; /* selected tv norm */ + v4l2_std_id norm; /* selected tv norm */ int ctl_freq; /* selected frequency */ unsigned int ctl_input; /* selected input */ unsigned int ctl_ainput; /* slected audio input */ @@ -256,13 +250,18 @@ struct em28xx { int vscale; /* vertical scale factor (see datasheet) */ int interlaced; /* 1=interlace fileds, 0=just top fileds */ int type; + unsigned int video_bytesread; /* Number of bytes read */ + + unsigned long hash; /* eeprom hash - for boards with generic ID */ + unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ /* states */ enum em28xx_dev_state state; enum em28xx_stream_state stream; enum em28xx_io_method io; + /* locks */ - struct mutex lock, fileop_lock; + struct mutex lock; spinlock_t queue_lock; struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; @@ -289,9 +288,15 @@ struct em28xx { int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg); }; +struct em28xx_fh { + struct em28xx *dev; + unsigned int stream_on:1; /* Locks streams */ +}; + /* Provided by em28xx-i2c.c */ void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg); +void em28xx_do_i2c_scan(struct em28xx *dev); int em28xx_i2c_register(struct em28xx *dev); int em28xx_i2c_unregister(struct em28xx *dev); @@ -332,6 +337,9 @@ extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; +/* em2800 registers */ +#define EM2800_AUDIOSRC_REG 0x08 + /* em28xx registers */ #define CHIPID_REG 0x0a #define USBSUSP_REG 0x0c /* */ @@ -387,6 +395,8 @@ extern const unsigned int em28xx_bcount; #define VIDEO_AC97 0x14 /* register settings */ +#define EM2800_AUDIO_SRC_TUNER 0x0d +#define EM2800_AUDIO_SRC_LINE 0x0c #define EM28XX_AUDIO_SRC_TUNER 0xc0 #define EM28XX_AUDIO_SRC_LINE 0x80 @@ -408,6 +418,12 @@ extern const unsigned int em28xx_bcount; inline static int em28xx_audio_source(struct em28xx *dev, int input) { + if(dev->is_em2800){ + u8 tmp = EM2800_AUDIO_SRC_TUNER; + if(input == EM28XX_AUDIO_SRC_LINE) + tmp = EM2800_AUDIO_SRC_LINE; + em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &tmp, 1); + } return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); } @@ -497,18 +513,21 @@ inline static int em28xx_gamma_set(struct em28xx *dev, s32 val) /*FIXME: maxw should be dependent of alt mode */ inline static unsigned int norm_maxw(struct em28xx *dev) { - switch(dev->model){ - case (EM2820_BOARD_MSI_VOX_USB_2): return(640); - default: return(720); + switch (dev->model) { + case EM2820_BOARD_MSI_VOX_USB_2: + return 640; + default: + return 720; } } inline static unsigned int norm_maxh(struct em28xx *dev) { - switch(dev->model){ - case (EM2820_BOARD_MSI_VOX_USB_2): return(480); - default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480; + switch (dev->model) { + case EM2820_BOARD_MSI_VOX_USB_2: + return 480; + default: + return (dev->norm & V4L2_STD_625_50) ? 576 : 480; } } - #endif diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index d19d73b..38d2ad0 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -227,7 +227,7 @@ int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index) } -int et61x251_read_reg(struct et61x251_device* cam, u16 index) +static int et61x251_read_reg(struct et61x251_device* cam, u16 index) { struct usb_device* udev = cam->usbdev; u8* buff = cam->control_buffer; @@ -268,9 +268,9 @@ et61x251_i2c_wait(struct et61x251_device* cam, } -int -et61x251_i2c_try_read(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, u8 address) +static int et61x251_i2c_try_read(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address) { struct usb_device* udev = cam->usbdev; u8* data = cam->control_buffer; @@ -301,10 +301,9 @@ et61x251_i2c_try_read(struct et61x251_device* cam, } -int -et61x251_i2c_try_write(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, u8 address, - u8 value) +static int et61x251_i2c_try_write(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address, u8 value) { struct usb_device* udev = cam->usbdev; u8* data = cam->control_buffer; @@ -387,13 +386,14 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, } -int et61x251_i2c_read(struct et61x251_device* cam, u8 address) +static int et61x251_i2c_read(struct et61x251_device* cam, u8 address) { return et61x251_i2c_try_read(cam, &cam->sensor, address); } -int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) +static int et61x251_i2c_write(struct et61x251_device* cam, + u8 address, u8 value) { return et61x251_i2c_try_write(cam, &cam->sensor, address, value); } diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h index e145863..71a0314 100644 --- a/drivers/media/video/et61x251/et61x251_sensor.h +++ b/drivers/media/video/et61x251/et61x251_sensor.h @@ -52,14 +52,6 @@ et61x251_attach_sensor(struct et61x251_device* cam, /*****************************************************************************/ extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index); -extern int et61x251_read_reg(struct et61x251_device*, u16 index); -extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value); -extern int et61x251_i2c_read(struct et61x251_device*, u8 address); -extern int et61x251_i2c_try_write(struct et61x251_device*, - const struct et61x251_sensor*, u8 address, - u8 value); -extern int et61x251_i2c_try_read(struct et61x251_device*, - const struct et61x251_sensor*, u8 address); extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1, u8 data2, u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, u8 data8, u8 address); diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 854cc9c..6e5eed5 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -12,6 +12,7 @@ config VIDEO_IVTV select VIDEO_SAA7127 select VIDEO_TVAUDIO select VIDEO_CS53L32A + select VIDEO_M52790 select VIDEO_WM8775 select VIDEO_WM8739 select VIDEO_VP27SMPX diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index b6a8be6..4bb2fe8 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -23,6 +23,7 @@ #include "ivtv-i2c.h" #include +#include #include #include #include @@ -848,7 +849,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_pg600v2, }; @@ -879,7 +880,7 @@ static const struct ivtv_card ivtv_card_club3d = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_club3d, }; @@ -910,11 +911,87 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { }, .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_avertv_mce116, }; +/* ------------------------------------------------------------------------- */ + +/* AVerMedia PVR-150 Plus (M113) card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_pvr150 = { + .type = IVTV_CARD_AVER_PVR150PLUS, + .name = "AVerMedia PVR-150 Plus", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_GPIO, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + .gpio_init = { .direction = 0x0800, .initial_value = 0 }, + .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, + .tuners = { + /* This card has a Partsnic PTI-5NF05 tuner */ + { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N }, + }, + .pci_list = ivtv_pci_aver_pvr150, +}; + +/* ------------------------------------------------------------------------- */ + +/* ASUS Falcon2 */ + +static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_asus_falcon2 = { + .type = IVTV_CARD_ASUS_FALCON2, + .name = "ASUS Falcon2", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_M52790, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, + M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, + .tuners = { + { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + }, + .pci_list = ivtv_pci_asus_falcon2, +}; + static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pvr250, &ivtv_card_pvr350, @@ -937,6 +1014,8 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pg600v2, &ivtv_card_club3d, &ivtv_card_avertv_mce116, + &ivtv_card_asus_falcon2, + &ivtv_card_aver_pvr150, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index ff46e5a..881b044 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -45,7 +45,9 @@ #define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ #define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ #define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ -#define IVTV_CARD_LAST 20 +#define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ +#define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ +#define IVTV_CARD_LAST 22 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -69,6 +71,7 @@ #define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 #define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 #define IVTV_PCI_ID_ADAPTEC 0x9005 +#define IVTV_PCI_ID_ASUSTEK 0x1043 #define IVTV_PCI_ID_AVERMEDIA 0x1461 #define IVTV_PCI_ID_YUAN1 0x12ab #define IVTV_PCI_ID_YUAN2 0xff01 @@ -96,7 +99,8 @@ #define IVTV_HW_SAA717X (1 << 12) #define IVTV_HW_WM8739 (1 << 13) #define IVTV_HW_VP27SMPX (1 << 14) -#define IVTV_HW_GPIO (1 << 15) +#define IVTV_HW_M52790 (1 << 15) +#define IVTV_HW_GPIO (1 << 16) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 6d2dd87..04179b7 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -185,6 +185,8 @@ MODULE_PARM_DESC(cardtype, "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n" "\t\t\t20 = Club3D ZAP-TV1x01\n" "\t\t\t21 = AverTV MCE 116 Plus\n" + "\t\t\t22 = ASUS Falcon2\n" + "\t\t\t23 = AverMedia PVR-150 Plus\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -829,7 +831,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) /* load modules */ #ifndef CONFIG_VIDEO_TUNER if (hw & IVTV_HW_TUNER) { - if (itv->options.tuner == TUNER_XCEIVE_XC3028) { + if (itv->options.tuner == TUNER_XC2028) { IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n"); itv->tunerid = 1; } @@ -882,6 +884,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) if (hw & IVTV_HW_CS53L32A) ivtv_request_module(itv, "cs53l32a"); #endif +#ifndef CONFIG_VIDEO_M52790 + if (hw & IVTV_HW_M52790) + ivtv_request_module(itv, "m52790"); +#endif /* check which i2c devices are actually found */ for (i = 0; i < 32; i++) { diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 623eea2..efa7c47 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -80,6 +80,7 @@ #endif /* I2C_ADAP_CLASS_TV_ANALOG */ #define IVTV_CS53L32A_I2C_ADDR 0x11 +#define IVTV_M52790_I2C_ADDR 0x48 #define IVTV_CX25840_I2C_ADDR 0x44 #define IVTV_SAA7115_I2C_ADDR 0x21 #define IVTV_SAA7127_I2C_ADDR 0x44 @@ -110,6 +111,7 @@ static const u8 hw_driverids[] = { I2C_DRIVERID_SAA717X, I2C_DRIVERID_WM8739, I2C_DRIVERID_VP27SMPX, + I2C_DRIVERID_M52790, 0 /* IVTV_HW_GPIO dummy driver ID */ }; @@ -130,6 +132,7 @@ static const char * const hw_drivernames[] = { "saa717x", "wm8739", "vp27smpx", + "m52790", "gpio", }; diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/video/ivtv/ivtv-routing.c index 398bd33..0556491 100644 --- a/drivers/media/video/ivtv/ivtv-routing.c +++ b/drivers/media/video/ivtv/ivtv-routing.c @@ -25,6 +25,7 @@ #include "ivtv-routing.h" #include +#include #include #include @@ -32,28 +33,26 @@ settings. */ void ivtv_audio_set_io(struct ivtv *itv) { + const struct ivtv_card_audio_input *in; struct v4l2_routing route; - u32 audio_input; - int mux_input; /* Determine which input to use */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - audio_input = itv->card->radio_input.audio_input; - mux_input = itv->card->radio_input.muxer_input; - } else { - audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; - mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; - } + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) + in = &itv->card->radio_input; + else + in = &itv->card->audio_inputs[itv->audio_input]; /* handle muxer chips */ - route.input = mux_input; + route.input = in->muxer_input; route.output = 0; + if (itv->card->hw_muxer & IVTV_HW_M52790) + route.output = M52790_OUT_STEREO; ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); - route.input = audio_input; - if (itv->card->hw_audio & IVTV_HW_MSP34XX) { + route.input = in->audio_input; + route.output = 0; + if (itv->card->hw_audio & IVTV_HW_MSP34XX) route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - } ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); } diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index aa03e61..a5bfbd9 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -43,7 +43,7 @@ #include "ivtv-cards.h" #include "ivtv-streams.h" -static struct file_operations ivtv_v4l2_enc_fops = { +static const struct file_operations ivtv_v4l2_enc_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, @@ -53,7 +53,7 @@ static struct file_operations ivtv_v4l2_enc_fops = { .poll = ivtv_v4l2_enc_poll, }; -static struct file_operations ivtv_v4l2_dec_fops = { +static const struct file_operations ivtv_v4l2_dec_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, @@ -76,7 +76,7 @@ static struct { int minor_offset; int dma, pio; enum v4l2_buf_type buf_type; - struct file_operations *fops; + const struct file_operations *fops; } ivtv_stream_info[] = { { /* IVTV_ENC_STREAM_TYPE_MPG */ "encoder MPG", diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c new file mode 100644 index 0000000..51ecbfb --- /dev/null +++ b/drivers/media/video/m52790.c @@ -0,0 +1,172 @@ +/* + * m52790 i2c ivtv driver. + * Copyright (C) 2007 Hans Verkuil + * + * A/V source switching Mitsubishi M52790SP/FP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static unsigned short normal_i2c[] = { 0x90 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; + +struct m52790_state { + u16 input; + u16 output; +}; + +/* ----------------------------------------------------------------------- */ + +static int m52790_write(struct i2c_client *client) +{ + struct m52790_state *state = i2c_get_clientdata(client); + u8 sw1 = (state->input | state->output) & 0xff; + u8 sw2 = (state->input | state->output) >> 8; + + return i2c_smbus_write_byte_data(client, sw1, sw2); +} + +static int m52790_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct m52790_state *state = i2c_get_clientdata(client); + struct v4l2_routing *route = arg; + + /* Note: audio and video are linked and cannot be switched separately. + So audio and video routing commands are identical for this chip. + In theory the video amplifier and audio modes could be handled + separately for the output, but that seems to be overkill right now. + The same holds for implementing an audio mute control, this is now + part of the audio output routing. The normal case is that another + chip takes care of the actual muting so making it part of the + output routing seems to be the right thing to do for now. */ + switch (cmd) { + case VIDIOC_INT_G_AUDIO_ROUTING: + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = state->input; + route->output = state->output; + break; + + case VIDIOC_INT_S_AUDIO_ROUTING: + case VIDIOC_INT_S_VIDEO_ROUTING: + state->input = route->input; + state->output = route->output; + m52790_write(client); + break; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_register *reg = arg; + + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (reg->reg != 0) + return -EINVAL; + if (cmd == VIDIOC_DBG_G_REGISTER) + reg->val = state->input | state->output; + else { + state->input = reg->val & 0x0303; + state->output = reg->val & ~0x0303; + m52790_write(client); + } + break; + } +#endif + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, arg, + V4L2_IDENT_M52790, 0); + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Switch 1: %02x\n", + (state->input | state->output) & 0xff); + v4l_info(client, "Switch 2: %02x\n", + (state->input | state->output) >> 8); + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +static int m52790_probe(struct i2c_client *client) +{ + struct m52790_state *state; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + snprintf(client->name, sizeof(client->name) - 1, "m52790"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + state->input = M52790_IN_TUNER; + state->output = M52790_OUT_STEREO; + i2c_set_clientdata(client, state); + m52790_write(client); + return 0; +} + +static int m52790_remove(struct i2c_client *client) +{ + kfree(i2c_get_clientdata(client)); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "m52790", + .driverid = I2C_DRIVERID_M52790, + .command = m52790_command, + .probe = m52790_probe, + .remove = m52790_remove, +}; + diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index c311632..3d51fa0 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -2023,7 +2023,7 @@ static int __init meye_init(void) if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE) gbufsize = MEYE_MAX_BUFSIZE; gbufsize = PAGE_ALIGN(gbufsize); - printk(KERN_INFO "meye: using %d buffers with %dk (%dk total)" + printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) " "for capture\n", gbuffers, gbufsize / 1024, gbuffers * gbufsize / 1024); diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index c0c87e0..f4c1460 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -783,7 +784,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) static int msp_suspend(struct i2c_client *client, pm_message_t state) { - v4l_dbg(1, msp_debug, client, "suspend\n"); msp_reset(client); return 0; @@ -791,7 +791,6 @@ static int msp_suspend(struct i2c_client *client, pm_message_t state) static int msp_resume(struct i2c_client *client) { - v4l_dbg(1, msp_debug, client, "resume\n"); msp_wake_thread(client); return 0; @@ -799,11 +798,8 @@ static int msp_resume(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver; - -static int msp_attach(struct i2c_adapter *adapter, int address, int kind) +static int msp_probe(struct i2c_client *client) { - struct i2c_client *client; struct msp_state *state; int (*thread_func)(void *data) = NULL; int msp_hard; @@ -812,24 +808,15 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) int msp_product, msp_prod_hi, msp_prod_lo; int msp_rom; - client = kzalloc(sizeof(*client), GFP_KERNEL); - if (!client) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "msp3400"); if (msp_reset(client) == -1) { v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); - kfree(client); - return 0; + return -ENODEV; } state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) { - kfree(client); return -ENOMEM; } @@ -857,8 +844,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n"); kfree(state); - kfree(client); - return 0; + return -ENODEV; } msp_set_audio(client); @@ -919,7 +905,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) } /* hello world :-) */ - v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); v4l_info(client, "%s ", client->name); if (state->has_nicam && state->has_radio) printk("supports nicam and radio, "); @@ -954,24 +940,12 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) v4l_warn(client, "kernel_thread() failed\n"); msp_wake_thread(client); } - - /* done */ - i2c_attach_client(client); - - return 0; -} - -static int msp_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, msp_attach); return 0; } -static int msp_detach(struct i2c_client *client) +static int msp_remove(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - int err; /* shutdown control thread */ if (state->kthread) { @@ -980,43 +954,22 @@ static int msp_detach(struct i2c_client *client) } msp_reset(client); - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .id = I2C_DRIVERID_MSP3400, - .attach_adapter = msp_probe, - .detach_client = msp_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "msp3400", + .driverid = I2C_DRIVERID_MSP3400, + .command = msp_command, + .probe = msp_probe, + .remove = msp_remove, .suspend = msp_suspend, - .resume = msp_resume, - .command = msp_command, - .driver = { - .name = "msp3400", - }, + .resume = msp_resume, }; -static int __init msp3400_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit msp3400_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(msp3400_init_module); -module_exit(msp3400_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index f49d1f4..b630c26 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -14,7 +14,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "mt20xx " +#define PREFIX "mt20xx" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 2d18f00..41e5e51 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -1230,7 +1231,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client, /* ============ SAA7115 AUDIO settings (end) ============= */ -static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct saa711x_state *state = i2c_get_clientdata(client); @@ -1449,26 +1450,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_saa711x; - -static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) +static int saa7115_probe(struct i2c_client *client) { - struct i2c_client *client; struct saa711x_state *state; int i; char name[17]; u8 chip_id; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_saa711x; snprintf(client->name, sizeof(client->name) - 1, "saa7115"); for (i = 0; i < 0x0f; i++) { @@ -1485,18 +1477,16 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) /* Check whether this chip is part of the saa711x series */ if (memcmp(name, "1f711", 5)) { v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", - address << 1, name); - kfree(client); - return 0; + client->addr << 1, name); + return -ENODEV; } snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id); - v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name); + v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL); i2c_set_clientdata(client, state); if (state == NULL) { - kfree(client); return -ENOMEM; } state->input = -1; @@ -1549,59 +1539,25 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) saa711x_writeregs(client, saa7115_init_misc); saa711x_set_v4lstd(client, V4L2_STD_NTSC); - i2c_attach_client(client); - v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n", saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC)); - return 0; } -static int saa711x_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL) - return i2c_probe(adapter, &addr_data, &saa711x_attach); - return 0; -} +/* ----------------------------------------------------------------------- */ -static int saa711x_detach(struct i2c_client *client) +static int saa7115_remove(struct i2c_client *client) { - struct saa711x_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - - kfree(state); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver_saa711x = { - .driver = { - .name = "saa7115", - }, - .id = I2C_DRIVERID_SAA711X, - .attach_adapter = saa711x_probe, - .detach_client = saa711x_detach, - .command = saa711x_command, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "saa7115", + .driverid = I2C_DRIVERID_SAA711X, + .command = saa7115_command, + .probe = saa7115_probe, + .remove = saa7115_remove, + .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL, }; - -static int __init saa711x_init_module(void) -{ - return i2c_add_driver(&i2c_driver_saa711x); -} - -static void __exit saa711x_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver_saa711x); -} - -module_init(saa711x_init_module); -module_exit(saa711x_cleanup_module); diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index e35ef32..0262acd 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -55,6 +55,7 @@ #include #include #include +#include #include static int debug = 0; @@ -662,31 +663,19 @@ static int saa7127_command(struct i2c_client *client, /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_saa7127; - -/* ----------------------------------------------------------------------- */ - -static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) +static int saa7127_probe(struct i2c_client *client) { - struct i2c_client *client; struct saa7127_state *state; struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ int read_result = 0; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_saa7127; snprintf(client->name, sizeof(client->name) - 1, "saa7127"); - v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", address << 1); + v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", client->addr << 1); /* First test register 0: Bits 5-7 are a version ID (should be 0), and bit 2 should also be 0. @@ -696,14 +685,12 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) if ((saa7127_read(client, 0) & 0xe4) != 0 || (saa7127_read(client, 0x29) & 0x3f) != 0x1d) { v4l_dbg(1, debug, client, "saa7127 not found\n"); - kfree(client); - return 0; + return -ENODEV; } state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL); if (state == NULL) { - kfree(client); - return (-ENOMEM); + return -ENOMEM; } i2c_set_clientdata(client, state); @@ -731,78 +718,34 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { - v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "saa7129 found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result); saa7127_write_inittab(client, saa7129_init_config_extra); state->ident = V4L2_IDENT_SAA7129; } else { - v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "saa7127 found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state->ident = V4L2_IDENT_SAA7127; } - - i2c_attach_client(client); - return 0; } /* ----------------------------------------------------------------------- */ -static int saa7127_probe(struct i2c_adapter *adapter) +static int saa7127_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, saa7127_attach); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_detach(struct i2c_client *client) -{ - struct saa7127_state *state = i2c_get_clientdata(client); - int err; - /* Turn off TV output */ saa7127_set_video_enable(client, 0); - - err = i2c_detach_client(client); - - if (err) { - return err; - } - - kfree(state); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_saa7127 = { - .driver = { - .name = "saa7127", - }, - .id = I2C_DRIVERID_SAA7127, - .attach_adapter = saa7127_probe, - .detach_client = saa7127_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "saa7127", + .driverid = I2C_DRIVERID_SAA7127, .command = saa7127_command, + .probe = saa7127_probe, + .remove = saa7127_remove, }; - -/* ----------------------------------------------------------------------- */ - -static int __init saa7127_init_module(void) -{ - return i2c_add_driver(&i2c_driver_saa7127); -} - -/* ----------------------------------------------------------------------- */ - -static void __exit saa7127_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver_saa7127); -} - -/* ----------------------------------------------------------------------- */ - -module_init(saa7127_init_module); -module_exit(saa7127_cleanup_module); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 4f3dad9..bef4b4f 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -26,6 +26,7 @@ #include "saa7134-reg.h" #include "saa7134.h" #include +#include /* commly used strings */ static char name_mute[] = "mute"; @@ -4206,11 +4207,41 @@ struct pci_device_id saa7134_pci_tbl[] = { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, + .subdevice = 0x6700, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, .subdevice = 0x6701, .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6702, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6703, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6704, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6705, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x153b, .subdevice = 0x1172, .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA, @@ -4350,6 +4381,34 @@ static void board_flyvideo(struct saa7134_dev *dev) /* ----------------------------------------------------------- */ +static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); + + /* Make sure we support the board model */ + switch (tv.model) { + case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */ + case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ + case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ + case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */ + case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */ + case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ + case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", dev->name, tv.model); + break; + } + + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + dev->name, tv.model); +} + +/* ----------------------------------------------------------- */ + int saa7134_board_init1(struct saa7134_dev *dev) { /* Always print gpio, often manufacturers encode tuner type and other info. */ @@ -4569,8 +4628,17 @@ int saa7134_board_init2(struct saa7134_dev *dev) printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { - dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE; - saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf); + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + dev->tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE; + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); } tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; @@ -4621,13 +4689,15 @@ int saa7134_board_init2(struct saa7134_dev *dev) i2c_transfer(&dev->i2c_adap, &msg, 1); } break; + case SAA7134_BOARD_HAUPPAUGE_HVR1110: + hauppauge_eeprom(dev, dev->eedata+0x80); + /* break intentionally omitted */ case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_KWORLD_DVBT_210: case SAA7134_BOARD_TEVION_DVBT_220RF: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_MEDION_MD8800_QUADRO: - case SAA7134_BOARD_HAUPPAUGE_HVR1110: /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index a499eea..7e66d8c 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -294,7 +294,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } /* ------------------------------------------------------------------ */ @@ -313,7 +313,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, buf->activate(dev,buf,NULL); } else if (list_empty(&q->queue)) { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; } else { next = list_entry(q->queue.next,struct saa7134_buf, vb.queue); @@ -322,7 +322,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, } } else { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; } return 0; } @@ -387,7 +387,7 @@ void saa7134_buffer_timeout(unsigned long data) try to start over with the next one. */ if (q->curr) { dprintk("timeout on %p\n",q->curr); - saa7134_buffer_finish(dev,q,STATE_ERROR); + saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR); } saa7134_buffer_next(dev,q); spin_unlock_irqrestore(&dev->slock,flags); @@ -395,8 +395,8 @@ void saa7134_buffer_timeout(unsigned long data) /* resends a current buffer in queue after resume */ -int saa7134_buffer_requeue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q) +static int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q) { struct saa7134_buf *buf, *next; diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 38d8733..566d071 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1072,14 +1072,21 @@ static int dvb_init(struct saa7134_dev *dev) static int dvb_fini(struct saa7134_dev *dev) { - static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; + /* FIXME: I suspect that this code is bogus, since the entry for + Pinnacle 300I DVB-T PAL already defines the proper init to allow + the detection of mt2032 (TDA9887_PORT2_INACTIVE) + */ + if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) { + struct v4l2_priv_tun_config tda9887_cfg; + static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &on; - switch (dev->board) { - case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: /* otherwise we don't detect the tuner on next insmod */ - saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on); - break; - }; + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg); + } + videobuf_dvb_unregister(&dev->dvb); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 75d0c5b..9322f44 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -110,11 +110,8 @@ static int ts_release(struct inode *inode, struct file *file) { struct saa7134_dev *dev = file->private_data; - if (dev->empress_tsq.streaming) - videobuf_streamoff(&dev->empress_tsq); mutex_lock(&dev->empress_tsq.lock); - if (dev->empress_tsq.reading) - videobuf_read_stop(&dev->empress_tsq); + videobuf_stop(&dev->empress_tsq); videobuf_mmap_free(&dev->empress_tsq); dev->empress_users--; diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 6deaad1..800b397 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -323,7 +323,6 @@ static int attach_inform(struct i2c_client *client) { struct saa7134_dev *dev = client->adapter->algo_data; int tuner = dev->tuner_type; - int conf = dev->tda9887_conf; struct tuner_setup tun_setup; d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", @@ -360,7 +359,6 @@ static int attach_inform(struct i2c_client *client) } if (tuner != UNSET) { - tun_setup.type = tuner; tun_setup.addr = saa7134_boards[dev->board].tuner_addr; tun_setup.config = saa7134_boards[dev->board].tuner_config; @@ -372,9 +370,18 @@ static int attach_inform(struct i2c_client *client) client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); } + + if (tuner == TUNER_TDA9887) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + client->driver->command(client, TUNER_SET_CONFIG, + &tda9887_cfg); + } } - client->driver->command(client, TDA9887_SET_CONFIG, &conf); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 3abaa1b..a485185 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -49,7 +49,7 @@ module_param(repeat_delay, int, 0644); MODULE_PARM_DESC(repeat_delay, "delay before key repeat started"); static int repeat_period = 33; module_param(repeat_period, int, 0644); -MODULE_PARM_DESC(repeat_period, "repeat period between" +MODULE_PARM_DESC(repeat_period, "repeat period between " "keypresses when key is down"); #define dprintk(fmt, arg...) if (ir_debug) \ diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 4b63ad3..f1b8fca 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -47,7 +47,7 @@ static int buffer_activate(struct saa7134_dev *dev, { dprintk("buffer_activate [%p]",buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->top_seen = 0; if (NULL == next) @@ -91,7 +91,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, saa7134_dma_free(q,buf); } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -121,7 +121,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE); saa_writel(SAA7134_RS_CONTROL(5),control); - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; return 0; @@ -242,7 +242,7 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) if ((status & 0x100000) != 0x100000) goto done; } - saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); + saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE); } saa7134_buffer_next(dev,&dev->ts_q); diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 81a2aed..f0d5ed9 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -85,7 +85,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long control,base; dprintk("buffer_activate [%p]\n",buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->top_seen = 0; task_init(dev,buf,TASK_A); @@ -136,7 +136,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (buf->vb.size != size) saa7134_dma_free(q,buf); - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -154,7 +154,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; return 0; @@ -240,7 +240,7 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status) goto done; dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount; - saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE); + saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE); } saa7134_buffer_next(dev,&dev->vbi_q); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 3b9ffb4..9c160b2 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -540,7 +540,7 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) /* ------------------------------------------------------------------ */ -void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) +static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { dprintk("set tv norm = %s\n",norm->name); @@ -945,7 +945,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ dprintk("buffer_activate buf=%p\n",buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->top_seen = 0; set_size(dev,TASK_A,buf->vb.width,buf->vb.height, @@ -1054,7 +1054,7 @@ static int buffer_prepare(struct videobuf_queue *q, saa7134_dma_free(q,buf); } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = fh->width; @@ -1074,7 +1074,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; @@ -1236,16 +1236,24 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, restart_overlay = 1; break; case V4L2_CID_PRIVATE_AUTOMUTE: + { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + dev->ctl_automute = c->value; if (dev->tda9887_conf) { if (dev->ctl_automute) dev->tda9887_conf |= TDA9887_AUTOMUTE; else dev->tda9887_conf &= ~TDA9887_AUTOMUTE; - saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG, - &dev->tda9887_conf); + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); } break; + } default: return -EINVAL; } @@ -1413,8 +1421,8 @@ video_poll(struct file *file, struct poll_table_struct *wait) return POLLERR; poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) + if (buf->state == VIDEOBUF_DONE || + buf->state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -1445,10 +1453,7 @@ static int video_release(struct inode *inode, struct file *file) /* stop vbi capture */ if (res_check(fh, RESOURCE_VBI)) { - if (fh->vbi.streaming) - videobuf_streamoff(&fh->vbi); - if (fh->vbi.reading) - videobuf_read_stop(&fh->vbi); + videobuf_stop(&fh->vbi); res_free(dev,fh,RESOURCE_VBI); } @@ -2514,7 +2519,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) goto done; } dev->video_q.curr->vb.field_count = dev->video_fieldcount; - saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE); + saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE); } saa7134_buffer_next(dev,&dev->video_q); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 66a390c..a531e3c 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -481,7 +481,7 @@ struct saa7134_dev { /* i2c i/o */ struct i2c_adapter i2c_adap; struct i2c_client i2c_client; - unsigned char eedata[128]; + unsigned char eedata[256]; /* video overlay */ struct v4l2_framebuffer ovbuf; @@ -596,9 +596,6 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); void saa7134_buffer_timeout(unsigned long data); void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf); -int saa7134_buffer_requeue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q); - int saa7134_set_dmabits(struct saa7134_dev *dev); extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev); @@ -631,7 +628,6 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev, extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; -void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm); int saa7134_videoport_init(struct saa7134_dev *dev); void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile index a56d16f..7ecd5a9 100644 --- a/drivers/media/video/sn9c102/Makefile +++ b/drivers/media/video/sn9c102/Makefile @@ -3,6 +3,7 @@ sn9c102-objs := sn9c102_core.o \ sn9c102_hv7131r.o \ sn9c102_mi0343.o \ sn9c102_mi0360.o \ + sn9c102_mt9v111.o \ sn9c102_ov7630.o \ sn9c102_ov7660.o \ sn9c102_pas106b.o \ diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 5118479..c40ba3a 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -47,7 +47,7 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.47" +#define SN9C102_MODULE_VERSION "1:1.47pre49" #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47) /*****************************************************************************/ @@ -3322,7 +3322,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; - video_set_drvdata(cam->v4ldev, cam); init_completion(&cam->probe); @@ -3340,6 +3339,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); + video_set_drvdata(cam->v4ldev, cam); cam->module_param.force_munmap = force_munmap[dev_nr]; cam->module_param.frame_timeout = frame_timeout[dev_nr]; diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 916054f..35223e0 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -126,6 +126,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); +extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam); extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); @@ -144,6 +145,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ + &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/video/sn9c102/sn9c102_mt9v111.c new file mode 100644 index 0000000..3b98ac3 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_mt9v111.c @@ -0,0 +1,259 @@ +/*************************************************************************** + * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera * + * Controllers * + * * + * Copyright (C) 2007 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static int mt9v111_init(struct sn9c102_device *cam) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + int err = 0; + + err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, + {0x00, 0x03}, {0x1a, 0x04}, + {0x1f, 0x05}, {0x20, 0x06}, + {0x1f, 0x07}, {0x81, 0x08}, + {0x5c, 0x09}, {0x00, 0x0a}, + {0x00, 0x0b}, {0x00, 0x0c}, + {0x00, 0x0d}, {0x00, 0x0e}, + {0x00, 0x0f}, {0x03, 0x10}, + {0x00, 0x11}, {0x00, 0x12}, + {0x02, 0x13}, {0x14, 0x14}, + {0x28, 0x15}, {0x1e, 0x16}, + {0xe2, 0x17}, {0x06, 0x18}, + {0x00, 0x19}, {0x00, 0x1a}, + {0x00, 0x1b}, {0x08, 0x20}, + {0x39, 0x21}, {0x51, 0x22}, + {0x63, 0x23}, {0x73, 0x24}, + {0x82, 0x25}, {0x8f, 0x26}, + {0x9b, 0x27}, {0xa7, 0x28}, + {0xb1, 0x29}, {0xbc, 0x2a}, + {0xc6, 0x2b}, {0xcf, 0x2c}, + {0xd8, 0x2d}, {0xe1, 0x2e}, + {0xea, 0x2f}, {0xf2, 0x30}, + {0x13, 0x84}, {0x00, 0x85}, + {0x25, 0x86}, {0x00, 0x87}, + {0x07, 0x88}, {0x00, 0x89}, + {0xee, 0x8a}, {0x0f, 0x8b}, + {0xe5, 0x8c}, {0x0f, 0x8d}, + {0x2e, 0x8e}, {0x00, 0x8f}, + {0x30, 0x90}, {0x00, 0x91}, + {0xd4, 0x92}, {0x0f, 0x93}, + {0xfc, 0x94}, {0x0f, 0x95}, + {0x14, 0x96}, {0x00, 0x97}, + {0x00, 0x98}, {0x60, 0x99}, + {0x07, 0x9a}, {0x40, 0x9b}, + {0x20, 0x9c}, {0x00, 0x9d}, + {0x00, 0x9e}, {0x00, 0x9f}, + {0x2d, 0xc0}, {0x2d, 0xc1}, + {0x3a, 0xc2}, {0x05, 0xc3}, + {0x04, 0xc4}, {0x3f, 0xc5}, + {0x00, 0xc6}, {0x00, 0xc7}, + {0x50, 0xc8}, {0x3c, 0xc9}, + {0x28, 0xca}, {0xd8, 0xcb}, + {0x14, 0xcc}, {0xec, 0xcd}, + {0x32, 0xce}, {0xdd, 0xcf}, + {0x2d, 0xd0}, {0xdd, 0xd1}, + {0x6a, 0xd2}, {0x50, 0xd3}, + {0x60, 0xd4}, {0x00, 0xd5}, + {0x00, 0xd6}); + + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, + 0x00, 0x01, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x01, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, + 0x04, 0x80, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, + 0x00, 0x04, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, + 0x00, 0x08, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02, + 0x00, 0x16, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, + 0x01, 0xe7, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, + 0x02, 0x87, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, + 0x00, 0x40, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, + 0x00, 0x09, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07, + 0x30, 0x02, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12, + 0x00, 0xb0, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13, + 0x00, 0x7c, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, + 0x00, 0x04, 0, 0); + + return err; +} + +static int mt9v111_get_ctrl(struct sn9c102_device *cam, + struct v4l2_control *ctrl) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + u8 data[2]; + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, + data) < 0) + return -EIO; + ctrl->value = data[1] & 0x80 ? 1 : 0; + return 0; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + +static int mt9v111_set_ctrl(struct sn9c102_device *cam, + const struct v4l2_control *ctrl) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x20, + ctrl->value ? 0x80 : 0x00, + ctrl->value ? 0x80 : 0x00, 0, + 0); + break; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + +static int mt9v111_set_crop(struct sn9c102_device *cam, + const struct v4l2_rect *rect) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + int err = 0; + u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2; + + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + +static int mt9v111_set_pix_format(struct sn9c102_device *cam, + const struct v4l2_pix_format *pix) +{ + int err = 0; + + if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { + err += sn9c102_write_reg(cam, 0xb4, 0x17); + } else { + err += sn9c102_write_reg(cam, 0xe2, 0x17); + } + + return err; +} + + +static const struct sn9c102_sensor mt9v111 = { + .name = "MT9V111", + .maintainer = "Luca Risolia ", + .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x5c, + .init = &mt9v111_init, + .qctrl = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + }, + .get_ctrl = &mt9v111_get_ctrl, + .set_ctrl = &mt9v111_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &mt9v111_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &mt9v111_set_pix_format +}; + + +int sn9c102_probe_mt9v111(struct sn9c102_device *cam) +{ + u8 data[2]; + int err = 0; + + err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, + {0x29, 0x01}, {0x42, 0x17}, + {0x62, 0x17}, {0x08, 0x01}); + err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4, + mt9v111.i2c_slave_id, 0x01, 0x00, + 0x04, 0, 0); + if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111, + mt9v111.i2c_slave_id, 0x36, 2, + data) < 0) + return -EIO; + + if (data[0] != 0x82 || data[1] != 0x3a) + return -ENODEV; + + sn9c102_attach_sensor(cam, &mt9v111); + + return 0; +} diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 4322580..b4d10f7 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -8,6 +8,7 @@ * Muting and tone control by Jonathan Isom * * Copyright (c) 2000 Eric Sandeen + * Copyright (c) 2006 Mauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 @@ -276,7 +277,7 @@ static void do_tda7432_init(struct i2c_client *client) t->volume = 0x3b ; /* -27dB Volume */ if (loudness) /* Turn loudness on? */ t->volume |= TDA7432_LD_ON; - t->muted = VIDEO_AUDIO_MUTE; + t->muted = 1; t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ @@ -332,151 +333,160 @@ static int tda7432_detach(struct i2c_client *client) return 0; } -static int tda7432_command(struct i2c_client *client, - unsigned int cmd, void *arg) +static int tda7432_get_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) { struct tda7432 *t = i2c_get_clientdata(client); - v4l_dbg(2, debug,client,"In tda7432_command\n"); - if (debug>1) - v4l_i2c_print_ioctl(client,cmd); - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - - /* Query card - scale from TDA7432 settings to V4L settings */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE | - VIDEO_AUDIO_MUTABLE; - if (t->muted) - va->flags |= VIDEO_AUDIO_MUTE; - va->mode |= VIDEO_SOUND_STEREO; - /* Master volume control - * V4L volume is min 0, max 65535 - * TDA7432 Volume: - * Min (-79dB) is 0x6f - * Max (+20dB) is 0x07 (630) - * Max (0dB) is 0x20 (829) - * (Mask out bit 7 of vol - it's for the loudness setting) - */ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=t->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: if (!maxvol){ /* max +20db */ - va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630; + ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630; } else { /* max 0db */ - va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829; + ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829; } - - /* Balance depends on L,R attenuation - * V4L balance is 0 to 65535, middle is 32768 - * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f - * to scale up to V4L numbers, mult by 1057 - * attenuation exists for lf, lr, rf, rr - * we use only lf and rf (front channels) - */ - + return 0; + case V4L2_CID_AUDIO_BALANCE: + { if ( (t->lf) < (t->rf) ) /* right is attenuated, balance shifted left */ - va->balance = (32768 - 1057*(t->rf)); + ctrl->value = (32768 - 1057*(t->rf)); else /* left is attenuated, balance shifted right */ - va->balance = (32768 + 1057*(t->lf)); - + ctrl->value = (32768 + 1057*(t->lf)); + return 0; + } + case V4L2_CID_AUDIO_BASS: + { /* Bass/treble 4 bits each */ - va->bass=t->bass; - if(va->bass >= 0x8) - va->bass = ~(va->bass - 0x8) & 0xf; - va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass); - va->treble=t->treble; - if(va->treble >= 0x8) - va->treble = ~(va->treble - 0x8) & 0xf; - va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble); - - break; /* VIDIOCGAUDIO case */ + int bass=t->bass; + if(bass >= 0x8) + bass = ~(bass - 0x8) & 0xf; + ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass); + return 0; } - - /* Set card - scale from V4L settings to TDA7432 settings */ - case VIDIOCSAUDIO: + case V4L2_CID_AUDIO_TREBLE: { - struct video_audio *va = arg; + int treble=t->treble; + if(treble >= 0x8) + treble = ~(treble - 0x8) & 0xf; + ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble); + return 0; + } + } + return -EINVAL; +} - if(va->flags & VIDEO_AUDIO_VOLUME){ - if(!maxvol){ /* max +20db */ - t->volume = 0x6f - ((va->volume)/630); - } else { /* max 0db */ - t->volume = 0x6f - ((va->volume)/829); - } +static int tda7432_set_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) +{ + struct tda7432 *t = i2c_get_clientdata(client); + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + t->muted=ctrl->value; + break; + case V4L2_CID_AUDIO_VOLUME: + if(!maxvol){ /* max +20db */ + t->volume = 0x6f - ((ctrl->value)/630); + } else { /* max 0db */ + t->volume = 0x6f - ((ctrl->value)/829); + } if (loudness) /* Turn on the loudness bit */ t->volume |= TDA7432_LD_ON; - tda7432_write(client,TDA7432_VL, t->volume); - } - - if(va->flags & VIDEO_AUDIO_BASS) - { - t->bass = va->bass >> 12; - if(t->bass>= 0x8) - t->bass = (~t->bass & 0xf) + 0x8 ; - } - if(va->flags & VIDEO_AUDIO_TREBLE) - { - t->treble= va->treble >> 12; - if(t->treble>= 0x8) - t->treble = (~t->treble & 0xf) + 0x8 ; - } - if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS)) - tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); - - if(va->flags & VIDEO_AUDIO_BALANCE) { - if (va->balance < 32768) - { + tda7432_write(client,TDA7432_VL, t->volume); + return 0; + case V4L2_CID_AUDIO_BALANCE: + if (ctrl->value < 32768) { /* shifted to left, attenuate right */ - t->rr = (32768 - va->balance)/1057; + t->rr = (32768 - ctrl->value)/1057; t->rf = t->rr; t->lr = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; - } - else if(va->balance > 32769) - { + } else if(ctrl->value > 32769) { /* shifted to right, attenuate left */ - t->lf = (va->balance - 32768)/1057; + t->lf = (ctrl->value - 32768)/1057; t->lr = t->lf; t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; - } - else - { + } else { /* centered */ t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; t->lr = TDA7432_ATTEN_0DB; } - } + break; + case V4L2_CID_AUDIO_BASS: + t->bass = ctrl->value >> 12; + if(t->bass>= 0x8) + t->bass = (~t->bass & 0xf) + 0x8 ; + + tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); + return 0; + case V4L2_CID_AUDIO_TREBLE: + t->treble= ctrl->value >> 12; + if(t->treble>= 0x8) + t->treble = (~t->treble & 0xf) + 0x8 ; + + tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); + return 0; + default: + return -EINVAL; + } - t->muted=(va->flags & VIDEO_AUDIO_MUTE); - if (t->muted) - { - /* Mute & update balance*/ - tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); - tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); - tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); - tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); - } else { - tda7432_write(client,TDA7432_LF, t->lf); - tda7432_write(client,TDA7432_LR, t->lr); - tda7432_write(client,TDA7432_RF, t->rf); - tda7432_write(client,TDA7432_RR, t->rr); - } + /* Used for both mute and balance changes */ + if (t->muted) + { + /* Mute & update balance*/ + tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); + tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); + tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); + tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); + } else { + tda7432_write(client,TDA7432_LF, t->lf); + tda7432_write(client,TDA7432_LR, t->lr); + tda7432_write(client,TDA7432_RF, t->rf); + tda7432_write(client,TDA7432_RR, t->rr); + } + return 0; +} - break; +static int tda7432_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + v4l_dbg(2, debug,client,"In tda7432_command\n"); + if (debug>1) + v4l_i2c_print_ioctl(client,cmd); + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + default: + return -EINVAL; + } + return v4l2_ctrl_query_fill_std(qc); + } + case VIDIOC_S_CTRL: + return tda7432_set_ctrl(client, arg); - } /* end of VIDEOCSAUDIO case */ + case VIDIOC_G_CTRL: + return tda7432_get_ctrl(client, arg); } /* end of (cmd) switch */ diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 0e5cf45..c606f3c 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -23,14 +23,15 @@ #include #include #include -#include "tuner-i2c.h" #include "tda8290.h" +#include "tda827x.h" +#include "tda18271.h" -static int debug = 0; -module_param(debug, int, 0644); +static int tuner_debug; +module_param_named(debug, tuner_debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tda8290 " +#define PREFIX "tda8290" /* ---------------------------------------------------------------------- */ @@ -38,401 +39,117 @@ struct tda8290_priv { struct tuner_i2c_props i2c_props; unsigned char tda8290_easy_mode; - unsigned char tda827x_lpsel; - unsigned char tda827x_addr; - unsigned char tda827x_ver; - unsigned int sgIF; - - u32 frequency; - - unsigned int *lna_cfg; - int (*tuner_callback) (void *dev, int command,int arg); -}; - -/* ---------------------------------------------------------------------- */ - -struct tda827x_data { - u32 lomax; - u8 spd; - u8 bs; - u8 bp; - u8 cp; - u8 gc3; - u8 div1p5; -}; - - /* Note lomax entry is lo / 62500 */ - -static struct tda827x_data tda827x_analog[] = { - { .lomax = 992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 62 MHz */ - { .lomax = 1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 66 MHz */ - { .lomax = 1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 76 MHz */ - { .lomax = 1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 84 MHz */ - { .lomax = 1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 93 MHz */ - { .lomax = 1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 98 MHz */ - { .lomax = 1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */ - { .lomax = 1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */ - { .lomax = 2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */ - { .lomax = 2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */ - { .lomax = 2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */ - { .lomax = 2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */ - { .lomax = 2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */ - { .lomax = 3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */ - { .lomax = 3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */ - { .lomax = 4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */ - { .lomax = 4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */ - { .lomax = 5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */ - { .lomax = 5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */ - { .lomax = 7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */ - { .lomax = 7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */ - { .lomax = 8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */ - { .lomax = 8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */ - { .lomax = 9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */ - { .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */ - { .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */ - { .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */ - { .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */ - { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ -}; - -static void tda827x_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[8]; - unsigned char reg2[2]; - u32 N; - int i; - struct tda8290_priv *priv = fe->tuner_priv; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; - unsigned int freq = params->frequency; - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - i = 0; - while (tda827x_analog[i].lomax < N) { - if(tda827x_analog[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827x_analog[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0x40; - tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5); - tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) + - (tda827x_analog[i].bs <<3) + tda827x_analog[i].bp; - tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4); - tuner_reg[7] = 0x8f; - - msg.buf = tuner_reg; - msg.len = 8; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msg.buf= reg2; - msg.len = 2; - reg2[0] = 0x80; - reg2[1] = 0; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0xbf; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 0x80; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 4; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4]; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(550); - reg2[0] = 0x30; - reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0x3f; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x80; - reg2[1] = 0x08; // Vsync en - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} - -static void tda827x_agcf(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->tuner_priv; - unsigned char data[] = {0x80, 0x0c}; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, - .flags = 0, .len = 2}; - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} + unsigned char tda827x_addr; -/* ---------------------------------------------------------------------- */ + unsigned char ver; +#define TDA8290 1 +#define TDA8295 2 +#define TDA8275 4 +#define TDA8275A 8 +#define TDA18271 16 -struct tda827xa_data { - u32 lomax; - u8 svco; - u8 spd; - u8 scr; - u8 sbs; - u8 gc3; -}; + struct tda827x_config cfg; -static struct tda827xa_data tda827xa_analog[] = { - { .lomax = 910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, /* 56.875 MHz */ - { .lomax = 1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 67.25 MHz */ - { .lomax = 1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 81.25 MHz */ - { .lomax = 1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 97.5 MHz */ - { .lomax = 1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, /* 113.75 MHz */ - { .lomax = 2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 134.5 MHz */ - { .lomax = 2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 154 MHz */ - { .lomax = 2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 162.5 MHz */ - { .lomax = 2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 183 MHz */ - { .lomax = 3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, /* 195 MHz */ - { .lomax = 3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, /* 227.5 MHz */ - { .lomax = 4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, /* 269 MHz */ - { .lomax = 5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, /* 325 MHz */ - { .lomax = 6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 390 MHz */ - { .lomax = 7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 455 MHz */ - { .lomax = 8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 520 MHz */ - { .lomax = 8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, /* 538 MHz */ - { .lomax = 8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 554 MHz */ - { .lomax = 9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 620 MHz */ - { .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 650 MHz */ - { .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 700 MHz */ - { .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 780 MHz */ - { .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 820 MHz */ - { .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 870 MHz */ - { .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, /* 911 MHz */ - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ + struct tuner *t; }; -static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, - struct analog_parameters *params) -{ - struct tda8290_priv *priv = fe->tuner_priv; - unsigned char buf[] = {0x22, 0x01}; - int arg; - struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; - - if ((priv->lna_cfg == NULL) || (priv->tuner_callback == NULL)) - return; - - if (*priv->lna_cfg) { - if (high) - tuner_dbg("setting LNA to high gain\n"); - else - tuner_dbg("setting LNA to low gain\n"); - } - switch (*priv->lna_cfg) { - case 0: /* no LNA */ - break; - case 1: /* switch is GPIO 0 of tda8290 */ - case 2: - /* turn Vsync on */ - if (params->std & V4L2_STD_MN) - arg = 1; - else - arg = 0; - if (priv->tuner_callback) - priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); - buf[1] = high ? 0 : 1; - if (*priv->lna_cfg == 2) - buf[1] = high ? 1 : 0; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - break; - case 3: /* switch with GPIO of saa713x */ - if (priv->tuner_callback) - priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); - break; - } -} +/*---------------------------------------------------------------------*/ -static void tda827xa_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) { - unsigned char tuner_reg[11]; - u32 N; - int i; - struct tda8290_priv *priv = fe->tuner_priv; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; - unsigned int freq = params->frequency; - - tda827xa_lna_gain(fe, 1, params); - msleep(10); + struct tda8290_priv *priv = fe->analog_demod_priv; - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; + unsigned char enable[2] = { 0x21, 0xC0 }; + unsigned char disable[2] = { 0x21, 0x00 }; + unsigned char *msg; - N = freq + priv->sgIF; - i = 0; - while (tda827xa_analog[i].lomax < N) { - if(tda827xa_analog[i + 1].lomax == 0) - break; - i++; + if (close) { + msg = enable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + /* let the bridge stabilize */ + msleep(20); + } else { + msg = disable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } - N = N << tda827xa_analog[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0; - tuner_reg[4] = 0x16; - tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) + - tda827xa_analog[i].sbs; - tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); - tuner_reg[7] = 0x1c; - tuner_reg[8] = 4; - tuner_reg[9] = 0x20; - tuner_reg[10] = 0x00; - msg.len = 11; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0x90; - tuner_reg[1] = 0xff; - tuner_reg[2] = 0xe0; - tuner_reg[3] = 0; - tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1); - msg.len = 5; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0xa0; - tuner_reg[1] = 0xc0; - msg.len = 2; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0x30; - tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msg.flags = I2C_M_RD; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - msg.flags = 0; - tuner_reg[1] >>= 4; - tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); - if (tuner_reg[1] < 1) - tda827xa_lna_gain(fe, 0, params); - - msleep(100); - tuner_reg[0] = 0x60; - tuner_reg[1] = 0x3c; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(163); - tuner_reg[0] = 0x50; - tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0x80; - tuner_reg[1] = 0x28; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0xb0; - tuner_reg[1] = 0x01; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0xc0; - tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1); - i2c_transfer(priv->i2c_props.adap, &msg, 1); + return 0; } -static void tda827xa_agcf(struct dvb_frontend *fe) +static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) { - struct tda8290_priv *priv = fe->tuner_priv; - unsigned char data[] = {0x80, 0x2c}; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, - .flags = 0, .len = 2}; - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} - -/*---------------------------------------------------------------------*/ + struct tda8290_priv *priv = fe->analog_demod_priv; -static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) -{ - struct tda8290_priv *priv = fe->tuner_priv; - - unsigned char enable[2] = { 0x21, 0xC0 }; - unsigned char disable[2] = { 0x21, 0x00 }; + unsigned char enable[2] = { 0x45, 0xc1 }; + unsigned char disable[2] = { 0x46, 0x00 }; + unsigned char buf[3] = { 0x45, 0x01, 0x00 }; unsigned char *msg; - if(close) { + + if (close) { msg = enable; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); /* let the bridge stabilize */ msleep(20); } else { msg = disable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1); + + buf[2] = msg[1]; + buf[2] &= ~0x04; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); + msleep(5); + + msg[1] |= 0x04; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } + + return 0; } /*---------------------------------------------------------------------*/ -static void set_audio(struct dvb_frontend *fe, - struct analog_parameters *params) +static void set_audio(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; char* mode; - priv->tda827x_lpsel = 0; - if (params->std & V4L2_STD_MN) { - priv->sgIF = 92; + if (t->std & V4L2_STD_MN) { priv->tda8290_easy_mode = 0x01; - priv->tda827x_lpsel = 1; mode = "MN"; - } else if (params->std & V4L2_STD_B) { - priv->sgIF = 108; + } else if (t->std & V4L2_STD_B) { priv->tda8290_easy_mode = 0x02; mode = "B"; - } else if (params->std & V4L2_STD_GH) { - priv->sgIF = 124; + } else if (t->std & V4L2_STD_GH) { priv->tda8290_easy_mode = 0x04; mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - priv->sgIF = 124; + } else if (t->std & V4L2_STD_PAL_I) { priv->tda8290_easy_mode = 0x08; mode = "I"; - } else if (params->std & V4L2_STD_DK) { - priv->sgIF = 124; + } else if (t->std & V4L2_STD_DK) { priv->tda8290_easy_mode = 0x10; mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - priv->sgIF = 124; + } else if (t->std & V4L2_STD_SECAM_L) { priv->tda8290_easy_mode = 0x20; mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - priv->sgIF = 20; + } else if (t->std & V4L2_STD_SECAM_LC) { priv->tda8290_easy_mode = 0x40; mode = "LC"; } else { - priv->sgIF = 124; priv->tda8290_easy_mode = 0x10; mode = "xx"; } - if (params->mode == V4L2_TUNER_RADIO) - priv->sgIF = 88; /* if frequency is 5.5 MHz */ - - tuner_dbg("setting tda8290 to system %s\n", mode); + tuner_dbg("setting tda829x to system %s\n", mode); } -static int tda8290_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static void tda8290_set_freq(struct dvb_frontend *fe, unsigned int freq) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; + unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; @@ -455,10 +172,16 @@ static int tda8290_set_params(struct dvb_frontend *fe, pll_stat; int i; - set_audio(fe, params); + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + set_audio(fe); - if (priv->lna_cfg) - tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg); + tuner_dbg("tda827xa config is 0x%02x\n", t->config); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); @@ -475,10 +198,10 @@ static int tda8290_set_params(struct dvb_frontend *fe, tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); tda8290_i2c_bridge(fe, 1); - if (priv->tda827x_ver != 0) - tda827xa_set_analog_params(fe, params); - else - tda827x_set_analog_params(fe, params); + + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, ¶ms); + for (i = 0; i < 3; i++) { tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); @@ -507,10 +230,8 @@ static int tda8290_set_params(struct dvb_frontend *fe, if ((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); - if (priv->tda827x_ver != 0) - tda827xa_agcf(fe); - else - tda827x_agcf(fe); + if (priv->cfg.agcf) + priv->cfg.agcf(fe); msleep(100); tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); @@ -541,99 +262,249 @@ static int tda8290_set_params(struct dvb_frontend *fe, tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); +} - priv->frequency = (V4L2_TUNER_RADIO == params->mode) ? - params->frequency * 125 / 2 : params->frequency * 62500; +/*---------------------------------------------------------------------*/ - return 0; +static void tda8295_power(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ + + tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); + + if (enable) + buf[1] = 0x01; + else + buf[1] = 0x03; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x01, 0x00 }; + + tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); + + if (enable) + buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ + else + buf[1] = 0x00; /* reset active bit */ + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_video_std(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); + + tda8295_set_easy_mode(fe, 1); + msleep(20); + tda8295_set_easy_mode(fe, 0); } /*---------------------------------------------------------------------*/ -static int tda8290_has_signal(struct dvb_frontend *fe) +static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) { - struct tda8290_priv *priv = fe->tuner_priv; - int ret; + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ - unsigned char i2c_get_afc[1] = { 0x1B }; - unsigned char afc = 0; + tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); - /* for now, report based on afc status */ - tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); - tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); + if (enable) + buf[1] &= ~0x40; + else + buf[1] |= 0x40; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char set_gpio_cf[] = { 0x44, 0x00 }; + unsigned char set_gpio_val[] = { 0x46, 0x00 }; - ret = (afc & 0x80) ? 65535 : 0; + tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1); + tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1); - tuner_dbg("AFC status: %d\n", ret); + set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ - return ret; + if (enable) { + set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ + set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ + } + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); } -static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) +static int tda8295_has_signal(struct dvb_frontend *fe) { - *status = 0; + struct tda8290_priv *priv = fe->analog_demod_priv; - if (tda8290_has_signal(fe)) - *status = TUNER_STATUS_LOCKED; + unsigned char hvpll_stat = 0x26; + unsigned char ret; - return 0; + tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1); + return (ret & 0x01) ? 65535 : 0; } -static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +/*---------------------------------------------------------------------*/ + +static void tda8295_set_freq(struct dvb_frontend *fe, unsigned int freq) { - *strength = tda8290_has_signal(fe); + struct tda8290_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; - return 0; + unsigned char blanking_mode[] = { 0x1d, 0x00 }; + + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + set_audio(fe); + + tuner_dbg("%s: freq = %d\n", __FUNCTION__, freq); + + tda8295_power(fe, 1); + tda8295_agc1_out(fe, 1); + + tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1); + + tda8295_set_video_std(fe); + + blanking_mode[1] = 0x03; + tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); + msleep(20); + + tda8295_i2c_bridge(fe, 1); + + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, ¶ms); + + if (priv->cfg.agcf) + priv->cfg.agcf(fe); + + if (tda8295_has_signal(fe)) + tuner_dbg("tda8295 is locked\n"); + else + tuner_dbg("tda8295 not locked, no signal?\n"); + + tda8295_i2c_bridge(fe, 0); +} + +/*---------------------------------------------------------------------*/ + +static int tda8290_has_signal(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char i2c_get_afc[1] = { 0x1B }; + unsigned char afc = 0; + + tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); + tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); + return (afc & 0x80)? 65535:0; } /*---------------------------------------------------------------------*/ -static int tda8290_standby(struct dvb_frontend *fe) +static void tda8290_standby(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; tda8290_i2c_bridge(fe, 1); - if (priv->tda827x_ver != 0) + if (priv->ver & TDA8275A) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); - - return 0; } +static void tda8295_standby(struct dvb_frontend *fe) +{ + tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ + + tda8295_power(fe, 0); +} static void tda8290_init_if(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((priv->lna_cfg) && - ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2))) + if ((t->config == 1) || (t->config == 2)) tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } +static void tda8295_init_if(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; + static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; + static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; + static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; + static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; + static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; + static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; + + tda8295_power(fe, 1); + + tda8295_set_easy_mode(fe, 0); + tda8295_set_video_std(fe); + + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); + + tda8295_agc1_out(fe, 0); + tda8295_agc2_out(fe, 0); +} + static void tda8290_init_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=tda8275_init, .len = 14}; - if (priv->tda827x_ver != 0) + if (priv->ver & TDA8275A) msg.buf = tda8275a_init; tda8290_i2c_bridge(fe, 1); @@ -643,58 +514,34 @@ static void tda8290_init_tuner(struct dvb_frontend *fe) /*---------------------------------------------------------------------*/ -static int tda8290_release(struct dvb_frontend *fe) +static void tda829x_release(struct dvb_frontend *fe) { - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); - return 0; + kfree(fe->analog_demod_priv); + fe->analog_demod_priv = NULL; } -static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency) +static int tda829x_find_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static struct dvb_tuner_ops tda8290_tuner_ops = { - .sleep = tda8290_standby, - .set_analog_params = tda8290_set_params, - .release = tda8290_release, - .get_frequency = tda8290_get_frequency, - .get_status = tda8290_get_status, - .get_rf_strength = tda8290_get_rf_strength, -}; - -struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr, - struct tda8290_config *cfg) -{ - struct tda8290_priv *priv = NULL; - u8 data; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; + struct tuner *t = priv->t; int i, ret, tuners_found; u32 tuner_addrs; - struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1}; + u8 data; + struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; - priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->tuner_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - if (cfg) { - priv->lna_cfg = cfg->lna_cfg; - priv->tuner_callback = cfg->tuner_callback; - } + if (NULL == ops) + return -EINVAL; + + ops->i2c_gate_ctrl(fe, 1); - tda8290_i2c_bridge(fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; - for (i=0x60; i<= 0x63; i++) { + for (i = 0x60; i <= 0x63; i++) { msg.addr = i; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret == 1) { @@ -706,20 +553,23 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(fe, 0); - if(tuners_found > 1) + + ops->i2c_gate_ctrl(fe, 0); + + if (tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if(ret == 1) + if (ret == 1) tuner_addrs = tuner_addrs >> 8; else break; } + if (tuner_addrs == 0) { - tuner_addrs = 0x61; - tuner_info("could not clearly identify tuner address, defaulting to %x\n", - tuner_addrs); + tuner_addrs = 0x60; + tuner_info("could not clearly identify tuner address, " + "defaulting to %x\n", tuner_addrs); } else { tuner_addrs = tuner_addrs & 0xff; tuner_info("setting tuner address to %x\n", tuner_addrs); @@ -727,42 +577,167 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(fe, 1); + ops->i2c_gate_ctrl(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if( ret != 1) - tuner_warn("TDA827x access failed!\n"); - - memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - if ((data & 0x3c) == 0) { - strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75", - sizeof(fe->ops.tuner_ops.info.name)); - fe->ops.tuner_ops.info.frequency_min = 55000000; - fe->ops.tuner_ops.info.frequency_max = 860000000; - fe->ops.tuner_ops.info.frequency_step = 250000; - priv->tda827x_ver = 0; + + if (ret != 1) { + tuner_warn("tuner access failed!\n"); + return -EREMOTEIO; + } + + if (data == 0x83) { + priv->ver |= TDA18271; + tda18271_attach(&t->fe, priv->tda827x_addr, + priv->i2c_props.adap); } else { - strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a", - sizeof(fe->ops.tuner_ops.info.name)); - fe->ops.tuner_ops.info.frequency_min = 44000000; - fe->ops.tuner_ops.info.frequency_max = 906000000; - fe->ops.tuner_ops.info.frequency_step = 62500; - priv->tda827x_ver = 2; + if ((data & 0x3c) == 0) + priv->ver |= TDA8275; + else + priv->ver |= TDA8275A; + + tda827x_attach(&t->fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); + + /* FIXME: tda827x module doesn't probe the tuner until + * tda827x_initial_sleep is called + */ + if (t->fe.ops.tuner_ops.sleep) + t->fe.ops.tuner_ops.sleep(&t->fe); + } + ops->i2c_gate_ctrl(fe, 0); + + switch (priv->ver) { + case TDA8290 | TDA8275: + strlcpy(t->i2c->name, "tda8290+75", sizeof(t->i2c->name)); + break; + case TDA8295 | TDA8275: + strlcpy(t->i2c->name, "tda8295+75", sizeof(t->i2c->name)); + break; + case TDA8290 | TDA8275A: + strlcpy(t->i2c->name, "tda8290+75a", sizeof(t->i2c->name)); + break; + case TDA8295 | TDA8275A: + strlcpy(t->i2c->name, "tda8295+75a", sizeof(t->i2c->name)); + break; + case TDA8290 | TDA18271: + strlcpy(t->i2c->name, "tda8290+18271", sizeof(t->i2c->name)); + break; + case TDA8295 | TDA18271: + strlcpy(t->i2c->name, "tda8295+18271", sizeof(t->i2c->name)); + break; + default: + return -EINVAL; } - priv->tda827x_lpsel = 0; + return 0; +} + +static int tda8290_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8290_ID 0x89 + unsigned char tda8290_id[] = { 0x1f, 0x00 }; + + /* detect tda8290 */ + tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1); + tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1); + + if (tda8290_id[1] == TDA8290_ID) { + if (tuner_debug) + printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", + __FUNCTION__, i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; + } - tda8290_init_tuner(fe); - tda8290_init_if(fe); - return fe; + return -ENODEV; } -int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) +static int tda8295_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8295_ID 0x8a + unsigned char tda8295_id[] = { 0x2f, 0x00 }; + + /* detect tda8295 */ + tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1); + tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1); + + if (tda8295_id[1] == TDA8295_ID) { + if (tuner_debug) + printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n", + __FUNCTION__, i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; + } + + return -ENODEV; +} + +static struct analog_tuner_ops tda8290_tuner_ops = { + .set_tv_freq = tda8290_set_freq, + .set_radio_freq = tda8290_set_freq, + .has_signal = tda8290_has_signal, + .standby = tda8290_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8290_i2c_bridge, +}; + +static struct analog_tuner_ops tda8295_tuner_ops = { + .set_tv_freq = tda8295_set_freq, + .set_radio_freq = tda8295_set_freq, + .has_signal = tda8295_has_signal, + .standby = tda8295_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8295_i2c_bridge, +}; + +int tda829x_attach(struct tuner *t) +{ + struct dvb_frontend *fe = &t->fe; + struct tda8290_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + fe->analog_demod_priv = priv; + + priv->i2c_props.addr = t->i2c->addr; + priv->i2c_props.adap = t->i2c->adapter; + priv->cfg.config = &t->config; + priv->cfg.tuner_callback = t->tuner_callback; + priv->t = t; + + if (tda8290_probe(&priv->i2c_props) == 0) { + priv->ver = TDA8290; + fe->ops.analog_demod_ops = &tda8290_tuner_ops; + } + + if (tda8295_probe(&priv->i2c_props) == 0) { + priv->ver = TDA8295; + fe->ops.analog_demod_ops = &tda8295_tuner_ops; + } + + if (tda829x_find_tuner(fe) < 0) + return -EINVAL; + + if (priv->ver & TDA8290) { + tda8290_init_tuner(fe); + tda8290_init_if(fe); + } else if (priv->ver & TDA8295) + tda8295_init_if(fe); + + tuner_info("type set to %s\n", t->i2c->name); + + t->mode = V4L2_TUNER_ANALOG_TV; + + return 0; +} +EXPORT_SYMBOL_GPL(tda829x_attach); + +int tda829x_probe(struct tuner *t) { struct tuner_i2c_props i2c_props = { - .adap = i2c_adap, - .addr = i2c_addr + .adap = t->i2c->adapter, + .addr = t->i2c->addr }; unsigned char soft_reset[] = { 0x00, 0x00 }; @@ -771,7 +746,27 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; unsigned char addr_dto_lsb = 0x07; unsigned char data; +#define PROBE_BUFFER_SIZE 8 + unsigned char buf[PROBE_BUFFER_SIZE]; + int i; + + /* rule out tda9887, which would return the same byte repeatedly */ + tuner_i2c_xfer_send(&i2c_props, soft_reset, 1); + tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE); + for (i = 1; i < PROBE_BUFFER_SIZE; i++) { + if (buf[i] != buf[0]) + break; + } + /* all bytes are equal, not a tda829x - probably a tda9887 */ + if (i == PROBE_BUFFER_SIZE) + return -ENODEV; + + if ((tda8290_probe(&i2c_props) == 0) || + (tda8295_probe(&i2c_props) == 0)) + return 0; + + /* fall back to old probing method */ tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); @@ -786,14 +781,12 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) } } tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); - return -1; + return -ENODEV; } +EXPORT_SYMBOL_GPL(tda829x_probe); -EXPORT_SYMBOL_GPL(tda8290_probe); -EXPORT_SYMBOL_GPL(tda8290_attach); - -MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); -MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann"); +MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); +MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); MODULE_LICENSE("GPL"); /* diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 107b24b..3a1f045 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -18,36 +18,24 @@ #define __TDA8290_H__ #include -#include "dvb_frontend.h" - -struct tda8290_config -{ - unsigned int *lna_cfg; - int (*tuner_callback) (void *dev, int command,int arg); -}; +#include "tuner-driver.h" #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) -extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); +extern int tda829x_probe(struct tuner *t); -extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr, - struct tda8290_config *cfg); +extern int tda829x_attach(struct tuner *t); #else -static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) +static inline int tda829x_probe(struct tuner *t) { - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __FUNCTION__); + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return -EINVAL; } -static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr, - struct tda8290_config *cfg) +static inline int tda829x_attach(struct tuner *t) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return NULL; + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; } #endif diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index d110441..3c05571 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -7,6 +7,7 @@ * * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and * Eric Sandeen + * Copyright (c) 2006 Mauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 @@ -268,87 +269,143 @@ static int tda9875_detach(struct i2c_client *client) return 0; } -static int tda9875_command(struct i2c_client *client, - unsigned int cmd, void *arg) +static int tda9875_get_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) { struct tda9875 *t = i2c_get_clientdata(client); - dprintk("In tda9875_command...\n"); + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + { + int left = (t->lvol+84)*606; + int right = (t->rvol+84)*606; - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: + ctrl->value=max(left,right); + return 0; + } + case V4L2_CID_AUDIO_BALANCE: { - struct video_audio *va = arg; - int left,right; + int left = (t->lvol+84)*606; + int right = (t->rvol+84)*606; + int volume = max(left,right); + int balance = (32768*min(left,right))/ + (volume ? volume : 1); + ctrl->value=(leftvalue = (t->bass+12)*2427; /* min -12 max +15 */ + return 0; + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */ + return 0; + } + return -EINVAL; +} - dprintk("VIDIOCGAUDIO\n"); +static int tda9875_set_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) +{ + struct tda9875 *t = i2c_get_clientdata(client); + int chvol=0, volume, balance, left, right; - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + left = (t->lvol+84)*606; + right = (t->rvol+84)*606; + + volume = max(left,right); + balance = (32768*min(left,right))/ + (volume ? volume : 1); + balance =(leftvalue; - /* min is -84 max is 24 */ + chvol=1; + break; + case V4L2_CID_AUDIO_BALANCE: left = (t->lvol+84)*606; right = (t->rvol+84)*606; - va->volume=max(left,right); - va->balance=(32768*min(left,right))/ - (va->volume ? va->volume : 1); - va->balance=(leftbalance) : va->balance; - va->bass = (t->bass+12)*2427; /* min -12 max +15 */ - va->treble = (t->treble+12)*2730;/* min -12 max +12 */ - va->mode |= VIDEO_SOUND_MONO; - - break; /* VIDIOCGAUDIO case */ + + volume=max(left,right); + + balance = ctrl->value; + + chvol=1; + break; + case V4L2_CID_AUDIO_BASS: + t->bass = ((ctrl->value/2400)-12) & 0xff; + if (t->bass > 15) + t->bass = 15; + if (t->bass < -12) + t->bass = -12 & 0xff; + break; + case V4L2_CID_AUDIO_TREBLE: + t->treble = ((ctrl->value/2700)-12) & 0xff; + if (t->treble > 12) + t->treble = 12; + if (t->treble < -12) + t->treble = -12 & 0xff; + break; + default: + return -EINVAL; } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - int left,right; - - dprintk("VIDEOCSAUDIO...\n"); - left = (min(65536 - va->balance,32768) * - va->volume) / 32768; - right = (min(va->balance,(__u16)32768) * - va->volume) / 32768; + if (chvol) { + left = (min(65536 - balance,32768) * + volume) / 32768; + right = (min(balance,32768) * + volume) / 32768; t->lvol = ((left/606)-84) & 0xff; if (t->lvol > 24) - t->lvol = 24; + t->lvol = 24; if (t->lvol < -84) - t->lvol = -84 & 0xff; + t->lvol = -84 & 0xff; t->rvol = ((right/606)-84) & 0xff; if (t->rvol > 24) - t->rvol = 24; + t->rvol = 24; if (t->rvol < -84) - t->rvol = -84 & 0xff; - - t->bass = ((va->bass/2400)-12) & 0xff; - if (t->bass > 15) - t->bass = 15; - if (t->bass < -12) - t->bass = -12 & 0xff; - - t->treble = ((va->treble/2700)-12) & 0xff; - if (t->treble > 12) - t->treble = 12; - if (t->treble < -12) - t->treble = -12 & 0xff; + t->rvol = -84 & 0xff; + } +//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); + tda9875_set(client); -//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); + return 0; +} - tda9875_set(client); +static int tda9875_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + dprintk("In tda9875_command...\n"); - break; + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + default: + return -EINVAL; + } + return v4l2_ctrl_query_fill_std(qc); + } + case VIDIOC_S_CTRL: + return tda9875_set_ctrl(client, arg); - } /* end of VIDEOCSAUDIO case */ + case VIDIOC_G_CTRL: + return tda9875_get_ctrl(client, arg); default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index be5387f..dfa2964 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -9,7 +9,7 @@ #include #include #include -#include "tuner-driver.h" +#include "tda9887.h" /* Chips: @@ -20,18 +20,25 @@ Used as part of several tuners */ +static int tda9887_debug; +module_param_named(debug, tda9887_debug, int, 0644); + #define tda9887_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \ + i2c_adapter_id(priv->t->i2c->adapter), \ + priv->t->i2c->addr, ##arg); } while (0) #define tda9887_dbg(fmt, arg...) do {\ - if (tuner_debug) \ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + if (tda9887_debug) \ + printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \ + i2c_adapter_id(priv->t->i2c->adapter), \ + priv->t->i2c->addr, ##arg); } while (0) struct tda9887_priv { struct tuner_i2c_props i2c_props; unsigned char data[4]; + + struct tuner *t; }; /* ---------------------------------------------------------------------- */ @@ -262,8 +269,10 @@ static struct tvnorm radio_mono = { /* ---------------------------------------------------------------------- */ -static void dump_read_message(struct tuner *t, unsigned char *buf) +static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) { + struct tda9887_priv *priv = fe->analog_demod_priv; + static char *afc[16] = { "- 12.5 kHz", "- 37.5 kHz", @@ -290,8 +299,10 @@ static void dump_read_message(struct tuner *t, unsigned char *buf) tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); } -static void dump_write_message(struct tuner *t, unsigned char *buf) +static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) { + struct tda9887_priv *priv = fe->analog_demod_priv; + static char *sound[4] = { "AM/TV", "FM/radio", @@ -386,9 +397,12 @@ static void dump_write_message(struct tuner *t, unsigned char *buf) /* ---------------------------------------------------------------------- */ -static int tda9887_set_tvnorm(struct tuner *t, char *buf) +static int tda9887_set_tvnorm(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; struct tvnorm *norm = NULL; + char *buf = priv->data; int i; if (t->mode == V4L2_TUNER_RADIO) { @@ -426,8 +440,11 @@ module_param(port2, int, 0644); module_param(qss, int, 0644); module_param(adjust, int, 0644); -static int tda9887_set_insmod(struct tuner *t, char *buf) +static int tda9887_set_insmod(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + if (UNSET != port1) { if (port1) buf[1] |= cOutputPort1Inactive; @@ -455,8 +472,12 @@ static int tda9887_set_insmod(struct tuner *t, char *buf) return 0; } -static int tda9887_set_config(struct tuner *t, char *buf) +static int tda9887_set_config(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; + char *buf = priv->data; + if (t->tda9887_config & TDA9887_PORT1_ACTIVE) buf[1] &= ~cOutputPort1Inactive; if (t->tda9887_config & TDA9887_PORT1_INACTIVE) @@ -510,26 +531,27 @@ static int tda9887_set_config(struct tuner *t, char *buf) /* ---------------------------------------------------------------------- */ -static int tda9887_status(struct tuner *t) +static int tda9887_status(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = fe->analog_demod_priv; unsigned char buf[1]; int rc; memset(buf,0,sizeof(buf)); if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); - dump_read_message(t, buf); + dump_read_message(fe, buf); return 0; } -static void tda9887_configure(struct tuner *t) +static void tda9887_configure(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; int rc; memset(priv->data,0,sizeof(priv->data)); - tda9887_set_tvnorm(t,priv->data); + tda9887_set_tvnorm(fe); /* A note on the port settings: These settings tend to depend on the specifics of the board. @@ -547,8 +569,8 @@ static void tda9887_configure(struct tuner *t) priv->data[1] |= cOutputPort1Inactive; priv->data[1] |= cOutputPort2Inactive; - tda9887_set_config(t,priv->data); - tda9887_set_insmod(t,priv->data); + tda9887_set_config(fe); + tda9887_set_insmod(fe); if (t->mode == T_STANDBY) { priv->data[1] |= cForcedMuteAudioON; @@ -556,29 +578,30 @@ static void tda9887_configure(struct tuner *t) tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1],priv->data[2],priv->data[3]); - if (tuner_debug > 1) - dump_write_message(t, priv->data); + if (tda9887_debug > 1) + dump_write_message(fe, priv->data); if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); - if (tuner_debug > 2) { + if (tda9887_debug > 2) { msleep_interruptible(1000); - tda9887_status(t); + tda9887_status(fe); } } /* ---------------------------------------------------------------------- */ -static void tda9887_tuner_status(struct tuner *t) +static void tda9887_tuner_status(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; - tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); + struct tda9887_priv *priv = fe->analog_demod_priv; + tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); } -static int tda9887_get_afc(struct tuner *t) +static int tda9887_get_afc(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = fe->analog_demod_priv; static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, @@ -594,23 +617,23 @@ static int tda9887_get_afc(struct tuner *t) return afc; } -static void tda9887_standby(struct tuner *t) +static void tda9887_standby(struct dvb_frontend *fe) { - tda9887_configure(t); + tda9887_configure(fe); } -static void tda9887_set_freq(struct tuner *t, unsigned int freq) +static void tda9887_set_freq(struct dvb_frontend *fe, unsigned int freq) { - tda9887_configure(t); + tda9887_configure(fe); } -static void tda9887_release(struct tuner *t) +static void tda9887_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->analog_demod_priv); + fe->analog_demod_priv = NULL; } -static struct tuner_operations tda9887_tuner_ops = { +static struct analog_tuner_ops tda9887_tuner_ops = { .set_tv_freq = tda9887_set_freq, .set_radio_freq = tda9887_set_freq, .standby = tda9887_standby, @@ -619,27 +642,31 @@ static struct tuner_operations tda9887_tuner_ops = { .release = tda9887_release, }; -int tda9887_tuner_init(struct tuner *t) +int tda9887_attach(struct tuner *t) { struct tda9887_priv *priv = NULL; priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - t->priv = priv; + t->fe.analog_demod_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = t->i2c->addr; + priv->i2c_props.adap = t->i2c->adapter; + priv->t = t; - strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name)); + strlcpy(t->i2c->name, "tda9887", sizeof(t->i2c->name)); - tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, - t->i2c.driver->driver.name); + tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c->addr, + t->i2c->driver->driver.name); - memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations)); + t->fe.ops.analog_demod_ops = &tda9887_tuner_ops; return 0; } +EXPORT_SYMBOL_GPL(tda9887_attach); + +MODULE_LICENSE("GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/media/video/tda9887.h b/drivers/media/video/tda9887.h new file mode 100644 index 0000000..b879f0e --- /dev/null +++ b/drivers/media/video/tda9887.h @@ -0,0 +1,33 @@ +/* + 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 __TDA9887_H__ +#define __TDA9887_H__ + +#include "tuner-driver.h" + +/* ------------------------------------------------------------------------ */ +#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE)) +extern int tda9887_attach(struct tuner *t); +#else +static inline int tda9887_attach(struct tuner *t) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return -EINVAL; +} +#endif + +#endif /* __TDA9887_H__ */ diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 2150222..5326eec 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -18,7 +18,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tea5761 " +#define PREFIX "tea5761" struct tea5761_priv { struct tuner_i2c_props i2c_props; diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 71df419..e1b48d8 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -20,12 +20,14 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tea5767 " +#define PREFIX "tea5767" -struct tea5767_priv { - struct tuner_i2c_props i2c_props; +/*****************************************************************************/ - u32 frequency; +struct tea5767_priv { + struct tuner_i2c_props i2c_props; + u32 frequency; + struct tea5767_ctrl ctrl; }; /*****************************************************************************/ @@ -127,17 +129,10 @@ struct tea5767_priv { /* Reserved for future extensions */ #define TEA5767_RESERVED_MASK 0xff -enum tea5767_xtal_freq { - TEA5767_LOW_LO_32768 = 0, - TEA5767_HIGH_LO_32768 = 1, - TEA5767_LOW_LO_13MHz = 2, - TEA5767_HIGH_LO_13MHz = 3, -}; - - /*****************************************************************************/ -static void tea5767_status_dump(unsigned char *buffer) +static void tea5767_status_dump(struct tea5767_priv *priv, + unsigned char *buffer) { unsigned int div, frq; @@ -153,7 +148,7 @@ static void tea5767_status_dump(unsigned char *buffer) div = ((buffer[0] & 0x3f) << 8) | buffer[1]; - switch (TEA5767_HIGH_LO_32768) { + switch (priv->ctrl.xtal_freq) { case TEA5767_HIGH_LO_13MHz: frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ break; @@ -202,13 +197,10 @@ static int set_radio_freq(struct dvb_frontend *fe, tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); - /* Rounds freq to next decimal value - for 62.5 KHz step */ - /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + buffer[2] = 0; - buffer[2] = TEA5767_PORT1_HIGH; - buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | - TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; - buffer[4] = 0; + if (priv->ctrl.port1) + buffer[2] |= TEA5767_PORT1_HIGH; if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); @@ -217,18 +209,45 @@ static int set_radio_freq(struct dvb_frontend *fe, tuner_dbg("TEA5767 set to stereo\n"); } - /* Should be replaced */ - switch (TEA5767_HIGH_LO_32768) { + + buffer[3] = 0; + + if (priv->ctrl.port2) + buffer[3] |= TEA5767_PORT2_HIGH; + + if (priv->ctrl.high_cut) + buffer[3] |= TEA5767_HIGH_CUT_CTRL; + + if (priv->ctrl.st_noise) + buffer[3] |= TEA5767_ST_NOISE_CTL; + + if (priv->ctrl.soft_mute) + buffer[3] |= TEA5767_SOFT_MUTE; + + if (priv->ctrl.japan_band) + buffer[3] |= TEA5767_JAPAN_BAND; + + buffer[4] = 0; + + if (priv->ctrl.deemph_75) + buffer[4] |= TEA5767_DEEMPH_75; + + if (priv->ctrl.pllref) + buffer[4] |= TEA5767_PLLREF_ENABLE; + + + /* Rounds freq to next decimal value - for 62.5 KHz step */ + /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + + switch (priv->ctrl.xtal_freq) { case TEA5767_HIGH_LO_13MHz: tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; - buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_13MHz: tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); - buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_32768: @@ -256,7 +275,7 @@ static int set_radio_freq(struct dvb_frontend *fe, if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else - tea5767_status_dump(buffer); + tea5767_status_dump(priv, buffer); } priv->frequency = frq * 125 / 2; @@ -382,7 +401,6 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) return EINVAL; } - printk(KERN_WARNING "TEA5767 detected.\n"); return 0; } @@ -398,6 +416,16 @@ static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tea5767_priv *priv = fe->tuner_priv; *frequency = priv->frequency; + + return 0; +} + +static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); + return 0; } @@ -407,6 +435,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = { }, .set_analog_params = set_radio_freq, + .set_config = tea5767_set_config, .sleep = tea5767_standby, .release = tea5767_release, .get_frequency = tea5767_get_frequency, @@ -425,8 +454,14 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, return NULL; fe->tuner_priv = priv; - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; + priv->ctrl.port1 = 1; + priv->ctrl.port2 = 1; + priv->ctrl.high_cut = 1; + priv->ctrl.st_noise = 1; + priv->ctrl.japan_band = 1; memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -436,7 +471,6 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, return fe; } - EXPORT_SYMBOL_GPL(tea5767_attach); EXPORT_SYMBOL_GPL(tea5767_autodetection); diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h index 5d78281..a44451f 100644 --- a/drivers/media/video/tea5767.h +++ b/drivers/media/video/tea5767.h @@ -20,6 +20,25 @@ #include #include "dvb_frontend.h" +enum tea5767_xtal { + TEA5767_LOW_LO_32768 = 0, + TEA5767_HIGH_LO_32768 = 1, + TEA5767_LOW_LO_13MHz = 2, + TEA5767_HIGH_LO_13MHz = 3, +}; + +struct tea5767_ctrl { + unsigned int port1:1; + unsigned int port2:1; + unsigned int high_cut:1; + unsigned int st_noise:1; + unsigned int soft_mute:1; + unsigned int japan_band:1; + unsigned int deemph_75:1; + unsigned int pllref:1; + enum tea5767_xtal xtal_freq; +}; + #if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index 76b2e96..e906528 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -31,6 +31,7 @@ #include #include #include +#include MODULE_DESCRIPTION("tlv320aic23b driver"); MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil"); @@ -126,31 +127,18 @@ static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind) +static int tlv320aic23b_probe(struct i2c_client *client) { - struct i2c_client *client; struct tlv320aic23b_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b"); - - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } state->muted = 0; @@ -163,55 +151,22 @@ static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kin tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */ tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */ tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */ - - i2c_attach_client(client); - return 0; } -static int tlv320aic23b_probe(struct i2c_adapter *adapter) +static int tlv320aic23b_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, tlv320aic23b_attach); - return 0; -} - -static int tlv320aic23b_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(client); - + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "tlv320aic23b", - }, - .id = I2C_DRIVERID_TLV320AIC23B, - .attach_adapter = tlv320aic23b_probe, - .detach_client = tlv320aic23b_detach, - .command = tlv320aic23b_command, -}; - -static int __init tlv320aic23b_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit tlv320aic23b_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(tlv320aic23b_init_module); -module_exit(tlv320aic23b_cleanup_module); +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tlv320aic23b", + .driverid = I2C_DRIVERID_TLV320AIC23B, + .command = tlv320aic23b_command, + .probe = tlv320aic23b_probe, + .remove = tlv320aic23b_remove, +}; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9e99f36..e56a419 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,15 +19,20 @@ #include #include #include +#include #include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" #include "tea5767.h" +#include "tuner-xc2028.h" #include "tuner-simple.h" +#include "tda9887.h" #define UNSET (-1U) +#define PREFIX t->i2c->driver->driver.name + /* standard i2c insmod options */ static unsigned short normal_i2c[] = { #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) @@ -71,14 +76,12 @@ MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); -static struct i2c_driver driver; -static struct i2c_client client_template; - /* ---------------------------------------------------------------------- */ -static void fe_set_freq(struct tuner *t, unsigned int freq) +static void fe_set_freq(struct dvb_frontend *fe, unsigned int freq) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; + struct tuner *t = fe->analog_demod_priv; struct analog_parameters params = { .frequency = freq, @@ -91,46 +94,67 @@ static void fe_set_freq(struct tuner *t, unsigned int freq) tuner_warn("Tuner frontend module has no way to set freq\n"); return; } - fe_tuner_ops->set_analog_params(&t->fe, ¶ms); + fe_tuner_ops->set_analog_params(fe, ¶ms); } -static void fe_release(struct tuner *t) +static void fe_release(struct dvb_frontend *fe) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - - if (fe_tuner_ops->release) - fe_tuner_ops->release(&t->fe); + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); + + fe->ops.analog_demod_ops = NULL; + + /* DO NOT kfree(fe->analog_demod_priv) + * + * If we are in this function, analog_demod_priv contains a pointer + * to struct tuner *t. This will be kfree'd in tuner_detach(). + * + * Otherwise, fe->ops.analog_demod_ops->release will + * handle the cleanup for analog demodulator modules. + */ + fe->analog_demod_priv = NULL; } -static void fe_standby(struct tuner *t) +static void fe_standby(struct dvb_frontend *fe) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; if (fe_tuner_ops->sleep) - fe_tuner_ops->sleep(&t->fe); + fe_tuner_ops->sleep(fe); } -static int fe_has_signal(struct tuner *t) +static int fe_has_signal(struct dvb_frontend *fe) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; u16 strength = 0; - if (fe_tuner_ops->get_rf_strength) - fe_tuner_ops->get_rf_strength(&t->fe, &strength); + if (fe->ops.tuner_ops.get_rf_strength) + fe->ops.tuner_ops.get_rf_strength(fe, &strength); return strength; } +static void tuner_status(struct dvb_frontend *fe); + +static struct analog_tuner_ops tuner_core_ops = { + .set_tv_freq = fe_set_freq, + .set_radio_freq = fe_set_freq, + .standby = fe_standby, + .release = fe_release, + .has_signal = fe_has_signal, + .tuner_status = tuner_status +}; + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->ops.set_tv_freq) { + if ((NULL == ops) || (NULL == ops->set_tv_freq)) { tuner_warn ("Tuner has no way to set tv freq\n"); return; } @@ -145,18 +169,19 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - t->ops.set_tv_freq(t, freq); + ops->set_tv_freq(&t->fe, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->ops.set_radio_freq) { + if ((NULL == ops) || (NULL == ops->set_radio_freq)) { tuner_warn ("tuner has no way to set radio frequency\n"); return; } @@ -172,7 +197,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } - t->ops.set_radio_freq(t, freq); + ops->set_radio_freq(&t->fe, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -193,46 +218,39 @@ static void set_freq(struct i2c_client *c, unsigned long freq) set_tv_freq(c, freq); t->tv_freq = freq; break; + default: + tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode); } } static void tuner_i2c_address_check(struct tuner *t) { if ((t->type == UNSET || t->type == TUNER_ABSENT) || - ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f))) + ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f))) return; tuner_warn("====================== WARNING! ======================\n"); tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); tuner_warn("will soon be dropped. This message indicates that your\n"); tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", - t->i2c.name, t->i2c.addr); + t->i2c->name, t->i2c->addr); tuner_warn("To ensure continued support for your device, please\n"); tuner_warn("send a copy of this message, along with full dmesg\n"); tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", - t->i2c.adapter->name, t->i2c.addr, t->type, + t->i2c->adapter->name, t->i2c->addr, t->type, tuners[t->type].name); tuner_warn("====================== WARNING! ======================\n"); } -static void attach_tda8290(struct tuner *t) -{ - struct tda8290_config cfg = { - .lna_cfg = &t->config, - .tuner_callback = t->tuner_callback - }; - tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); -} - static void attach_simple_tuner(struct tuner *t) { struct simple_tuner_config cfg = { .type = t->type, .tun = &tuners[t->type] }; - simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); + simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); } static void set_type(struct i2c_client *c, unsigned int type, @@ -241,6 +259,7 @@ static void set_type(struct i2c_client *c, unsigned int type, { struct tuner *t = i2c_get_clientdata(c); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -260,32 +279,27 @@ static void set_type(struct i2c_client *c, unsigned int type, t->tuner_callback = tuner_callback; } - /* This code detects calls by card attach_inform */ - if (NULL == t->i2c.dev.driver) { + if (t->mode == T_UNINITIALIZED) { tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); return; } /* discard private data, in case set_type() was previously called */ - if (t->ops.release) - t->ops.release(t); - else { - kfree(t->priv); - t->priv = NULL; - } + if (ops && ops->release) + ops->release(&t->fe); switch (t->type) { case TUNER_MT2032: - microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); + microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr); break; case TUNER_PHILIPS_TDA8290: { - attach_tda8290(t); + tda829x_attach(t); break; } case TUNER_TEA5767: - if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { + if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -293,7 +307,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->mode_mask = T_RADIO; break; case TUNER_TEA5761: - if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { + if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -320,25 +334,42 @@ static void set_type(struct i2c_client *c, unsigned int type, i2c_master_send(c,buffer,4); attach_simple_tuner(t); break; + case TUNER_XC2028: + { + struct xc2028_config cfg = { + .i2c_adap = t->i2c->adapter, + .i2c_addr = t->i2c->addr, + .video_dev = c->adapter->algo_data, + .callback = t->tuner_callback, + }; + if (!xc2028_attach(&t->fe, &cfg)) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + break; + } case TUNER_TDA9887: - tda9887_tuner_init(t); + tda9887_attach(t); break; default: attach_simple_tuner(t); break; } - if (fe_tuner_ops->set_analog_params) { - strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); + ops = t->fe.ops.analog_demod_ops; + + if (((NULL == ops) || + ((NULL == ops->set_tv_freq) && (NULL == ops->set_radio_freq))) && + (fe_tuner_ops->set_analog_params)) { + strlcpy(t->i2c->name, fe_tuner_ops->info.name, + sizeof(t->i2c->name)); - t->ops.set_tv_freq = fe_set_freq; - t->ops.set_radio_freq = fe_set_freq; - t->ops.standby = fe_standby; - t->ops.release = fe_release; - t->ops.has_signal = fe_has_signal; + t->fe.ops.analog_demod_ops = &tuner_core_ops; + t->fe.analog_demod_priv = t; } - tuner_info("type set to %s\n", t->i2c.name); + tuner_dbg("type set to %s\n", t->i2c->name); if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -508,10 +539,12 @@ static int tuner_fixup_std(struct tuner *t) return 0; } -static void tuner_status(struct tuner *t) +static void tuner_status(struct dvb_frontend *fe) { + struct tuner *t = fe->analog_demod_priv; unsigned long freq, freq_fraction; struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; const char *p; switch (t->mode) { @@ -541,172 +574,18 @@ static void tuner_status(struct tuner *t) if (tuner_status & TUNER_STATUS_STEREO) tuner_info("Stereo: yes\n"); } - if (t->ops.has_signal) { - tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); - } - if (t->ops.is_stereo) { - tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no"); + if (ops) { + if (ops->has_signal) + tuner_info("Signal strength: %d\n", + ops->has_signal(fe)); + if (ops->is_stereo) + tuner_info("Stereo: %s\n", + ops->is_stereo(fe) ? "yes" : "no"); } } /* ---------------------------------------------------------------------- */ -/* static vars: used only in tuner_attach and tuner_probe */ -static unsigned default_mode_mask; - -/* During client attach, set_type is called by adapter's attach_inform callback. - set_type must then be completed by tuner_attach. - */ -static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) -{ - struct tuner *t; - - client_template.adapter = adap; - client_template.addr = addr; - - t = kzalloc(sizeof(struct tuner), GFP_KERNEL); - if (NULL == t) - return -ENOMEM; - memcpy(&t->i2c, &client_template, sizeof(struct i2c_client)); - i2c_set_clientdata(&t->i2c, t); - t->type = UNSET; - t->audmode = V4L2_TUNER_MODE_STEREO; - t->mode_mask = T_UNINITIALIZED; - t->ops.tuner_status = tuner_status; - - if (show_i2c) { - unsigned char buffer[16]; - int i,rc; - - memset(buffer, 0, sizeof(buffer)); - rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer)); - tuner_info("I2C RECV = "); - for (i=0;iid == I2C_HW_SAA7146 && addr < 0x4a) - return -ENODEV; - - /* autodetection code based on the i2c addr */ - if (!no_autodetect) { - switch (addr) { - case 0x10: - if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { - t->type = TUNER_TEA5761; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - default_mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - case 0x42: - case 0x43: - case 0x4a: - case 0x4b: - /* If chip is not tda8290, don't register. - since it can be tda9887*/ - if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) { - tuner_dbg("chip at addr %x is a tda8290\n", addr); - } else { - /* Default is being tda9887 */ - t->type = TUNER_TDA9887; - t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; - t->mode = T_STANDBY; - goto register_client; - } - break; - case 0x60: - if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { - t->type = TUNER_TEA5767; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - default_mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - } - } - - /* Initializes only the first adapter found */ - if (default_mode_mask != T_UNINITIALIZED) { - tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask); - t->mode_mask = default_mode_mask; - t->tv_freq = 400 * 16; /* Sets freq to VHF High */ - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - default_mode_mask = T_UNINITIALIZED; - } - - /* Should be just before return */ -register_client: - tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); - i2c_attach_client (&t->i2c); - set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback); - return 0; -} - -static int tuner_probe(struct i2c_adapter *adap) -{ - if (0 != addr) { - normal_i2c[0] = addr; - normal_i2c[1] = I2C_CLIENT_END; - } - - /* HACK: Ignore 0x6b and 0x6f on cx88 boards. - * FusionHDTV5 RT Gold has an ir receiver at 0x6b - * and an RTC at 0x6f which can get corrupted if probed. - */ - if ((adap->id == I2C_HW_B_CX2388x) || - (adap->id == I2C_HW_B_CX23885)) { - unsigned int i = 0; - - while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) - i += 2; - if (i + 4 < I2C_CLIENT_MAX_OPTS) { - ignore[i+0] = adap->nr; - ignore[i+1] = 0x6b; - ignore[i+2] = adap->nr; - ignore[i+3] = 0x6f; - ignore[i+4] = I2C_CLIENT_END; - } else - printk(KERN_WARNING "tuner: " - "too many options specified " - "in i2c probe ignore list!\n"); - } - - default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; - - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, tuner_attach); - return 0; -} - -static int tuner_detach(struct i2c_client *client) -{ - struct tuner *t = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(&t->i2c); - if (err) { - tuner_warn - ("Client deregistration failed, client not detached.\n"); - return err; - } - - if (t->ops.release) - t->ops.release(t); - else { - kfree(t->priv); - } - kfree(t); - return 0; -} - /* * Switch tuner to other mode. If tuner support both tv and radio, * set another frequency to some value (This is needed for some pal @@ -716,6 +595,8 @@ static int tuner_detach(struct i2c_client *client) static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) { + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + if (mode == t->mode) return 0; @@ -723,8 +604,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; - if (t->ops.standby) - t->ops.standby(t); + if (ops && ops->standby) + ops->standby(&t->fe); return EINVAL; } return 0; @@ -747,9 +628,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; if (tuner_debug>1) - v4l_i2c_print_ioctl(&(t->i2c),cmd); + v4l_i2c_print_ioctl(client,cmd); switch (cmd) { /* --- configuration --- */ @@ -773,8 +655,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) return 0; t->mode = T_STANDBY; - if (t->ops.standby) - t->ops.standby(t); + if (ops && ops->standby) + ops->standby(&t->fe); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -842,8 +724,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) else vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { - if (t->ops.is_stereo) { - if (t->ops.is_stereo(t)) + if (ops && ops->is_stereo) { + if (ops->is_stereo(&t->fe)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -851,8 +733,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ~VIDEO_TUNER_STEREO_ON; } } - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(t); + if (ops && ops->has_signal) + vt->signal = ops->has_signal(&t->fe); vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -882,21 +764,36 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) fe_tuner_ops->get_status(&t->fe, &tuner_status); va->mode = (tuner_status & TUNER_STATUS_STEREO) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; - } else if (t->ops.is_stereo) - va->mode = t->ops.is_stereo(t) + } else if (ops && ops->is_stereo) + va->mode = ops->is_stereo(&t->fe) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; } return 0; } #endif - case TDA9887_SET_CONFIG: - if (t->type == TUNER_TDA9887) { - int *i = arg; + case TUNER_SET_CONFIG: + { + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct v4l2_priv_tun_config *cfg = arg; - t->tda9887_config = *i; + if (t->type != cfg->tuner) + break; + + if (t->type == TUNER_TDA9887) { + t->tda9887_config = *(unsigned int *)cfg->priv; set_freq(client, t->tv_freq); + break; } + + if (NULL == fe_tuner_ops->set_config) { + tuner_warn("Tuner frontend module has no way to " + "set config\n"); + break; + } + fe_tuner_ops->set_config(&t->fe, cfg->priv); + break; + } /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -958,8 +855,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); tuner->type = t->mode; - if (t->ops.get_afc) - tuner->afc=t->ops.get_afc(t); + if (ops && ops->get_afc) + tuner->afc = ops->get_afc(&t->fe); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -975,16 +872,20 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) u32 tuner_status; fe_tuner_ops->get_status(&t->fe, &tuner_status); - tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + tuner->rxsubchans = + (tuner_status & TUNER_STATUS_STEREO) ? + V4L2_TUNER_SUB_STEREO : + V4L2_TUNER_SUB_MONO; } else { - if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(t) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + if (ops && ops->is_stereo) { + tuner->rxsubchans = + ops->is_stereo(&t->fe) ? + V4L2_TUNER_SUB_STEREO : + V4L2_TUNER_SUB_MONO; } } - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(t); + if (ops && ops->has_signal) + tuner->signal = ops->has_signal(&t->fe); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; @@ -1009,8 +910,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } case VIDIOC_LOG_STATUS: - if (t->ops.tuner_status) - t->ops.tuner_status(t); + if (ops && ops->tuner_status) + ops->tuner_status(&t->fe); break; } @@ -1019,18 +920,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) static int tuner_suspend(struct i2c_client *c, pm_message_t state) { - struct tuner *t = i2c_get_clientdata (c); + struct tuner *t = i2c_get_clientdata(c); - tuner_dbg ("suspend\n"); + tuner_dbg("suspend\n"); /* FIXME: power down ??? */ return 0; } static int tuner_resume(struct i2c_client *c) { - struct tuner *t = i2c_get_clientdata (c); + struct tuner *t = i2c_get_clientdata(c); - tuner_dbg ("resume\n"); + tuner_dbg("resume\n"); if (V4L2_TUNER_RADIO == t->mode) { if (t->radio_freq) set_freq(c, t->radio_freq); @@ -1041,36 +942,226 @@ static int tuner_resume(struct i2c_client *c) return 0; } -/* ----------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- */ -static struct i2c_driver driver = { - .id = I2C_DRIVERID_TUNER, - .attach_adapter = tuner_probe, - .detach_client = tuner_detach, - .command = tuner_command, - .suspend = tuner_suspend, - .resume = tuner_resume, - .driver = { - .name = "tuner", - }, -}; -static struct i2c_client client_template = { - .name = "(tuner unset)", - .driver = &driver, -}; +LIST_HEAD(tuner_list); + +/* Search for existing radio and/or TV tuners on the given I2C adapter. + Note that when this function is called from tuner_probe you can be + certain no other devices will be added/deleted at the same time, I2C + core protects against that. */ +static void tuner_lookup(struct i2c_adapter *adap, + struct tuner **radio, struct tuner **tv) +{ + struct tuner *pos; + + *radio = NULL; + *tv = NULL; + + list_for_each_entry(pos, &tuner_list, list) { + int mode_mask; + + if (pos->i2c->adapter != adap || + pos->i2c->driver->id != I2C_DRIVERID_TUNER) + continue; + + mode_mask = pos->mode_mask & ~T_STANDBY; + if (*radio == NULL && mode_mask == T_RADIO) + *radio = pos; + /* Note: currently TDA9887 is the only demod-only + device. If other devices appear then we need to + make this test more general. */ + else if (*tv == NULL && pos->type != TUNER_TDA9887 && + (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV))) + *tv = pos; + } +} + +/* During client attach, set_type is called by adapter's attach_inform callback. + set_type must then be completed by tuner_probe. + */ +static int tuner_probe(struct i2c_client *client) +{ + struct tuner *t; + struct tuner *radio; + struct tuner *tv; + + t = kzalloc(sizeof(struct tuner), GFP_KERNEL); + if (NULL == t) + return -ENOMEM; + t->i2c = client; + strlcpy(client->name, "(tuner unset)", sizeof(client->name)); + i2c_set_clientdata(client, t); + t->type = UNSET; + t->audmode = V4L2_TUNER_MODE_STEREO; + t->mode_mask = T_UNINITIALIZED; + + if (show_i2c) { + unsigned char buffer[16]; + int i, rc; + + memset(buffer, 0, sizeof(buffer)); + rc = i2c_master_recv(client, buffer, sizeof(buffer)); + tuner_info("I2C RECV = "); + for (i = 0; i < rc; i++) + printk(KERN_CONT "%02x ", buffer[i]); + printk("\n"); + } + /* HACK: This test was added to avoid tuner to probe tda9840 and + tea6415c on the MXB card */ + if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) { + kfree(t); + return -ENODEV; + } + + /* autodetection code based on the i2c addr */ + if (!no_autodetect) { + switch (client->addr) { + case 0x10: + if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr) + != EINVAL) { + t->type = TUNER_TEA5761; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + /* Sets freq to FM range */ + t->radio_freq = 87.5 * 16000; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; + + goto register_client; + } + break; + case 0x42: + case 0x43: + case 0x4a: + case 0x4b: + /* If chip is not tda8290, don't register. + since it can be tda9887*/ + if (tda829x_probe(t) == 0) { + tuner_dbg("tda829x detected\n"); + } else { + /* Default is being tda9887 */ + t->type = TUNER_TDA9887; + t->mode_mask = T_RADIO | T_ANALOG_TV | + T_DIGITAL_TV; + t->mode = T_STANDBY; + goto register_client; + } + break; + case 0x60: + if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) + != EINVAL) { + t->type = TUNER_TEA5767; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + /* Sets freq to FM range */ + t->radio_freq = 87.5 * 16000; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; + + goto register_client; + } + break; + } + } -static int __init tuner_init_module(void) + /* Initializes only the first TV tuner on this adapter. Why only the + first? Because there are some devices (notably the ones with TI + tuners) that have more than one i2c address for the *same* device. + Experience shows that, except for just one case, the first + address is the right one. The exception is a Russian tuner + (ACORP_Y878F). So, the desired behavior is just to enable the + first found TV tuner. */ + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv == NULL) { + t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV; + if (radio == NULL) + t->mode_mask |= T_RADIO; + tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); + t->tv_freq = 400 * 16; /* Sets freq to VHF High */ + t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ + } + + /* Should be just before return */ +register_client: + tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1, + client->adapter->name); + + /* Sets a default mode */ + if (t->mode_mask & T_ANALOG_TV) { + t->mode = T_ANALOG_TV; + } else if (t->mode_mask & T_RADIO) { + t->mode = T_RADIO; + } else { + t->mode = T_DIGITAL_TV; + } + set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback); + list_add_tail(&t->list, &tuner_list); + return 0; +} + +static int tuner_legacy_probe(struct i2c_adapter *adap) { - return i2c_add_driver(&driver); + if (0 != addr) { + normal_i2c[0] = addr; + normal_i2c[1] = I2C_CLIENT_END; + } + + if ((adap->class & I2C_CLASS_TV_ANALOG) == 0) + return 0; + + /* HACK: Ignore 0x6b and 0x6f on cx88 boards. + * FusionHDTV5 RT Gold has an ir receiver at 0x6b + * and an RTC at 0x6f which can get corrupted if probed. + */ + if ((adap->id == I2C_HW_B_CX2388x) || + (adap->id == I2C_HW_B_CX23885)) { + unsigned int i = 0; + + while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) + i += 2; + if (i + 4 < I2C_CLIENT_MAX_OPTS) { + ignore[i+0] = adap->nr; + ignore[i+1] = 0x6b; + ignore[i+2] = adap->nr; + ignore[i+3] = 0x6f; + ignore[i+4] = I2C_CLIENT_END; + } else + printk(KERN_WARNING "tuner: " + "too many options specified " + "in i2c probe ignore list!\n"); + } + return 1; } -static void __exit tuner_cleanup_module(void) +static int tuner_remove(struct i2c_client *client) { - i2c_del_driver(&driver); + struct tuner *t = i2c_get_clientdata(client); + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + + if (ops && ops->release) + ops->release(&t->fe); + + list_del(&t->list); + kfree(t); + return 0; } -module_init(tuner_init_module); -module_exit(tuner_cleanup_module); +/* ----------------------------------------------------------------------- */ + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tuner", + .driverid = I2C_DRIVERID_TUNER, + .command = tuner_command, + .probe = tuner_probe, + .remove = tuner_remove, + .suspend = tuner_suspend, + .resume = tuner_resume, + .legacy_probe = tuner_legacy_probe, +}; + /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 28a10da..a4db32d 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -31,20 +31,22 @@ extern unsigned const int tuner_count; struct tuner; -struct tuner_operations { - void (*set_tv_freq)(struct tuner *t, unsigned int freq); - void (*set_radio_freq)(struct tuner *t, unsigned int freq); - int (*has_signal)(struct tuner *t); - int (*is_stereo)(struct tuner *t); - int (*get_afc)(struct tuner *t); - void (*tuner_status)(struct tuner *t); - void (*standby)(struct tuner *t); - void (*release)(struct tuner *t); +struct analog_tuner_ops { + void (*set_tv_freq)(struct dvb_frontend *fe, unsigned int freq); + void (*set_radio_freq)(struct dvb_frontend *fe, unsigned int freq); + int (*has_signal)(struct dvb_frontend *fe); + int (*is_stereo)(struct dvb_frontend *fe); + int (*get_afc)(struct dvb_frontend *fe); + void (*tuner_status)(struct dvb_frontend *fe); + void (*standby)(struct dvb_frontend *fe); + void (*release)(struct dvb_frontend *fe); + int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); }; struct tuner { /* device */ - struct i2c_client i2c; + struct i2c_client *i2c; + struct list_head list; /* list of tuners */ unsigned int type; /* chip type */ @@ -57,7 +59,6 @@ struct tuner { v4l2_std_id std; int using_v4l2; - void *priv; struct dvb_frontend fe; @@ -66,34 +67,30 @@ struct tuner { unsigned int config; int (*tuner_callback) (void *dev, int command,int arg); - - struct tuner_operations ops; }; /* ------------------------------------------------------------------------ */ -extern int tda9887_tuner_init(struct tuner *t); +#define tuner_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr, ##arg); \ + } while (0) -/* ------------------------------------------------------------------------ */ +#define tuner_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); \ + } while (0) -#define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -#define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -#define tuner_dbg(fmt, arg...) do {\ - extern int tuner_debug; \ - if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) +#define tuner_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); \ + } while (0) -#endif /* __TUNER_DRIVER_H__ */ +#define tuner_dbg(fmt, arg...) do { \ + extern int tuner_debug; \ + if (tuner_debug) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); \ + } while (0) -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ +#endif /* __TUNER_DRIVER_H__ */ diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h index 159019e..b5ac189 100644 --- a/drivers/media/video/tuner-i2c.h +++ b/drivers/media/video/tuner-i2c.h @@ -47,24 +47,30 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, } #ifndef __TUNER_DRIVER_H__ -#define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \ - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) -#define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO PREFIX "%d-%04x: " fmt, \ - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) -#define tuner_dbg(fmt, arg...) do {\ - if ((debug)) \ - printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \ - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr, ##arg); \ + } while (0) + +#define tuner_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr , ##arg); \ + } while (0) + +#define tuner_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr , ##arg); \ + } while (0) + +#define tuner_dbg(fmt, arg...) do { \ + if ((debug)) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr , ##arg); \ + } while (0) #endif /* __TUNER_DRIVER_H__ */ #endif /* __TUNER_I2C_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 7b93d3b..c1db576 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -17,7 +17,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tuner-simple " +#define PREFIX "tuner-simple" static int offset = 0; module_param(offset, int, 0664); @@ -355,10 +355,14 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, } priv->last_div = div; if (t_params->has_tda9887) { + struct v4l2_priv_tun_config tda9887_cfg; int config = 0; int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &config; + if (params->std == V4L2_STD_SECAM_LC) { if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) config |= TDA9887_PORT1_ACTIVE; @@ -391,7 +395,8 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, } if (t_params->default_pll_gating_18) config |= TDA9887_GATING_18; - i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); } tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); @@ -534,6 +539,11 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, if (t_params->has_tda9887) { int config = 0; + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &config; + if (t_params->port1_active && !t_params->port1_fm_high_sensitivity) config |= TDA9887_PORT1_ACTIVE; if (t_params->port2_active && !t_params->port2_fm_high_sensitivity) @@ -546,7 +556,8 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, config |= TDA9887_GAIN_NORMAL; if (t_params->radio_if == 2) config |= TDA9887_RIF_41_3; - i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); } if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index c6a7934..e2cd05a 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -1366,7 +1366,7 @@ struct tunertype tuners[] = { .count = ARRAY_SIZE(tuner_philips_fq1286_params), }, [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ - .name = "tda8290+75", + .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", /* see tda8290.c for details */ }, [TUNER_TCL_2002MB] = { /* TCL PAL */ .name = "TCL 2002MB", @@ -1452,9 +1452,9 @@ struct tunertype tuners[] = { .params = tuner_samsung_tcpn_2121p30a_params, .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), }, - [TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */ - .name = "Xceive xc3028", - /* see xc3028.c for details */ + [TUNER_XC2028] = { /* Xceive 2028 */ + .name = "Xceive xc2028/xc3028 tuner", + /* see tuner-xc2028.c for details */ }, [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ .name = "Thomson FE6600", diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h new file mode 100644 index 0000000..a9e2e05 --- /dev/null +++ b/drivers/media/video/tuner-xc2028-types.h @@ -0,0 +1,115 @@ +/* tuner-xc2028_types + * + * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +/* xc3028 firmware types */ + +/* BASE firmware should be loaded before any other firmware */ +#define BASE (1<<0) + +/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ +#define F8MHZ (1<<1) + +/* Multichannel Television Sound (MTS) + Those firmwares are capable of using xc2038 DSP to decode audio and + produce a baseband audio output on some pins of the chip. + There are MTS firmwares for the most used video standards. It should be + required to use MTS firmwares, depending on the way audio is routed into + the bridge chip + */ +#define MTS (1<<2) + +/* FIXME: I have no idea what's the difference between + D2620 and D2633 firmwares + */ +#define D2620 (1<<3) +#define D2633 (1<<4) + +/* DTV firmwares for 6, 7 and 8 MHz + DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS + DTV8 - 8MHz - DVB-C/DVB-T + */ +#define DTV6 (1 << 5) +#define QAM (1 << 6) +#define DTV7 (1<<7) +#define DTV78 (1<<8) +#define DTV8 (1<<9) + +/* There's a FM | BASE firmware + FM specific firmware (std=0) */ +#define FM (1<<10) + +/* Applies only for FM firmware + Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) + */ +#define INPUT1 (1<<11) + + +/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + There are variants both with and without NOGD + */ +#define LCD (1<<12) + +/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + */ +#define NOGD (1<<13) + +/* Old firmwares were broken into init0 and init1 */ +#define INIT1 (1<<14) + +#define MONO (1 << 15) +#define ATSC (1 << 16) +#define IF (1 << 17) +#define LG60 (1 << 18) +#define ATI638 (1 << 19) +#define OREN538 (1 << 20) +#define OREN36 (1 << 21) +#define TOYOTA388 (1 << 22) +#define TOYOTA794 (1 << 23) +#define DIBCOM52 (1 << 24) +#define ZARLINK456 (1 << 25) +#define CHINA (1 << 26) +#define F6MHZ (1 << 27) +#define INPUT2 (1 << 28) +#define SCODE (1 << 29) + +/* Newer types to be moved to videodev2.h */ + +#define V4L2_STD_SECAM_K3 (0x04000000) + +/* Audio types */ + +#define V4L2_STD_A2_A (1LL<<32) +#define V4L2_STD_A2_B (1LL<<33) +#define V4L2_STD_NICAM_A (1LL<<34) +#define V4L2_STD_NICAM_B (1LL<<35) +#define V4L2_STD_AM (1LL<<36) +#define V4L2_STD_BTSC (1LL<<37) +#define V4L2_STD_EIAJ (1LL<<38) + +#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) +#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) + +/* To preserve backward compatibilty, + (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported + */ + +#define V4L2_STD_AUDIO (V4L2_STD_A2 | \ + V4L2_STD_NICAM | \ + V4L2_STD_AM | \ + V4L2_STD_BTSC | \ + V4L2_STD_EIAJ) + +/* Used standards with audio restrictions */ + +#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) +#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) +#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) +#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) +#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) +#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c new file mode 100644 index 0000000..d23b33a --- /dev/null +++ b/drivers/media/video/tuner-xc2028.c @@ -0,0 +1,970 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * + * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) + * - frontend interface + * + * This code is placed under the terms of the GNU General Public License v2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tuner-xc2028.h" +#include "tuner-xc2028-types.h" + +#include +#include "dvb_frontend.h" + + +#define PREFIX "xc2028" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static char audio_std[8]; +module_param_string(audio_std, audio_std, sizeof(audio_std), 0); +MODULE_PARM_DESC(audio_std, + "Audio standard. XC3028 audio decoder explicitly " + "needs to know what audio\n" + "standard is needed for some video standards with audio A2 or NICAM.\n" + "The valid values are:\n" + "A2\n" + "A2/A\n" + "A2/B\n" + "NICAM\n" + "NICAM/A\n" + "NICAM/B\n"); + +static LIST_HEAD(xc2028_list); +/* struct for storing firmware table */ +struct firmware_description { + unsigned int type; + v4l2_std_id id; + unsigned char *ptr; + unsigned int size; +}; + +struct xc2028_data { + struct list_head xc2028_list; + struct tuner_i2c_props i2c_props; + int (*tuner_callback) (void *dev, + int command, int arg); + void *video_dev; + int count; + __u32 frequency; + + struct firmware_description *firm; + int firm_size; + + __u16 version; + + struct xc2028_ctrl ctrl; + + v4l2_std_id firm_type; /* video stds supported + by current firmware */ + fe_bandwidth_t bandwidth; /* Firmware bandwidth: + 6M, 7M or 8M */ + int need_load_generic; /* The generic firmware + were loaded? */ + + int max_len; /* Max firmware chunk */ + + enum tuner_mode mode; + struct i2c_client *i2c_client; + + struct mutex lock; +}; + +#define i2c_send(rc, priv, buf, size) do { \ + rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ + if (size != rc) \ + tuner_err("i2c output error: rc = %d (should be %d)\n", \ + rc, (int)size); \ +} while (0) + +#define i2c_rcv(rc, priv, buf, size) do { \ + rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ + if (size != rc) \ + tuner_err("i2c input error: rc = %d (should be %d)\n", \ + rc, (int)size); \ +} while (0) + +#define send_seq(priv, data...) do { \ + int rc; \ + static u8 _val[] = data; \ + if (sizeof(_val) != \ + (rc = tuner_i2c_xfer_send(&priv->i2c_props, \ + _val, sizeof(_val)))) { \ + tuner_err("Error on line %d: %d\n", __LINE__, rc); \ + return -EINVAL; \ + } \ + msleep(10); \ +} while (0) + +static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg) +{ + int rc; + unsigned char buf[2]; + + tuner_dbg("%s called\n", __FUNCTION__); + + buf[0] = reg>>8; + buf[1] = (unsigned char) reg; + + i2c_send(rc, priv, buf, 2); + if (rc < 0) + return rc; + + i2c_rcv(rc, priv, buf, 2); + if (rc < 0) + return rc; + + return (buf[1]) | (buf[0] << 8); +} + +void dump_firm_type(unsigned int type) +{ + if (type & BASE) + printk("BASE "); + if (type & INIT1) + printk("INIT1 "); + if (type & F8MHZ) + printk("F8MHZ "); + if (type & MTS) + printk("MTS "); + if (type & D2620) + printk("D2620 "); + if (type & D2633) + printk("D2633 "); + if (type & DTV6) + printk("DTV6 "); + if (type & QAM) + printk("QAM "); + if (type & DTV7) + printk("DTV7 "); + if (type & DTV78) + printk("DTV78 "); + if (type & DTV8) + printk("DTV8 "); + if (type & FM) + printk("FM "); + if (type & INPUT1) + printk("INPUT1 "); + if (type & LCD) + printk("LCD "); + if (type & NOGD) + printk("NOGD "); + if (type & MONO) + printk("MONO "); + if (type & ATSC) + printk("ATSC "); + if (type & IF) + printk("IF "); + if (type & LG60) + printk("LG60 "); + if (type & ATI638) + printk("ATI638 "); + if (type & OREN538) + printk("OREN538 "); + if (type & OREN36) + printk("OREN36 "); + if (type & TOYOTA388) + printk("TOYOTA388 "); + if (type & TOYOTA794) + printk("TOYOTA794 "); + if (type & DIBCOM52) + printk("DIBCOM52 "); + if (type & ZARLINK456) + printk("ZARLINK456 "); + if (type & CHINA) + printk("CHINA "); + if (type & F6MHZ) + printk("F6MHZ "); + if (type & INPUT2) + printk("INPUT2 "); + if (type & SCODE) + printk("SCODE "); +} + +static v4l2_std_id parse_audio_std_option(void) +{ + if (strcasecmp(audio_std, "A2")) + return V4L2_STD_A2; + if (strcasecmp(audio_std, "A2/A")) + return V4L2_STD_A2_A; + if (strcasecmp(audio_std, "A2/B")) + return V4L2_STD_A2_B; + if (strcasecmp(audio_std, "NICAM")) + return V4L2_STD_NICAM; + if (strcasecmp(audio_std, "NICAM/A")) + return V4L2_STD_NICAM_A; + if (strcasecmp(audio_std, "NICAM/B")) + return V4L2_STD_NICAM_B; + + return 0; +} + +static void free_firmware(struct xc2028_data *priv) +{ + int i; + + if (!priv->firm) + return; + + for (i = 0; i < priv->firm_size; i++) + kfree(priv->firm[i].ptr); + + kfree(priv->firm); + + priv->firm = NULL; + priv->need_load_generic = 1; +} + +static int load_all_firmwares(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + const struct firmware *fw = NULL; + unsigned char *p, *endp; + int rc = 0; + int n, n_array; + char name[33]; + + tuner_dbg("%s called\n", __FUNCTION__); + + tuner_info("Reading firmware %s\n", priv->ctrl.fname); + rc = request_firmware(&fw, priv->ctrl.fname, + &priv->i2c_props.adap->dev); + if (rc < 0) { + if (rc == -ENOENT) + tuner_err("Error: firmware %s not found.\n", + priv->ctrl.fname); + else + tuner_err("Error %d while requesting firmware %s \n", + rc, priv->ctrl.fname); + + return rc; + } + p = fw->data; + endp = p + fw->size; + + if (fw->size < sizeof(name) - 1 + 2) { + tuner_err("Error: firmware size is zero!\n"); + rc = -EINVAL; + goto done; + } + + memcpy(name, p, sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + p += sizeof(name) - 1; + + priv->version = le16_to_cpu(*(__u16 *) p); + p += 2; + + tuner_info("Firmware: %s, ver %d.%d\n", name, + priv->version >> 8, priv->version & 0xff); + + if (p + 2 > endp) + goto corrupt; + + n_array = le16_to_cpu(*(__u16 *) p); + p += 2; + + tuner_info("There are %d firmwares at %s\n", + n_array, priv->ctrl.fname); + + priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); + + if (!fw) { + tuner_err("Not enough memory for reading firmware.\n"); + rc = -ENOMEM; + goto done; + } + + priv->firm_size = n_array; + n = -1; + while (p < endp) { + __u32 type, size; + v4l2_std_id id; + + n++; + if (n >= n_array) { + tuner_err("Too much firmwares at the file\n"); + goto corrupt; + } + + /* 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; + } + + type = le32_to_cpu(*(__u32 *) p); + p += sizeof(type); + + id = le64_to_cpu(*(v4l2_std_id *) p); + p += sizeof(id); + + size = le32_to_cpu(*(__u32 *) p); + p += sizeof(size); + + if ((!size) || (size + p > endp)) { + tuner_err("Firmware type "); + dump_firm_type(type); + printk("(%x), id %llx is corrupted " + "(size=%d, expected %d)\n", + type, id, + (unsigned)(endp - p), size); + goto corrupt; + } + + priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); + if (!priv->firm[n].ptr) { + tuner_err("Not enough memory.\n"); + rc = -ENOMEM; + goto err; + } + tuner_info("Reading firmware type "); + dump_firm_type(type); + printk("(%x), id %lx, size=%d.\n", + type, (unsigned long)id, size); + + memcpy(priv->firm[n].ptr, p, size); + priv->firm[n].type = type; + priv->firm[n].id = id; + priv->firm[n].size = size; + + p += size; + } + + if (n + 1 != priv->firm_size) { + tuner_err("Firmware file is incomplete!\n"); + goto corrupt; + } + + goto done; + +corrupt: + rc = -EINVAL; + tuner_err("Error: firmware file is corrupted!\n"); + +err: + tuner_info("Releasing loaded firmware file.\n"); + + free_firmware(priv); + +done: + release_firmware(fw); + tuner_dbg("Firmware files loaded.\n"); + + return rc; +} + +static int seek_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int i; + + tuner_dbg("%s called\n", __FUNCTION__); + + if (!priv->firm) { + tuner_err("Error! firmware not loaded\n"); + return -EINVAL; + } + + if (((type & ~SCODE) == 0) && (*id == 0)) + *id = V4L2_STD_PAL; + + /* Seek for exact match */ + for (i = 0; i < priv->firm_size; i++) { + if ((type == priv->firm[i].type) && (*id == priv->firm[i].id)) + goto found; + } + + /* Seek for generic video standard match */ + for (i = 0; i < priv->firm_size; i++) { + if ((type == priv->firm[i].type) && (*id & priv->firm[i].id)) + goto found; + } + + /*FIXME: Would make sense to seek for type "hint" match ? */ + + i = -EINVAL; + goto ret; + +found: + *id = priv->firm[i].id; + +ret: + tuner_dbg("%s firmware for type=", (i < 0)? "Can't find": "Found"); + if (debug) { + dump_firm_type(type); + printk("(%x), id %08lx.\n", type, (unsigned long)*id); + } + return i; +} + +static int load_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p, *endp, buf[priv->max_len]; + + tuner_dbg("%s called\n", __FUNCTION__); + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + tuner_info("Loading firmware for type="); + dump_firm_type(type); + printk("(%x), id %08lx.\n", type, (unsigned long)*id); + + p = priv->firm[pos].ptr; + + if (!p) { + tuner_err("Firmware pointer were freed!"); + return -EINVAL; + } + endp = p + priv->firm[pos].size; + + while (p < endp) { + __u16 size; + + /* Checks if there's enough bytes to read */ + if (p + sizeof(size) > endp) { + tuner_err("Firmware chunk size is wrong\n"); + return -EINVAL; + } + + size = le16_to_cpu(*(__u16 *) p); + p += sizeof(size); + + if (size == 0xffff) + return 0; + + if (!size) { + /* Special callback command received */ + rc = priv->tuner_callback(priv->video_dev, + XC2028_TUNER_RESET, 0); + if (rc < 0) { + tuner_err("Error at RESET code %d\n", + (*p) & 0x7f); + return -EINVAL; + } + continue; + } + if (size >= 0xff00) { + switch (size) { + case 0xff00: + rc = priv->tuner_callback(priv->video_dev, + XC2028_RESET_CLK, 0); + if (rc < 0) { + tuner_err("Error at RESET code %d\n", + (*p) & 0x7f); + return -EINVAL; + } + default: + tuner_info("Invalid RESET code %d\n", + size & 0x7f); + return -EINVAL; + + } + continue; + } + + /* Checks for a sleep command */ + if (size & 0x8000) { + msleep(size & 0x7fff); + continue; + } + + if ((size + p > endp)) { + tuner_err("missing bytes: need %d, have %d\n", + size, (int)(endp - p)); + return -EINVAL; + } + + buf[0] = *p; + p++; + size--; + + /* Sends message chunks */ + while (size > 0) { + int len = (size < priv->max_len - 1) ? + size : priv->max_len - 1; + + memcpy(buf + 1, p, len); + + i2c_send(rc, priv, buf, len + 1); + if (rc < 0) { + tuner_err("%d returned from send\n", rc); + return -EINVAL; + } + + p += len; + size -= len; + } + } + return 0; +} + +static int load_scode(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id, int scode) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + + tuner_dbg("%s called\n", __FUNCTION__); + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + p = priv->firm[pos].ptr; + + if (!p) { + tuner_err("Firmware pointer were freed!"); + return -EINVAL; + } + + if ((priv->firm[pos].size != 12 * 16) || (scode >= 16)) + return -EINVAL; + + if (priv->version < 0x0202) { + send_seq(priv, {0x20, 0x00, 0x00, 0x00}); + } else { + send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); + } + + i2c_send(rc, priv, p + 12 * scode, 12); + + send_seq(priv, {0x00, 0x8c}); + + return 0; +} + +static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, + v4l2_std_id std, fe_bandwidth_t bandwidth) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc, version, hwmodel; + v4l2_std_id std0 = 0; + unsigned int type0 = 0, type = 0; + int change_digital_bandwidth; + + tuner_dbg("%s called\n", __FUNCTION__); + + if (!priv->firm) { + if (!priv->ctrl.fname) { + tuner_info("xc2028/3028 firmware name not set!\n"); + return -EINVAL; + } + + rc = load_all_firmwares(fe); + if (rc < 0) + return rc; + } + + tuner_dbg("I am in mode %u and I should switch to mode %i\n", + priv->mode, new_mode); + + /* first of all, determine whether we have switched the mode */ + if (new_mode != priv->mode) { + priv->mode = new_mode; + priv->need_load_generic = 1; + } + + change_digital_bandwidth = (priv->mode == T_DIGITAL_TV + && bandwidth != priv->bandwidth) ? 1 : 0; + tuner_dbg("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, + bandwidth); + + if (priv->need_load_generic) { + /* Reset is needed before loading firmware */ + rc = priv->tuner_callback(priv->video_dev, + XC2028_TUNER_RESET, 0); + if (rc < 0) + return rc; + + type0 = BASE; + + if (priv->ctrl.type == XC2028_FIRM_MTS) + type0 |= MTS; + + if (priv->bandwidth == 8) + type0 |= F8MHZ; + + /* FIXME: How to load FM and FM|INPUT1 firmwares? */ + + rc = load_firmware(fe, type0, &std0); + if (rc < 0) { + tuner_err("Error %d while loading generic firmware\n", + rc); + return rc; + } + + priv->need_load_generic = 0; + priv->firm_type = 0; + if (priv->mode == T_DIGITAL_TV) + change_digital_bandwidth = 1; + } + + tuner_dbg("I should change bandwidth %u\n", change_digital_bandwidth); + + if (change_digital_bandwidth) { + + /*FIXME: Should allow selecting between D2620 and D2633 */ + type |= D2620; + + /* FIXME: When should select a DTV78 firmware? + */ + switch (bandwidth) { + case BANDWIDTH_8_MHZ: + type |= DTV8; + break; + case BANDWIDTH_7_MHZ: + type |= DTV7; + break; + case BANDWIDTH_6_MHZ: + /* FIXME: Should allow select also ATSC */ + type |= DTV6 | QAM; + break; + + default: + tuner_err("error: bandwidth not supported.\n"); + }; + priv->bandwidth = bandwidth; + } + + if (!change_digital_bandwidth && priv->mode == T_DIGITAL_TV) + return 0; + + /* Load INIT1, if needed */ + tuner_dbg("Load init1 firmware, if exists\n"); + type0 = BASE | INIT1; + if (priv->ctrl.type == XC2028_FIRM_MTS) + type0 |= MTS; + + /* FIXME: Should handle errors - if INIT1 found */ + rc = load_firmware(fe, type0, &std0); + + /* FIXME: Should add support for FM radio + */ + + if (priv->ctrl.type == XC2028_FIRM_MTS) + type |= MTS; + + if (priv->firm_type & std) { + tuner_dbg("Std-specific firmware already loaded.\n"); + return 0; + } + + /* Add audio hack to std mask */ + std |= parse_audio_std_option(); + + rc = load_firmware(fe, type, &std); + if (rc < 0) + return rc; + + /* Load SCODE firmware, if exists */ + tuner_dbg("Trying to load scode 0\n"); + type |= SCODE; + + rc = load_scode(fe, type, &std, 0); + + version = xc2028_get_reg(priv, 0x0004); + hwmodel = xc2028_get_reg(priv, 0x0008); + + tuner_info("Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, + (version & 0xf0) >> 4, version & 0xf); + + priv->firm_type = std; + + return 0; +} + +static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) +{ + struct xc2028_data *priv = fe->tuner_priv; + int frq_lock, signal = 0; + + tuner_dbg("%s called\n", __FUNCTION__); + + mutex_lock(&priv->lock); + + *strength = 0; + + /* Sync Lock Indicator */ + frq_lock = xc2028_get_reg(priv, 0x0002); + if (frq_lock <= 0) + goto ret; + + /* Frequency is locked. Return signal quality */ + + /* Get SNR of the video signal */ + signal = xc2028_get_reg(priv, 0x0040); + + if (signal <= 0) + signal = frq_lock; + +ret: + mutex_unlock(&priv->lock); + + *strength = signal; + + return 0; +} + +#define DIV 15625 + +static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , + enum tuner_mode new_mode, + v4l2_std_id std, fe_bandwidth_t bandwidth) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc = -EINVAL; + unsigned char buf[5]; + u32 div, offset = 0; + + tuner_dbg("%s called\n", __FUNCTION__); + + mutex_lock(&priv->lock); + + /* HACK: It seems that specific firmware need to be reloaded + when freq is changed */ + + priv->firm_type = 0; + + /* Reset GPIO 1 */ + rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0); + if (rc < 0) + goto ret; + + msleep(10); + tuner_dbg("should set frequency %d kHz)\n", freq / 1000); + + if (check_firmware(fe, new_mode, std, bandwidth) < 0) + goto ret; + + if (new_mode == T_DIGITAL_TV) + offset = 2750000; + + div = (freq - offset + DIV / 2) / DIV; + + /* CMD= Set frequency */ + + if (priv->version < 0x0202) { + send_seq(priv, {0x00, 0x02, 0x00, 0x00}); + } else { + send_seq(priv, {0x80, 0x02, 0x00, 0x00}); + } + + rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); + if (rc < 0) + goto ret; + + msleep(10); + + buf[0] = 0xff & (div >> 24); + buf[1] = 0xff & (div >> 16); + buf[2] = 0xff & (div >> 8); + buf[3] = 0xff & (div); + buf[4] = 0; + + i2c_send(rc, priv, buf, sizeof(buf)); + if (rc < 0) + goto ret; + msleep(100); + + priv->frequency = freq; + + tuner_dbg("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", + buf[1], buf[2], buf[3], buf[4], + freq / 1000000, (freq % 1000000) / 10000); + + rc = 0; + +ret: + mutex_unlock(&priv->lock); + + return rc; +} + +static int xc2028_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *p) +{ + struct xc2028_data *priv = fe->tuner_priv; + + tuner_dbg("%s called\n", __FUNCTION__); + + return generic_set_tv_freq(fe, 62500l * p->frequency, T_ANALOG_TV, + p->std, BANDWIDTH_8_MHZ /* NOT USED */); +} + +static int xc2028_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct xc2028_data *priv = fe->tuner_priv; + + tuner_dbg("%s called\n", __FUNCTION__); + + /* FIXME: Only OFDM implemented */ + if (fe->ops.info.type != FE_OFDM) { + tuner_err("DTV type not implemented.\n"); + return -EINVAL; + } + + return generic_set_tv_freq(fe, p->frequency, T_DIGITAL_TV, + 0 /* NOT USED */, + p->u.ofdm.bandwidth); + +} + +static int xc2028_dvb_release(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + + tuner_dbg("%s called\n", __FUNCTION__); + + priv->count--; + + if (!priv->count) { + list_del(&priv->xc2028_list); + + kfree(priv->ctrl.fname); + + free_firmware(priv); + kfree(priv); + } + + return 0; +} + +static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct xc2028_data *priv = fe->tuner_priv; + + tuner_dbg("%s called\n", __FUNCTION__); + + *frequency = priv->frequency; + + return 0; +} + +static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct xc2028_data *priv = fe->tuner_priv; + struct xc2028_ctrl *p = priv_cfg; + + tuner_dbg("%s called\n", __FUNCTION__); + + priv->ctrl.type = p->type; + + if (p->fname) { + kfree(priv->ctrl.fname); + + priv->ctrl.fname = kmalloc(strlen(p->fname) + 1, GFP_KERNEL); + if (!priv->ctrl.fname) + return -ENOMEM; + + free_firmware(priv); + strcpy(priv->ctrl.fname, p->fname); + } + + if (p->max_len > 0) + priv->max_len = p->max_len; + + return 0; +} + +static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { + .info = { + .name = "Xceive XC3028", + .frequency_min = 42000000, + .frequency_max = 864000000, + .frequency_step = 50000, + }, + + .set_config = xc2028_set_config, + .set_analog_params = xc2028_set_tv_freq, + .release = xc2028_dvb_release, + .get_frequency = xc2028_get_frequency, + .get_rf_strength = xc2028_signal, + .set_params = xc2028_set_params, + +}; + +void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) +{ + struct xc2028_data *priv; + void *video_dev; + + if (debug) + printk(KERN_DEBUG PREFIX "Xcv2028/3028 init called!\n"); + + if (NULL == cfg->video_dev) + return NULL; + + if (!fe) { + printk(KERN_ERR PREFIX "No frontend!\n"); + return NULL; + } + + video_dev = cfg->video_dev; + + list_for_each_entry(priv, &xc2028_list, xc2028_list) { + if (priv->video_dev == cfg->video_dev) { + video_dev = NULL; + break; + } + } + + if (video_dev) { + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->need_load_generic = 1; + priv->mode = T_UNINITIALIZED; + priv->i2c_props.addr = cfg->i2c_addr; + priv->i2c_props.adap = cfg->i2c_adap; + priv->video_dev = video_dev; + priv->tuner_callback = cfg->callback; + priv->max_len = 13; + + mutex_init(&priv->lock); + + list_add_tail(&priv->xc2028_list, &xc2028_list); + } + + fe->tuner_priv = priv; + priv->count++; + + memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, + sizeof(xc2028_dvb_tuner_ops)); + + tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); + + return fe; +} + +EXPORT_SYMBOL(xc2028_attach); + +MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); +MODULE_AUTHOR("Michel Ludwig "); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h new file mode 100644 index 0000000..a20eeb4 --- /dev/null +++ b/drivers/media/video/tuner-xc2028.h @@ -0,0 +1,48 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +#ifndef __TUNER_XC2028_H__ +#define __TUNER_XC2028_H__ + +#include "dvb_frontend.h" + +#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" + +enum xc2028_firm_type { + XC2028_FIRM_NORMAL, + XC2028_FIRM_MTS, +}; + +struct xc2028_ctrl { + enum xc2028_firm_type type; + char *fname; + int max_len; +}; + +struct xc2028_config { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + void *video_dev; + int (*callback) (void *dev, int command, int arg); +}; + +/* xc2028 commands for callback */ +#define XC2028_TUNER_RESET 0 +#define XC2028_RESET_CLK 1 + +#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) +void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg); +#else +void *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} +#endif + +#endif /* __TUNER_XC2028_H__ */ diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index a19cdcc..a755605 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -109,7 +110,7 @@ static struct CHIPDESC chiplist[]; /* current state of the chip */ struct CHIPSTATE { - struct i2c_client c; + struct i2c_client *c; /* index into CHIPDESC array */ int type; @@ -145,10 +146,6 @@ static unsigned short normal_i2c[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; -static struct i2c_driver driver; -static struct i2c_client client_template; - - /* ---------------------------------------------------------------------- */ /* i2c I/O functions */ @@ -157,24 +154,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) unsigned char buffer[2]; if (-1 == subaddr) { - v4l_dbg(1, debug, &chip->c, "%s: chip_write: 0x%x\n", - chip->c.name, val); + v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n", + chip->c->name, val); chip->shadow.bytes[1] = val; buffer[0] = val; - if (1 != i2c_master_send(&chip->c,buffer,1)) { - v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n", - chip->c.name, val); + if (1 != i2c_master_send(chip->c,buffer,1)) { + v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n", + chip->c->name, val); return -1; } } else { - v4l_dbg(1, debug, &chip->c, "%s: chip_write: reg%d=0x%x\n", - chip->c.name, subaddr, val); + v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n", + chip->c->name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; - if (2 != i2c_master_send(&chip->c,buffer,2)) { - v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n", - chip->c.name, subaddr, val); + if (2 != i2c_master_send(chip->c,buffer,2)) { + v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n", + chip->c->name, subaddr, val); return -1; } } @@ -197,12 +194,12 @@ static int chip_read(struct CHIPSTATE *chip) { unsigned char buffer; - if (1 != i2c_master_recv(&chip->c,&buffer,1)) { - v4l_warn(&chip->c, "%s: I/O error (read)\n", - chip->c.name); + if (1 != i2c_master_recv(chip->c,&buffer,1)) { + v4l_warn(chip->c, "%s: I/O error (read)\n", + chip->c->name); return -1; } - v4l_dbg(1, debug, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer); + v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer); return buffer; } @@ -211,17 +208,17 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr) unsigned char write[1]; unsigned char read[1]; struct i2c_msg msgs[2] = { - { chip->c.addr, 0, 1, write }, - { chip->c.addr, I2C_M_RD, 1, read } + { chip->c->addr, 0, 1, write }, + { chip->c->addr, I2C_M_RD, 1, read } }; write[0] = subaddr; - if (2 != i2c_transfer(chip->c.adapter,msgs,2)) { - v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name); + if (2 != i2c_transfer(chip->c->adapter,msgs,2)) { + v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name); return -1; } - v4l_dbg(1, debug, &chip->c, "%s: chip_read2: reg%d=0x%x\n", - chip->c.name, subaddr,read[0]); + v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n", + chip->c->name, subaddr,read[0]); return read[0]; } @@ -233,8 +230,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) return 0; /* update our shadow register set; print bytes if (debug > 0) */ - v4l_dbg(1, debug, &chip->c, "%s: chip_cmd(%s): reg=%d, data:", - chip->c.name, name,cmd->bytes[0]); + v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:", + chip->c->name, name,cmd->bytes[0]); for (i = 1; i < cmd->count; i++) { if (debug) printk(" 0x%x",cmd->bytes[i]); @@ -244,8 +241,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) printk("\n"); /* send data to the chip */ - if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) { - v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name); + if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) { + v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name); return -1; } return 0; @@ -269,7 +266,7 @@ static int chip_thread(void *data) struct CHIPSTATE *chip = data; struct CHIPDESC *desc = chiplist + chip->type; - v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name); set_freezable(); for (;;) { set_current_state(TASK_INTERRUPTIBLE); @@ -279,7 +276,7 @@ static int chip_thread(void *data) try_to_freeze(); if (kthread_should_stop()) break; - v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name); /* don't do anything for radio or if mode != auto */ if (chip->radio || chip->mode != 0) @@ -292,7 +289,7 @@ static int chip_thread(void *data) mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); } - v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name); return 0; } @@ -304,17 +301,19 @@ static void generic_checkmode(struct CHIPSTATE *chip) if (mode == chip->prevmode) return; - v4l_dbg(1, debug, &chip->c, "%s: thread checkmode\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name); chip->prevmode = mode; - if (mode & VIDEO_SOUND_STEREO) - desc->setmode(chip,VIDEO_SOUND_STEREO); - else if (mode & VIDEO_SOUND_LANG1) - desc->setmode(chip,VIDEO_SOUND_LANG1); - else if (mode & VIDEO_SOUND_LANG2) - desc->setmode(chip,VIDEO_SOUND_LANG2); + if (mode & V4L2_TUNER_MODE_STEREO) + desc->setmode(chip,V4L2_TUNER_MODE_STEREO); + if (mode & V4L2_TUNER_MODE_LANG1_LANG2) + desc->setmode(chip,V4L2_TUNER_MODE_STEREO); + else if (mode & V4L2_TUNER_MODE_LANG1) + desc->setmode(chip,V4L2_TUNER_MODE_LANG1); + else if (mode & V4L2_TUNER_MODE_LANG2) + desc->setmode(chip,V4L2_TUNER_MODE_LANG2); else - desc->setmode(chip,VIDEO_SOUND_MONO); + desc->setmode(chip,V4L2_TUNER_MODE_MONO); } /* ---------------------------------------------------------------------- */ @@ -345,13 +344,13 @@ static int tda9840_getmode(struct CHIPSTATE *chip) int val, mode; val = chip_read(chip); - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if (val & TDA9840_DS_DUAL) - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; if (val & TDA9840_ST_STEREO) - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; - v4l_dbg(1, debug, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", + v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -362,16 +361,16 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode) int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e; switch (mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: t |= TDA9840_MONO; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: t |= TDA9840_STEREO; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: t |= TDA9840_DUALA; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: t |= TDA9840_DUALB; break; default: @@ -502,7 +501,7 @@ static int tda985x_getmode(struct CHIPSTATE *chip) chip_read(chip)) >> 4; /* Add mono mode regardless of SAP and stereo */ /* Allows forced mono */ - return mode | VIDEO_SOUND_MONO; + return mode | V4L2_TUNER_MODE_MONO; } static void tda985x_setmode(struct CHIPSTATE *chip, int mode) @@ -511,13 +510,13 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode) int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f; switch (mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: c6 |= TDA985x_MONO; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: c6 |= TDA985x_STEREO; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: c6 |= TDA985x_SAP; break; default: @@ -650,12 +649,12 @@ static int tda9873_getmode(struct CHIPSTATE *chip) int val,mode; val = chip_read(chip); - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if (val & TDA9873_STEREO) - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; if (val & TDA9873_DUAL) - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - v4l_dbg(1, debug, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -666,24 +665,24 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): external input\n"); + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n"); return; } - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); switch (mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: sw_data |= TDA9873_TR_MONO; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: sw_data |= TDA9873_TR_STEREO; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: sw_data |= TDA9873_TR_DUALA; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: sw_data |= TDA9873_TR_DUALB; break; default: @@ -692,7 +691,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) } chip_write(chip, TDA9873_SW, sw_data); - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n", + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data); } @@ -831,7 +830,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip) chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */ } - v4l_dbg(1, debug, &chip->c, "tda9874a_setup(): %s [0x%02X].\n", + v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n", tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); return 1; } @@ -841,7 +840,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) int dsr,nsr,mode; int necr; /* just for debugging */ - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR))) return mode; @@ -860,21 +859,21 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) * that sound has (temporarily) switched from NICAM to * mono FM (or AM) on 1st sound carrier due to high NICAM bit * error count. So in fact there is no stereo in this case :-( - * But changing the mode to VIDEO_SOUND_MONO would switch + * But changing the mode to V4L2_TUNER_MODE_MONO would switch * external 4052 multiplexer in audio_hook(). */ if(nsr & 0x02) /* NSR.S/MB=1 */ - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; if(nsr & 0x01) /* NSR.D/SB=1 */ - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } else { if(dsr & 0x02) /* DSR.IDSTE=1 */ - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; if(dsr & 0x04) /* DSR.IDDUA=1 */ - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } - v4l_dbg(1, debug, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", dsr, nsr, necr, mode); return mode; } @@ -902,14 +901,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) int mdacosr = (tda9874a_mode) ? 0x82:0x80; switch(mode) { - case VIDEO_SOUND_MONO: - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_STEREO: break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: aosr = 0x80; /* auto-select, dual A/A */ mdacosr = (tda9874a_mode) ? 0x82:0x80; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: aosr = 0xa0; /* auto-select, dual B/B */ mdacosr = (tda9874a_mode) ? 0x83:0x81; break; @@ -920,18 +919,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_AOSR, aosr); chip_write(chip, TDA9874A_MDACOSR, mdacosr); - v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", mode, aosr, mdacosr); } else { /* dic == 0x07 */ int fmmr,aosr; switch(mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: fmmr = 0x00; /* mono */ aosr = 0x10; /* A/A */ break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: if(tda9874a_mode) { fmmr = 0x00; aosr = 0x00; /* handled by NICAM auto-mute */ @@ -940,11 +939,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) aosr = 0x00; } break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: fmmr = 0x02; /* dual */ aosr = 0x10; /* dual A/A */ break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: fmmr = 0x02; /* dual */ aosr = 0x20; /* dual B/B */ break; @@ -955,7 +954,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_FMMR, fmmr); chip_write(chip, TDA9874A_AOSR, aosr); - v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", mode, fmmr, aosr); } } @@ -969,10 +968,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip) if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) return 0; - v4l_dbg(1, debug, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); + v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); if((dic == 0x11)||(dic == 0x07)) { - v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h"); + v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h"); tda9874a_dic = dic; /* remember device id. */ return 1; } @@ -1095,7 +1094,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip) int inputmap[4] = { /* tuner */ TDA8425_S1_CH2, /* radio */ TDA8425_S1_CH1, /* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF}; - if (chip->c.adapter->id == I2C_HW_B_RIVA) { + if (chip->c->adapter->id == I2C_HW_B_RIVA) { memcpy (desc->inputmap, inputmap, sizeof (inputmap)); } return 0; @@ -1105,20 +1104,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode) { int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1; - if (mode & VIDEO_SOUND_LANG1) { + if (mode & V4L2_TUNER_MODE_LANG1) { s1 |= TDA8425_S1_ML_SOUND_A; s1 |= TDA8425_S1_STEREO_PSEUDO; - } else if (mode & VIDEO_SOUND_LANG2) { + } else if (mode & V4L2_TUNER_MODE_LANG2) { s1 |= TDA8425_S1_ML_SOUND_B; s1 |= TDA8425_S1_STEREO_PSEUDO; } else { s1 |= TDA8425_S1_ML_STEREO; - if (mode & VIDEO_SOUND_MONO) + if (mode & V4L2_TUNER_MODE_MONO) s1 |= TDA8425_S1_STEREO_MONO; - if (mode & VIDEO_SOUND_STEREO) + if (mode & V4L2_TUNER_MODE_STEREO) s1 |= TDA8425_S1_STEREO_SPATIAL; } chip_write(chip,TDA8425_S1,s1); @@ -1177,13 +1176,13 @@ static int ta8874z_getmode(struct CHIPSTATE *chip) int val, mode; val = chip_read(chip); - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if (val & TA8874Z_B1){ - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; }else if (!(val & TA8874Z_B0)){ - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; } - /* v4l_dbg(1, debug, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ + /* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ return mode; } @@ -1196,19 +1195,19 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; audiocmd *t = NULL; - v4l_dbg(1, debug, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); + v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); switch(mode){ - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: t = &ta8874z_mono; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: t = &ta8874z_stereo; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: t = &ta8874z_main; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: t = &ta8874z_sub; break; default: @@ -1462,51 +1461,55 @@ static struct CHIPDESC chiplist[] = { /* ---------------------------------------------------------------------- */ /* i2c registration */ -static int chip_attach(struct i2c_adapter *adap, int addr, int kind) +static int chip_probe(struct i2c_client *client) { struct CHIPSTATE *chip; struct CHIPDESC *desc; + if (debug) { + printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); + printk(KERN_INFO "tvaudio: known chips: "); + for (desc = chiplist; desc->name != NULL; desc++) + printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); + printk("\n"); + } + chip = kzalloc(sizeof(*chip),GFP_KERNEL); if (!chip) return -ENOMEM; - memcpy(&chip->c,&client_template,sizeof(struct i2c_client)); - chip->c.adapter = adap; - chip->c.addr = addr; - i2c_set_clientdata(&chip->c, chip); + chip->c = client; + i2c_set_clientdata(client, chip); /* find description for the chip */ - v4l_dbg(1, debug, &chip->c, "chip found @ 0x%x\n", addr<<1); + v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; - if (addr < desc->addr_lo || - addr > desc->addr_hi) + if (client->addr < desc->addr_lo || + client->addr > desc->addr_hi) continue; if (desc->checkit && !desc->checkit(chip)) continue; break; } if (desc->name == NULL) { - v4l_dbg(1, debug, &chip->c, "no matching chip description found\n"); + v4l_dbg(1, debug, client, "no matching chip description found\n"); return -EIO; } - v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name); if (desc->flags) { - v4l_dbg(1, debug, &chip->c, "matches:%s%s%s.\n", + v4l_dbg(1, debug, client, "matches:%s%s%s.\n", (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); } /* fill required data structures */ - strcpy(chip->c.name, desc->name); + strcpy(client->name, desc->name); chip->type = desc-chiplist; chip->shadow.count = desc->registers+1; chip->prevmode = -1; chip->audmode = V4L2_TUNER_MODE_LANG1; - /* register */ - i2c_attach_client(&chip->c); /* initialization */ if (desc->initialize != NULL) @@ -1533,28 +1536,17 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) init_timer(&chip->wt); chip->wt.function = chip_thread_wake; chip->wt.data = (unsigned long)chip; - chip->thread = kthread_run(chip_thread, chip, chip->c.name); + chip->thread = kthread_run(chip_thread, chip, chip->c->name); if (IS_ERR(chip->thread)) { - v4l_warn(&chip->c, "%s: failed to create kthread\n", - chip->c.name); + v4l_warn(chip->c, "%s: failed to create kthread\n", + chip->c->name); chip->thread = NULL; } } return 0; } -static int chip_probe(struct i2c_adapter *adap) -{ - /* don't attach on saa7146 based cards, - because dedicated drivers are used */ - if ((adap->id == I2C_HW_SAA7146)) - return 0; - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, chip_attach); - return 0; -} - -static int chip_detach(struct i2c_client *client) +static int chip_remove(struct i2c_client *client) { struct CHIPSTATE *chip = i2c_get_clientdata(client); @@ -1565,12 +1557,52 @@ static int chip_detach(struct i2c_client *client) chip->thread = NULL; } - i2c_detach_client(&chip->c); kfree(chip); return 0; } -static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl) +static int tvaudio_get_ctrl(struct CHIPSTATE *chip, + struct v4l2_control *ctrl) +{ + struct CHIPDESC *desc = chiplist + chip->type; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=chip->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: + if (!desc->flags & CHIP_HAS_VOLUME) + break; + ctrl->value = max(chip->left,chip->right); + return 0; + case V4L2_CID_AUDIO_BALANCE: + { + int volume; + if (!desc->flags & CHIP_HAS_VOLUME) + break; + volume = max(chip->left,chip->right); + if (volume) + ctrl->value=(32768*min(chip->left,chip->right))/volume; + else + ctrl->value=32768; + return 0; + } + case V4L2_CID_AUDIO_BASS: + if (desc->flags & CHIP_HAS_BASSTREBLE) + break; + ctrl->value = chip->bass; + return 0; + case V4L2_CID_AUDIO_TREBLE: + if (desc->flags & CHIP_HAS_BASSTREBLE) + return -EINVAL; + ctrl->value = chip->treble; + return 0; + } + return -EINVAL; +} + +static int tvaudio_set_ctrl(struct CHIPSTATE *chip, + struct v4l2_control *ctrl) { struct CHIPDESC *desc = chiplist + chip->type; @@ -1584,11 +1616,60 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl) else chip_write_masked(chip,desc->inputreg, desc->inputmap[chip->input],desc->inputmask); - break; - default: - return -EINVAL; + return 0; + case V4L2_CID_AUDIO_VOLUME: + { + int volume,balance; + + if (!desc->flags & CHIP_HAS_VOLUME) + break; + + volume = max(chip->left,chip->right); + if (volume) + balance=(32768*min(chip->left,chip->right))/volume; + else + balance=32768; + + volume=ctrl->value; + chip->left = (min(65536 - balance,32768) * volume) / 32768; + chip->right = (min(balance,volume *(__u16)32768)) / 32768; + + chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); + chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); + + return 0; } - return 0; + case V4L2_CID_AUDIO_BALANCE: + { + int volume, balance; + if (!desc->flags & CHIP_HAS_VOLUME) + break; + + volume = max(chip->left,chip->right); + balance = ctrl->value; + + chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); + chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); + + return 0; + } + case V4L2_CID_AUDIO_BASS: + if (desc->flags & CHIP_HAS_BASSTREBLE) + break; + chip->bass = ctrl->value; + chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); + + return 0; + case V4L2_CID_AUDIO_TREBLE: + if (desc->flags & CHIP_HAS_BASSTREBLE) + return -EINVAL; + + chip->treble = ctrl->value; + chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); + + return 0; + } + return -EINVAL; } @@ -1601,7 +1682,7 @@ static int chip_command(struct i2c_client *client, struct CHIPSTATE *chip = i2c_get_clientdata(client); struct CHIPDESC *desc = chiplist + chip->type; - v4l_dbg(1, debug, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd); + v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd); switch (cmd) { case AUDC_SET_RADIO: @@ -1609,67 +1690,36 @@ static int chip_command(struct i2c_client *client, chip->watch_stereo = 0; /* del_timer(&chip->wt); */ break; - /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - if (desc->flags & CHIP_HAS_VOLUME) { - va->flags |= VIDEO_AUDIO_VOLUME; - va->volume = max(chip->left,chip->right); - if (va->volume) - va->balance = (32768*min(chip->left,chip->right))/ - va->volume; - else - va->balance = 32768; - } - if (desc->flags & CHIP_HAS_BASSTREBLE) { - va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; - va->bass = chip->bass; - va->treble = chip->treble; - } - if (!chip->radio) { - if (desc->getmode) - va->mode = desc->getmode(chip); - else - va->mode = VIDEO_SOUND_MONO; - } - break; - } - - case VIDIOCSAUDIO: + case VIDIOC_QUERYCTRL: { - struct video_audio *va = arg; - - if (desc->flags & CHIP_HAS_VOLUME) { - chip->left = (min(65536 - va->balance,32768) * - va->volume) / 32768; - chip->right = (min(va->balance,(__u16)32768) * - va->volume) / 32768; - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); - } - if (desc->flags & CHIP_HAS_BASSTREBLE) { - chip->bass = va->bass; - chip->treble = va->treble; - chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); - chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); - } - if (desc->setmode && va->mode) { - chip->watch_stereo = 0; - /* del_timer(&chip->wt); */ - chip->mode = va->mode; - desc->setmode(chip,va->mode); + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + if (!desc->flags & CHIP_HAS_VOLUME) + return -EINVAL; + break; + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + if (desc->flags & CHIP_HAS_BASSTREBLE) + return -EINVAL; + break; + default: + return -EINVAL; } - break; + return v4l2_ctrl_query_fill_std(qc); } - case VIDIOC_S_CTRL: return tvaudio_set_ctrl(chip, arg); + case VIDIOC_G_CTRL: + return tvaudio_get_ctrl(chip, arg); case VIDIOC_INT_G_AUDIO_ROUTING: { struct v4l2_routing *rt = arg; @@ -1678,7 +1728,6 @@ static int chip_command(struct i2c_client *client, rt->output = 0; break; } - case VIDIOC_INT_S_AUDIO_ROUTING: { struct v4l2_routing *rt = arg; @@ -1693,7 +1742,6 @@ static int chip_command(struct i2c_client *client, desc->inputmap[chip->input], desc->inputmask); break; } - case VIDIOC_S_TUNER: { struct v4l2_tuner *vt = arg; @@ -1703,17 +1751,13 @@ static int chip_command(struct i2c_client *client, break; switch (vt->audmode) { case V4L2_TUNER_MODE_MONO: - mode = VIDEO_SOUND_MONO; - break; case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - mode = VIDEO_SOUND_STEREO; - break; case V4L2_TUNER_MODE_LANG1: - mode = VIDEO_SOUND_LANG1; - break; case V4L2_TUNER_MODE_LANG2: - mode = VIDEO_SOUND_LANG2; + mode = vt->audmode; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + mode = V4L2_TUNER_MODE_STEREO; break; default: return -EINVAL; @@ -1728,11 +1772,10 @@ static int chip_command(struct i2c_client *client, } break; } - case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; - int mode = VIDEO_SOUND_MONO; + int mode = V4L2_TUNER_MODE_MONO; if (chip->radio) break; @@ -1744,30 +1787,26 @@ static int chip_command(struct i2c_client *client, if (desc->getmode) mode = desc->getmode(chip); - if (mode & VIDEO_SOUND_MONO) + if (mode & V4L2_TUNER_MODE_MONO) vt->rxsubchans |= V4L2_TUNER_SUB_MONO; - if (mode & VIDEO_SOUND_STEREO) + if (mode & V4L2_TUNER_MODE_STEREO) vt->rxsubchans |= V4L2_TUNER_SUB_STEREO; /* Note: for SAP it should be mono/lang2 or stereo/lang2. When this module is converted fully to v4l2, then this should change for those chips that can detect SAP. */ - if (mode & VIDEO_SOUND_LANG1) + if (mode & V4L2_TUNER_MODE_LANG1) vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; break; } - - case VIDIOCSCHAN: case VIDIOC_S_STD: chip->radio = 0; break; - - case VIDIOCSFREQ: case VIDIOC_S_FREQUENCY: chip->mode = 0; /* automatic */ if (desc->checkmode) { - desc->setmode(chip,VIDEO_SOUND_MONO); - if (chip->prevmode != VIDEO_SOUND_MONO) + desc->setmode(chip,V4L2_TUNER_MODE_MONO); + if (chip->prevmode != V4L2_TUNER_MODE_MONO) chip->prevmode = -1; /* reset previous mode */ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); /* the thread will call checkmode() later */ @@ -1780,44 +1819,25 @@ static int chip_command(struct i2c_client *client, return 0; } -static struct i2c_driver driver = { - .driver = { - .name = "tvaudio", - }, - .id = I2C_DRIVERID_TVAUDIO, - .attach_adapter = chip_probe, - .detach_client = chip_detach, - .command = chip_command, -}; - -static struct i2c_client client_template = +static int chip_legacy_probe(struct i2c_adapter *adap) { - .name = "(unset)", - .driver = &driver, -}; - -static int __init audiochip_init_module(void) -{ - struct CHIPDESC *desc; - - if (debug) { - printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); - printk(KERN_INFO "tvaudio: known chips: "); - for (desc = chiplist; desc->name != NULL; desc++) - printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); - printk("\n"); - } - - return i2c_add_driver(&driver); -} - -static void __exit audiochip_cleanup_module(void) -{ - i2c_del_driver(&driver); + /* don't attach on saa7146 based cards, + because dedicated drivers are used */ + if ((adap->id == I2C_HW_SAA7146)) + return 0; + if (adap->class & I2C_CLASS_TV_ANALOG) + return 1; + return 0; } -module_init(audiochip_init_module); -module_exit(audiochip_cleanup_module); +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tvaudio", + .driverid = I2C_DRIVERID_TVAUDIO, + .command = chip_command, + .probe = chip_probe, + .remove = chip_remove, + .legacy_probe = chip_legacy_probe, +}; /* * Local variables: diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 4b2c403..403fbd0 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -226,7 +226,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "TCL M2523_3DI_E"}, { TUNER_ABSENT, "Samsung THPD5222FG30A"}, /* 120-129 */ - { TUNER_ABSENT, "Xceive XC3028"}, + { TUNER_XC2028, "Xceive XC3028"}, { TUNER_ABSENT, "Philips FQ1216LME MK5"}, { TUNER_ABSENT, "Philips FQD1216LME"}, { TUNER_ABSENT, "Conexant CX24118A"}, @@ -257,7 +257,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "LG TAPQ_H702F"}, { TUNER_ABSENT, "TCL M09WPP_4N_E"}, { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, - { TUNER_ABSENT, "Philips 18271_8295"}, + { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, }; static struct HAUPPAUGE_AUDIOIC diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 25d0aef..445eba4 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -290,6 +290,7 @@ static inline void tvp5150_selmux(struct i2c_client *c) int opmode=0; struct tvp5150 *decoder = i2c_get_clientdata(c); int input = 0; + unsigned char val; if ((decoder->route.output & TVP5150_BLACK_SCREEN) || !decoder->enable) input = 8; @@ -315,6 +316,16 @@ static inline void tvp5150_selmux(struct i2c_client *c) tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode); tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input); + + /* Svideo should enable YCrCb output and disable GPCL output + * For Composite and TV, it should be the reverse + */ + val = tvp5150_read(c, TVP5150_MISC_CTL); + if (decoder->route.input == TVP5150_SVIDEO) + val = (val & ~0x40) | 0x10; + else + val = (val & ~0x10) | 0x40; + tvp5150_write(c, TVP5150_MISC_CTL, val); }; struct i2c_reg_value { diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 0b2a961..0318432 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -28,6 +28,7 @@ #include #include #include +#include #include // --------------------- read registers functions define ----------------------- @@ -193,32 +194,18 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * /* i2c implementation */ -static struct i2c_driver i2c_driver; - -static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind) +static int upd64031a_probe(struct i2c_client *client) { - struct i2c_client *client; struct upd64031a_state *state; int i; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) { - return -ENOMEM; - } - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "uPD64031A"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } i2c_set_clientdata(client, state); @@ -229,54 +216,22 @@ static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind) for (i = 0; i < TOT_REGS; i++) { upd64031a_write(client, i, state->regs[i]); } - - i2c_attach_client(client); - return 0; } -static int upd64031a_probe(struct i2c_adapter *adapter) +static int upd64031a_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, upd64031a_attach); - return 0; -} - -static int upd64031a_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) - return err; - - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "upd64031a", - }, - .id = I2C_DRIVERID_UPD64031A, - .attach_adapter = upd64031a_probe, - .detach_client = upd64031a_detach, + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "upd64031a", + .driverid = I2C_DRIVERID_UPD64031A, .command = upd64031a_command, + .probe = upd64031a_probe, + .remove = upd64031a_remove, }; - - -static int __init upd64031a_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit upd64031a_exit_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(upd64031a_init_module); -module_exit(upd64031a_exit_module); diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 401bd21..7e32c5b 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -27,6 +27,7 @@ #include #include #include +#include #include MODULE_DESCRIPTION("uPD64083 driver"); @@ -171,32 +172,18 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a /* i2c implementation */ -static struct i2c_driver i2c_driver; - -static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind) +static int upd64083_probe(struct i2c_client *client) { - struct i2c_client *client; struct upd64083_state *state; int i; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) { - return -ENOMEM; - } - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "uPD64083"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } i2c_set_clientdata(client, state); @@ -207,53 +194,22 @@ static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind) for (i = 0; i < TOT_REGS; i++) { upd64083_write(client, i, state->regs[i]); } - i2c_attach_client(client); - return 0; } -static int upd64083_probe(struct i2c_adapter *adapter) +static int upd64083_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, upd64083_attach); - return 0; -} - -static int upd64083_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) - return err; - - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "upd64083", - }, - .id = I2C_DRIVERID_UPD64083, - .attach_adapter = upd64083_probe, - .detach_client = upd64083_detach, + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "upd64083", + .driverid = I2C_DRIVERID_UPD64083, .command = upd64083_command, + .probe = upd64083_probe, + .remove = upd64083_remove, }; - - -static int __init upd64083_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit upd64083_exit_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(upd64083_init_module); -module_exit(upd64083_exit_module); diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index c7d5f9e..2038d40 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -2242,14 +2242,18 @@ static void call_usbvision_power_off(struct work_struct *work) struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork); PDEBUG(DBG_FUNC, ""); - down_interruptible(&usbvision->lock); + if(mutex_lock_interruptible(&usbvision->lock)) { + return; + } + + if(usbvision->user == 0) { usbvision_i2c_unregister(usbvision); usbvision_power_off(usbvision); usbvision->initialized = 0; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); } static void usbvision_powerOffTimer(unsigned long data) diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 36e689f..e34f311 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -410,7 +410,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) /* If so far no errors then we shall start the camera */ if (!errCode) { - down(&usbvision->lock); + mutex_lock(&usbvision->lock); if (usbvision->power == 0) { usbvision_power_on(usbvision); usbvision_i2c_register(usbvision); @@ -439,7 +439,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) usbvision->initialized = 0; } } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); } if (errCode) { @@ -467,7 +467,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) (struct usb_usbvision *) video_get_drvdata(dev); PDEBUG(DBG_IO, "close"); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_audio_off(usbvision); usbvision_restart_isoc(usbvision); @@ -487,7 +487,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) usbvision->initialized = 0; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__); @@ -647,13 +647,13 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input) if ((input >= usbvision->video_inputs) || (input < 0) ) return -EINVAL; - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_muxsel(usbvision, input); usbvision_set_input(usbvision); usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return 0; } @@ -664,10 +664,10 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) (struct usb_usbvision *) video_get_drvdata(dev); usbvision->tvnormId=*id; - down(&usbvision->lock); + mutex_lock(&usbvision->lock); call_i2c_clients(usbvision, VIDIOC_S_STD, &usbvision->tvnormId); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); /* propagate the change to the decoder */ usbvision_muxsel(usbvision, usbvision->ctl_input); @@ -1083,9 +1083,9 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, usbvision->curFrame = NULL; /* by now we are committed to the new data... */ - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return 0; } @@ -1211,16 +1211,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) PDEBUG(DBG_MMAP, "mmap"); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); if (!USBVISION_IS_OPERATIONAL(usbvision)) { - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EFAULT; } if (!(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(usbvision->max_frame_size)) { - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EINVAL; } @@ -1232,7 +1232,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) if (i == usbvision->num_frames) { PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range"); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EINVAL; } @@ -1245,7 +1245,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed"); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -1253,7 +1253,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) size -= PAGE_SIZE; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return 0; } @@ -1271,7 +1271,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) PDEBUG(DBG_IO, "%s:", __FUNCTION__); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); if (usbvision->user) { err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__); @@ -1307,7 +1307,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) usbvision->initialized = 0; } } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return errCode; } @@ -1321,7 +1321,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) PDEBUG(DBG_IO, ""); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); /* Set packet size to 0 */ usbvision->ifaceAlt=0; @@ -1337,7 +1337,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) usbvision->initialized = 0; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__); @@ -1641,7 +1641,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) usbvision->dev = dev; - init_MUTEX(&usbvision->lock); /* to 1 == available */ + mutex_init(&usbvision->lock); /* available */ // prepare control urb for control messages during interrupts usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); @@ -1676,13 +1676,13 @@ static void usbvision_release(struct usb_usbvision *usbvision) { PDEBUG(DBG_PROBE, ""); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_reset_powerOffTimer(usbvision); usbvision->initialized = 0; - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); usbvision_remove_sysfs(usbvision->vdev); usbvision_unregister_video(usbvision); @@ -1796,7 +1796,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, } PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); /* compute alternate max packet sizes */ uif = dev->actconfig->interface[0]; @@ -1840,7 +1840,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, usbvision->streaming = Stream_Off; usbvision_register_video(usbvision); usbvision_configure_video(usbvision); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); usb_set_intfdata (intf, usbvision); @@ -1871,7 +1871,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) } usb_set_intfdata (intf, NULL); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); // At this time we ask to cancel outstanding URBs usbvision_stop_isoc(usbvision); @@ -1885,7 +1885,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) usb_put_dev(usbvision->dev); usbvision->dev = NULL; // USB device is no more - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); if (usbvision->user) { printk(KERN_INFO "%s: In use, disconnect pending\n", diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index c5b6c50..c32f685 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -396,7 +397,7 @@ struct usb_usbvision { unsigned char iface; /* Video interface number */ unsigned char ifaceAlt; /* Alt settings */ unsigned char Vin_Reg2_Preset; - struct semaphore lock; + struct mutex lock; struct timer_list powerOffTimer; struct work_struct powerOffWork; int power; /* is the device powered on? */ diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 1141b4b..c056ff6 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -400,7 +400,7 @@ static const char *v4l2_int_ioctls[] = { [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", - [_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG", + [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", @@ -1013,6 +1013,34 @@ int v4l2_chip_match_host(u32 match_type, u32 match_chip) /* ----------------------------------------------------------------- */ +/* Helper function for I2C legacy drivers */ + +int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, + const char *name, int (*probe)(struct i2c_client *)) +{ + struct i2c_client *client; + int err; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = driver; + strlcpy(client->name, name, sizeof(client->name)); + + err = probe(client); + if (err == 0) { + i2c_attach_client(client); + } else { + kfree(client); + } + return err != -ENOMEM ? 0 : err; +} + +/* ----------------------------------------------------------------- */ + EXPORT_SYMBOL(v4l2_norm_to_name); EXPORT_SYMBOL(v4l2_video_std_construct); @@ -1038,6 +1066,8 @@ EXPORT_SYMBOL(v4l2_chip_match_i2c_client); EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); EXPORT_SYMBOL(v4l2_chip_match_host); +EXPORT_SYMBOL(v4l2_i2c_attach); + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 8b4ef53..a545dca 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -57,12 +57,12 @@ static void v4l2_int_device_try_attach_all(void) if (!try_module_get(m->module)) continue; - if (m->u.master->attach(m, s)) { + s->u.slave->master = m; + if (m->u.master->attach(s)) { + s->u.slave->master = NULL; module_put(m->module); continue; } - - s->u.slave->master = m; } } } diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 89a44f1..6171ab7 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -68,14 +68,14 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) MAGIC_CHECK(vb->magic,MAGIC_BUFFER); add_wait_queue(&vb->done, &wait); - while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { + while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) { if (non_blocking) { retval = -EAGAIN; break; } set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) + if (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) schedule(); set_current_state(TASK_RUNNING); if (intr && signal_pending(current)) { @@ -141,6 +141,7 @@ void videobuf_queue_core_init(struct videobuf_queue* q, INIT_LIST_HEAD(&q->stream); } +/* Locking: Only usage in bttv unsafe find way to remove */ int videobuf_queue_is_busy(struct videobuf_queue *q) { int i; @@ -166,11 +167,11 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) dprintk(1,"busy: buffer #%d mapped\n",i); return 1; } - if (q->bufs[i]->state == STATE_QUEUED) { + if (q->bufs[i]->state == VIDEOBUF_QUEUED) { dprintk(1,"busy: buffer #%d queued\n",i); return 1; } - if (q->bufs[i]->state == STATE_ACTIVE) { + if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { dprintk(1,"busy: buffer #%d avtive\n",i); return 1; } @@ -178,6 +179,7 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) return 0; } +/* Locking: Caller holds q->lock */ void videobuf_queue_cancel(struct videobuf_queue *q) { unsigned long flags=0; @@ -189,9 +191,9 @@ void videobuf_queue_cancel(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - if (q->bufs[i]->state == STATE_QUEUED) { + if (q->bufs[i]->state == VIDEOBUF_QUEUED) { list_del(&q->bufs[i]->queue); - q->bufs[i]->state = STATE_ERROR; + q->bufs[i]->state = VIDEOBUF_ERROR; } } if (q->irqlock) @@ -208,6 +210,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q) /* --------------------------------------------------------------------- */ +/* Locking: Caller holds q->lock */ enum v4l2_field videobuf_next_field(struct videobuf_queue *q) { enum v4l2_field field = q->field; @@ -226,6 +229,7 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q) return field; } +/* Locking: Caller holds q->lock */ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, struct videobuf_buffer *vb, enum v4l2_buf_type type) { @@ -255,17 +259,17 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, b->flags |= V4L2_BUF_FLAG_MAPPED; switch (vb->state) { - case STATE_PREPARED: - case STATE_QUEUED: - case STATE_ACTIVE: + case VIDEOBUF_PREPARED: + case VIDEOBUF_QUEUED: + case VIDEOBUF_ACTIVE: b->flags |= V4L2_BUF_FLAG_QUEUED; break; - case STATE_DONE: - case STATE_ERROR: + case VIDEOBUF_DONE: + case VIDEOBUF_ERROR: b->flags |= V4L2_BUF_FLAG_DONE; break; - case STATE_NEEDS_INIT: - case STATE_IDLE: + case VIDEOBUF_NEEDS_INIT: + case VIDEOBUF_IDLE: /* nothing */ break; } @@ -281,20 +285,108 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, b->sequence = vb->field_count >> 1; } +/* Locking: Caller holds q->lock */ +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + int i; + int rc; + + if (!q) + return 0; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + rc = CALL(q,mmap_free,q); + if (rc<0) + return rc; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + q->ops->buf_release(q,q->bufs[i]); + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + + return rc; +} + +int videobuf_mmap_free(struct videobuf_queue *q) +{ + int ret; + mutex_lock(&q->lock); + ret = __videobuf_mmap_free(q); + mutex_unlock(&q->lock); + return ret; +} + +/* Locking: Caller holds q->lock */ +static int __videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory) +{ + unsigned int i; + int err; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + err = __videobuf_mmap_free(q); + if (0 != err) + return err; + + /* Allocate and initialize buffers */ + for (i = 0; i < bcount; i++) { + q->bufs[i] = videobuf_alloc(q); + + if (q->bufs[i] == NULL) + break; + + q->bufs[i]->i = i; + q->bufs[i]->input = UNSET; + q->bufs[i]->memory = memory; + q->bufs[i]->bsize = bsize; + switch (memory) { + case V4L2_MEMORY_MMAP: + q->bufs[i]->boff = bsize * i; + break; + case V4L2_MEMORY_USERPTR: + case V4L2_MEMORY_OVERLAY: + /* nothing */ + break; + } + } + + if (!i) + return -ENOMEM; + + dprintk(1,"mmap setup: %d buffers, %d bytes each\n", + i, bsize); + + return i; +} + +int videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory) +{ + int ret; + mutex_lock(&q->lock); + ret = __videobuf_mmap_setup(q, bcount, bsize, memory); + mutex_unlock(&q->lock); + return ret; +} + int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req) { unsigned int size,count; int retval; - if (req->type != q->type) { - dprintk(1,"reqbufs: queue type invalid\n"); - return -EINVAL; - } if (req->count < 1) { dprintk(1,"reqbufs: count invalid (%d)\n",req->count); return -EINVAL; } + if (req->memory != V4L2_MEMORY_MMAP && req->memory != V4L2_MEMORY_USERPTR && req->memory != V4L2_MEMORY_OVERLAY) { @@ -303,6 +395,12 @@ int videobuf_reqbufs(struct videobuf_queue *q, } mutex_lock(&q->lock); + if (req->type != q->type) { + dprintk(1,"reqbufs: queue type invalid\n"); + retval = -EINVAL; + goto done; + } + if (q->streaming) { dprintk(1,"reqbufs: streaming already exists\n"); retval = -EBUSY; @@ -323,7 +421,7 @@ int videobuf_reqbufs(struct videobuf_queue *q, dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", count, size, (count*size)>>PAGE_SHIFT); - retval = videobuf_mmap_setup(q,count,size,req->memory); + retval = __videobuf_mmap_setup(q,count,size,req->memory); if (retval < 0) { dprintk(1,"reqbufs: mmap setup returned %d\n",retval); goto done; @@ -338,20 +436,28 @@ int videobuf_reqbufs(struct videobuf_queue *q, int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) { + int ret = -EINVAL; + + mutex_lock(&q->lock); if (unlikely(b->type != q->type)) { dprintk(1,"querybuf: Wrong type.\n"); - return -EINVAL; + goto done; } if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { dprintk(1,"querybuf: index out of range.\n"); - return -EINVAL; + goto done; } if (unlikely(NULL == q->bufs[b->index])) { dprintk(1,"querybuf: buffer is null.\n"); - return -EINVAL; + goto done; } + videobuf_status(q,b,q->bufs[b->index],q->type); - return 0; + + ret = 0; +done: + mutex_unlock(&q->lock); + return ret; } int videobuf_qbuf(struct videobuf_queue *q, @@ -392,7 +498,7 @@ int videobuf_qbuf(struct videobuf_queue *q, dprintk(1,"qbuf: memory type is wrong.\n"); goto done; } - if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { + if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { dprintk(1,"qbuf: buffer is already queued or active.\n"); goto done; } @@ -419,7 +525,7 @@ int videobuf_qbuf(struct videobuf_queue *q, dprintk(1,"qbuf: buffer length is not enough\n"); goto done; } - if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) + if (VIDEOBUF_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) q->ops->buf_release(q,buf); buf->baddr = b->m.userptr; break; @@ -489,16 +595,16 @@ int videobuf_dqbuf(struct videobuf_queue *q, goto done; } switch (buf->state) { - case STATE_ERROR: + case VIDEOBUF_ERROR: dprintk(1,"dqbuf: state is error\n"); retval = -EIO; CALL(q,sync,q, buf); - buf->state = STATE_IDLE; + buf->state = VIDEOBUF_IDLE; break; - case STATE_DONE: + case VIDEOBUF_DONE: dprintk(1,"dqbuf: state is done\n"); CALL(q,sync,q, buf); - buf->state = STATE_IDLE; + buf->state = VIDEOBUF_IDLE; break; default: dprintk(1,"dqbuf: state invalid\n"); @@ -531,7 +637,7 @@ int videobuf_streamon(struct videobuf_queue *q) if (q->irqlock) spin_lock_irqsave(q->irqlock,flags); list_for_each_entry(buf, &q->stream, stream) - if (buf->state == STATE_PREPARED) + if (buf->state == VIDEOBUF_PREPARED) q->ops->buf_queue(q,buf); if (q->irqlock) spin_unlock_irqrestore(q->irqlock,flags); @@ -541,22 +647,30 @@ int videobuf_streamon(struct videobuf_queue *q) return retval; } -int videobuf_streamoff(struct videobuf_queue *q) +/* Locking: Caller holds q->lock */ +static int __videobuf_streamoff(struct videobuf_queue *q) { - int retval = -EINVAL; - - mutex_lock(&q->lock); if (!q->streaming) - goto done; + return -EINVAL; + videobuf_queue_cancel(q); q->streaming = 0; - retval = 0; - done: + return 0; +} + +int videobuf_streamoff(struct videobuf_queue *q) +{ + int retval; + + mutex_lock(&q->lock); + retval = __videobuf_streamoff(q); mutex_unlock(&q->lock); + return retval; } +/* Locking: Caller holds q->lock */ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data, size_t count, loff_t *ppos) @@ -590,7 +704,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, retval = videobuf_waiton(q->read_buf,0,0); if (0 == retval) { CALL(q,sync,q,q->read_buf); - if (STATE_ERROR == q->read_buf->state) + if (VIDEOBUF_ERROR == q->read_buf->state) retval = -EIO; else retval = q->read_buf->size; @@ -664,7 +778,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, CALL(q,sync,q,q->read_buf); - if (STATE_ERROR == q->read_buf->state) { + if (VIDEOBUF_ERROR == q->read_buf->state) { /* catch I/O errors */ q->ops->buf_release(q,q->read_buf); kfree(q->read_buf); @@ -691,7 +805,8 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, return retval; } -int videobuf_read_start(struct videobuf_queue *q) +/* Locking: Caller holds q->lock */ +int __videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; unsigned long flags=0; @@ -705,7 +820,7 @@ int videobuf_read_start(struct videobuf_queue *q) count = VIDEO_MAX_FRAME; size = PAGE_ALIGN(size); - err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); + err = __videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); if (err < 0) return err; @@ -728,12 +843,13 @@ int videobuf_read_start(struct videobuf_queue *q) return 0; } -void videobuf_read_stop(struct videobuf_queue *q) +static void __videobuf_read_stop(struct videobuf_queue *q) { int i; + videobuf_queue_cancel(q); - videobuf_mmap_free(q); + __videobuf_mmap_free(q); INIT_LIST_HEAD(&q->stream); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) @@ -743,8 +859,41 @@ void videobuf_read_stop(struct videobuf_queue *q) } q->read_buf = NULL; q->reading = 0; + } +int videobuf_read_start(struct videobuf_queue *q) +{ + int rc; + + mutex_lock(&q->lock); + rc = __videobuf_read_start(q); + mutex_unlock(&q->lock); + + return rc; +} + +void videobuf_read_stop(struct videobuf_queue *q) +{ + mutex_lock(&q->lock); + __videobuf_read_stop(q); + mutex_unlock(&q->lock); +} + +void videobuf_stop(struct videobuf_queue *q) +{ + mutex_lock(&q->lock); + + if (q->streaming) + __videobuf_streamoff(q); + + if (q->reading) + __videobuf_read_stop(q); + + mutex_unlock(&q->lock); +} + + ssize_t videobuf_read_stream(struct videobuf_queue *q, char __user *data, size_t count, loff_t *ppos, int vbihack, int nonblocking) @@ -782,7 +931,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, break; } - if (q->read_buf->state == STATE_DONE) { + if (q->read_buf->state == VIDEOBUF_DONE) { rc = CALL (q,copy_stream, q, data + retval, count, retval, vbihack, nonblocking); if (rc < 0) { @@ -850,83 +999,14 @@ unsigned int videobuf_poll_stream(struct file *file, if (0 == rc) { poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) + if (buf->state == VIDEOBUF_DONE || + buf->state == VIDEOBUF_ERROR) rc = POLLIN|POLLRDNORM; } mutex_unlock(&q->lock); return rc; } -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - unsigned int i; - int err; - - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); - - err = videobuf_mmap_free(q); - if (0 != err) - return err; - - /* Allocate and initialize buffers */ - for (i = 0; i < bcount; i++) { - q->bufs[i] = videobuf_alloc(q); - - if (q->bufs[i] == NULL) - break; - - q->bufs[i]->i = i; - q->bufs[i]->input = UNSET; - q->bufs[i]->memory = memory; - q->bufs[i]->bsize = bsize; - switch (memory) { - case V4L2_MEMORY_MMAP: - q->bufs[i]->boff = bsize * i; - break; - case V4L2_MEMORY_USERPTR: - case V4L2_MEMORY_OVERLAY: - /* nothing */ - break; - } - } - - if (!i) - return -ENOMEM; - - dprintk(1,"mmap setup: %d buffers, %d bytes each\n", - i, bsize); - - return i; -} - -int videobuf_mmap_free(struct videobuf_queue *q) -{ - int i; - int rc; - - if (!q) - return 0; - - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); - - rc = CALL(q,mmap_free,q); - if (rc<0) - return rc; - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q,q->bufs[i]); - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - - return rc; -} - int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma) { @@ -991,6 +1071,7 @@ EXPORT_SYMBOL_GPL(videobuf_streamoff); EXPORT_SYMBOL_GPL(videobuf_read_start); EXPORT_SYMBOL_GPL(videobuf_read_stop); +EXPORT_SYMBOL_GPL(videobuf_stop); EXPORT_SYMBOL_GPL(videobuf_read_stream); EXPORT_SYMBOL_GPL(videobuf_read_one); EXPORT_SYMBOL_GPL(videobuf_poll_stream); diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c index 880317e..b73aba6 100644 --- a/drivers/media/video/videobuf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -67,7 +67,7 @@ static int videobuf_dvb_thread(void *data) /* feed buffer data to demux */ dma=videobuf_to_dma(buf); - if (buf->state == STATE_DONE) + if (buf->state == VIDEOBUF_DONE) dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, buf->size); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index ee73dc7..fe9784a 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -370,7 +370,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) (unsigned long)tmpbuf,pos); /* Advice that buffer was filled */ - buf->vb.state = STATE_DONE; + buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; do_gettimeofday(&ts); buf->vb.ts = ts; @@ -522,7 +522,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) /* cancel all outstanding capture / vbi requests */ list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) { list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); } mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); @@ -543,7 +543,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) vivi_stop_thread(dma_q); vivi_start_thread(dma_q); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] restart_queue - first active\n", buf,buf->vb.i); @@ -553,7 +553,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&dma_q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; dprintk(2,"[%p/%d] restart_queue - move to active\n", buf,buf->vb.i); } else { @@ -572,7 +572,7 @@ static void vivi_vid_timeout(unsigned long data) while (!list_empty(&vidq->active)) { buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); } @@ -610,7 +610,7 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) videobuf_waiton(&buf->vb,0,0); videobuf_vmalloc_free(&buf->vb); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } #define norm_maxw() 1024 @@ -644,12 +644,12 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, init_buffer = 1; } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL))) goto fail; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; @@ -670,13 +670,13 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (!list_empty(&vidq->queued)) { dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue); list_add_tail(&buf->vb.queue,&vidq->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&vidq->active)) { list_add_tail(&buf->vb.queue,&vidq->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] buffer_queue - first active\n", buf, buf->vb.i); @@ -688,13 +688,13 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_add_tail(&buf->vb.queue,&vidq->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; dprintk(2,"[%p/%d] buffer_queue - append to active\n", buf, buf->vb.i); } else { list_add_tail(&buf->vb.queue,&vidq->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } @@ -1076,6 +1076,7 @@ static int vivi_release(struct inode *inode, struct file *file) int minor = iminor(inode); vivi_stop_thread(vidq); + videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); kfree (fh); diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 63002e0..97e2476 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -30,6 +30,7 @@ #include #include #include +#include MODULE_DESCRIPTION("vp27smpx driver"); MODULE_AUTHOR("Hans Verkuil"); @@ -73,8 +74,7 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) } } -static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct vp27smpx_state *state = i2c_get_clientdata(client); struct v4l2_tuner *vt = arg; @@ -125,31 +125,20 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) +static int vp27smpx_probe(struct i2c_client *client) { - struct i2c_client *client; struct vp27smpx_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } state->audmode = V4L2_TUNER_MODE_STEREO; @@ -157,56 +146,22 @@ static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) /* initialize vp27smpx */ vp27smpx_set_audmode(client, state->audmode); - i2c_attach_client(client); - - return 0; -} - -static int vp27smpx_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, vp27smpx_attach); return 0; } -static int vp27smpx_detach(struct i2c_client *client) +static int vp27smpx_remove(struct i2c_client *client) { - struct vp27smpx_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); - + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "vp27smpx", - }, - .id = I2C_DRIVERID_VP27SMPX, - .attach_adapter = vp27smpx_probe, - .detach_client = vp27smpx_detach, - .command = vp27smpx_command, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "vp27smpx", + .driverid = I2C_DRIVERID_VP27SMPX, + .command = vp27smpx_command, + .probe = vp27smpx_probe, + .remove = vp27smpx_remove, }; - -static int __init vp27smpx_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit vp27smpx_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(vp27smpx_init_module); -module_exit(vp27smpx_cleanup_module); diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 1bf4cbe..3d9e709 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -30,6 +30,7 @@ #include #include #include +#include MODULE_DESCRIPTION("wm8739 driver"); MODULE_AUTHOR("T. Adachi, Hans Verkuil"); @@ -259,27 +260,15 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg /* i2c implementation */ -static struct i2c_driver i2c_driver; - -static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind) +static int wm8739_probe(struct i2c_client *client) { - struct i2c_client *client; struct wm8739_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) - return -ENOMEM; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "wm8739"); - - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL); if (state == NULL) { @@ -306,56 +295,20 @@ static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind) /* normal, 256fs, 48KHz sampling rate */ wm8739_write(client, R9, 0x001); /* activate */ wm8739_set_audio(client); /* set volume/mute */ - - i2c_attach_client(client); - return 0; } -static int wm8739_probe(struct i2c_adapter *adapter) +static int wm8739_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, wm8739_attach); - return 0; -} - -static int wm8739_detach(struct i2c_client *client) -{ - struct wm8739_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) - return err; - - kfree(state); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "wm8739", - }, - .id = I2C_DRIVERID_WM8739, - .attach_adapter = wm8739_probe, - .detach_client = wm8739_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "wm8739", + .driverid = I2C_DRIVERID_WM8739, .command = wm8739_command, + .probe = wm8739_probe, + .remove = wm8739_remove, }; - -static int __init wm8739_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit wm8739_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(wm8739_init_module); -module_exit(wm8739_cleanup_module); diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 9f7e894..c31a0c3 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -34,6 +34,7 @@ #include #include #include +#include MODULE_DESCRIPTION("wm8775 driver"); MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); @@ -44,6 +45,7 @@ static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; + /* ----------------------------------------------------------------------- */ enum { @@ -76,8 +78,7 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val) return -1; } -static int wm8775_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int wm8775_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct wm8775_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -159,31 +160,18 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind) +static int wm8775_probe(struct i2c_client *client) { - struct i2c_client *client; struct wm8775_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "wm8775"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } state->input = 2; @@ -208,56 +196,20 @@ static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind) wm8775_write(client, R20, 0x07a); /* Transient window 4ms, lower PGA gain */ /* limit -1dB */ wm8775_write(client, R21, 0x102); /* LRBOTH = 1, use input 2. */ - i2c_attach_client(client); - return 0; } -static int wm8775_probe(struct i2c_adapter *adapter) +static int wm8775_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, wm8775_attach); - return 0; -} - -static int wm8775_detach(struct i2c_client *client) -{ - struct wm8775_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); - + kfree(i2c_get_clientdata(client)); return 0; } -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "wm8775", - }, - .id = I2C_DRIVERID_WM8775, - .attach_adapter = wm8775_probe, - .detach_client = wm8775_detach, - .command = wm8775_command, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "wm8775", + .driverid = I2C_DRIVERID_WM8775, + .command = wm8775_command, + .probe = wm8775_probe, + .remove = wm8775_remove, }; - -static int __init wm8775_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit wm8775_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(wm8775_init_module); -module_exit(wm8775_cleanup_module); diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index 6f18925..1fdbb46 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -749,7 +749,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) } -static struct file_operations zr364xx_fops = { +static const struct file_operations zr364xx_fops = { .owner = THIS_MODULE, .open = zr364xx_open, .release = zr364xx_release, diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 88c8140..e59613c 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -121,6 +121,7 @@ #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */ #define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */ #define I2C_DRIVERID_CS4270 94 /* Cirrus Logic 4270 audio codec */ +#define I2C_DRIVERID_M52790 95 /* Mitsubishi M52790SP/FP AV switch */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 7a785fa..b904d32 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -97,7 +97,6 @@ int ir_dump_samples(u32 *samples, int count); int ir_decode_biphase(u32 *samples, int count, int low, int high); int ir_decode_pulsedistance(u32 *samples, int count, int low, int high); -u32 ir_rc5_decode(unsigned int code); void ir_rc5_timer_end(unsigned long data); void ir_rc5_timer_keyup(unsigned long data); diff --git a/include/media/m52790.h b/include/media/m52790.h new file mode 100644 index 0000000..7ddffae --- /dev/null +++ b/include/media/m52790.h @@ -0,0 +1,93 @@ +/* + m52790.h - definition for m52790 inputs and outputs + + Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _M52790_H_ +#define _M52790_H_ + +/* Input routing switch 1 */ + +#define M52790_SW1_IN_MASK 0x0003 +#define M52790_SW1_IN_TUNER 0x0000 +#define M52790_SW1_IN_V2 0x0001 +#define M52790_SW1_IN_V3 0x0002 +#define M52790_SW1_IN_V4 0x0003 + +/* Selects component input instead of composite */ +#define M52790_SW1_YCMIX 0x0004 + + +/* Input routing switch 2 */ + +#define M52790_SW2_IN_MASK 0x0300 +#define M52790_SW2_IN_TUNER 0x0000 +#define M52790_SW2_IN_V2 0x0100 +#define M52790_SW2_IN_V3 0x0200 +#define M52790_SW2_IN_V4 0x0300 + +/* Selects component input instead of composite */ +#define M52790_SW2_YCMIX 0x0400 + + +/* Output routing switch 1 */ + +/* Enable 6dB amplifier for composite out */ +#define M52790_SW1_V_AMP 0x0008 + +/* Enable 6dB amplifier for component out */ +#define M52790_SW1_YC_AMP 0x0010 + +/* Audio output mode */ +#define M52790_SW1_AUDIO_MASK 0x00c0 +#define M52790_SW1_AUDIO_MUTE 0x0000 +#define M52790_SW1_AUDIO_R 0x0040 +#define M52790_SW1_AUDIO_L 0x0080 +#define M52790_SW1_AUDIO_STEREO 0x00c0 + + +/* Output routing switch 2 */ + +/* Enable 6dB amplifier for composite out */ +#define M52790_SW2_V_AMP 0x0800 + +/* Enable 6dB amplifier for component out */ +#define M52790_SW2_YC_AMP 0x1000 + +/* Audio output mode */ +#define M52790_SW2_AUDIO_MASK 0xc000 +#define M52790_SW2_AUDIO_MUTE 0x0000 +#define M52790_SW2_AUDIO_R 0x4000 +#define M52790_SW2_AUDIO_L 0x8000 +#define M52790_SW2_AUDIO_STEREO 0xc000 + + +/* Common values */ +#define M52790_IN_TUNER (M52790_SW1_IN_TUNER | M52790_SW2_IN_TUNER) +#define M52790_IN_V2 (M52790_SW1_IN_V2 | M52790_SW2_IN_V2) +#define M52790_IN_V3 (M52790_SW1_IN_V3 | M52790_SW2_IN_V3) +#define M52790_IN_V4 (M52790_SW1_IN_V4 | M52790_SW2_IN_V4) + +#define M52790_OUT_STEREO (M52790_SW1_AUDIO_STEREO | \ + M52790_SW2_AUDIO_STEREO) +#define M52790_OUT_AMP_STEREO (M52790_SW1_AUDIO_STEREO | \ + M52790_SW1_V_AMP | \ + M52790_SW2_AUDIO_STEREO | \ + M52790_SW2_V_AMP) + +#endif diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index e49f7e1..89c442e 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h @@ -1,7 +1,6 @@ #ifndef __SAA7146_VV__ #define __SAA7146_VV__ -#include #include #include #include diff --git a/include/media/tuner.h b/include/media/tuner.h index c03dceb..d49392d 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -117,7 +117,7 @@ extern int tuner_debug; #define TUNER_PHILIPS_TUV1236D 68 /* ATI HDTV Wonder */ #define TUNER_TNF_5335MF 69 /* Sabrent Bt848 */ #define TUNER_SAMSUNG_TCPN_2121P30A 70 /* Hauppauge PVR-500MCE NTSC */ -#define TUNER_XCEIVE_XC3028 71 +#define TUNER_XC2028 71 #define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */ #define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */ diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 8ae42c4..2442c28 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -83,6 +83,9 @@ enum { /* module upd64083: just ident 64083 */ V4L2_IDENT_UPD64083 = 64083, + /* module m52790: just ident 52790 */ + V4L2_IDENT_M52790 = 52790, + /* module msp34xx: reserved range 34000-34999 */ V4L2_IDENT_MSP3400B = 34002, V4L2_IDENT_MSP3410B = 34102, diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 181a40c..475d0d8 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -104,6 +104,17 @@ int v4l2_chip_match_host(u32 id_type, u32 chip_id); /* ------------------------------------------------------------------------- */ +/* Helper function for I2C legacy drivers */ + +struct i2c_driver; +struct i2c_adapter; +struct i2c_client; + +int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, + const char *name, int (*probe)(struct i2c_client *)); + +/* ------------------------------------------------------------------------- */ + /* Internal ioctls */ /* VIDIOC_INT_DECODE_VBI_LINE */ @@ -116,6 +127,11 @@ struct v4l2_decode_vbi_line { u32 type; /* VBI service type (V4L2_SLICED_*). 0 if no service found */ }; +struct v4l2_priv_tun_config { + int tuner; + void *priv; +}; + /* audio ioctls */ /* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */ @@ -131,7 +147,7 @@ struct v4l2_decode_vbi_line { #define TUNER_SET_STANDBY _IOW('d', 91, int) /* Sets tda9887 specific stuff, like port1, port2 and qss */ -#define TDA9887_SET_CONFIG _IOW('d', 92, int) +#define TUNER_SET_CONFIG _IOW('d', 92, struct v4l2_priv_tun_config) /* Switch the tuner to a specific tuner mode. Replacement of AUDC_SET_RADIO */ #define VIDIOC_INT_S_TUNER_MODE _IOW('d', 93, enum v4l2_tuner_type) diff --git a/include/media/v4l2-i2c-drv-legacy.h b/include/media/v4l2-i2c-drv-legacy.h new file mode 100644 index 0000000..2418542 --- /dev/null +++ b/include/media/v4l2-i2c-drv-legacy.h @@ -0,0 +1,140 @@ +/* + * v4l2-i2c-drv-legacy.h - contains I2C handling code that's identical + * for all V4L2 I2C drivers. Use this header if the + * I2C driver is used by both legacy drivers and + * drivers converted to the bus-based I2C API. + * + * Copyright (C) 2007 Hans Verkuil + * + * 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. + */ + +struct v4l2_i2c_driver_data { + const char * const name; + int driverid; + int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); + int (*probe)(struct i2c_client *client); + int (*remove)(struct i2c_client *client); + int (*suspend)(struct i2c_client *client, pm_message_t state); + int (*resume)(struct i2c_client *client); + int (*legacy_probe)(struct i2c_adapter *adapter); + int legacy_class; +}; + +static struct v4l2_i2c_driver_data v4l2_i2c_data; +static struct i2c_client_address_data addr_data; +static struct i2c_driver v4l2_i2c_driver_legacy; +static char v4l2_i2c_drv_name_legacy[32]; + +static int v4l2_i2c_drv_attach_legacy(struct i2c_adapter *adapter, int address, int kind) +{ + return v4l2_i2c_attach(adapter, address, &v4l2_i2c_driver_legacy, + v4l2_i2c_drv_name_legacy, v4l2_i2c_data.probe); +} + +static int v4l2_i2c_drv_probe_legacy(struct i2c_adapter *adapter) +{ + if (v4l2_i2c_data.legacy_probe) { + if (v4l2_i2c_data.legacy_probe(adapter)) + return i2c_probe(adapter, &addr_data, v4l2_i2c_drv_attach_legacy); + return 0; + } + if (adapter->class & v4l2_i2c_data.legacy_class) + return i2c_probe(adapter, &addr_data, v4l2_i2c_drv_attach_legacy); + return 0; +} + +static int v4l2_i2c_drv_detach_legacy(struct i2c_client *client) +{ + int err; + + if (v4l2_i2c_data.remove) + v4l2_i2c_data.remove(client); + + err = i2c_detach_client(client); + if (err) + return err; + kfree(client); + + return 0; +} + +static int v4l2_i2c_drv_suspend_helper(struct i2c_client *client, pm_message_t state) +{ + return v4l2_i2c_data.suspend ? v4l2_i2c_data.suspend(client, state) : 0; +} + +static int v4l2_i2c_drv_resume_helper(struct i2c_client *client) +{ + return v4l2_i2c_data.resume ? v4l2_i2c_data.resume(client) : 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver v4l2_i2c_driver_legacy = { + .driver = { + .owner = THIS_MODULE, + }, + .attach_adapter = v4l2_i2c_drv_probe_legacy, + .detach_client = v4l2_i2c_drv_detach_legacy, + .suspend = v4l2_i2c_drv_suspend_helper, + .resume = v4l2_i2c_drv_resume_helper, +}; + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver v4l2_i2c_driver = { + .suspend = v4l2_i2c_drv_suspend_helper, + .resume = v4l2_i2c_drv_resume_helper, +}; + +static int __init v4l2_i2c_drv_init(void) +{ + int err; + + strlcpy(v4l2_i2c_drv_name_legacy, v4l2_i2c_data.name, sizeof(v4l2_i2c_drv_name_legacy)); + strlcat(v4l2_i2c_drv_name_legacy, "'", sizeof(v4l2_i2c_drv_name_legacy)); + + if (v4l2_i2c_data.legacy_class == 0) + v4l2_i2c_data.legacy_class = I2C_CLASS_TV_ANALOG; + + v4l2_i2c_driver_legacy.driver.name = v4l2_i2c_drv_name_legacy; + v4l2_i2c_driver_legacy.id = v4l2_i2c_data.driverid; + v4l2_i2c_driver_legacy.command = v4l2_i2c_data.command; + err = i2c_add_driver(&v4l2_i2c_driver_legacy); + + if (err) + return err; + v4l2_i2c_driver.driver.name = v4l2_i2c_data.name; + v4l2_i2c_driver.id = v4l2_i2c_data.driverid; + v4l2_i2c_driver.command = v4l2_i2c_data.command; + v4l2_i2c_driver.probe = v4l2_i2c_data.probe; + v4l2_i2c_driver.remove = v4l2_i2c_data.remove; + err = i2c_add_driver(&v4l2_i2c_driver); + if (err) + i2c_del_driver(&v4l2_i2c_driver_legacy); + return err; +} + +static void __exit v4l2_i2c_drv_cleanup(void) +{ + i2c_del_driver(&v4l2_i2c_driver_legacy); + i2c_del_driver(&v4l2_i2c_driver); +} + +module_init(v4l2_i2c_drv_init); +module_exit(v4l2_i2c_drv_cleanup); diff --git a/include/media/v4l2-i2c-drv.h b/include/media/v4l2-i2c-drv.h new file mode 100644 index 0000000..bc61ab2 --- /dev/null +++ b/include/media/v4l2-i2c-drv.h @@ -0,0 +1,62 @@ +/* + * v4l2-i2c-drv.h - contains I2C handling code that's identical for + * all V4L2 I2C drivers. Use this header if the + * I2C driver is only used by drivers converted + * to the bus-based I2C API. + * + * Copyright (C) 2007 Hans Verkuil + * + * 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. + */ + +struct v4l2_i2c_driver_data { + const char * const name; + int driverid; + int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); + int (*probe)(struct i2c_client *client); + int (*remove)(struct i2c_client *client); + int (*suspend)(struct i2c_client *client, pm_message_t state); + int (*resume)(struct i2c_client *client); + int (*legacy_probe)(struct i2c_adapter *adapter); + int legacy_class; +}; + +static struct v4l2_i2c_driver_data v4l2_i2c_data; +static struct i2c_client_address_data addr_data; +static struct i2c_driver v4l2_i2c_driver; + + +/* Bus-based I2C implementation for kernels >= 2.6.22 */ + +static int __init v4l2_i2c_drv_init(void) +{ + v4l2_i2c_driver.driver.name = v4l2_i2c_data.name; + v4l2_i2c_driver.id = v4l2_i2c_data.driverid; + v4l2_i2c_driver.command = v4l2_i2c_data.command; + v4l2_i2c_driver.probe = v4l2_i2c_data.probe; + v4l2_i2c_driver.remove = v4l2_i2c_data.remove; + v4l2_i2c_driver.suspend = v4l2_i2c_data.suspend; + v4l2_i2c_driver.resume = v4l2_i2c_data.resume; + return i2c_add_driver(&v4l2_i2c_driver); +} + + +static void __exit v4l2_i2c_drv_cleanup(void) +{ + i2c_del_driver(&v4l2_i2c_driver); +} + +module_init(v4l2_i2c_drv_init); +module_exit(v4l2_i2c_drv_cleanup); diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 066ebfc..c8b80e0 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -44,9 +44,8 @@ enum v4l2_int_type { struct v4l2_int_device; struct v4l2_int_master { - int (*attach)(struct v4l2_int_device *master, - struct v4l2_int_device *slave); - void (*detach)(struct v4l2_int_device *master); + int (*attach)(struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *slave); }; typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 0fa5d59..7aa7a7b 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -56,13 +56,13 @@ struct videobuf_mapping { }; enum videobuf_state { - STATE_NEEDS_INIT = 0, - STATE_PREPARED = 1, - STATE_QUEUED = 2, - STATE_ACTIVE = 3, - STATE_DONE = 4, - STATE_ERROR = 5, - STATE_IDLE = 6, + VIDEOBUF_NEEDS_INIT = 0, + VIDEOBUF_PREPARED = 1, + VIDEOBUF_QUEUED = 2, + VIDEOBUF_ACTIVE = 3, + VIDEOBUF_DONE = 4, + VIDEOBUF_ERROR = 5, + VIDEOBUF_IDLE = 6, }; struct videobuf_buffer { @@ -162,12 +162,12 @@ struct videobuf_queue { struct videobuf_queue_ops *ops; struct videobuf_qtype_ops *int_ops; + unsigned int streaming:1; + unsigned int reading:1; /* capture via mmap() + ioctl(QBUF/DQBUF) */ - unsigned int streaming; struct list_head stream; /* capture via read() */ - unsigned int reading; unsigned int read_off; struct videobuf_buffer *read_buf; @@ -208,6 +208,8 @@ int videobuf_cgmbuf(struct videobuf_queue *q, int videobuf_streamon(struct videobuf_queue *q); int videobuf_streamoff(struct videobuf_queue *q); +void videobuf_stop(struct videobuf_queue *q); + int videobuf_read_start(struct videobuf_queue *q); void videobuf_read_stop(struct videobuf_queue *q); ssize_t videobuf_read_stream(struct videobuf_queue *q,