aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/cx18
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx18')
-rw-r--r--drivers/media/video/cx18/cx18-audio.c15
-rw-r--r--drivers/media/video/cx18/cx18-av-audio.c12
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c225
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h16
-rw-r--r--drivers/media/video/cx18/cx18-av-firmware.c72
-rw-r--r--drivers/media/video/cx18/cx18-av-vbi.c152
-rw-r--r--drivers/media/video/cx18/cx18-cards.c89
-rw-r--r--drivers/media/video/cx18/cx18-cards.h9
-rw-r--r--drivers/media/video/cx18/cx18-controls.c216
-rw-r--r--drivers/media/video/cx18/cx18-controls.h7
-rw-r--r--drivers/media/video/cx18/cx18-driver.c21
-rw-r--r--drivers/media/video/cx18/cx18-driver.h7
-rw-r--r--drivers/media/video/cx18/cx18-firmware.c10
-rw-r--r--drivers/media/video/cx18/cx18-gpio.c90
-rw-r--r--drivers/media/video/cx18/cx18-gpio.h2
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c25
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c1179
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.h6
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c1
-rw-r--r--drivers/media/video/cx18/cx18-streams.c12
-rw-r--r--drivers/media/video/cx18/cx23418.h5
21 files changed, 1167 insertions, 1004 deletions
diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c
index 1adc404d955..6d5b94fc708 100644
--- a/drivers/media/video/cx18/cx18-audio.c
+++ b/drivers/media/video/cx18/cx18-audio.c
@@ -26,13 +26,17 @@
#include "cx18-cards.h"
#include "cx18-audio.h"
+#define CX18_AUDIO_ENABLE 0xc72014
+
/* Selects the audio input and output according to the current
settings. */
int cx18_audio_set_io(struct cx18 *cx)
{
struct v4l2_routing route;
u32 audio_input;
+ u32 val;
int mux_input;
+ int err;
/* Determine which input to use */
if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
@@ -51,8 +55,17 @@ int cx18_audio_set_io(struct cx18 *cx)
cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
route.input = audio_input;
- return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+ err = cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ if (err)
+ return err;
+
+ val = read_reg(CX18_AUDIO_ENABLE) & ~0x30;
+ val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
+ (audio_input << 4);
+ write_reg(val | 0xb00, CX18_AUDIO_ENABLE);
+ cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
+ return 0;
}
void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c
index 2dc3a5dd170..c40a286de1b 100644
--- a/drivers/media/video/cx18/cx18-av-audio.c
+++ b/drivers/media/video/cx18/cx18-av-audio.c
@@ -34,7 +34,7 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
cx18_av_write(cx, 0x127, 0x50);
- if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
switch (freq) {
case 32000:
/* VID_PLL and AUX_PLL */
@@ -148,7 +148,7 @@ void cx18_av_audio_set_path(struct cx18 *cx)
/* Mute everything to prevent the PFFT! */
cx18_av_write(cx, 0x8d3, 0x1f);
- if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) {
/* Set Path1 to Serial Audio Input */
cx18_av_write4(cx, 0x8d0, 0x01011012);
@@ -165,7 +165,7 @@ void cx18_av_audio_set_path(struct cx18 *cx)
/* deassert soft reset */
cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
- if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
/* When the microcontroller detects the
* audio format, it will unmute the lines */
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
@@ -271,7 +271,7 @@ static void set_mute(struct cx18 *cx, int mute)
{
struct cx18_av_state *state = &cx->av_state;
- if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
/* Must turn off microcontroller in order to mute sound.
* Not sure if this is the best method, but it does work.
* If the microcontroller is running, then it will undo any
@@ -298,14 +298,14 @@ int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
switch (cmd) {
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
cx18_av_and_or(cx, 0x803, ~0x10, 0);
cx18_av_write(cx, 0x8d3, 0x1f);
}
cx18_av_and_or(cx, 0x810, ~0x1, 1);
retval = set_audclk_freq(cx, *(u32 *)arg);
cx18_av_and_or(cx, 0x810, ~0x1, 0);
- if (state->aud_input != CX18_AV_AUDIO_SERIAL)
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2)
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
return retval;
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index faca43eb940..3b0a2c45060 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -69,58 +69,6 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
or_value);
}
-int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value, int no_acfg_mask)
-{
- int retval;
- u32 saved_reg[8] = {0};
-
- if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
- saved_reg[0] = cx18_av_read4(cx, CXADEC_CHIP_CTRL);
- saved_reg[1] = cx18_av_read4(cx, CXADEC_AFE_CTRL);
- }
-
- if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
- saved_reg[2] = cx18_av_read4(cx, CXADEC_PLL_CTRL1);
- saved_reg[3] = cx18_av_read4(cx, CXADEC_VID_PLL_FRAC);
- }
-
- if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
- saved_reg[4] = cx18_av_read4(cx, CXADEC_HORIZ_TIM_CTRL);
- saved_reg[5] = cx18_av_read4(cx, CXADEC_VERT_TIM_CTRL);
- saved_reg[6] = cx18_av_read4(cx, CXADEC_SRC_COMB_CFG);
- saved_reg[7] = cx18_av_read4(cx, CXADEC_CHROMA_VBIOFF_CFG);
- }
-
- retval = cx18_av_write(cx, addr, value);
-
- if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
- cx18_av_write4(cx, CXADEC_CHIP_CTRL, saved_reg[0]);
- cx18_av_write4(cx, CXADEC_AFE_CTRL, saved_reg[1]);
- }
-
- if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
- cx18_av_write4(cx, CXADEC_PLL_CTRL1, saved_reg[2]);
- cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, saved_reg[3]);
- }
-
- if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
- cx18_av_write4(cx, CXADEC_HORIZ_TIM_CTRL, saved_reg[4]);
- cx18_av_write4(cx, CXADEC_VERT_TIM_CTRL, saved_reg[5]);
- cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, saved_reg[6]);
- cx18_av_write4(cx, CXADEC_CHROMA_VBIOFF_CFG, saved_reg[7]);
- }
-
- return retval;
-}
-
-int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned and_mask,
- u8 or_value, int no_acfg_mask)
-{
- return cx18_av_write_no_acfg(cx, addr,
- (cx18_av_read(cx, addr) & and_mask) |
- or_value, no_acfg_mask);
-}
-
/* ----------------------------------------------------------------------- */
static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
@@ -132,6 +80,7 @@ static void log_video_status(struct cx18 *cx);
static void cx18_av_initialize(struct cx18 *cx)
{
+ struct cx18_av_state *state = &cx->av_state;
u32 v;
cx18_av_loadfw(cx);
@@ -211,6 +160,149 @@ static void cx18_av_initialize(struct cx18 *cx)
/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
/* } */
cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
+ state->default_volume = 228 - cx18_av_read(cx, 0x8d4);
+ state->default_volume = ((state->default_volume / 2) + 23) << 9;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void cx18_av_std_setup(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ v4l2_std_id std = state->std;
+ int hblank, hactive, burst, vblank, vactive, sc;
+ int vblank656, src_decimation;
+ int luma_lpf, uv_lpf, comb;
+ u32 pll_int, pll_frac, pll_post;
+
+ /* datasheet startup, step 8d */
+ if (std & ~V4L2_STD_NTSC)
+ cx18_av_write(cx, 0x49f, 0x11);
+ else
+ cx18_av_write(cx, 0x49f, 0x14);
+
+ if (std & V4L2_STD_625_50) {
+ hblank = 132;
+ hactive = 720;
+ burst = 93;
+ vblank = 36;
+ vactive = 580;
+ vblank656 = 40;
+ src_decimation = 0x21f;
+
+ luma_lpf = 2;
+ if (std & V4L2_STD_PAL) {
+ uv_lpf = 1;
+ comb = 0x20;
+ sc = 688739;
+ } else if (std == V4L2_STD_PAL_Nc) {
+ uv_lpf = 1;
+ comb = 0x20;
+ sc = 556453;
+ } else { /* SECAM */
+ uv_lpf = 0;
+ comb = 0;
+ sc = 672351;
+ }
+ } else {
+ hactive = 720;
+ hblank = 122;
+ vactive = 487;
+ luma_lpf = 1;
+ uv_lpf = 1;
+ vblank = 26;
+ vblank656 = 26;
+
+ src_decimation = 0x21f;
+ if (std == V4L2_STD_PAL_60) {
+ burst = 0x5b;
+ luma_lpf = 2;
+ comb = 0x20;
+ sc = 688739;
+ } else if (std == V4L2_STD_PAL_M) {
+ burst = 0x61;
+ comb = 0x20;
+ sc = 555452;
+ } else {
+ burst = 0x5b;
+ comb = 0x66;
+ sc = 556063;
+ }
+ }
+
+ /* DEBUG: Displays configured PLL frequency */
+ pll_int = cx18_av_read(cx, 0x108);
+ pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
+ pll_post = cx18_av_read(cx, 0x109);
+ CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
+ pll_int, pll_frac, pll_post);
+
+ if (pll_post) {
+ int fin, fsc;
+ int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
+
+ pll >>= 25;
+ pll /= pll_post;
+ CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
+ pll / 1000000, pll % 1000000);
+ CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
+ pll / 8000000, (pll / 8) % 1000000);
+
+ fin = ((u64)src_decimation * pll) >> 12;
+ CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
+ fin / 1000000, fin % 1000000);
+
+ fsc = (((u64)sc) * pll) >> 24L;
+ CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
+ fsc / 1000000, fsc % 1000000);
+
+ CX18_DEBUG_INFO("hblank %i, hactive %i, "
+ "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+ "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+ " sc 0x%06x\n",
+ hblank, hactive, vblank, vactive, vblank656,
+ src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ }
+
+ /* Sets horizontal blanking delay and active lines */
+ cx18_av_write(cx, 0x470, hblank);
+ cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
+ (hactive << 4)));
+ cx18_av_write(cx, 0x472, hactive >> 4);
+
+ /* Sets burst gate delay */
+ cx18_av_write(cx, 0x473, burst);
+
+ /* Sets vertical blanking delay and active duration */
+ cx18_av_write(cx, 0x474, vblank);
+ cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
+ (vactive << 4)));
+ cx18_av_write(cx, 0x476, vactive >> 4);
+ cx18_av_write(cx, 0x477, vblank656);
+
+ /* Sets src decimation rate */
+ cx18_av_write(cx, 0x478, 0xff & src_decimation);
+ cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
+
+ /* Sets Luma and UV Low pass filters */
+ cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
+
+ /* Enables comb filters */
+ cx18_av_write(cx, 0x47b, comb);
+
+ /* Sets SC Step*/
+ cx18_av_write(cx, 0x47c, sc);
+ cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
+ cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
+
+ /* Sets VBI parameters */
+ if (std & V4L2_STD_625_50) {
+ cx18_av_write(cx, 0x47f, 0x01);
+ state->vbi_line_offset = 5;
+ } else {
+ cx18_av_write(cx, 0x47f, 0x00);
+ state->vbi_line_offset = 8;
+ }
}
/* ----------------------------------------------------------------------- */
@@ -221,16 +313,9 @@ static void input_change(struct cx18 *cx)
v4l2_std_id std = state->std;
/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
- if (std & V4L2_STD_SECAM)
- cx18_av_write_no_acfg(cx, 0x402, 0, CXADEC_NO_ACFG_ALL);
- else {
- cx18_av_write_no_acfg(cx, 0x402, 0x04, CXADEC_NO_ACFG_ALL);
- cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
- }
- cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0,
- CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
- cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0x60,
- CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
+ cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+ cx18_av_and_or(cx, 0x401, ~0x60, 0);
+ cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
if (std & V4L2_STD_525_60) {
if (std == V4L2_STD_NTSC_M_JP) {
@@ -300,7 +385,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
}
switch (aud_input) {
- case CX18_AV_AUDIO_SERIAL:
+ case CX18_AV_AUDIO_SERIAL1:
+ case CX18_AV_AUDIO_SERIAL2:
/* do nothing, use serial audio input */
break;
case CX18_AV_AUDIO4: reg &= ~0x30; break;
@@ -316,8 +402,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
cx18_av_write(cx, 0x103, reg);
/* Set INPUT_MODE to Composite (0) or S-Video (1) */
- cx18_av_and_or_no_acfg(cx, 0x401, ~0x6, is_composite ? 0 : 0x02,
- CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
+ cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
@@ -373,13 +458,13 @@ static int set_v4lstd(struct cx18 *cx)
This happens for example with the Yuan MPC622. */
if (fmt >= 4 && fmt < 8) {
/* Set format to NTSC-M */
- cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, 1, CXADEC_NO_ACFG_AFE);
+ cx18_av_and_or(cx, 0x400, ~0xf, 1);
/* Turn off LCOMB */
cx18_av_and_or(cx, 0x47b, ~6, 0);
}
- cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, fmt, CXADEC_NO_ACFG_AFE);
- cx18_av_and_or_no_acfg(cx, 0x403, ~0x3, pal_m, CXADEC_NO_ACFG_ALL);
- cx18_av_vbi_setup(cx);
+ cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20);
+ cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
+ cx18_av_std_setup(cx);
input_change(cx);
return 0;
}
@@ -618,6 +703,8 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
switch (qc->id) {
case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(qc, 0, 65535,
+ 65535 / 100, state->default_volume);
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index c172823ce1d..eb61fa1e096 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -62,7 +62,8 @@ enum cx18_av_video_input {
enum cx18_av_audio_input {
/* Audio inputs: serial or In4-In8 */
- CX18_AV_AUDIO_SERIAL,
+ CX18_AV_AUDIO_SERIAL1,
+ CX18_AV_AUDIO_SERIAL2,
CX18_AV_AUDIO4 = 4,
CX18_AV_AUDIO5,
CX18_AV_AUDIO6,
@@ -78,6 +79,7 @@ struct cx18_av_state {
u32 audclk_freq;
int audmode;
int vbi_line_offset;
+ int default_volume;
u32 id;
u32 rev;
int is_initialized;
@@ -295,25 +297,16 @@ struct cx18_av_state {
#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */
#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */
-/* Flags on what to preserve on write to 0x400-0x403 with cx18_av_.*_no_acfg()*/
-#define CXADEC_NO_ACFG_AFE 0x01 /* Preserve 0x100-0x107 */
-#define CXADEC_NO_ACFG_PLL 0x02 /* Preserve 0x108-0x10f */
-#define CXADEC_NO_ACFG_VID 0x04 /* Preserve 0x470-0x47f */
-#define CXADEC_NO_ACFG_ALL 0x07
-
/* ----------------------------------------------------------------------- */
/* cx18_av-core.c */
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
-int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value,
- int no_acfg_mask);
u8 cx18_av_read(struct cx18 *cx, u16 addr);
u32 cx18_av_read4(struct cx18 *cx, u16 addr);
int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
-int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned mask, u8 value,
- int no_acfg_mask);
int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
+void cx18_av_std_setup(struct cx18 *cx);
/* ----------------------------------------------------------------------- */
/* cx18_av-firmware.c */
@@ -326,7 +319,6 @@ void cx18_av_audio_set_path(struct cx18 *cx);
/* ----------------------------------------------------------------------- */
/* cx18_av-vbi.c */
-void cx18_av_vbi_setup(struct cx18 *cx);
int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
#endif
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index a1a6af6c1c8..834b9248242 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -22,6 +22,7 @@
#include "cx18-driver.h"
#include <linux/firmware.h>
+#define CX18_AUDIO_ENABLE 0xc72014
#define FWFILE "v4l-cx23418-dig.fw"
int cx18_av_loadfw(struct cx18 *cx)
@@ -31,40 +32,58 @@ int cx18_av_loadfw(struct cx18 *cx)
u32 v;
const u8 *ptr;
int i;
+ int retries = 0;
if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
CX18_ERR("unable to open firmware %s\n", FWFILE);
return -EINVAL;
}
- cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
- cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
-
- /* Reset the Mako core (Register is undocumented.) */
- cx18_av_write4(cx, 0x8100, 0x00010000);
-
- /* Put the 8051 in reset and enable firmware upload */
- cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
-
- ptr = fw->data;
- size = fw->size;
-
- for (i = 0; i < size; i++) {
- u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
- u32 value = 0;
- int retries;
-
- for (retries = 0; retries < 5; retries++) {
- cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
- value = cx18_av_read4(cx, CXADEC_DL_CTL);
- if ((value & 0x3F00) == (dl_control & 0x3F00))
+ /* The firmware load often has byte errors, so allow for several
+ retries, both at byte level and at the firmware load level. */
+ while (retries < 5) {
+ cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
+ cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
+
+ /* Reset the Mako core (Register is undocumented.) */
+ cx18_av_write4(cx, 0x8100, 0x00010000);
+
+ /* Put the 8051 in reset and enable firmware upload */
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+
+ ptr = fw->data;
+ size = fw->size;
+
+ for (i = 0; i < size; i++) {
+ u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
+ u32 value = 0;
+ int retries;
+
+ for (retries = 0; retries < 5; retries++) {
+ cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+ udelay(10);
+ value = cx18_av_read4(cx, CXADEC_DL_CTL);
+ if (value == dl_control)
+ break;
+ /* Check if we can correct the byte by changing
+ the address. We can only write the lower
+ address byte of the address. */
+ if ((value & 0x3F00) != (dl_control & 0x3F00)) {
+ retries = 5;
+ break;
+ }
+ }
+ if (retries >= 5)
break;
}
- if (retries >= 5) {
- CX18_ERR("unable to load firmware %s\n", FWFILE);
- release_firmware(fw);
- return -EIO;
- }
+ if (i == size)
+ break;
+ retries++;
+ }
+ if (retries >= 5) {
+ CX18_ERR("unable to load firmware %s\n", FWFILE);
+ release_firmware(fw);
+ return -EIO;
}
cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
@@ -100,7 +119,6 @@ int cx18_av_loadfw(struct cx18 *cx)
have a name in the spec. */
cx18_av_write4(cx, 0x09CC, 1);
-#define CX18_AUDIO_ENABLE 0xc72014
v = read_reg(CX18_AUDIO_ENABLE);
/* If bit 11 is 1 */
if (v & 0x800)
diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c
index d09f1daf4eb..02fdf57bb67 100644
--- a/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/drivers/media/video/cx18/cx18-av-vbi.c
@@ -83,150 +83,6 @@ static int decode_vps(u8 *dst, u8 *p)
return err & 0xf0;
}
-void cx18_av_vbi_setup(struct cx18 *cx)
-{
- struct cx18_av_state *state = &cx->av_state;
- v4l2_std_id std = state->std;
- int hblank, hactive, burst, vblank, vactive, sc;
- int vblank656, src_decimation;
- int luma_lpf, uv_lpf, comb;
- u32 pll_int, pll_frac, pll_post;
-
- /* datasheet startup, step 8d */
- if (std & ~V4L2_STD_NTSC)
- cx18_av_write(cx, 0x49f, 0x11);
- else
- cx18_av_write(cx, 0x49f, 0x14);
-
- if (std & V4L2_STD_625_50) {
- hblank = 0x084;
- hactive = 0x2d0;
- burst = 0x5d;
- vblank = 0x024;
- vactive = 0x244;
- vblank656 = 0x28;
- src_decimation = 0x21f;
-
- luma_lpf = 2;
- if (std & V4L2_STD_SECAM) {
- uv_lpf = 0;
- comb = 0;
- sc = 0x0a425f;
- } else if (std == V4L2_STD_PAL_Nc) {
- uv_lpf = 1;
- comb = 0x20;
- sc = 556453;
- } else {
- uv_lpf = 1;
- comb = 0x20;
- sc = 0x0a8263;
- }
- } else {
- hactive = 720;
- hblank = 122;
- vactive = 487;
- luma_lpf = 1;
- uv_lpf = 1;
-
- src_decimation = 0x21f;
- if (std == V4L2_STD_PAL_60) {
- vblank = 26;
- vblank656 = 26;
- burst = 0x5b;
- luma_lpf = 2;
- comb = 0x20;
- sc = 0x0a8263;
- } else if (std == V4L2_STD_PAL_M) {
- vblank = 20;
- vblank656 = 24;
- burst = 0x61;
- comb = 0x20;
-
- sc = 555452;
- } else {
- vblank = 26;
- vblank656 = 26;
- burst = 0x5b;
- comb = 0x66;
- sc = 556063;
- }
- }
-
- /* DEBUG: Displays configured PLL frequency */
- pll_int = cx18_av_read(cx, 0x108);
- pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
- pll_post = cx18_av_read(cx, 0x109);
- CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
- pll_int, pll_frac, pll_post);
-
- if (pll_post) {
- int fin, fsc;
- int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
-
- pll >>= 25;
- pll /= pll_post;
- CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
- pll / 1000000, pll % 1000000);
- CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
- pll / 8000000, (pll / 8) % 1000000);
-
- fin = ((u64)src_decimation * pll) >> 12;
- CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
- fin / 1000000, fin % 1000000);
-
- fsc = (((u64)sc) * pll) >> 24L;
- CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
- fsc / 1000000, fsc % 1000000);
-
- CX18_DEBUG_INFO("hblank %i, hactive %i, "
- "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
- "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
- " sc 0x%06x\n",
- hblank, hactive, vblank, vactive, vblank656,
- src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
- }
-
- /* Sets horizontal blanking delay and active lines */
- cx18_av_write(cx, 0x470, hblank);
- cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
- (hactive << 4)));
- cx18_av_write(cx, 0x472, hactive >> 4);
-
- /* Sets burst gate delay */
- cx18_av_write(cx, 0x473, burst);
-
- /* Sets vertical blanking delay and active duration */
- cx18_av_write(cx, 0x474, vblank);
- cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
- (vactive << 4)));
- cx18_av_write(cx, 0x476, vactive >> 4);
- cx18_av_write(cx, 0x477, vblank656);
-
- /* Sets src decimation rate */
- cx18_av_write(cx, 0x478, 0xff & src_decimation);
- cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
-
- /* Sets Luma and UV Low pass filters */
- cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
-
- /* Enables comb filters */
- cx18_av_write(cx, 0x47b, comb);
-
- /* Sets SC Step*/
- cx18_av_write(cx, 0x47c, sc);
- cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
- cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
-
- /* Sets VBI parameters */
- if (std & V4L2_STD_625_50) {
- cx18_av_write(cx, 0x47f, 0x01);
- state->vbi_line_offset = 5;
- } else {
- cx18_av_write(cx, 0x47f, 0x00);
- state->vbi_line_offset = 8;
- }
-}
-
int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
{
struct cx18_av_state *state = &cx->av_state;
@@ -292,8 +148,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
/* raw VBI */
memset(svbi, 0, sizeof(*svbi));
- /* Setup VBI */
- cx18_av_vbi_setup(cx);
+ /* Setup standard */
+ cx18_av_std_setup(cx);
/* VBI Offset */
cx18_av_write(cx, 0x47f, vbi_offset);
@@ -304,8 +160,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
for (x = 0; x <= 23; x++)
lcr[x] = 0x00;
- /* Setup VBI */
- cx18_av_vbi_setup(cx);
+ /* Setup standard */
+ cx18_av_std_setup(cx);
/* Sliced VBI */
cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index c26e0ef5b07..8fe5f38c4d7 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -27,6 +27,8 @@
#include "cx18-i2c.h"
#include <media/cs5345.h>
+#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
+
/********************** card configuration *******************************/
/* usual i2c tuner addresses to probe */
@@ -65,12 +67,12 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
{ CX18_CARD_INPUT_AUD_TUNER,
CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
{ CX18_CARD_INPUT_LINE_IN1,
- CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
{ CX18_CARD_INPUT_LINE_IN2,
- CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
.ddr = {
/* ESMT M13S128324A-5B memory */
.chip_config = 0x003,
@@ -86,6 +88,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
.active_lo_mask = 0x3001,
.msecs_asserted = 10,
.msecs_recovery = 40,
+ .ir_reset_mask = 0x0001,
},
.i2c = &cx18_i2c_std,
};
@@ -110,12 +113,12 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
{ CX18_CARD_INPUT_AUD_TUNER,
CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
{ CX18_CARD_INPUT_LINE_IN1,
- CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
{ CX18_CARD_INPUT_LINE_IN2,
- CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
.ddr = {
/* Samsung K4D263238G-VC33 memory */
.chip_config = 0x003,
@@ -131,6 +134,7 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
.active_lo_mask = 0x3001,
.msecs_asserted = 10,
.msecs_recovery = 40,
+ .ir_reset_mask = 0x0001,
},
.i2c = &cx18_i2c_std,
};
@@ -161,10 +165,10 @@ static const struct cx18_card cx18_card_h900 = {
{ CX18_CARD_INPUT_AUD_TUNER,
CX18_AV_AUDIO8, 0 },
{ CX18_CARD_INPUT_LINE_IN1,
- CX18_AV_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL1, 0 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX18_AV_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL1, 0 },
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
@@ -194,7 +198,7 @@ static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
static const struct cx18_card cx18_card_mpc718 = {
.type = CX18_CARD_YUAN_MPC718,
.name = "Yuan MPC718",
- .comment = "Some Composite and S-Video inputs are currently working.\n",
+ .comment = "Analog video capture works; some audio line in may not.\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_all = CX18_HW_TUNER,
@@ -209,11 +213,11 @@ static const struct cx18_card cx18_card_mpc718 = {
{ CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 },
},
.audio_inputs = {
- { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
- { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL, 0 },
- { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL, 0 },
+ { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
+ { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 0 },
+ { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL1, 0 },
},
- .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL, 0 },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 0 },
.tuners = {
/* XC3028 tuner */
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
@@ -227,16 +231,73 @@ static const struct cx18_card cx18_card_mpc718 = {
.tune_lane = 0,
.initial_emrs = 2,
},
- .xceive_pin = 15,
+ .xceive_pin = 0,
.pci_list = cx18_pci_mpc718,
.i2c = &cx18_i2c_std,
};
+/* ------------------------------------------------------------------------- */
+
+/* Conexant Raptor PAL/SECAM: note that this card is analog only! */
+
+static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_cnxt_raptor_pal = {
+ .type = CX18_CARD_CNXT_RAPTOR_PAL,
+ .name = "Conexant Raptor PAL/SECAM",
+ .comment = "VBI is not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_muxer = CX18_HW_GPIO,
+ .hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+ CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+ { CX18_CARD_INPUT_SVIDEO2, 2,
+ CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
+ { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 },
+ { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 },
+ },
+ .tuners = {
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 },
+ .ddr = {
+ /* MT 46V16M16 memory */
+ .chip_config = 0x50306,
+ .refresh = 0x753,
+ .timing1 = 0x33220953,
+ .timing2 = 0x09,
+ .tune_lane = 0,
+ .initial_emrs = 0,
+ },
+ .gpio_init.initial_value = 0x1002,
+ .gpio_init.direction = 0xf002,
+ .gpio_audio_input = { .mask = 0xf002,
+ .tuner = 0x1002, /* LED D1 Tuner AF */
+ .linein = 0x2000, /* LED D2 Line In 1 */
+ .radio = 0x4002 }, /* LED D3 Tuner AF */
+ .pci_list = cx18_pci_cnxt_raptor_pal,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
static const struct cx18_card *cx18_card_list[] = {
&cx18_card_hvr1600_esmt,
&cx18_card_hvr1600_samsung,
&cx18_card_h900,
&cx18_card_mpc718,
+ &cx18_card_cnxt_raptor_pal,
};
const struct cx18_card *cx18_get_card(u16 index)
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index dc2dd945d4c..32155f6e6fe 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -83,6 +83,14 @@ struct cx18_gpio_i2c_slave_reset {
u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
int msecs_asserted; /* time period reset must remain asserted */
int msecs_recovery; /* time after deassert for chips to be ready */
+ u32 ir_reset_mask; /* GPIO to reset the Zilog Z8F0811 IR contoller */
+};
+
+struct cx18_gpio_audio_input { /* select tuner/line in input */
+ u32 mask; /* leave to 0 if not supported */
+ u32 tuner;
+ u32 linein;
+ u32 radio;
};
struct cx18_card_tuner {
@@ -123,6 +131,7 @@ struct cx18_card {
u8 xceive_pin; /* XCeive tuner GPIO reset pin */
struct cx18_gpio_init gpio_init;
struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;
+ struct cx18_gpio_audio_input gpio_audio_input;
struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
struct cx18_card_tuner_i2c *i2c;
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
index 87cf4102166..f46c7e5ed74 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -51,12 +51,11 @@ static const u32 *ctrl_classes[] = {
NULL
};
-static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
+int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
const char *name;
- CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
-
qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
if (qctrl->id == 0)
return -EINVAL;
@@ -91,21 +90,35 @@ static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
return 0;
}
-static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu)
+int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
struct v4l2_queryctrl qctrl;
qctrl.id = qmenu->id;
- cx18_queryctrl(cx, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+ cx18_queryctrl(file, fh, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ cx2341x_ctrl_get_menu(&cx->params, qmenu->id));
}
-static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+static int cx18_try_ctrl(struct file *file, void *fh,
+ struct v4l2_ext_control *vctrl)
{
- s32 v = vctrl->value;
-
- CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
+ struct v4l2_queryctrl qctrl;
+ const char **menu_items = NULL;
+ int err;
+
+ qctrl.id = vctrl->id;
+ err = cx18_queryctrl(file, fh, &qctrl);
+ if (err)
+ return err;
+ if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+ menu_items = v4l2_ctrl_get_menu(qctrl.id);
+ return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
+}
+static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+{
switch (vctrl->id) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS:
@@ -123,7 +136,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
default:
- CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
return -EINVAL;
}
return 0;
@@ -131,8 +144,6 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
{
- CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
-
switch (vctrl->id) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS:
@@ -149,7 +160,7 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
case V4L2_CID_AUDIO_LOUDNESS:
return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
default:
- CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
return -EINVAL;
}
return 0;
@@ -194,113 +205,110 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
return 0;
}
-int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
+int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
struct v4l2_control ctrl;
- switch (cmd) {
- case VIDIOC_QUERYMENU:
- CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
- return cx18_querymenu(cx, arg);
-
- case VIDIOC_QUERYCTRL:
- return cx18_queryctrl(cx, arg);
-
- case VIDIOC_S_CTRL:
- return cx18_s_ctrl(cx, arg);
-
- case VIDIOC_G_CTRL:
- return cx18_g_ctrl(cx, arg);
-
- case VIDIOC_S_EXT_CTRLS:
- {
- struct v4l2_ext_controls *c = arg;
-
- if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
- int i;
- int err = 0;
-
- for (i = 0; i < c->count; i++) {
- ctrl.id = c->controls[i].id;
- ctrl.value = c->controls[i].value;
- err = cx18_s_ctrl(cx, &ctrl);
- c->controls[i].value = ctrl.value;
- if (err) {
- c->error_idx = i;
- break;
- }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_g_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
}
- return err;
}
- CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- struct cx2341x_mpeg_params p = cx->params;
- int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd);
+ return err;
+ }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS);
+ return -EINVAL;
+}
- if (err)
- return err;
+int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
+ struct v4l2_control ctrl;
- if (p.video_encoding != cx->params.video_encoding) {
- int is_mpeg1 = p.video_encoding ==
- V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- struct v4l2_format fmt;
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- /* fix videodecoder resolution */
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1);
- fmt.fmt.pix.height = cx->params.height;
- cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_s_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
}
- err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
- if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
- err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
- cx->params = p;
- cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
- cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
- return err;
}
- return -EINVAL;
+ return err;
}
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ struct cx2341x_mpeg_params p = cx->params;
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
+ c, VIDIOC_S_EXT_CTRLS);
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *c = arg;
-
- if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
- int i;
- int err = 0;
-
- for (i = 0; i < c->count; i++) {
- ctrl.id = c->controls[i].id;
- ctrl.value = c->controls[i].value;
- err = cx18_g_ctrl(cx, &ctrl);
- c->controls[i].value = ctrl.value;
- if (err) {
- c->error_idx = i;
- break;
- }
- }
+ if (err)
return err;
+
+ if (p.video_encoding != cx->params.video_encoding) {
+ int is_mpeg1 = p.video_encoding ==
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ struct v4l2_format fmt;
+
+ /* fix videodecoder resolution */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = cx->params.width
+ / (is_mpeg1 ? 2 : 1);
+ fmt.fmt.pix.height = cx->params.height;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
}
- CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd);
- return -EINVAL;
+ err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
+ if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
+ err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+ cx->params = p;
+ cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+ cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
+ return err;
}
+ return -EINVAL;
+}
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *c = arg;
+int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&cx->params,
- atomic_read(&cx->ana_capturing), arg, cmd);
- return -EINVAL;
- }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
- default:
- return -EINVAL;
+ for (i = 0; i < c->count; i++) {
+ err = cx18_try_ctrl(file, fh, &c->controls[i]);
+ if (err) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return err;
}
- return 0;
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params,
+ atomic_read(&cx->ana_capturing),
+ c, VIDIOC_TRY_EXT_CTRLS);
+ return -EINVAL;
}
diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h
index 6e985cf422a..e46323700b8 100644
--- a/drivers/media/video/cx18/cx18-controls.h
+++ b/drivers/media/video/cx18/cx18-controls.h
@@ -21,4 +21,9 @@
* 02111-1307 USA
*/
-int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg);
+int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
+int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int cx18_try_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *a);
+int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 2b810bb2a4c..22434aadde3 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -120,6 +120,7 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
"\t\t\t 3 = Compro VideoMate H900\n"
"\t\t\t 4 = Yuan MPC718\n"
+ "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -420,6 +421,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
mutex_init(&cx->serialize_lock);
mutex_init(&cx->i2c_bus_lock[0]);
mutex_init(&cx->i2c_bus_lock[1]);
+ mutex_init(&cx->gpio_lock);
spin_lock_init(&cx->lock);
spin_lock_init(&cx->dma_reg_lock);
@@ -435,7 +437,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
(cx->params.video_temporal_filter_mode << 1) |
(cx->params.video_median_filter_type << 2);
cx->params.port = CX2341X_PORT_MEMORY;
- cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+ cx->params.capabilities = CX2341X_CAP_HAS_TS;
init_waitqueue_head(&cx->cap_w);
init_waitqueue_head(&cx->mb_apu_waitq);
init_waitqueue_head(&cx->mb_cpu_waitq);
@@ -614,7 +616,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
cx18_cards[cx18_cards_active] = cx;
cx->dev = dev;
cx->num = cx18_cards_active++;
- snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num);
+ snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num);
CX18_INFO("Initializing card #%d\n", cx->num);
spin_unlock(&cx18_cards_lock);
@@ -721,6 +723,12 @@ static int __devinit cx18_probe(struct pci_dev *dev,
/* if no tuner was found, then pick the first tuner in the card list */
if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
cx->std = cx->card->tuners[0].std;
+ if (cx->std & V4L2_STD_PAL)
+ cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+ else if (cx->std & V4L2_STD_NTSC)
+ cx->std = V4L2_STD_NTSC_M;
+ else if (cx->std & V4L2_STD_SECAM)
+ cx->std = V4L2_STD_SECAM_L;
cx->options.tuner = cx->card->tuners[0].tuner;
}
if (cx->options.radio == -1)
@@ -818,6 +826,9 @@ int cx18_init_on_first_open(struct cx18 *cx)
int video_input;
int fw_retry_count = 3;
struct v4l2_frequency vf;
+ struct cx18_open_id fh;
+
+ fh.cx = cx;
if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
return -ENXIO;
@@ -869,13 +880,13 @@ int cx18_init_on_first_open(struct cx18 *cx)
video_input = cx->active_input;
cx->active_input++; /* Force update of input */
- cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input);
+ cx18_s_input(NULL, &fh, video_input);
/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
in one place. */
cx->std++; /* Force full standard initialization */
- cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std);
- cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf);
+ cx18_s_std(NULL, &fh, &cx->tuner_std);
+ cx18_s_frequency(NULL, &fh, &vf);
return 0;
}
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index de14ab59a20..45e31b04730 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -75,7 +75,8 @@
#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */
#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */
#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
-#define CX18_CARD_LAST 3
+#define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */
+#define CX18_CARD_LAST 4
#define CX18_ENC_STREAM_TYPE_MPG 0
#define CX18_ENC_STREAM_TYPE_TS 1
@@ -94,6 +95,7 @@
#define CX18_PCI_ID_HAUPPAUGE 0x0070
#define CX18_PCI_ID_COMPRO 0x185b
#define CX18_PCI_ID_YUAN 0x12ab
+#define CX18_PCI_ID_CONEXANT 0x14f1
/* ======================================================================== */
/* ========================== START USER SETTABLE DMA VARIABLES =========== */
@@ -228,9 +230,7 @@ struct cx18_dvb {
struct dvb_net dvbnet;
int enabled;
int feeding;
-
struct mutex feedlock;
-
};
struct cx18; /* forward reference */
@@ -427,6 +427,7 @@ struct cx18 {
/* gpio */
u32 gpio_dir;
u32 gpio_val;
+ struct mutex gpio_lock;
/* v4l2 and User settings */
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
index 2694ce35063..2d630d9f749 100644
--- a/drivers/media/video/cx18/cx18-firmware.c
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -41,9 +41,6 @@
#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
-#define CX18_AUDIO_ENABLE 0xc72014
-#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
-
#define CX18_FAST_CLOCK_PLL_INT 0xc78000
#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
#define CX18_FAST_CLOCK_PLL_POST 0xc78008
@@ -90,7 +87,7 @@
#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
/* Encoder/decoder firmware sizes */
-#define CX18_FW_CPU_SIZE (174716)
+#define CX18_FW_CPU_SIZE (158332)
#define CX18_FW_APU_SIZE (141200)
#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
@@ -345,6 +342,11 @@ int cx18_firmware_init(struct cx18 *cx)
int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
cx->enc_mem, cx, CX18_FW_APU_SIZE);
+ write_enc(0xE51FF004, 0);
+ write_enc(0xa00000, 4); /* todo: not hardcoded */
+ write_reg(0x00010000, CX18_PROC_SOFT_RESET); /* Start APU */
+ cx18_msleep_timeout(500, 0);
+
sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
cx->enc_mem, cx, CX18_FW_CPU_SIZE);
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index b302833f6f9..3d495dba498 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -69,6 +69,7 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
/* Assuming that the masks are a subset of the bits in gpio_dir */
/* Assert */
+ mutex_lock(&cx->gpio_lock);
cx->gpio_val =
(cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
gpio_write(cx);
@@ -79,10 +80,53 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
(cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
gpio_write(cx);
schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+ mutex_unlock(&cx->gpio_lock);
}
+void cx18_reset_ir_gpio(void *data)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ const struct cx18_gpio_i2c_slave_reset *p;
+
+ p = &cx->card->gpio_i2c_slave_reset;
+
+ if (p->ir_reset_mask == 0)
+ return;
+
+ CX18_DEBUG_INFO("Resetting IR microcontroller\n");
+
+ /*
+ Assert timing for the Z8F0811 on HVR-1600 boards:
+ 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to initiate
+ 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock cycles
+ (6,601,085 nanoseconds ~= 7 milliseconds)
+ 3. DBG pin must be high before chip exits reset for normal operation.
+ DBG is open drain and hopefully pulled high since we don't
+ normally drive it (GPIO 1?) for the HVR-1600
+ 4. Z8F0811 won't exit reset until RESET is deasserted
+ */
+ mutex_lock(&cx->gpio_lock);
+ cx->gpio_val = cx->gpio_val & ~p->ir_reset_mask;
+ gpio_write(cx);
+ mutex_unlock(&cx->gpio_lock);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
+
+ /*
+ Zilog comes out of reset, loads reset vector address and executes
+ from there. Required recovery delay unknown.
+ */
+ mutex_lock(&cx->gpio_lock);
+ cx->gpio_val = cx->gpio_val | p->ir_reset_mask;
+ gpio_write(cx);
+ mutex_unlock(&cx->gpio_lock);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+}
+EXPORT_SYMBOL(cx18_reset_ir_gpio);
+/* This symbol is exported for use by an infrared module for the IR-blaster */
+
void cx18_gpio_init(struct cx18 *cx)
{
+ mutex_lock(&cx->gpio_lock);
cx->gpio_dir = cx->card->gpio_init.direction;
cx->gpio_val = cx->card->gpio_init.initial_value;
@@ -91,14 +135,17 @@ void cx18_gpio_init(struct cx18 *cx)
cx->gpio_val |= 1 << cx->card->xceive_pin;
}
- if (cx->gpio_dir == 0)
+ if (cx->gpio_dir == 0) {
+ mutex_unlock(&cx->gpio_lock);
return;
+ }
CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
gpio_write(cx);
+ mutex_unlock(&cx->gpio_lock);
}
/* Xceive tuner reset function */
@@ -112,13 +159,52 @@ int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
return 0;
CX18_DEBUG_INFO("Resetting tuner\n");
+ mutex_lock(&cx->gpio_lock);
cx->gpio_val &= ~(1 << cx->card->xceive_pin);
-
gpio_write(cx);
+ mutex_unlock(&cx->gpio_lock);
schedule_timeout_interruptible(msecs_to_jiffies(1));
+ mutex_lock(&cx->gpio_lock);
cx->gpio_val |= 1 << cx->card->xceive_pin;
gpio_write(cx);
+ mutex_unlock(&cx->gpio_lock);
schedule_timeout_interruptible(msecs_to_jiffies(1));
return 0;
}
+
+int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg)
+{
+ struct v4l2_routing *route = arg;
+ u32 mask, data;
+
+ switch (command) {
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ if (route->input > 2)
+ return -EINVAL;
+ mask = cx->card->gpio_audio_input.mask;
+ switch (route->input) {
+ case 0:
+ data = cx->card->gpio_audio_input.tuner;
+ break;
+ case 1:
+ data = cx->card->gpio_audio_input.linein;
+ break;
+ case 2:
+ default:
+ data = cx->card->gpio_audio_input.radio;
+ break;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if (mask) {
+ mutex_lock(&cx->gpio_lock);
+ cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
+ gpio_write(cx);
+ mutex_unlock(&cx->gpio_lock);
+ }
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
index 525c328f748..22cd7ddf855 100644
--- a/drivers/media/video/cx18/cx18-gpio.h
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -22,4 +22,6 @@
void cx18_gpio_init(struct cx18 *cx);
void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
+void cx18_reset_ir_gpio(void *data);
int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
+int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 680bc4e35b7..6023ba3bd3a 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -39,10 +39,6 @@
#define GETSCL_BIT 0x0004
#define GETSDL_BIT 0x0008
-#ifndef I2C_ADAP_CLASS_TV_ANALOG
-#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
-#endif
-
#define CX18_CS5345_I2C_ADDR 0x4c
/* This array should match the CX18_HW_ defines */
@@ -311,8 +307,12 @@ int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
{
int addr;
- if (hw == CX18_HW_GPIO || hw == 0)
+ if (hw == 0)
return 0;
+
+ if (hw == CX18_HW_GPIO)
+ return cx18_gpio(cx, cmd, arg);
+
if (hw == CX18_HW_CX23418)
return cx18_av_cmd(cx, cmd, arg);
@@ -350,6 +350,8 @@ void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
cx18_av_cmd(cx, cmd, arg);
i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
+ if (cx->hw_flags & CX18_HW_GPIO)
+ cx18_gpio(cx, cmd, arg);
}
/* init + register i2c algo-bit adapter */
@@ -358,6 +360,18 @@ int init_cx18_i2c(struct cx18 *cx)
int i;
CX18_DEBUG_I2C("i2c init\n");
+ /* Sanity checks for the I2C hardware arrays. They must be the
+ * same size and GPIO/CX23418 must be the last entries.
+ */
+ if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
+ ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
+ CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) ||
+ CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
+ hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+ CX18_ERR("Mismatched I2C hardware arrays\n");
+ return -ENODEV;
+ }
+
for (i = 0; i < 2; i++) {
memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
sizeof(struct i2c_adapter));
@@ -391,6 +405,7 @@ int init_cx18_i2c(struct cx18 *cx)
write_reg_sync(0x00c000c0, 0xc7001c);
mdelay(10);
write_reg_sync(0x00c00000, 0xc7001c);
+ mdelay(10);
write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 4151f1e5493..0d74e59e503 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -100,19 +100,6 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
}
}
-static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
-{
- int f, l;
- u16 set = 0;
-
- for (f = 0; f < 2; f++) {
- for (l = 0; l < 24; l++) {
- fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
- set |= fmt->service_lines[f][l];
- }
- }
- return set != 0;
-}
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
{
@@ -126,35 +113,167 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
return set;
}
-static const struct {
- v4l2_std_id std;
- char *name;
-} enum_stds[] = {
- { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
- { V4L2_STD_PAL_DK, "PAL-DK" },
- { V4L2_STD_PAL_I, "PAL-I" },
- { V4L2_STD_PAL_M, "PAL-M" },
- { V4L2_STD_PAL_N, "PAL-N" },
- { V4L2_STD_PAL_Nc, "PAL-Nc" },
- { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
- { V4L2_STD_SECAM_DK, "SECAM-DK" },
- { V4L2_STD_SECAM_L, "SECAM-L" },
- { V4L2_STD_SECAM_LC, "SECAM-L'" },
- { V4L2_STD_NTSC_M, "NTSC-M" },
- { V4L2_STD_NTSC_M_JP, "NTSC-J" },
- { V4L2_STD_NTSC_M_KR, "NTSC-K" },
-};
-
-static const struct v4l2_standard cx18_std_60hz = {
- .frameperiod = {.numerator = 1001, .denominator = 30000},
- .framelines = 525,
-};
-
-static const struct v4l2_standard cx18_std_50hz = {
- .frameperiod = { .numerator = 1, .denominator = 25 },
- .framelines = 625,
-};
+static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+ pixfmt->width = cx->params.width;
+ pixfmt->height = cx->params.height;
+ pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ pixfmt->priv = 0;
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+ pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+ /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+ pixfmt->sizeimage =
+ pixfmt->height * pixfmt->width +
+ pixfmt->height * (pixfmt->width / 2);
+ pixfmt->bytesperline = 720;
+ } else {
+ pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+ pixfmt->sizeimage = 128 * 1024;
+ pixfmt->bytesperline = 0;
+ }
+ return 0;
+}
+
+static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+ struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
+
+ vbifmt->sampling_rate = 27000000;
+ vbifmt->offset = 248;
+ vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+ vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+ vbifmt->start[0] = cx->vbi.start[0];
+ vbifmt->start[1] = cx->vbi.start[1];
+ vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
+ vbifmt->flags = 0;
+ vbifmt->reserved[0] = 0;
+ vbifmt->reserved[1] = 0;
+ return 0;
+}
+
+static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ return -EINVAL;
+}
+
+static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
+
+ w = min(w, 720);
+ w = max(w, 1);
+ h = min(h, cx->is_50hz ? 576 : 480);
+ h = max(h, 2);
+ cx18_g_fmt_vid_cap(file, fh, fmt);
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+ return 0;
+}
+
+static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ return -EINVAL;
+}
+
+static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
+
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
+
+ ret = cx18_try_fmt_vid_cap(file, fh, fmt);
+ if (ret)
+ return ret;
+
+ if (cx->params.width == w && cx->params.height == h)
+ return 0;
+
+ if (atomic_read(&cx->ana_capturing) > 0)
+ return -EBUSY;
+
+ cx->params.width = w;
+ cx->params.height = h;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ return cx18_g_fmt_vid_cap(file, fh, fmt);
+}
+
+static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
+
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
+
+ if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
+ cx->vbi.sliced_in->service_set &&
+ atomic_read(&cx->ana_capturing) > 0)
+ return -EBUSY;
+
+ cx->vbi.sliced_in->service_set = 0;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+ return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ return -EINVAL;
+}
+static int cx18_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_chip_ident *chip)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
+ chip->ident = V4L2_IDENT_CX23418;
+ return 0;
+ }
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT,
+ chip);
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+ return cx18_call_i2c_client(cx, chip->match_chip,
+ VIDIOC_G_CHIP_IDENT, chip);
+ return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
{
struct v4l2_register *regs = arg;
@@ -174,665 +293,478 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
return 0;
}
-static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- fmt->fmt.pix.width = cx->params.width;
- fmt->fmt.pix.height = cx->params.height;
- fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
- if (streamtype == CX18_ENC_STREAM_TYPE_YUV) {
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
- /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
- fmt->fmt.pix.sizeimage =
- fmt->fmt.pix.height * fmt->fmt.pix.width +
- fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
- } else {
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- fmt->fmt.pix.sizeimage = 128 * 1024;
- }
- break;
-
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- fmt->fmt.vbi.sampling_rate = 27000000;
- fmt->fmt.vbi.offset = 248;
- fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4;
- fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- fmt->fmt.vbi.start[0] = cx->vbi.start[0];
- fmt->fmt.vbi.start[1] = cx->vbi.start[1];
- fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count;
- break;
+static int cx18_g_register(struct file *file, void *fh,
+ struct v4l2_register *reg)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
+ reg);
+ return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
+ reg);
+}
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- {
- struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+static int cx18_s_register(struct file *file, void *fh,
+ struct v4l2_register *reg)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
+ reg);
+ return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
+ reg);
+}
+#endif
- vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
- memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
- memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
- vbifmt->service_set = cx18_get_service_set(vbifmt);
- break;
- }
- default:
- return -EINVAL;
- }
+ *p = v4l2_prio_max(&cx->prio);
return 0;
}
-static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
- struct v4l2_format *fmt, int set_fmt)
+static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
{
- struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
- u16 set;
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
- /* set window size */
- if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- int w = fmt->fmt.pix.width;
- int h = fmt->fmt.pix.height;
+ return v4l2_prio_change(&cx->prio, &id->prio, prio);
+}
- if (w > 720)
- w = 720;
- else if (w < 1)
- w = 1;
- if (h > (cx->is_50hz ? 576 : 480))
- h = (cx->is_50hz ? 576 : 480);
- else if (h < 2)
- h = 2;
- cx18_get_fmt(cx, streamtype, fmt);
- fmt->fmt.pix.width = w;
- fmt->fmt.pix.height = h;
+static int cx18_querycap(struct file *file, void *fh,
+ struct v4l2_capability *vcap)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- if (!set_fmt || (cx->params.width == w && cx->params.height == h))
- return 0;
- if (atomic_read(&cx->ana_capturing) > 0)
- return -EBUSY;
-
- cx->params.width = w;
- cx->params.height = h;
- if (w != 720 || h != (cx->is_50hz ? 576 : 480))
- cx->params.video_temporal_filter = 0;
- else
- cx->params.video_temporal_filter = 8;
- cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
- return cx18_get_fmt(cx, streamtype, fmt);
- }
+ strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+ strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
+ vcap->version = CX18_DRIVER_VERSION; /* version */
+ vcap->capabilities = cx->v4l2_cap; /* capabilities */
+ return 0;
+}
- /* set raw VBI format */
- if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
- cx->vbi.sliced_in->service_set &&
- atomic_read(&cx->ana_capturing) > 0)
- return -EBUSY;
- if (set_fmt) {
- cx->vbi.sliced_in->service_set = 0;
- cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
- }
- return cx18_get_fmt(cx, streamtype, fmt);
- }
+static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- /* any else but sliced VBI capture is an error */
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
+ return cx18_get_audio_input(cx, vin->index, vin);
+}
- /* TODO: implement sliced VBI, for now silently return 0 */
- return 0;
+static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- /* set sliced VBI capture format */
- vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
- memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+ vin->index = cx->audio_input;
+ return cx18_get_audio_input(cx, vin->index, vin);
+}
- if (vbifmt->service_set)
- cx18_expand_service_set(vbifmt, cx->is_50hz);
- set = check_service_set(vbifmt, cx->is_50hz);
- vbifmt->service_set = cx18_get_service_set(vbifmt);
+static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- if (!set_fmt)
- return 0;
- if (set == 0)
+ if (vout->index >= cx->nof_audio_inputs)
return -EINVAL;
- if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
- return -EBUSY;
- cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
- memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
+ cx->audio_input = vout->index;
+ cx18_audio_set_io(cx);
return 0;
}
-static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
{
- struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
- struct cx18 *cx = id->cx;
- struct v4l2_register *reg = arg;
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- switch (cmd) {
- /* ioctls to allow direct access to the encoder registers for testing */
- case VIDIOC_DBG_G_REGISTER:
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
- return cx18_cxc(cx, cmd, arg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
- return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-
- case VIDIOC_DBG_S_REGISTER:
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
- return cx18_cxc(cx, cmd, arg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
- return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-
- case VIDIOC_G_CHIP_IDENT: {
- struct v4l2_chip_ident *chip = arg;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
- struct v4l2_chip_ident *chip = arg;
-
- chip->ident = V4L2_IDENT_CX23418;
- }
- return 0;
- }
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
- return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
- return -EINVAL;
- }
-
- case VIDIOC_INT_S_AUDIO_ROUTING: {
- struct v4l2_routing *route = arg;
+ /* set it to defaults from our table */
+ return cx18_get_input(cx, vin->index, vin);
+}
- cx18_audio_set_route(cx, route);
- break;
- }
+static int cx18_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- default:
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- }
+ cropcap->bounds.top = cropcap->bounds.left = 0;
+ cropcap->bounds.width = 720;
+ cropcap->bounds.height = cx->is_50hz ? 576 : 480;
+ cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
+ cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+ cropcap->defrect = cropcap->bounds;
return 0;
}
-int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg)
+static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
{
- struct cx18_open_id *id = NULL;
-
- if (filp)
- id = (struct cx18_open_id *)filp->private_data;
-
- switch (cmd) {
- case VIDIOC_G_PRIORITY:
- {
- enum v4l2_priority *p = arg;
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
- *p = v4l2_prio_max(&cx->prio);
- break;
- }
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- case VIDIOC_S_PRIORITY:
- {
- enum v4l2_priority *prio = arg;
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);
+}
- return v4l2_prio_change(&cx->prio, &id->prio, *prio);
- }
+static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- case VIDIOC_QUERYCAP:{
- struct v4l2_capability *vcap = arg;
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);
+}
- memset(vcap, 0, sizeof(*vcap));
- strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
- strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
- strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
- vcap->version = CX18_DRIVER_VERSION; /* version */
- vcap->capabilities = cx->v4l2_cap; /* capabilities */
+static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *fmt)
+{
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+ "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
+ },
+ { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
+ "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
+ }
+ };
- /* reserved.. must set to 0! */
- vcap->reserved[0] = vcap->reserved[1] =
- vcap->reserved[2] = vcap->reserved[3] = 0;
- break;
- }
+ if (fmt->index > 1)
+ return -EINVAL;
+ *fmt = formats[fmt->index];
+ return 0;
+}
- case VIDIOC_ENUMAUDIO:{
- struct v4l2_audio *vin = arg;
+static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- return cx18_get_audio_input(cx, vin->index, vin);
- }
+ *i = cx->active_input;
+ return 0;
+}
- case VIDIOC_G_AUDIO:{
- struct v4l2_audio *vin = arg;
+int cx18_s_input(struct file *file, void *fh, unsigned int inp)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
- vin->index = cx->audio_input;
- return cx18_get_audio_input(cx, vin->index, vin);
- }
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- case VIDIOC_S_AUDIO:{
- struct v4l2_audio *vout = arg;
+ if (inp < 0 || inp >= cx->nof_inputs)
+ return -EINVAL;
- if (vout->index >= cx->nof_audio_inputs)
- return -EINVAL;
- cx->audio_input = vout->index;
- cx18_audio_set_io(cx);
- break;
+ if (inp == cx->active_input) {
+ CX18_DEBUG_INFO("Input unchanged\n");
+ return 0;
}
- case VIDIOC_ENUMINPUT:{
- struct v4l2_input *vin = arg;
-
- /* set it to defaults from our table */
- return cx18_get_input(cx, vin->index, vin);
- }
+ CX18_DEBUG_INFO("Changing input from %d to %d\n",
+ cx->active_input, inp);
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT: {
- struct v4l2_format *fmt = arg;
+ cx->active_input = inp;
+ /* Set the audio input to whatever is appropriate for the input type. */
+ cx->audio_input = cx->card->video_inputs[inp].audio_index;
- return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT);
- }
+ /* prevent others from messing with the streams until
+ we're finished changing inputs. */
+ cx18_mute(cx);
+ cx18_video_set_io(cx);
+ cx18_audio_set_io(cx);
+ cx18_unmute(cx);
+ return 0;
+}
- case VIDIOC_G_FMT: {
- struct v4l2_format *fmt = arg;
- int type = fmt->type;
+static int cx18_g_frequency(struct file *file, void *fh,
+ struct v4l2_frequency *vf)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- memset(fmt, 0, sizeof(*fmt));
- fmt->type = type;
- return cx18_get_fmt(cx, id->type, fmt);
- }
+ if (vf->tuner != 0)
+ return -EINVAL;
- case VIDIOC_CROPCAP: {
- struct v4l2_cropcap *cropcap = arg;
-
- if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- cropcap->bounds.top = cropcap->bounds.left = 0;
- cropcap->bounds.width = 720;
- cropcap->bounds.height = cx->is_50hz ? 576 : 480;
- cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
- cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
- cropcap->defrect = cropcap->bounds;
- return 0;
- }
+ cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);
+ return 0;
+}
- case VIDIOC_S_CROP: {
- struct v4l2_crop *crop = arg;
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- return cx18_av_cmd(cx, VIDIOC_S_CROP, arg);
- }
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- case VIDIOC_G_CROP: {
- struct v4l2_crop *crop = arg;
+ if (vf->tuner != 0)
+ return -EINVAL;
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- return cx18_av_cmd(cx, VIDIOC_G_CROP, arg);
- }
+ cx18_mute(cx);
+ CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+ cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);
+ cx18_unmute(cx);
+ return 0;
+}
- case VIDIOC_ENUM_FMT: {
- static struct v4l2_fmtdesc formats[] = {
- { 0, 0, 0,
- "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
- { 0, 0, 0, 0 }
- },
- { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
- "MPEG", V4L2_PIX_FMT_MPEG,
- { 0, 0, 0, 0 }
- }
- };
- struct v4l2_fmtdesc *fmt = arg;
- enum v4l2_buf_type type = fmt->type;
-
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- break;
- default:
- return -EINVAL;
- }
- if (fmt->index > 1)
- return -EINVAL;
- *fmt = formats[fmt->index];
- fmt->type = type;
- return 0;
- }
+static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- case VIDIOC_G_INPUT:{
- *(int *)arg = cx->active_input;
- break;
- }
+ *std = cx->std;
+ return 0;
+}
- case VIDIOC_S_INPUT:{
- int inp = *(int *)arg;
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
- if (inp < 0 || inp >= cx->nof_inputs)
- return -EINVAL;
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- if (inp == cx->active_input) {
- CX18_DEBUG_INFO("Input unchanged\n");
- break;
- }
- CX18_DEBUG_INFO("Changing input from %d to %d\n",
- cx->active_input, inp);
+ if ((*std & V4L2_STD_ALL) == 0)
+ return -EINVAL;
- cx->active_input = inp;
- /* Set the audio input to whatever is appropriate for the
- input type. */
- cx->audio_input = cx->card->video_inputs[inp].audio_index;
+ if (*std == cx->std)
+ return 0;
- /* prevent others from messing with the streams until
- we're finished changing inputs. */
- cx18_mute(cx);
- cx18_video_set_io(cx);
- cx18_audio_set_io(cx);
- cx18_unmute(cx);
- break;
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
+ atomic_read(&cx->ana_capturing) > 0) {
+ /* Switching standard would turn off the radio or mess
+ with already running streams, prevent that by
+ returning EBUSY. */
+ return -EBUSY;
}
- case VIDIOC_G_FREQUENCY:{
- struct v4l2_frequency *vf = arg;
+ cx->std = *std;
+ cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+ cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
+ cx->params.width = 720;
+ cx->params.height = cx->is_50hz ? 576 : 480;
+ cx->vbi.count = cx->is_50hz ? 18 : 12;
+ cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
+ cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
+ cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
+ CX18_DEBUG_INFO("Switching standard to %llx.\n",
+ (unsigned long long) cx->std);
+
+ /* Tuner */
+ cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+ return 0;
+}
- if (vf->tuner != 0)
- return -EINVAL;
- cx18_call_i2c_clients(cx, cmd, arg);
- break;
- }
+static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
- case VIDIOC_S_FREQUENCY:{
- struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- if (vf.tuner != 0)
- return -EINVAL;
+ if (vt->index != 0)
+ return -EINVAL;
- cx18_mute(cx);
- CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
- cx18_call_i2c_clients(cx, cmd, &vf);
- cx18_unmute(cx);
- break;
- }
+ /* Setting tuner can only set audio mode */
+ cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
- case VIDIOC_ENUMSTD:{
- struct v4l2_standard *vs = arg;
- int idx = vs->index;
+ return 0;
+}
- if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
- return -EINVAL;
+static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- *vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
- cx18_std_60hz : cx18_std_50hz;
- vs->index = idx;
- vs->id = enum_stds[idx].std;
- strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
- break;
- }
+ if (vt->index != 0)
+ return -EINVAL;
- case VIDIOC_G_STD:{
- *(v4l2_std_id *) arg = cx->std;
- break;
+ cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
+
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_ANALOG_TV;
}
- case VIDIOC_S_STD: {
- v4l2_std_id std = *(v4l2_std_id *) arg;
+ return 0;
+}
- if ((std & V4L2_STD_ALL) == 0)
- return -EINVAL;
+static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_sliced_vbi_cap *cap)
+{
+ return -EINVAL;
+}
- if (std == cx->std)
- break;
+static int cx18_g_enc_index(struct file *file, void *fh,
+ struct v4l2_enc_idx *idx)
+{
+ return -EINVAL;
+}
- if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
- atomic_read(&cx->ana_capturing) > 0) {
- /* Switching standard would turn off the radio or mess
- with already running streams, prevent that by
- returning EBUSY. */
- return -EBUSY;
- }
+static int cx18_encoder_cmd(struct file *file, void *fh,
+ struct v4l2_encoder_cmd *enc)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
- cx->std = std;
- cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
- cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
- cx->params.width = 720;
- cx->params.height = cx->is_50hz ? 576 : 480;
- cx->vbi.count = cx->is_50hz ? 18 : 12;
- cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
- cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
- cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
- CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std);
-
- /* Tuner */
- cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+ switch (enc->cmd) {
+ case V4L2_ENC_CMD_START:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+ enc->flags = 0;
+ return cx18_start_capture(id);
+
+ case V4L2_ENC_CMD_STOP:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+ enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+ cx18_stop_capture(id,
+ enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
break;
- }
-
- case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */
- struct v4l2_tuner *vt = arg;
- if (vt->index != 0)
- return -EINVAL;
-
- cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
+ case V4L2_ENC_CMD_PAUSE:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+ enc->flags = 0;
+ if (!atomic_read(&cx->ana_capturing))
+ return -EPERM;
+ if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ return 0;
+ cx18_mute(cx);
+ cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
break;
- }
-
- case VIDIOC_G_TUNER: {
- struct v4l2_tuner *vt = arg;
-
- if (vt->index != 0)
- return -EINVAL;
-
- memset(vt, 0, sizeof(*vt));
- cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
- if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
- strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_RADIO;
- } else {
- strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_ANALOG_TV;
- }
+ case V4L2_ENC_CMD_RESUME:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+ enc->flags = 0;
+ if (!atomic_read(&cx->ana_capturing))
+ return -EPERM;
+ if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ return 0;
+ cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+ cx18_unmute(cx);
break;
- }
- case VIDIOC_G_SLICED_VBI_CAP: {
- struct v4l2_sliced_vbi_cap *cap = arg;
- int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
- int f, l;
- enum v4l2_buf_type type = cap->type;
-
- memset(cap, 0, sizeof(*cap));
- cap->type = type;
- if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- for (f = 0; f < 2; f++) {
- for (l = 0; l < 24; l++) {
- if (valid_service_line(f, l, cx->is_50hz))
- cap->service_lines[f][l] = set;
- }
- }
- return 0;
- }
+ default:
+ CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
return -EINVAL;
}
+ return 0;
+}
- case VIDIOC_ENCODER_CMD:
- case VIDIOC_TRY_ENCODER_CMD: {
- struct v4l2_encoder_cmd *enc = arg;
- int try = cmd == VIDIOC_TRY_ENCODER_CMD;
-
- memset(&enc->raw, 0, sizeof(enc->raw));
- switch (enc->cmd) {
- case V4L2_ENC_CMD_START:
- enc->flags = 0;
- if (try)
- return 0;
- return cx18_start_capture(id);
-
- case V4L2_ENC_CMD_STOP:
- enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
- if (try)
- return 0;
- cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
- return 0;
+static int cx18_try_encoder_cmd(struct file *file, void *fh,
+ struct v4l2_encoder_cmd *enc)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- case V4L2_ENC_CMD_PAUSE:
- enc->flags = 0;
- if (try)
- return 0;
- if (!atomic_read(&cx->ana_capturing))
- return -EPERM;
- if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
- return 0;
- cx18_mute(cx);
- cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
- break;
-
- case V4L2_ENC_CMD_RESUME:
- enc->flags = 0;
- if (try)
- return 0;
- if (!atomic_read(&cx->ana_capturing))
- return -EPERM;
- if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
- return 0;
- cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
- cx18_unmute(cx);
- break;
- default:
- return -EINVAL;
- }
+ switch (enc->cmd) {
+ case V4L2_ENC_CMD_START:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+ enc->flags = 0;
break;
- }
- case VIDIOC_LOG_STATUS:
- {
- struct v4l2_input vidin;
- struct v4l2_audio audin;
- int i;
+ case V4L2_ENC_CMD_STOP:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+ enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+ break;
- CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num);
- if (cx->hw_flags & CX18_HW_TVEEPROM) {
- struct tveeprom tv;
+ case V4L2_ENC_CMD_PAUSE:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+ enc->flags = 0;
+ break;
- cx18_read_eeprom(cx, &tv);
- }
- cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
- cx18_get_input(cx, cx->active_input, &vidin);
- cx18_get_audio_input(cx, cx->audio_input, &audin);
- CX18_INFO("Video Input: %s\n", vidin.name);
- CX18_INFO("Audio Input: %s\n", audin.name);
- CX18_INFO("Tuner: %s\n",
- test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?
- "Radio" : "TV");
- cx2341x_log_status(&cx->params, cx->name);
- CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
- for (i = 0; i < CX18_MAX_STREAMS; i++) {
- struct cx18_stream *s = &cx->streams[i];
-
- if (s->v4l2dev == NULL || s->buffers == 0)
- continue;
- CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
- s->name, s->s_flags,
- (s->buffers - s->q_free.buffers) * 100 / s->buffers,
- (s->buffers * s->buf_size) / 1024, s->buffers);
- }
- CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
- (long long)cx->mpg_data_received,
- (long long)cx->vbi_data_inserted);
- CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
+ case V4L2_ENC_CMD_RESUME:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+ enc->flags = 0;
break;
- }
default:
+ CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
return -EINVAL;
}
return 0;
}
-static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, void *arg)
+static int cx18_log_status(struct file *file, void *fh)
{
- struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
- struct cx18 *cx = id->cx;
- int ret;
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+ struct v4l2_input vidin;
+ struct v4l2_audio audin;
+ int i;
+
+ CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num);
+ if (cx->hw_flags & CX18_HW_TVEEPROM) {
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+ }
+ cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
+ cx18_get_input(cx, cx->active_input, &vidin);
+ cx18_get_audio_input(cx, cx->audio_input, &audin);
+ CX18_INFO("Video Input: %s\n", vidin.name);
+ CX18_INFO("Audio Input: %s\n", audin.name);
+ mutex_lock(&cx->gpio_lock);
+ CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n",
+ cx->gpio_dir, cx->gpio_val);
+ mutex_unlock(&cx->gpio_lock);
+ CX18_INFO("Tuner: %s\n",
+ test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV");
+ cx2341x_log_status(&cx->params, cx->name);
+ CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev == NULL || s->buffers == 0)
+ continue;
+ CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
+ s->name, s->s_flags,
+ (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+ (s->buffers * s->buf_size) / 1024, s->buffers);
+ }
+ CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
+ (long long)cx->mpg_data_received,
+ (long long)cx->vbi_data_inserted);
+ CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
+ return 0;
+}
+
+static int cx18_default(struct file *file, void *fh, int cmd, void *arg)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- /* check priority */
switch (cmd) {
- case VIDIOC_S_CTRL:
- case VIDIOC_S_STD:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_TUNER:
- case VIDIOC_S_FREQUENCY:
- case VIDIOC_S_FMT:
- case VIDIOC_S_CROP:
- case VIDIOC_S_EXT_CTRLS:
- ret = v4l2_prio_check(&cx->prio, &id->prio);
- if (ret)
- return ret;
+ case VIDIOC_INT_S_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
+
+ CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
+ route->input, route->output);
+ cx18_audio_set_route(cx, route);
+ break;
}
- switch (cmd) {
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- case VIDIOC_G_CHIP_IDENT:
- case VIDIOC_INT_S_AUDIO_ROUTING:
- case VIDIOC_INT_RESET:
- if (cx18_debug & CX18_DBGFLG_IOCTL) {
- printk(KERN_INFO "cx18%d ioctl: ", cx->num);
- v4l_printk_ioctl(cmd);
- }
- return cx18_debug_ioctls(filp, cmd, arg);
-
- case VIDIOC_G_PRIORITY:
- case VIDIOC_S_PRIORITY:
- case VIDIOC_QUERYCAP:
- case VIDIOC_ENUMINPUT:
- case VIDIOC_G_INPUT:
- case VIDIOC_S_INPUT:
- case VIDIOC_G_FMT:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT:
- case VIDIOC_ENUM_FMT:
- case VIDIOC_CROPCAP:
- case VIDIOC_G_CROP:
- case VIDIOC_S_CROP:
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_S_FREQUENCY:
- case VIDIOC_ENUMSTD:
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
- case VIDIOC_S_TUNER:
- case VIDIOC_G_TUNER:
- case VIDIOC_ENUMAUDIO:
- case VIDIOC_S_AUDIO:
- case VIDIOC_G_AUDIO:
- case VIDIOC_G_SLICED_VBI_CAP:
- case VIDIOC_LOG_STATUS:
- case VIDIOC_G_ENC_INDEX:
- case VIDIOC_ENCODER_CMD:
- case VIDIOC_TRY_ENCODER_CMD:
- if (cx18_debug & CX18_DBGFLG_IOCTL) {
- printk(KERN_INFO "cx18%d ioctl: ", cx->num);
- v4l_printk_ioctl(cmd);
- }
- return cx18_v4l2_ioctls(cx, filp, cmd, arg);
-
- case VIDIOC_QUERYMENU:
- case VIDIOC_QUERYCTRL:
- case VIDIOC_S_CTRL:
- case VIDIOC_G_CTRL:
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_G_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- if (cx18_debug & CX18_DBGFLG_IOCTL) {
- printk(KERN_INFO "cx18%d ioctl: ", cx->num);
- v4l_printk_ioctl(cmd);
- }
- return cx18_control_ioctls(cx, cmd, arg);
+ case VIDIOC_INT_RESET: {
+ u32 val = *(u32 *)arg;
+
+ if ((val == 0) || (val & 0x01))
+ cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]);
+ break;
+ }
- case 0x00005401: /* Handle isatty() calls */
- return -EINVAL;
default:
- return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
- cx18_v4l2_do_ioctl);
+ return -EINVAL;
}
return 0;
}
@@ -840,12 +772,65 @@ static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
+ struct video_device *vfd = video_devdata(filp);
struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
struct cx18 *cx = id->cx;
int res;
mutex_lock(&cx->serialize_lock);
- res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl);
+
+ if (cx18_debug & CX18_DBGFLG_IOCTL)
+ vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+ res = video_ioctl2(inode, filp, cmd, arg);
+ vfd->debug = 0;
mutex_unlock(&cx->serialize_lock);
return res;
}
+
+void cx18_set_funcs(struct video_device *vdev)
+{
+ vdev->vidioc_querycap = cx18_querycap;
+ vdev->vidioc_g_priority = cx18_g_priority;
+ vdev->vidioc_s_priority = cx18_s_priority;
+ vdev->vidioc_s_audio = cx18_s_audio;
+ vdev->vidioc_g_audio = cx18_g_audio;
+ vdev->vidioc_enumaudio = cx18_enumaudio;
+ vdev->vidioc_enum_input = cx18_enum_input;
+ vdev->vidioc_cropcap = cx18_cropcap;
+ vdev->vidioc_s_crop = cx18_s_crop;
+ vdev->vidioc_g_crop = cx18_g_crop;
+ vdev->vidioc_g_input = cx18_g_input;
+ vdev->vidioc_s_input = cx18_s_input;
+ vdev->vidioc_g_frequency = cx18_g_frequency;
+ vdev->vidioc_s_frequency = cx18_s_frequency;
+ vdev->vidioc_s_tuner = cx18_s_tuner;
+ vdev->vidioc_g_tuner = cx18_g_tuner;
+ vdev->vidioc_g_enc_index = cx18_g_enc_index;
+ vdev->vidioc_g_std = cx18_g_std;
+ vdev->vidioc_s_std = cx18_s_std;
+ vdev->vidioc_log_status = cx18_log_status;
+ vdev->vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap;
+ vdev->vidioc_encoder_cmd = cx18_encoder_cmd;
+ vdev->vidioc_try_encoder_cmd = cx18_try_encoder_cmd;
+ vdev->vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap;
+ vdev->vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap;
+ vdev->vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap;
+ vdev->vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap;
+ vdev->vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap;
+ vdev->vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap;
+ vdev->vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap;
+ vdev->vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap;
+ vdev->vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap;
+ vdev->vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap;
+ vdev->vidioc_g_chip_ident = cx18_g_chip_ident;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ vdev->vidioc_g_register = cx18_g_register;
+ vdev->vidioc_s_register = cx18_s_register;
+#endif
+ vdev->vidioc_default = cx18_default;
+ vdev->vidioc_queryctrl = cx18_queryctrl;
+ vdev->vidioc_querymenu = cx18_querymenu;
+ vdev->vidioc_g_ext_ctrls = cx18_g_ext_ctrls;
+ vdev->vidioc_s_ext_ctrls = cx18_s_ext_ctrls;
+ vdev->vidioc_try_ext_ctrls = cx18_try_ext_ctrls;
+}
diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h
index 9f4c7eb2897..2222f679d86 100644
--- a/drivers/media/video/cx18/cx18-ioctl.h
+++ b/drivers/media/video/cx18/cx18-ioctl.h
@@ -24,7 +24,9 @@
u16 cx18_service2vbi(int type);
void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
+void cx18_set_funcs(struct video_device *vdev);
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std);
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int cx18_s_input(struct file *file, void *fh, unsigned int inp);
int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg);
-int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd,
- void *arg);
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 2a5ccef9185..93177514e84 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = {
API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
+ API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST),
API_ENTRY(0, 0, 0),
};
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 1b921a33609..1728b1d832a 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -39,6 +39,7 @@ static struct file_operations cx18_v4l2_enc_fops = {
.owner = THIS_MODULE,
.read = cx18_v4l2_read,
.open = cx18_v4l2_open,
+ /* FIXME change to video_ioctl2 if serialization lock can be removed */
.ioctl = cx18_v4l2_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.release = cx18_v4l2_close,
@@ -189,14 +190,15 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
s->v4l2dev->type =
VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT |
VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER;
- snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s",
- cx->num, s->name);
+ snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d",
+ cx->num);
s->v4l2dev->minor = minor;
s->v4l2dev->dev = &cx->dev->dev;
s->v4l2dev->fops = cx18_stream_info[type].fops;
s->v4l2dev->release = video_device_release;
-
+ s->v4l2dev->tvnorms = V4L2_STD_ALL;
+ cx18_set_funcs(s->v4l2dev);
return 0;
}
@@ -309,8 +311,10 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
/* Teardown all streams */
for (type = 0; type < CX18_MAX_STREAMS; type++) {
- if (cx->streams[type].dvb.enabled)
+ if (cx->streams[type].dvb.enabled) {
cx18_dvb_unregister(&cx->streams[type]);
+ cx->streams[type].dvb.enabled = false;
+ }
vdev = cx->streams[type].v4l2dev;
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 33f78da9dba..e7ed053059a 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -52,6 +52,11 @@
#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000)
#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000)
+#define APU_CMD_MASK 0x10000000
+#define APU_CMD_MASK_ACK (APU_CMD_MASK | 0x80000000)
+
+#define CX18_APU_RESETAI (APU_CMD_MASK | 0x05)
+
/* Description: This command indicates that a Memory Descriptor List has been
filled with the requested channel type
IN[0] - Task handle. Handle of the task