summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xhgimport3
-rw-r--r--linux/Documentation/video4linux/CARDLIST.em28xx1
-rw-r--r--linux/Documentation/video4linux/si470x.txt11
-rw-r--r--linux/drivers/media/common/tuners/tuner-simple.c10
-rw-r--r--linux/drivers/media/radio/radio-si470x.c249
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.c1
-rw-r--r--linux/drivers/media/video/cx2341x.c3
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-video.c1
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c1
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c32
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h1
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-controls.c1
-rw-r--r--linux/drivers/media/video/saa6588.c195
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c2
-rw-r--r--linux/drivers/media/video/v4l2-common.c2
-rw-r--r--linux/drivers/media/video/v4l2-subdev.c4
-rw-r--r--linux/include/media/v4l2-chip-ident.h3
-rw-r--r--linux/include/media/v4l2-common.h8
-rw-r--r--linux/include/media/v4l2-subdev.h2
19 files changed, 348 insertions, 182 deletions
diff --git a/hgimport b/hgimport
index 099acbc52..ad73f2caf 100755
--- a/hgimport
+++ b/hgimport
@@ -104,3 +104,6 @@ done
echo To cherry pick all files, you can do something like:
echo "for i in $TMP/*.patch; do ./mailimport \$i; done"
+echo "To merge it, the better is to do:"
+echo "hg pull $1; hg merge && hg commit && make && hg push"
+
diff --git a/linux/Documentation/video4linux/CARDLIST.em28xx b/linux/Documentation/video4linux/CARDLIST.em28xx
index 69601089f..f97c8533d 100644
--- a/linux/Documentation/video4linux/CARDLIST.em28xx
+++ b/linux/Documentation/video4linux/CARDLIST.em28xx
@@ -61,3 +61,4 @@
62 -> Gadmei TVR200 (em2820/em2840)
63 -> Kaiomy TVnPC U2 (em2860) [eb1a:e303]
64 -> Easy Cap Capture DC-60 (em2860)
+ 65 -> IO-DATA GV-MVP/SZ (em2820/em2840) [04bb:0515]
diff --git a/linux/Documentation/video4linux/si470x.txt b/linux/Documentation/video4linux/si470x.txt
index 49679e6aa..3a7823e01 100644
--- a/linux/Documentation/video4linux/si470x.txt
+++ b/linux/Documentation/video4linux/si470x.txt
@@ -1,6 +1,6 @@
Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers
-Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net>
+Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
Information from Silicon Labs
@@ -41,7 +41,7 @@ chips are known to work:
- 10c4:818a: Silicon Labs USB FM Radio Reference Design
- 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
- 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
-- 10c5:819a: DealExtreme USB Radio
+- 10c5:819a: Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear)
Software
@@ -52,6 +52,7 @@ Testing is usually done with most application under Debian/testing:
- gradio - GTK FM radio tuner
- kradio - Comfortable Radio Application for KDE
- radio - ncurses-based radio application
+- mplayer - The Ultimate Movie Player For Linux
There is also a library libv4l, which can be used. It's going to have a function
for frequency seeking, either by using hardware functionality as in radio-si470x
@@ -69,7 +70,7 @@ Audio Listing
USB Audio is provided by the ALSA snd_usb_audio module. It is recommended to
also select SND_USB_AUDIO, as this is required to get sound from the radio. For
listing you have to redirect the sound, for example using one of the following
-commands.
+commands. Please adjust the audio devices to your needs (/dev/dsp* and hw:x,x).
If you just want to test audio (very poor quality):
cat /dev/dsp1 > /dev/dsp
@@ -80,6 +81,10 @@ sox -2 --endian little -r 96000 -t oss /dev/dsp1 -t oss /dev/dsp
If you use arts try:
arecord -D hw:1,0 -r96000 -c2 -f S16_LE | artsdsp aplay -B -
+If you use mplayer try:
+mplayer -radio adevice=hw=1.0:arate=96000 \
+ -rawaudio rate=96000 \
+ radio://<frequency>/capture
Module Parameters
=================
diff --git a/linux/drivers/media/common/tuners/tuner-simple.c b/linux/drivers/media/common/tuners/tuner-simple.c
index 36aaa7e75..233476df9 100644
--- a/linux/drivers/media/common/tuners/tuner-simple.c
+++ b/linux/drivers/media/common/tuners/tuner-simple.c
@@ -325,7 +325,6 @@ static int simple_std_setup(struct dvb_frontend *fe,
u8 *config, u8 *cb)
{
struct tuner_simple_priv *priv = fe->tuner_priv;
- u8 tuneraddr;
int rc;
/* tv norm specific stuff for multi-norm tuners */
@@ -394,6 +393,7 @@ static int simple_std_setup(struct dvb_frontend *fe,
case TUNER_PHILIPS_TUV1236D:
{
+ struct tuner_i2c_props i2c = priv->i2c_props;
/* 0x40 -> ATSC antenna input 1 */
/* 0x48 -> ATSC antenna input 2 */
/* 0x00 -> NTSC antenna input 1 */
@@ -405,17 +405,15 @@ static int simple_std_setup(struct dvb_frontend *fe,
buffer[1] = 0x04;
}
/* set to the correct mode (analog or digital) */
- tuneraddr = priv->i2c_props.addr;
- priv->i2c_props.addr = 0x0a;
- rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[0], 2);
+ i2c.addr = 0x0a;
+ rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2);
if (2 != rc)
tuner_warn("i2c i/o error: rc == %d "
"(should be 2)\n", rc);
- rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[2], 2);
+ rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2);
if (2 != rc)
tuner_warn("i2c i/o error: rc == %d "
"(should be 2)\n", rc);
- priv->i2c_props.addr = tuneraddr;
break;
}
}
diff --git a/linux/drivers/media/radio/radio-si470x.c b/linux/drivers/media/radio/radio-si470x.c
index f77a65d2a..b0a1e5832 100644
--- a/linux/drivers/media/radio/radio-si470x.c
+++ b/linux/drivers/media/radio/radio-si470x.c
@@ -5,8 +5,9 @@
* - Silicon Labs USB FM Radio Reference Design
* - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
* - KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
+ * - Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear)
*
- * Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net>
+ * Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -29,7 +30,7 @@
* 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net>
* Version 1.0.0
* - First working version
- * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net>
+ * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net>
* Version 1.0.1
* - Improved error handling, every function now returns errno
* - Improved multi user access (start/mute/stop)
@@ -98,21 +99,27 @@
* - blacklisted KWorld radio in hid-core.c and hid-ids.h
* 2008-12-03 Mark Lord <mlord@pobox.com>
* - add support for DealExtreme USB Radio
+ * 2009-01-31 Bob Ross <pigiron@gmx.com>
+ * - correction of stereo detection/setting
+ * - correction of signal strength indicator scaling
+ * 2009-01-31 Rick Bronson <rick@efn.org>
+ * Tobias Lorenz <tobias.lorenz@gmx.net>
+ * - add LED status output
+ * - get HW/SW version from scratchpad
*
* ToDo:
* - add firmware download/update support
* - RDS support: interrupt mode, instead of polling
- * - add LED status output (check if that's not already done in firmware)
*/
/* driver definitions */
#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
#define DRIVER_NAME "radio-si470x"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 8)
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 9)
#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.8"
+#define DRIVER_VERSION "1.0.9"
/* kernel includes */
@@ -141,7 +148,7 @@ static struct usb_device_id si470x_usb_driver_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
/* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) },
- /* DealExtreme USB Radio */
+ /* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) },
/* Terminating entry */
{ }
@@ -341,7 +348,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
/* Report 19: stream */
#define STREAM_REPORT_SIZE 3
-#define STREAM_REPORT 19
+#define STREAM_REPORT 19
/* Report 20: scratch */
#define SCRATCH_PAGE_SIZE 63
@@ -349,9 +356,13 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
#define SCRATCH_REPORT 20
/* Reports 19-22: flash upgrade of the C8051F321 */
+#define WRITE_REPORT_SIZE 4
#define WRITE_REPORT 19
+#define FLASH_REPORT_SIZE 64
#define FLASH_REPORT 20
+#define CRC_REPORT_SIZE 3
#define CRC_REPORT 21
+#define RESPONSE_REPORT_SIZE 2
#define RESPONSE_REPORT 22
/* Report 23: currently unused, but can accept 60 byte reports on the HID */
@@ -410,7 +421,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
/* bootloader commands */
#define GET_SW_VERSION_COMMAND 0x00
-#define SET_PAGE_COMMAND 0x01
+#define SET_PAGE_COMMAND 0x01
#define ERASE_PAGE_COMMAND 0x02
#define WRITE_PAGE_COMMAND 0x03
#define CRC_ON_PAGE_COMMAND 0x04
@@ -424,12 +435,6 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
#define COMMAND_FAILED 0x02
#define COMMAND_PENDING 0x03
-/* buffer sizes */
-#define COMMAND_BUFFER_SIZE 4
-#define RESPONSE_BUFFER_SIZE 2
-#define FLASH_BUFFER_SIZE 64
-#define CRC_BUFFER_SIZE 3
-
/**************************************************************************
@@ -465,6 +470,10 @@ struct si470x_device {
unsigned int buf_size;
unsigned int rd_index;
unsigned int wr_index;
+
+ /* scratch page */
+ unsigned char software_version;
+ unsigned char hardware_version;
};
@@ -480,7 +489,7 @@ struct si470x_device {
/**************************************************************************
- * General Driver Functions
+ * General Driver Functions - REGISTER_REPORTs
**************************************************************************/
/*
@@ -566,60 +575,6 @@ static int si470x_set_register(struct si470x_device *radio, int regnr)
/*
- * si470x_get_all_registers - read entire registers
- */
-static int si470x_get_all_registers(struct si470x_device *radio)
-{
- unsigned char buf[ENTIRE_REPORT_SIZE];
- int retval;
- unsigned char regnr;
-
- buf[0] = ENTIRE_REPORT;
-
- retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
-
- if (retval >= 0)
- for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
- radio->registers[regnr] = get_unaligned_be16(
- &buf[regnr * RADIO_REGISTER_SIZE + 1]);
-
- return (retval < 0) ? -EINVAL : 0;
-}
-
-
-/*
- * si470x_get_rds_registers - read rds registers
- */
-static int si470x_get_rds_registers(struct si470x_device *radio)
-{
- unsigned char buf[RDS_REPORT_SIZE];
- int retval;
- int size;
- unsigned char regnr;
-
- buf[0] = RDS_REPORT;
-
- retval = usb_interrupt_msg(radio->usbdev,
- usb_rcvintpipe(radio->usbdev, 1),
- (void *) &buf, sizeof(buf), &size, usb_timeout);
- if (size != sizeof(buf))
- printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
- "return size differs: %d != %zu\n", size, sizeof(buf));
- if (retval < 0)
- printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
- "usb_interrupt_msg returned %d\n", retval);
-
- if (retval >= 0)
- for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
- radio->registers[STATUSRSSI + regnr] =
- get_unaligned_be16(
- &buf[regnr * RADIO_REGISTER_SIZE + 1]);
-
- return (retval < 0) ? -EINVAL : 0;
-}
-
-
-/*
* si470x_set_chan - set the channel
*/
static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
@@ -887,6 +842,123 @@ static int si470x_rds_on(struct si470x_device *radio)
/**************************************************************************
+ * General Driver Functions - ENTIRE_REPORT
+ **************************************************************************/
+
+/*
+ * si470x_get_all_registers - read entire registers
+ */
+static int si470x_get_all_registers(struct si470x_device *radio)
+{
+ unsigned char buf[ENTIRE_REPORT_SIZE];
+ int retval;
+ unsigned char regnr;
+
+ buf[0] = ENTIRE_REPORT;
+
+ retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
+
+ if (retval >= 0)
+ for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
+ radio->registers[regnr] = get_unaligned_be16(
+ &buf[regnr * RADIO_REGISTER_SIZE + 1]);
+
+ return (retval < 0) ? -EINVAL : 0;
+}
+
+
+
+/**************************************************************************
+ * General Driver Functions - RDS_REPORT
+ **************************************************************************/
+
+/*
+ * si470x_get_rds_registers - read rds registers
+ */
+static int si470x_get_rds_registers(struct si470x_device *radio)
+{
+ unsigned char buf[RDS_REPORT_SIZE];
+ int retval;
+ int size;
+ unsigned char regnr;
+
+ buf[0] = RDS_REPORT;
+
+ retval = usb_interrupt_msg(radio->usbdev,
+ usb_rcvintpipe(radio->usbdev, 1),
+ (void *) &buf, sizeof(buf), &size, usb_timeout);
+ if (size != sizeof(buf))
+ printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
+ "return size differs: %d != %zu\n", size, sizeof(buf));
+ if (retval < 0)
+ printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
+ "usb_interrupt_msg returned %d\n", retval);
+
+ if (retval >= 0)
+ for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
+ radio->registers[STATUSRSSI + regnr] =
+ get_unaligned_be16(
+ &buf[regnr * RADIO_REGISTER_SIZE + 1]);
+
+ return (retval < 0) ? -EINVAL : 0;
+}
+
+
+
+/**************************************************************************
+ * General Driver Functions - LED_REPORT
+ **************************************************************************/
+
+/*
+ * si470x_set_led_state - sets the led state
+ */
+static int si470x_set_led_state(struct si470x_device *radio,
+ unsigned char led_state)
+{
+ unsigned char buf[LED_REPORT_SIZE];
+ int retval;
+
+ buf[0] = LED_REPORT;
+ buf[1] = LED_COMMAND;
+ buf[2] = led_state;
+
+ retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
+
+ return (retval < 0) ? -EINVAL : 0;
+}
+
+
+
+/**************************************************************************
+ * General Driver Functions - SCRATCH_REPORT
+ **************************************************************************/
+
+/*
+ * si470x_get_scratch_versions - gets the scratch page and version infos
+ */
+static int si470x_get_scratch_page_versions(struct si470x_device *radio)
+{
+ unsigned char buf[SCRATCH_REPORT_SIZE];
+ int retval;
+
+ buf[0] = SCRATCH_REPORT;
+
+ retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
+
+ if (retval < 0)
+ printk(KERN_WARNING DRIVER_NAME ": si470x_get_scratch: "
+ "si470x_get_report returned %d\n", retval);
+ else {
+ radio->software_version = buf[1];
+ radio->hardware_version = buf[2];
+ }
+
+ return (retval < 0) ? -EINVAL : 0;
+}
+
+
+
+/**************************************************************************
* RDS Driver Functions
**************************************************************************/
@@ -1100,6 +1172,7 @@ static int si470x_fops_open(struct file *file)
}
if (radio->users == 1) {
+ /* start radio */
retval = si470x_start(radio);
if (retval < 0)
usb_autopm_put_interface(radio->intf);
@@ -1141,6 +1214,7 @@ static int si470x_fops_release(struct file *file)
/* cancel read processes */
wake_up_interruptible(&radio->read_queue);
+ /* stop radio */
retval = si470x_stop(radio);
usb_autopm_put_interface(radio->intf);
}
@@ -1392,20 +1466,22 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
};
/* stereo indicator == stereo (instead of mono) */
- if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
- tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- else
+ if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+ else
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
/* mono/stereo selector */
- if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 1)
- tuner->audmode = V4L2_TUNER_MODE_MONO;
- else
+ if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
tuner->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ tuner->audmode = V4L2_TUNER_MODE_MONO;
/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
- tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
- * 0x0101;
+ /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */
+ tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
+ /* the ideal factor is 0xffff/75 = 873,8 */
+ tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
/* automatic frequency control: -1: freq to low, 1 freq to high */
/* AFCRL does only indicate that freq. differs, not if too low/high */
@@ -1612,7 +1688,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
sizeof(si470x_viddev_template));
video_set_drvdata(radio->videodev, radio);
- /* show some infos about the specific device */
+ /* show some infos about the specific si470x device */
if (si470x_get_all_registers(radio) < 0) {
retval = -EIO;
goto err_all;
@@ -1620,7 +1696,16 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
radio->registers[DEVICEID], radio->registers[CHIPID]);
- /* check if firmware is current */
+ /* get software and hardware versions */
+ if (si470x_get_scratch_page_versions(radio) < 0) {
+ retval = -EIO;
+ goto err_all;
+ }
+ printk(KERN_INFO DRIVER_NAME
+ ": software version %d, hardware version %d\n",
+ radio->software_version, radio->hardware_version);
+
+ /* check if device and firmware is current */
if ((radio->registers[CHIPID] & CHIPID_FIRMWARE)
< RADIO_SW_VERSION_CURRENT) {
printk(KERN_WARNING DRIVER_NAME
@@ -1639,6 +1724,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
/* set initial frequency */
si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
+ /* set led to connect state */
+ si470x_set_led_state(radio, BLINK_GREEN_LED);
+
/* rds buffer allocation */
radio->buf_size = rds_buf * 3;
radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
@@ -1722,6 +1810,9 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
cancel_delayed_work_sync(&radio->work);
usb_set_intfdata(intf, NULL);
if (radio->users == 0) {
+ /* set led to disconnect state */
+ si470x_set_led_state(radio, BLINK_ORANGE_LED);
+
video_unregister_device(radio->videodev);
kfree(radio->buffer);
kfree(radio);
diff --git a/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c
index 6af4d5c19..10a4e07b7 100644
--- a/linux/drivers/media/video/cx18/cx18-controls.c
+++ b/linux/drivers/media/video/cx18/cx18-controls.c
@@ -30,6 +30,7 @@
#include "cx18-mailbox.h"
#include "cx18-controls.h"
+/* Must be sorted from low to high control ID! */
static const u32 user_ctrls[] = {
V4L2_CID_USER_CLASS,
V4L2_CID_BRIGHTNESS,
diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c
index c92b98135..01c4d2d02 100644
--- a/linux/drivers/media/video/cx2341x.c
+++ b/linux/drivers/media/video/cx2341x.c
@@ -39,6 +39,7 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
+/* Must be sorted from low to high control ID! */
const u32 cx2341x_mpeg_ctrls[] = {
V4L2_CID_MPEG_CLASS,
V4L2_CID_MPEG_STREAM_TYPE,
@@ -46,12 +47,12 @@ const u32 cx2341x_mpeg_ctrls[] = {
V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
V4L2_CID_MPEG_AUDIO_ENCODING,
V4L2_CID_MPEG_AUDIO_L2_BITRATE,
- V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
V4L2_CID_MPEG_AUDIO_MODE,
V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
V4L2_CID_MPEG_AUDIO_EMPHASIS,
V4L2_CID_MPEG_AUDIO_CRC,
V4L2_CID_MPEG_AUDIO_MUTE,
+ V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
V4L2_CID_MPEG_VIDEO_ENCODING,
V4L2_CID_MPEG_VIDEO_ASPECT,
V4L2_CID_MPEG_VIDEO_B_FRAMES,
diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c
index 09291888d..131fc740a 100644
--- a/linux/drivers/media/video/cx23885/cx23885-video.c
+++ b/linux/drivers/media/video/cx23885/cx23885-video.c
@@ -276,6 +276,7 @@ static struct cx23885_ctrl cx23885_ctls[] = {
};
static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
+/* Must be sorted from low to high control ID! */
static const u32 cx23885_user_ctrls[] = {
V4L2_CID_USER_CLASS,
V4L2_CID_BRIGHTNESS,
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index a95bcb0ea..c8870cf06 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -299,6 +299,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
};
static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);
+/* Must be sorted from low to high control ID! */
const u32 cx88_user_ctrls[] = {
V4L2_CID_USER_CLASS,
V4L2_CID_BRIGHTNESS,
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index 8e285fc84..d69000674 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -1362,6 +1362,26 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
+ [EM2820_BOARD_IODATA_GVMVP_SZ] = {
+ .name = "IO-DATA GV-MVP/SZ",
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .tuner_gpio = default_tuner_gpio,
+ .tda9887_conf = TDA9887_PRESENT,
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = EM28XX_AMUX_VIDEO,
+ }, { /* Composite has not been tested yet */
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = EM28XX_AMUX_VIDEO,
+ }, { /* S-video has not been tested yet */
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = EM28XX_AMUX_VIDEO,
+ } },
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1465,6 +1485,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
{ USB_DEVICE(0x093b, 0xa005),
.driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
+ { USB_DEVICE(0x04bb, 0x0515),
+ .driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -1658,6 +1680,16 @@ void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_write_regs(dev, 0x08, "\xf8", 1);
break;
+ case EM2820_BOARD_IODATA_GVMVP_SZ:
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+ msleep(70);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+ msleep(10);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+ msleep(70);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+ msleep(70);
+ break;
}
em28xx_gpio_set(dev, dev->board.tuner_gpio);
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index a0128819d..4aebda6c7 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -102,6 +102,7 @@
#define EM2820_BOARD_GADMEI_TVR200 62
#define EM2860_BOARD_KAIOMY_TVNPC_U2 63
#define EM2860_BOARD_EASYCAP 64
+#define EM2820_BOARD_IODATA_GVMVP_SZ 65
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
diff --git a/linux/drivers/media/video/ivtv/ivtv-controls.c b/linux/drivers/media/video/ivtv/ivtv-controls.c
index 62aa06f5d..84995bcf4 100644
--- a/linux/drivers/media/video/ivtv/ivtv-controls.c
+++ b/linux/drivers/media/video/ivtv/ivtv-controls.c
@@ -26,6 +26,7 @@
#include "ivtv-mailbox.h"
#include "ivtv-controls.h"
+/* Must be sorted from low to high control ID! */
static const u32 user_ctrls[] = {
V4L2_CID_USER_CLASS,
V4L2_CID_BRIGHTNESS,
diff --git a/linux/drivers/media/video/saa6588.c b/linux/drivers/media/video/saa6588.c
index ab41d9526..77c3b59e8 100644
--- a/linux/drivers/media/video/saa6588.c
+++ b/linux/drivers/media/video/saa6588.c
@@ -32,6 +32,9 @@
#include <asm/uaccess.h>
#include <media/rds.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
#include "compat.h"
/* Addresses to scan */
@@ -73,7 +76,7 @@ MODULE_LICENSE("GPL");
#define dprintk if (debug) printk
struct saa6588 {
- struct i2c_client client;
+ struct v4l2_subdev sd;
struct work_struct work;
struct timer_list timer;
spinlock_t lock;
@@ -87,8 +90,10 @@ struct saa6588 {
int data_available_for_read;
};
-static struct i2c_driver driver;
-static struct i2c_client client_template;
+static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa6588, sd);
+}
/* ---------------------------------------------------------------------- */
@@ -259,6 +264,7 @@ static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
static void saa6588_i2c_poll(struct saa6588 *s)
{
+ struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
unsigned long flags;
unsigned char tmpbuf[6];
unsigned char blocknum;
@@ -266,7 +272,7 @@ static void saa6588_i2c_poll(struct saa6588 *s)
/* Although we only need 3 bytes, we have to read at least 6.
SAA6588 returns garbage otherwise */
- if (6 != i2c_master_recv(&s->client, &tmpbuf[0], 6)) {
+ if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
if (debug > 1)
dprintk(PREFIX "read error!\n");
return;
@@ -342,6 +348,7 @@ static void saa6588_work(struct work_struct *work)
static int saa6588_configure(struct saa6588 *s)
{
+ struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
unsigned char buf[3];
int rc;
@@ -389,7 +396,8 @@ static int saa6588_configure(struct saa6588 *s)
dprintk(PREFIX "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n",
buf[0], buf[1], buf[2]);
- if (3 != (rc = i2c_master_send(&s->client, buf, 3)))
+ rc = i2c_master_send(client, buf, 3);
+ if (rc != 3)
printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
return 0;
@@ -397,38 +405,101 @@ static int saa6588_configure(struct saa6588 *s)
/* ---------------------------------------------------------------------- */
-static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
+static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct saa6588 *s = to_saa6588(sd);
+ struct rds_command *a = arg;
+
+ switch (cmd) {
+ /* --- open() for /dev/radio --- */
+ case RDS_CMD_OPEN:
+ a->result = 0; /* return error if chip doesn't work ??? */
+ break;
+ /* --- close() for /dev/radio --- */
+ case RDS_CMD_CLOSE:
+ s->data_available_for_read = 1;
+ wake_up_interruptible(&s->read_queue);
+ a->result = 0;
+ break;
+ /* --- read() for /dev/radio --- */
+ case RDS_CMD_READ:
+ read_from_buf(s, a);
+ break;
+ /* --- poll() for /dev/radio --- */
+ case RDS_CMD_POLL:
+ a->result = 0;
+ if (s->data_available_for_read) {
+ a->result |= POLLIN | POLLRDNORM;
+ }
+ poll_wait(a->instance, &s->read_queue, a->event_list);
+ break;
+
+ default:
+ /* nothing */
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA6588, 0);
+}
+
+static int saa6588_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa6588_core_ops = {
+ .g_chip_ident = saa6588_g_chip_ident,
+ .ioctl = saa6588_ioctl,
+};
+
+static const struct v4l2_subdev_ops saa6588_ops = {
+ .core = &saa6588_core_ops,
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int saa6588_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct saa6588 *s;
- client_template.adapter = adap;
- client_template.addr = addr;
+ struct v4l2_subdev *sd;
- printk(PREFIX "chip found @ 0x%x\n", addr << 1);
+ v4l_info(client, "saa6588 found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
- if (NULL == (s = kmalloc(sizeof(*s), GFP_KERNEL)))
+ s = kzalloc(sizeof(*s), GFP_KERNEL);
+ if (s == NULL)
return -ENOMEM;
s->buf_size = bufblocks * 3;
- if (NULL == (s->buffer = kmalloc(s->buf_size, GFP_KERNEL))) {
+ s->buffer = kmalloc(s->buf_size, GFP_KERNEL);
+ if (s->buffer == NULL) {
kfree(s);
return -ENOMEM;
}
+ sd = &s->sd;
+ v4l2_i2c_subdev_init(sd, client, &saa6588_ops);
spin_lock_init(&s->lock);
- s->client = client_template;
s->block_count = 0;
s->wr_index = 0;
s->rd_index = 0;
s->last_blocknum = 0xff;
init_waitqueue_head(&s->read_queue);
s->data_available_for_read = 0;
- i2c_set_clientdata(&s->client, s);
- i2c_attach_client(&s->client);
saa6588_configure(s);
/* start polling via eventd */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
INIT_WORK(&s->work, saa6588_work, s);
#else
INIT_WORK(&s->work, saa6588_work);
@@ -440,97 +511,37 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
return 0;
}
-static int saa6588_probe(struct i2c_adapter *adap)
+static int saa6588_remove(struct i2c_client *client)
{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, saa6588_attach);
- return 0;
-}
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct saa6588 *s = to_saa6588(sd);
-static int saa6588_detach(struct i2c_client *client)
-{
- struct saa6588 *s = i2c_get_clientdata(client);
+ v4l2_device_unregister_subdev(sd);
del_timer_sync(&s->timer);
flush_scheduled_work();
- i2c_detach_client(client);
kfree(s->buffer);
kfree(s);
return 0;
}
-static int saa6588_command(struct i2c_client *client, unsigned int cmd,
- void *arg)
-{
- struct saa6588 *s = i2c_get_clientdata(client);
- struct rds_command *a = (struct rds_command *)arg;
-
- switch (cmd) {
- /* --- open() for /dev/radio --- */
- case RDS_CMD_OPEN:
- a->result = 0; /* return error if chip doesn't work ??? */
- break;
- /* --- close() for /dev/radio --- */
- case RDS_CMD_CLOSE:
- s->data_available_for_read = 1;
- wake_up_interruptible(&s->read_queue);
- a->result = 0;
- break;
- /* --- read() for /dev/radio --- */
- case RDS_CMD_READ:
- read_from_buf(s, a);
- break;
- /* --- poll() for /dev/radio --- */
- case RDS_CMD_POLL:
- a->result = 0;
- if (s->data_available_for_read) {
- a->result |= POLLIN | POLLRDNORM;
- }
- poll_wait(a->instance, &s->read_queue, a->event_list);
- break;
-
- default:
- /* nothing */
- break;
- }
- return 0;
-}
-
/* ----------------------------------------------------------------------- */
-static struct i2c_driver driver = {
- .driver = {
- .name = "saa6588",
- },
- .id = -1, /* FIXME */
- .attach_adapter = saa6588_probe,
- .detach_client = saa6588_detach,
- .command = saa6588_command,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id saa6588_id[] = {
+ { "saa6588", 0 },
+ { }
};
+MODULE_DEVICE_TABLE(i2c, saa6588_id);
-static struct i2c_client client_template = {
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa6588",
- .driver = &driver,
+ .command = saa6588_command,
+ .probe = saa6588_probe,
+ .remove = saa6588_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa6588_id,
+#endif
};
-
-static int __init saa6588_init_module(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit saa6588_cleanup_module(void)
-{
- i2c_del_driver(&driver);
-}
-
-module_init(saa6588_init_module);
-module_exit(saa6588_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c
index 3b0b42545..813f5f88d 100644
--- a/linux/drivers/media/video/saa7134/saa7134-empress.c
+++ b/linux/drivers/media/video/saa7134/saa7134-empress.c
@@ -352,6 +352,7 @@ static int empress_s_ctrl(struct file *file, void *priv,
static int empress_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *c)
{
+ /* Must be sorted from low to high control ID! */
static const u32 user_ctrls[] = {
V4L2_CID_USER_CLASS,
V4L2_CID_BRIGHTNESS,
@@ -364,6 +365,7 @@ static int empress_queryctrl(struct file *file, void *priv,
0
};
+ /* Must be sorted from low to high control ID! */
static const u32 mpeg_ctrls[] = {
V4L2_CID_MPEG_CLASS,
V4L2_CID_MPEG_STREAM_TYPE,
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index 6cc7d4058..8ae8dd366 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -750,7 +750,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items);
/* ctrl_classes points to an array of u32 pointers, the last element is
a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
Each array must be sorted low to high and belong to the same control
- class. The array of u32 pointer must also be sorted, from low class IDs
+ class. The array of u32 pointers must also be sorted, from low class IDs
to high class IDs.
This function returns the first ID that follows after the given ID.
diff --git a/linux/drivers/media/video/v4l2-subdev.c b/linux/drivers/media/video/v4l2-subdev.c
index 158bc55de..923ec8d01 100644
--- a/linux/drivers/media/video/v4l2-subdev.c
+++ b/linux/drivers/media/video/v4l2-subdev.c
@@ -104,6 +104,10 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg)
return v4l2_subdev_call(sd, video, g_fmt, arg);
case VIDIOC_INT_S_STD_OUTPUT:
return v4l2_subdev_call(sd, video, s_std_output, *(v4l2_std_id *)arg);
+ case VIDIOC_QUERYSTD:
+ return v4l2_subdev_call(sd, video, querystd, arg);
+ case VIDIOC_INT_G_INPUT_STATUS:
+ return v4l2_subdev_call(sd, video, g_input_status, arg);
case VIDIOC_STREAMON:
return v4l2_subdev_call(sd, video, s_stream, 1);
case VIDIOC_STREAMOFF:
diff --git a/linux/include/media/v4l2-chip-ident.h b/linux/include/media/v4l2-chip-ident.h
index 4e2182e52..bbe2bb6a5 100644
--- a/linux/include/media/v4l2-chip-ident.h
+++ b/linux/include/media/v4l2-chip-ident.h
@@ -92,6 +92,9 @@ enum {
/* module tea6420: just ident 6420 */
V4L2_IDENT_TEA6420 = 6420,
+ /* module saa6588: just ident 6588 */
+ V4L2_IDENT_SAA6588 = 6588,
+
/* module saa6752hs: reserved range 6750-6759 */
V4L2_IDENT_SAA6752HS = 6752,
V4L2_IDENT_SAA6752HS_AC3 = 6753,
diff --git a/linux/include/media/v4l2-common.h b/linux/include/media/v4l2-common.h
index 0f864f8da..de785da45 100644
--- a/linux/include/media/v4l2-common.h
+++ b/linux/include/media/v4l2-common.h
@@ -107,6 +107,11 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
struct v4l2_queryctrl *qctrl, const char **menu_items);
#define V4L2_CTRL_MENU_IDS_END (0xffffffff)
int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids);
+
+/* Note: ctrl_classes points to an array of u32 pointers. Each u32 array is a
+ 0-terminated array of control IDs. Each array must be sorted low to high
+ and belong to the same control class. The array of u32 pointers must also
+ be sorted, from low class IDs to high class IDs. */
u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
/* ------------------------------------------------------------------------- */
@@ -297,4 +302,7 @@ struct v4l2_crystal_freq {
a v4l2_gpio struct if a direction is also needed. */
#define VIDIOC_INT_S_GPIO _IOW('d', 117, u32)
+/* Get input status. Same as the status field in the v4l2_input struct. */
+#define VIDIOC_INT_G_INPUT_STATUS _IOR('d', 118, u32)
+
#endif /* V4L2_COMMON_H_ */
diff --git a/linux/include/media/v4l2-subdev.h b/linux/include/media/v4l2-subdev.h
index 9c1663d91..cd640c6f0 100644
--- a/linux/include/media/v4l2-subdev.h
+++ b/linux/include/media/v4l2-subdev.h
@@ -115,6 +115,8 @@ struct v4l2_subdev_video_ops {
int (*g_vbi_data)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *vbi_data);
int (*g_sliced_vbi_cap)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap);
int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
+ int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
+ int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
int (*s_stream)(struct v4l2_subdev *sd, int enable);
int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
int (*g_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);