summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/saa7134
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/saa7134')
-rw-r--r--linux/drivers/media/video/saa7134/Kconfig2
-rw-r--r--linux/drivers/media/video/saa7134/saa6752hs.c322
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c3
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-core.c66
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c77
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-input.c144
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-video.c106
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h6
8 files changed, 507 insertions, 219 deletions
diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig
index 83f076abc..7021bbf58 100644
--- a/linux/drivers/media/video/saa7134/Kconfig
+++ b/linux/drivers/media/video/saa7134/Kconfig
@@ -27,9 +27,7 @@ config VIDEO_SAA7134_ALSA
config VIDEO_SAA7134_DVB
tristate "DVB/ATSC Support for saa7134 based TV cards"
depends on VIDEO_SAA7134 && DVB_CORE
- depends on HOTPLUG # due to FW_LOADER
select VIDEOBUF_DVB
- select FW_LOADER
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c
index c5c19a2e3..011fc19f6 100644
--- a/linux/drivers/media/video/saa7134/saa6752hs.c
+++ b/linux/drivers/media/video/saa7134/saa6752hs.c
@@ -1,3 +1,27 @@
+ /*
+ saa6752hs - i2c-driver for the saa6752hs by Philips
+
+ Copyright (C) 2004 Andrew de Quincey
+
+ AC-3 support:
+
+ Copyright (C) 2008 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 vs 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 Mvss Ave, Cambridge, MA 02139, USA.
+ */
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -11,6 +35,8 @@
#include "compat.h"
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
#include <linux/init.h>
#include <linux/crc32.h>
@@ -28,9 +54,6 @@ MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
MODULE_AUTHOR("Andrew de Quincey");
MODULE_LICENSE("GPL");
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
enum saa6752hs_videoformat {
SAA6752HS_VF_D1 = 0, /* standard D1 video format: 720x576 */
SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */
@@ -47,7 +70,9 @@ struct saa6752hs_mpeg_params {
__u16 ts_pid_pcr;
/* audio */
- enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+ enum v4l2_mpeg_audio_encoding au_encoding;
+ enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+ enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate;
/* video */
enum v4l2_mpeg_video_aspect vi_aspect;
@@ -71,7 +96,9 @@ static const struct v4l2_format v4l2_format_table[] =
};
struct saa6752hs_state {
- struct i2c_client client;
+ int chip;
+ u32 revision;
+ int has_ac3;
struct saa6752hs_mpeg_params params;
enum saa6752hs_videoformat video_format;
v4l2_std_id standard;
@@ -146,6 +173,39 @@ static u8 PMT[] = {
0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
+static u8 PMT_AC3[] = {
+ 0xc2, /* i2c register */
+ 0x01, /* table number for encoder(1) */
+ 0x47, /* sync */
+
+ 0x40, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */
+ 0x10, /* PMT PID (0x0010) */
+ 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
+
+ 0x00, /* PSI pointer to start of table */
+
+ 0x02, /* TID (2) */
+ 0xb0, 0x1a, /* section_syntax_indicator(1), section_length(26) */
+
+ 0x00, 0x01, /* program_number(1) */
+
+ 0xc1, /* version_number(0), current_next_indicator(1) */
+
+ 0x00, 0x00, /* section_number(0), last_section_number(0) */
+
+ 0xe1, 0x04, /* PCR_PID (0x0104) */
+
+ 0xf0, 0x00, /* program_info_length(0) */
+
+ 0x02, 0xe1, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+ 0x06, 0xe1, 0x03, 0xf0, 0x03, /* audio stream type(6), pid */
+ 0x6a, /* AC3 */
+ 0x01, /* Descriptor_length(1) */
+ 0x00, /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */
+
+ 0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */
+};
+
static struct saa6752hs_mpeg_params param_defaults =
{
.ts_pid_pmt = 16,
@@ -158,7 +218,9 @@ static struct saa6752hs_mpeg_params param_defaults =
.vi_bitrate_peak = 6000,
.vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .au_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+ .au_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
};
/* ---------------------------------------------------------------------- */
@@ -231,8 +293,9 @@ static int saa6752hs_chip_command(struct i2c_client* client,
static int saa6752hs_set_bitrate(struct i2c_client* client,
- struct saa6752hs_mpeg_params* params)
+ struct saa6752hs_state *h)
{
+ struct saa6752hs_mpeg_params *params = &h->params;
u8 buf[3];
int tot_bitrate;
@@ -264,11 +327,19 @@ static int saa6752hs_set_bitrate(struct i2c_client* client,
tot_bitrate = params->vi_bitrate;
}
+ /* set the audio encoding */
+ buf[0] = 0x93;
+ buf[1] = (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3);
+ i2c_master_send(client, buf, 2);
+
/* set the audio bitrate */
buf[0] = 0x94;
- buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1;
+ if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3)
+ buf[1] = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate;
+ else
+ buf[1] = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate;
+ tot_bitrate += buf[1] ? 384 : 256;
i2c_master_send(client, buf, 2);
- tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384;
/* Note: the total max bitrate is determined by adding the video and audio
bitrates together and also adding an extra 768kbit/s to stay on the
@@ -333,7 +404,7 @@ static void saa6752hs_set_subsampling(struct i2c_client* client,
}
-static int handle_ctrl(struct saa6752hs_mpeg_params *params,
+static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
struct v4l2_ext_control *ctrl, unsigned int cmd)
{
int old = 0, new;
@@ -380,8 +451,9 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
params->ts_pid_pcr = new;
break;
case V4L2_CID_MPEG_AUDIO_ENCODING:
- old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
- if (set && new != old)
+ old = params->au_encoding;
+ if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+ (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
return -ERANGE;
new = old;
break;
@@ -396,6 +468,19 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
params->au_l2_bitrate = new;
break;
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ if (!has_ac3)
+ return -EINVAL;
+ old = params->au_ac3_bitrate;
+ if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
+ new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
+ return -ERANGE;
+ if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
+ new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
+ else
+ new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
+ params->au_ac3_bitrate = new;
+ break;
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
if (set && new != old)
@@ -449,17 +534,19 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
return 0;
}
-static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
+static int saa6752hs_qctrl(struct saa6752hs_state *h,
struct v4l2_queryctrl *qctrl)
{
+ struct saa6752hs_mpeg_params *params = &h->params;
int err;
switch (qctrl->id) {
case V4L2_CID_MPEG_AUDIO_ENCODING:
return v4l2_ctrl_query_fill(qctrl,
V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+ h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
return v4l2_ctrl_query_fill(qctrl,
@@ -467,6 +554,14 @@ static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
V4L2_MPEG_AUDIO_L2_BITRATE_256K);
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ if (!h->has_ac3)
+ return -EINVAL;
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
+
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
return v4l2_ctrl_query_fill(qctrl,
V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
@@ -513,44 +608,57 @@ static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
return -EINVAL;
}
-static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params,
+static int saa6752hs_qmenu(struct saa6752hs_state *h,
struct v4l2_querymenu *qmenu)
{
- static const char *mpeg_audio_l2_bitrate[] = {
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "256 kbps",
- "",
- "384 kbps",
- NULL
+ static const u32 mpeg_audio_encoding[] = {
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_CTRL_MENU_IDS_END
+ };
+ static const u32 mpeg_audio_ac3_encoding[] = {
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_MPEG_AUDIO_ENCODING_AC3,
+ V4L2_CTRL_MENU_IDS_END
+ };
+ static u32 mpeg_audio_l2_bitrate[] = {
+ V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K,
+ V4L2_CTRL_MENU_IDS_END
+ };
+ static u32 mpeg_audio_ac3_bitrate[] = {
+ V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
+ V4L2_CTRL_MENU_IDS_END
};
struct v4l2_queryctrl qctrl;
int err;
qctrl.id = qmenu->id;
- err = saa6752hs_qctrl(params, &qctrl);
+ err = saa6752hs_qctrl(h, &qctrl);
if (err)
return err;
- if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE)
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ switch (qmenu->id) {
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return v4l2_ctrl_query_menu_valid_items(qmenu,
mpeg_audio_l2_bitrate);
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
- v4l2_ctrl_get_menu(qmenu->id));
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ if (!h->has_ac3)
+ return -EINVAL;
+ return v4l2_ctrl_query_menu_valid_items(qmenu,
+ mpeg_audio_ac3_bitrate);
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_menu_valid_items(qmenu,
+ h->has_ac3 ? mpeg_audio_ac3_encoding :
+ mpeg_audio_encoding);
+ }
+ return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
}
static int saa6752hs_init(struct i2c_client* client)
{
unsigned char buf[9], buf2[4];
struct saa6752hs_state *h;
+ unsigned size;
u32 crc;
unsigned char localPAT[256];
unsigned char localPMT[256];
@@ -570,7 +678,7 @@ static int saa6752hs_init(struct i2c_client* client)
i2c_master_send(client, buf, 2);
/* set bitrate */
- saa6752hs_set_bitrate(client, &h->params);
+ saa6752hs_set_bitrate(client, h);
/* Set GOP structure {3, 13} */
buf[0] = 0x72;
@@ -609,7 +717,13 @@ static int saa6752hs_init(struct i2c_client* client)
localPAT[sizeof(PAT) - 1] = crc & 0xFF;
/* compute PMT */
- memcpy(localPMT, PMT, sizeof(PMT));
+ if (h->params.au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+ size = sizeof(PMT_AC3);
+ memcpy(localPMT, PMT_AC3, size);
+ } else {
+ size = sizeof(PMT);
+ memcpy(localPMT, PMT, size);
+ }
localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
localPMT[4] = h->params.ts_pid_pmt & 0xff;
localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
@@ -618,11 +732,11 @@ static int saa6752hs_init(struct i2c_client* client)
localPMT[21] = h->params.ts_pid_video & 0xFF;
localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F);
localPMT[26] = h->params.ts_pid_audio & 0xFF;
- crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4);
- localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF;
- localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF;
- localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
- localPMT[sizeof(PMT) - 1] = crc & 0xFF;
+ crc = crc32_be(~0, &localPMT[7], size - 7 - 4);
+ localPMT[size - 4] = (crc >> 24) & 0xFF;
+ localPMT[size - 3] = (crc >> 16) & 0xFF;
+ localPMT[size - 2] = (crc >> 8) & 0xFF;
+ localPMT[size - 1] = crc & 0xFF;
/* Set Audio PID */
buf[0] = 0xC1;
@@ -643,8 +757,8 @@ static int saa6752hs_init(struct i2c_client* client)
i2c_master_send(client,buf,3);
/* Send SI tables */
- i2c_master_send(client,localPAT,sizeof(PAT));
- i2c_master_send(client,localPMT,sizeof(PMT));
+ i2c_master_send(client, localPAT, sizeof(PAT));
+ i2c_master_send(client, localPMT, size);
/* mute then unmute audio. This removes buzzing artefacts */
buf[0] = 0xa4;
@@ -689,45 +803,6 @@ static int saa6752hs_init(struct i2c_client* client)
return 0;
}
-static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
-{
- struct saa6752hs_state *h;
-
-
- if (NULL == (h = kzalloc(sizeof(*h), GFP_KERNEL)))
- return -ENOMEM;
- h->client = client_template;
- h->params = param_defaults;
- h->client.adapter = adap;
- h->client.addr = addr;
-
- /* Assume 625 input lines */
- h->standard = 0;
-
- i2c_set_clientdata(&h->client, h);
- i2c_attach_client(&h->client);
-
- v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1);
- return 0;
-}
-
-static int saa6752hs_probe(struct i2c_adapter *adap)
-{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, saa6752hs_attach);
- return 0;
-}
-
-static int saa6752hs_detach(struct i2c_client *client)
-{
- struct saa6752hs_state *h;
-
- h = i2c_get_clientdata(client);
- i2c_detach_client(client);
- kfree(h);
- return 0;
-}
-
static int
saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
@@ -753,7 +828,8 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
return -EINVAL;
params = h->params;
for (i = 0; i < ctrls->count; i++) {
- if ((err = handle_ctrl(&params, ctrls->controls + i, cmd))) {
+ err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, cmd);
+ if (err) {
ctrls->error_idx = i;
return err;
}
@@ -761,9 +837,9 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
h->params = params;
break;
case VIDIOC_QUERYCTRL:
- return saa6752hs_qctrl(&h->params, arg);
+ return saa6752hs_qctrl(h, arg);
case VIDIOC_QUERYMENU:
- return saa6752hs_qmenu(&h->params, arg);
+ return saa6752hs_qmenu(h, arg);
case VIDIOC_G_FMT:
{
struct v4l2_format *f = arg;
@@ -786,6 +862,11 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_S_STD:
h->standard = *((v4l2_std_id *) arg);
break;
+
+ case VIDIOC_G_CHIP_IDENT:
+ return v4l2_chip_ident_i2c_client(client,
+ arg, h->chip, h->revision);
+
default:
/* nothing */
break;
@@ -794,36 +875,59 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
return err;
}
-/* ----------------------------------------------------------------------- */
+static int saa6752hs_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
+ u8 addr = 0x13;
+ u8 data[12];
-static struct i2c_driver driver = {
- .driver = {
- .name = "saa6752hs",
- },
- .id = I2C_DRIVERID_SAA6752HS,
- .attach_adapter = saa6752hs_probe,
- .detach_client = saa6752hs_detach,
- .command = saa6752hs_command,
-};
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
+ if (h == NULL)
+ return -ENOMEM;
-static struct i2c_client client_template =
-{
- .name = "saa6752hs",
- .driver = &driver,
-};
+ i2c_master_send(client, &addr, 1);
+ i2c_master_recv(client, data, sizeof(data));
+ h->chip = V4L2_IDENT_SAA6752HS;
+ h->revision = (data[8] << 8) | data[9];
+ h->has_ac3 = 0;
+ if (h->revision == 0x0206) {
+ h->chip = V4L2_IDENT_SAA6752HS_AC3;
+ h->has_ac3 = 1;
+ v4l_info(client, "support AC-3\n");
+ }
+ h->params = param_defaults;
+ h->standard = 0; /* Assume 625 input lines */
-static int __init saa6752hs_init_module(void)
-{
- return i2c_add_driver(&driver);
+ i2c_set_clientdata(client, h);
+ return 0;
}
-static void __exit saa6752hs_cleanup_module(void)
+static int saa6752hs_remove(struct i2c_client *client)
{
- i2c_del_driver(&driver);
+ kfree(i2c_get_clientdata(client));
+ return 0;
}
-module_init(saa6752hs_init_module);
-module_exit(saa6752hs_cleanup_module);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id saa6752hs_id[] = {
+ { "saa6752hs", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
+
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa6752hs",
+ .driverid = I2C_DRIVERID_SAA6752HS,
+ .command = saa6752hs_command,
+ .probe = saa6752hs_probe,
+ .remove = saa6752hs_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa6752hs_id,
+#endif
+};
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index 8ec09c97e..dfe4f7169 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -5956,9 +5956,6 @@ int saa7134_board_init2(struct saa7134_dev *dev)
unsigned char buf;
int board;
- dev->tuner_type = saa7134_boards[dev->board].tuner_type;
- dev->tuner_addr = saa7134_boards[dev->board].tuner_addr;
-
switch (dev->board) {
case SAA7134_BOARD_BMK_MPEX_NOTUNER:
case SAA7134_BOARD_BMK_MPEX_TUNER:
diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c
index 254a04717..62c9322aa 100644
--- a/linux/drivers/media/video/saa7134/saa7134-core.c
+++ b/linux/drivers/media/video/saa7134/saa7134-core.c
@@ -408,32 +408,6 @@ void saa7134_buffer_timeout(unsigned long data)
spin_unlock_irqrestore(&dev->slock,flags);
}
-/* resends a current buffer in queue after resume */
-
-static int saa7134_buffer_requeue(struct saa7134_dev *dev,
- struct saa7134_dmaqueue *q)
-{
- struct saa7134_buf *buf, *next;
-
- assert_spin_locked(&dev->slock);
-
- buf = q->curr;
- next = buf;
- dprintk("buffer_requeue\n");
-
- if (!buf)
- return 0;
-
- dprintk("buffer_requeue : resending active buffers \n");
-
- if (!list_empty(&q->queue))
- next = list_entry(q->queue.next, struct saa7134_buf,
- vb.queue);
- buf->activate(dev, buf, next);
-
- return 0;
-}
-
/* ------------------------------------------------------------------ */
int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -1006,11 +980,12 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
dev->board = SAA7134_BOARD_UNKNOWN;
}
dev->autodetected = card[dev->nr] != dev->board;
- dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ dev->tuner_addr = saa7134_boards[dev->board].tuner_addr;
dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
if (UNSET != tuner[dev->nr])
dev->tuner_type = tuner[dev->nr];
- printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
dev->name,pci_dev->subsystem_vendor,
pci_dev->subsystem_device,saa7134_boards[dev->board].name,
dev->board, dev->autodetected ?
@@ -1068,11 +1043,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
v4l2_prio_init(&dev->prio);
/* register v4l devices */
- if (saa7134_no_overlay <= 0) {
- saa7134_video_template.type |= VID_TYPE_OVERLAY;
- } else {
- printk("%s: Overlay support disabled.\n",dev->name);
- }
+ if (saa7134_no_overlay > 0)
+ printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name);
+
dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
video_nr[dev->nr]);
@@ -1085,7 +1058,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
dev->name,dev->video_dev->minor & 0x1f);
dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
- dev->vbi_dev->type = VID_TYPE_TUNER | VID_TYPE_TELETEXT;
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[dev->nr]);
@@ -1205,6 +1177,32 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
}
#ifdef CONFIG_PM
+
+/* resends a current buffer in queue after resume */
+static int saa7134_buffer_requeue(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q)
+{
+ struct saa7134_buf *buf, *next;
+
+ assert_spin_locked(&dev->slock);
+
+ buf = q->curr;
+ next = buf;
+ dprintk("buffer_requeue\n");
+
+ if (!buf)
+ return 0;
+
+ dprintk("buffer_requeue : resending active buffers \n");
+
+ if (!list_empty(&q->queue))
+ next = list_entry(q->queue.next, struct saa7134_buf,
+ vb.queue);
+ buf->activate(dev, buf, next);
+
+ return 0;
+}
+
static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
{
diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c
index dc3c2a6cb..5225ed6b8 100644
--- a/linux/drivers/media/video/saa7134/saa7134-empress.c
+++ b/linux/drivers/media/video/saa7134/saa7134-empress.c
@@ -29,6 +29,7 @@
#include <media/saa6752hs.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
/* ------------------------------------------------------------------ */
@@ -79,9 +80,11 @@ static int ts_open(struct inode *inode, struct file *file)
struct saa7134_dev *dev;
int err;
+ lock_kernel();
list_for_each_entry(dev, &saa7134_devlist, devlist)
if (dev->empress_dev && dev->empress_dev->minor == minor)
goto found;
+ unlock_kernel();
return -ENODEV;
found:
@@ -89,20 +92,21 @@ static int ts_open(struct inode *inode, struct file *file)
err = -EBUSY;
if (!mutex_trylock(&dev->empress_tsq.vb_lock))
goto done;
- if (dev->empress_users)
+ if (atomic_read(&dev->empress_users))
goto done_up;
/* Unmute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
- dev->empress_users++;
+ atomic_inc(&dev->empress_users);
file->private_data = dev;
err = 0;
done_up:
mutex_unlock(&dev->empress_tsq.vb_lock);
done:
+ unlock_kernel();
return err;
}
@@ -110,8 +114,6 @@ static int ts_release(struct inode *inode, struct file *file)
{
struct saa7134_dev *dev = file->private_data;
- mutex_lock(&dev->empress_tsq.vb_lock);
-
videobuf_stop(&dev->empress_tsq);
videobuf_mmap_free(&dev->empress_tsq);
@@ -122,9 +124,7 @@ static int ts_release(struct inode *inode, struct file *file)
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
- dev->empress_users--;
-
- mutex_unlock(&dev->empress_tsq.vb_lock);
+ atomic_dec(&dev->empress_users);
return 0;
}
@@ -333,6 +333,22 @@ static int empress_g_ext_ctrls(struct file *file, void *priv,
return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls);
}
+static int empress_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *c)
+{
+ struct saa7134_dev *dev = file->private_data;
+
+ return saa7134_g_ctrl_internal(dev, NULL, c);
+}
+
+static int empress_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *c)
+{
+ struct saa7134_dev *dev = file->private_data;
+
+ return saa7134_s_ctrl_internal(dev, NULL, c);
+}
+
static int empress_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *c)
{
@@ -388,6 +404,25 @@ static int empress_querymenu(struct file *file, void *priv,
return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c);
}
+static int empress_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_chip_ident *chip)
+{
+ struct saa7134_dev *dev = file->private_data;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (dev->mpeg_i2c_client == NULL)
+ return -EINVAL;
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match_chip == I2C_DRIVERID_SAA6752HS)
+ return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR &&
+ chip->match_chip == dev->mpeg_i2c_client->addr)
+ return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip);
+ return -EINVAL;
+}
+
+
static const struct file_operations ts_fops =
{
.owner = THIS_MODULE,
@@ -400,16 +435,7 @@ static const struct file_operations ts_fops =
.llseek = no_llseek,
};
-/* ----------------------------------------------------------- */
-
-static struct video_device saa7134_empress_template =
-{
- .name = "saa7134-empress",
- .type = 0 /* FIXME */,
- .type2 = 0 /* FIXME */,
- .fops = &ts_fops,
- .minor = -1,
-
+static const struct v4l2_ioctl_ops ts_ioctl_ops = {
.vidioc_querycap = empress_querycap,
.vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap,
@@ -425,11 +451,20 @@ static struct video_device saa7134_empress_template =
.vidioc_enum_input = empress_enum_input,
.vidioc_g_input = empress_g_input,
.vidioc_s_input = empress_s_input,
-
.vidioc_queryctrl = empress_queryctrl,
.vidioc_querymenu = empress_querymenu,
- .vidioc_g_ctrl = saa7134_g_ctrl,
- .vidioc_s_ctrl = saa7134_s_ctrl,
+ .vidioc_g_ctrl = empress_g_ctrl,
+ .vidioc_s_ctrl = empress_s_ctrl,
+ .vidioc_g_chip_ident = empress_g_chip_ident,
+};
+
+/* ----------------------------------------------------------- */
+
+static struct video_device saa7134_empress_template = {
+ .name = "saa7134-empress",
+ .fops = &ts_fops,
+ .minor = -1,
+ .ioctl_ops = &ts_ioctl_ops,
.tvnorms = SAA7134_NORMS,
.current_norm = V4L2_STD_PAL,
@@ -453,7 +488,7 @@ static void empress_signal_update(struct work_struct *work)
ts_reset_encoder(dev);
} else {
dprintk("video signal acquired\n");
- if (dev->empress_users)
+ if (atomic_read(&dev->empress_users))
ts_init_encoder(dev);
}
}
diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c
index f26fd7061..a9f6df2dd 100644
--- a/linux/drivers/media/video/saa7134/saa7134-input.c
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c
@@ -62,8 +62,11 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
#define i2cdprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
-/** rc5 functions */
+/* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
static int saa7134_rc5_irq(struct saa7134_dev *dev);
+static int saa7134_nec_irq(struct saa7134_dev *dev);
+static void nec_task(unsigned long data);
+static void saa7134_nec_timer(unsigned long data);
/* -------------------- GPIO generic keycode builder -------------------- */
@@ -280,7 +283,9 @@ void saa7134_input_irq(struct saa7134_dev *dev)
{
struct card_ir *ir = dev->remote;
- if (!ir->polling && !ir->rc5_gpio) {
+ if (ir->nec_gpio) {
+ saa7134_nec_irq(dev);
+ } else if (!ir->polling && !ir->rc5_gpio) {
build_key(dev);
} else if (ir->rc5_gpio) {
saa7134_rc5_irq(dev);
@@ -316,6 +321,10 @@ void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
ir->addr = 0x17;
ir->rc5_key_timeout = ir_rc5_key_timeout;
ir->rc5_remote_gap = ir_rc5_remote_gap;
+ } else if (ir->nec_gpio) {
+ setup_timer(&ir->timer_keyup, saa7134_nec_timer,
+ (unsigned long)dev);
+ tasklet_init(&ir->tlet, nec_task, (unsigned long)dev);
}
}
@@ -335,6 +344,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
u32 mask_keyup = 0;
int polling = 0;
int rc5_gpio = 0;
+ int nec_gpio = 0;
int ir_type = IR_TYPE_OTHER;
int err;
@@ -533,6 +543,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
ir->mask_keyup = mask_keyup;
ir->polling = polling;
ir->rc5_gpio = rc5_gpio;
+ ir->nec_gpio = nec_gpio;
/* init input device */
snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -679,8 +690,129 @@ static int saa7134_rc5_irq(struct saa7134_dev *dev)
return 1;
}
-/* ----------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
+
+/* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms
+ The first pulse (start) has 9 + 4.5 ms
*/
+
+static void saa7134_nec_timer(unsigned long data)
+{
+ struct saa7134_dev *dev = (struct saa7134_dev *) data;
+ struct card_ir *ir = dev->remote;
+
+ dprintk("Cancel key repeat\n");
+
+ ir_input_nokey(ir->dev, &ir->ir);
+}
+
+static void nec_task(unsigned long data)
+{
+ struct saa7134_dev *dev = (struct saa7134_dev *) data;
+ struct card_ir *ir;
+ struct timeval tv;
+ int count, pulse, oldpulse, gap;
+ u32 ircode = 0, not_code = 0;
+ int ngap = 0;
+
+ if (!data) {
+ printk(KERN_ERR "saa713x/ir: Can't recover dev struct\n");
+ /* GPIO will be kept disabled */
+ return;
+ }
+
+ ir = dev->remote;
+
+ /* rising SAA7134_GPIO_GPRESCAN reads the status */
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+ oldpulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
+ pulse = oldpulse;
+
+ do_gettimeofday(&tv);
+ ir->base_time = tv;
+
+ /* Decode NEC pulsecode. This code can take up to 76.5 ms to run.
+ Unfortunately, using IRQ to decode pulse didn't work, since it uses
+ a pulse train of 38KHz. This means one pulse on each 52 us
+ */
+ do {
+ /* Wait until the end of pulse/space or 5 ms */
+ for (count = 0; count < 500; count++) {
+ udelay(10);
+ /* rising SAA7134_GPIO_GPRESCAN reads the status */
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)
+ & ir->mask_keydown;
+ if (pulse != oldpulse)
+ break;
+ }
+
+ do_gettimeofday(&tv);
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+
+ if (!pulse) {
+#if 0
+ if (!ngap && gap < 4000)
+ break;
+#endif
+ /* Bit 0 has 560 us, while bit 1 has 1120 us.
+ Do something only if bit == 1
+ */
+ if (ngap && (gap > 560 + 280)) {
+ unsigned int shift = ngap - 1;
+
+ /* Address first, then command */
+ if (shift < 8) {
+ shift += 8;
+ ircode |= 1 << shift;
+ } else if (shift < 16) {
+ not_code |= 1 << shift;
+ } else if (shift < 24) {
+ shift -= 16;
+ ircode |= 1 << shift;
+ } else {
+ shift -= 24;
+ not_code |= 1 << shift;
+ }
+ }
+ ngap++;
+ }
+
+
+ ir->base_time = tv;
+
+ /* TIMEOUT - Long pulse */
+ if (gap >= 5000)
+ break;
+ oldpulse = pulse;
+ } while (ngap < 32);
+
+ if (ngap == 32) {
+ /* FIXME: should check if not_code == ~ircode */
+ ir->code = ir_extract_bits(ircode, ir->mask_keycode);
+
+ dprintk("scancode = 0x%02x (code = 0x%02x, notcode= 0x%02x)\n",
+ ir->code, ircode, not_code);
+
+ ir_input_keydown(ir->dev, &ir->ir, ir->code, ir->code);
+ } else
+ dprintk("Repeat last key\n");
+
+ /* Keep repeating the last key */
+ mod_timer(&ir->timer_keyup, jiffies + msecs_to_jiffies(150));
+
+ saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
+}
+
+static int saa7134_nec_irq(struct saa7134_dev *dev)
+{
+ struct card_ir *ir = dev->remote;
+
+ saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
+ tasklet_schedule(&ir->tlet);
+
+ return 1;
+}
diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c
index e02bd2659..547c0401a 100644
--- a/linux/drivers/media/video/saa7134/saa7134-video.c
+++ b/linux/drivers/media/video/saa7134/saa7134-video.c
@@ -1112,10 +1112,8 @@ static struct videobuf_queue_ops video_qops = {
/* ------------------------------------------------------------------ */
-int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
+int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
const struct v4l2_queryctrl* ctrl;
ctrl = ctrl_by_id(c->id);
@@ -1160,20 +1158,31 @@ int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
}
return 0;
}
-EXPORT_SYMBOL_GPL(saa7134_g_ctrl);
+EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal);
-int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
+static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
+{
+ struct saa7134_fh *fh = priv;
+
+ return saa7134_g_ctrl_internal(fh->dev, fh, c);
+}
+
+int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c)
{
const struct v4l2_queryctrl* ctrl;
- struct saa7134_fh *fh = f;
- struct saa7134_dev *dev = fh->dev;
unsigned long flags;
int restart_overlay = 0;
- int err = -EINVAL;
+ int err;
- err = v4l2_prio_check(&dev->prio, &fh->prio);
- if (0 != err)
- return err;
+ /* When called from the empress code fh == NULL.
+ That needs to be fixed somehow, but for now this is
+ good enough. */
+ if (fh) {
+ err = v4l2_prio_check(&dev->prio, &fh->prio);
+ if (0 != err)
+ return err;
+ }
+ err = -EINVAL;
mutex_lock(&dev->lock);
@@ -1274,7 +1283,14 @@ error:
mutex_unlock(&dev->lock);
return err;
}
-EXPORT_SYMBOL_GPL(saa7134_s_ctrl);
+EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal);
+
+static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
+{
+ struct saa7134_fh *fh = f;
+
+ return saa7134_s_ctrl_internal(fh->dev, fh, c);
+}
/* ------------------------------------------------------------------ */
@@ -1314,6 +1330,8 @@ static int video_open(struct inode *inode, struct file *file)
struct saa7134_fh *fh;
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int radio = 0;
+
+ lock_kernel();
list_for_each_entry(dev, &saa7134_devlist, devlist) {
if (dev->video_dev && (dev->video_dev->minor == minor))
goto found;
@@ -1326,6 +1344,7 @@ static int video_open(struct inode *inode, struct file *file)
goto found;
}
}
+ unlock_kernel();
return -ENODEV;
found:
@@ -1334,8 +1353,10 @@ static int video_open(struct inode *inode, struct file *file)
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
- if (NULL == fh)
+ if (NULL == fh) {
+ unlock_kernel();
return -ENOMEM;
+ }
file->private_data = fh;
fh->dev = dev;
fh->radio = radio;
@@ -1368,6 +1389,7 @@ static int video_open(struct inode *inode, struct file *file)
/* switch to video/vbi mode */
video_mux(dev,dev->ctl_input);
}
+ unlock_kernel();
return 0;
}
@@ -2360,26 +2382,7 @@ static const struct file_operations video_fops =
.llseek = no_llseek,
};
-static const struct file_operations radio_fops =
-{
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
-};
-
-/* ----------------------------------------------------------- */
-/* exported stuff */
-
-struct video_device saa7134_video_template =
-{
- .name = "saa7134-video",
- .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER |
- VID_TYPE_CLIPPING|VID_TYPE_SCALES,
- .fops = &video_fops,
- .minor = -1,
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_querycap = saa7134_querycap,
.vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap,
@@ -2428,16 +2431,18 @@ struct video_device saa7134_video_template =
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
- .tvnorms = SAA7134_NORMS,
- .current_norm = V4L2_STD_PAL,
};
-struct video_device saa7134_radio_template =
-{
- .name = "saa7134-radio",
- .type = VID_TYPE_TUNER,
- .fops = &radio_fops,
- .minor = -1,
+static const struct file_operations radio_fops = {
+ .owner = THIS_MODULE,
+ .open = video_open,
+ .release = video_release,
+ .ioctl = video_ioctl2,
+ .compat_ioctl = v4l_compat_ioctl32,
+ .llseek = no_llseek,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
.vidioc_querycap = radio_querycap,
.vidioc_g_tuner = radio_g_tuner,
.vidioc_enum_input = radio_enum_input,
@@ -2454,6 +2459,25 @@ struct video_device saa7134_radio_template =
.vidioc_s_frequency = saa7134_s_frequency,
};
+/* ----------------------------------------------------------- */
+/* exported stuff */
+
+struct video_device saa7134_video_template = {
+ .name = "saa7134-video",
+ .fops = &video_fops,
+ .ioctl_ops = &video_ioctl_ops,
+ .minor = -1,
+ .tvnorms = SAA7134_NORMS,
+ .current_norm = V4L2_STD_PAL,
+};
+
+struct video_device saa7134_radio_template = {
+ .name = "saa7134-radio",
+ .fops = &radio_fops,
+ .ioctl_ops = &radio_ioctl_ops,
+ .minor = -1,
+};
+
int saa7134_video_init1(struct saa7134_dev *dev)
{
/* sanitycheck insmod options */
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index 053c358ff..e3ad9d9e7 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -566,7 +566,7 @@ struct saa7134_dev {
/* SAA7134_MPEG_EMPRESS only */
struct video_device *empress_dev;
struct videobuf_queue empress_tsq;
- unsigned int empress_users;
+ atomic_t empress_users;
struct work_struct empress_workqueue;
int empress_started;
@@ -668,8 +668,8 @@ extern unsigned int video_debug;
extern struct video_device saa7134_video_template;
extern struct video_device saa7134_radio_template;
-int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c);
-int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c);
+int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
+int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
int saa7134_videoport_init(struct saa7134_dev *dev);