summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
Diffstat (limited to 'linux')
-rw-r--r--linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c140
-rw-r--r--linux/drivers/media/dvb/dvb-usb/gp8psk.c2
-rw-r--r--linux/drivers/media/dvb/dvb-usb/gp8psk.h1
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-audio.c189
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.c2
-rw-r--r--linux/drivers/media/video/cx18/cx18-firmware.c69
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c17
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c89
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h7
-rw-r--r--linux/drivers/media/video/tuner-core.c9
-rw-r--r--linux/drivers/media/video/v4l2-compat-ioctl32.c850
-rw-r--r--linux/include/linux/videodev2.h2
12 files changed, 880 insertions, 497 deletions
diff --git a/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index 262a858c3..20eadf931 100644
--- a/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -25,6 +25,20 @@ struct gp8psk_fe_state {
unsigned long status_check_interval;
};
+static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 status;
+ gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
+ return status & bmDCtuned;
+}
+
+static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
+{
+ struct gp8psk_fe_state *state = fe->demodulator_priv;
+ return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
+}
+
static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
{
u8 buf[6];
@@ -99,39 +113,114 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
return 0;
}
+static int gp8psk_fe_set_property(struct dvb_frontend *fe,
+ struct dtv_property *tvp)
+{
+ deb_fe("%s(..)\n", __func__);
+ return 0;
+}
+
+static int gp8psk_fe_get_property(struct dvb_frontend *fe,
+ struct dtv_property *tvp)
+{
+ deb_fe("%s(..)\n", __func__);
+ return 0;
+}
+
+
static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct gp8psk_fe_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u8 cmd[10];
u32 freq = fep->frequency * 1000;
+ int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
+
+ deb_fe("%s()\n", __func__);
cmd[4] = freq & 0xff;
cmd[5] = (freq >> 8) & 0xff;
cmd[6] = (freq >> 16) & 0xff;
cmd[7] = (freq >> 24) & 0xff;
- switch(fe->ops.info.type) {
- case FE_QPSK:
- cmd[0] = fep->u.qpsk.symbol_rate & 0xff;
- cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff;
- cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
- cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
- cmd[8] = ADV_MOD_DVB_QPSK;
- cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+ switch (c->delivery_system) {
+ case SYS_DVBS:
+ /* Only QPSK is supported for DVB-S */
+ if (c->modulation != QPSK) {
+ deb_fe("%s: unsupported modulation selected (%d)\n",
+ __func__, c->modulation);
+ return -EOPNOTSUPP;
+ }
+ c->fec_inner = FEC_AUTO;
break;
+ case SYS_DVBS2:
+ deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
+ break;
+
default:
- // other modes are unsuported right now
- cmd[0] = 0;
- cmd[1] = 0;
- cmd[2] = 0;
- cmd[3] = 0;
- cmd[8] = 0;
+ deb_fe("%s: unsupported delivery system selected (%d)\n",
+ __func__, c->delivery_system);
+ return -EOPNOTSUPP;
+ }
+
+ cmd[0] = c->symbol_rate & 0xff;
+ cmd[1] = (c->symbol_rate >> 8) & 0xff;
+ cmd[2] = (c->symbol_rate >> 16) & 0xff;
+ cmd[3] = (c->symbol_rate >> 24) & 0xff;
+ switch (c->modulation) {
+ case QPSK:
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ if (gp8psk_tuned_to_DCII(fe))
+ gp8psk_bcm4500_reload(state->d);
+ switch (c->fec_inner) {
+ case FEC_1_2:
+ cmd[9] = 0; break;
+ case FEC_2_3:
+ cmd[9] = 1; break;
+ case FEC_3_4:
+ cmd[9] = 2; break;
+ case FEC_5_6:
+ cmd[9] = 3; break;
+ case FEC_7_8:
+ cmd[9] = 4; break;
+ case FEC_AUTO:
+ cmd[9] = 5; break;
+ default:
+ cmd[9] = 5; break;
+ }
+ cmd[8] = ADV_MOD_DVB_QPSK;
+ break;
+ case PSK_8: /* PSK_8 is for compatibility with DN */
+ cmd[8] = ADV_MOD_TURBO_8PSK;
+ switch (c->fec_inner) {
+ case FEC_2_3:
+ cmd[9] = 0; break;
+ case FEC_3_4:
+ cmd[9] = 1; break;
+ case FEC_3_5:
+ cmd[9] = 2; break;
+ case FEC_5_6:
+ cmd[9] = 3; break;
+ case FEC_8_9:
+ cmd[9] = 4; break;
+ default:
+ cmd[9] = 0; break;
+ }
+ break;
+ case QAM_16: /* QAM_16 is for compatibility with DN */
+ cmd[8] = ADV_MOD_TURBO_16QAM;
cmd[9] = 0;
break;
+ default: /* Unknown modulation */
+ deb_fe("%s: unsupported modulation selected (%d)\n",
+ __func__, c->modulation);
+ return -EOPNOTSUPP;
}
- gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ gp8psk_set_tuner_mode(fe, 0);
+ gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
state->lock = 0;
state->next_status_check = jiffies;
@@ -140,13 +229,6 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
return 0;
}
-static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
-{
- return 0;
-}
-
-
static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
struct dvb_diseqc_master_cmd *m)
{
@@ -261,9 +343,13 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
.symbol_rate_max = 45000000,
.symbol_rate_tolerance = 500, /* ppm */
.caps = FE_CAN_INVERSION_AUTO |
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ /*
+ * FE_CAN_QAM_16 is for compatibility
+ * (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
+ */
+ FE_CAN_QPSK | FE_CAN_QAM_16
},
.release = gp8psk_fe_release,
@@ -271,8 +357,10 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
.init = NULL,
.sleep = NULL,
+ .set_property = gp8psk_fe_set_property,
+ .get_property = gp8psk_fe_get_property,
.set_frontend = gp8psk_fe_set_frontend,
- .get_frontend = gp8psk_fe_get_frontend,
+
.get_tune_settings = gp8psk_fe_get_tune_settings,
.read_status = gp8psk_fe_read_status,
diff --git a/linux/drivers/media/dvb/dvb-usb/gp8psk.c b/linux/drivers/media/dvb/dvb-usb/gp8psk.c
index 1b002909b..c1da962cc 100644
--- a/linux/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/linux/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -174,7 +174,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
return 0;
}
-#if 0
int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
{
u8 buf;
@@ -191,7 +190,6 @@ int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
return EINVAL;
return 0;
}
-#endif /* 0 */
static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
diff --git a/linux/drivers/media/dvb/dvb-usb/gp8psk.h b/linux/drivers/media/dvb/dvb-usb/gp8psk.h
index e5cd8149c..e83a57506 100644
--- a/linux/drivers/media/dvb/dvb-usb/gp8psk.h
+++ b/linux/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -92,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen);
+extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
#endif
diff --git a/linux/drivers/media/video/cx18/cx18-av-audio.c b/linux/drivers/media/video/cx18/cx18-av-audio.c
index fd85b9b2d..a2f0ad570 100644
--- a/linux/drivers/media/video/cx18/cx18-av-audio.c
+++ b/linux/drivers/media/video/cx18/cx18-av-audio.c
@@ -31,98 +31,165 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
if (freq != 32000 && freq != 44100 && freq != 48000)
return -EINVAL;
- /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
- cx18_av_write(cx, 0x127, 0x50);
+ /*
+ * The PLL parameters are based on the external crystal frequency that
+ * would ideally be:
+ *
+ * NTSC Color subcarrier freq * 8 =
+ * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+ *
+ * The accidents of history and rationale that explain from where this
+ * combination of magic numbers originate can be found in:
+ *
+ * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
+ * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
+ *
+ * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
+ * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
+ *
+ * As Mike Bradley has rightly pointed out, it's not the exact crystal
+ * frequency that matters, only that all parts of the driver and
+ * firmware are using the same value (close to the ideal value).
+ *
+ * Since I have a strong suspicion that, if the firmware ever assumes a
+ * crystal value at all, it will assume 28.636360 MHz, the crystal
+ * freq used in calculations in this driver will be:
+ *
+ * xtal_freq = 28.636360 MHz
+ *
+ * an error of less than 0.13 ppm which is way, way better than any off
+ * the shelf crystal will have for accuracy anyway.
+ *
+ * Below I aim to run the PLLs' VCOs near 400 MHz to minimze error.
+ *
+ * Many thanks to Jeff Campbell and Mike Bradley for their extensive
+ * investigation, experimentation, testing, and suggested solutions of
+ * of audio/video sync problems with SVideo and CVBS captures.
+ */
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
switch (freq) {
case 32000:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x1408040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
+ */
+ cx18_av_write4(cx, 0x108, 0x200d040f);
+
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
- /* AUX_PLL_FRAC */
- /* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */
- cx18_av_write4(cx, 0x110, 0x012a0863);
+ /* AUX_PLL Fraction = 0x176740c */
+ /* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0176740c);
/* src3/4/6_ctl */
- /* 0x1.f77f = (4 * 15734.26) / 32000 */
+ /* 0x1.f77f = (4 * xtal/8*2/455) / 32000 */
cx18_av_write4(cx, 0x900, 0x0801f77f);
cx18_av_write4(cx, 0x904, 0x0801f77f);
cx18_av_write4(cx, 0x90c, 0x0801f77f);
- /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
- cx18_av_write(cx, 0x127, 0x54);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
+ cx18_av_write(cx, 0x127, 0x60);
/* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x11202fff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
* ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa10d2ef8);
+ cx18_av_write4(cx, 0x128, 0xa00d2ef8);
break;
case 44100:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x1009040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x18
+ */
+ cx18_av_write4(cx, 0x108, 0x180e040f);
+
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
- /* AUX_PLL_FRAC */
- /* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */
- cx18_av_write4(cx, 0x110, 0x00ec6bce);
+ /* AUX_PLL Fraction = 0x062a1f2 */
+ /* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0062a1f2);
/* src3/4/6_ctl */
- /* 0x1.6d59 = (4 * 15734.26) / 44100 */
+ /* 0x1.6d59 = (4 * xtal/8*2/455) / 44100 */
cx18_av_write4(cx, 0x900, 0x08016d59);
cx18_av_write4(cx, 0x904, 0x08016d59);
cx18_av_write4(cx, 0x90c, 0x08016d59);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x18 */
+ cx18_av_write(cx, 0x127, 0x58);
+
/* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x112092ff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
* ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa11d4bf8);
+ cx18_av_write4(cx, 0x128, 0xa01d4bf8);
break;
case 48000:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x100a040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x16
+ */
+ cx18_av_write4(cx, 0x108, 0x160e040f);
- /* AUX_PLL_FRAC */
- /* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */
- cx18_av_write4(cx, 0x110, 0x0098d6dd);
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+ /* AUX_PLL Fraction = 0x05227ad */
+ /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x005227ad);
/* src3/4/6_ctl */
- /* 0x1.4faa = (4 * 15734.26) / 48000 */
+ /* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */
cx18_av_write4(cx, 0x900, 0x08014faa);
cx18_av_write4(cx, 0x904, 0x08014faa);
cx18_av_write4(cx, 0x90c, 0x08014faa);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+ cx18_av_write(cx, 0x127, 0x56);
+
/* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */
cx18_av_write4(cx, 0x12c, 0x11205fff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x1193f8 = 143999.000 * 8 =
* ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa11193f8);
+ cx18_av_write4(cx, 0x128, 0xa01193f8);
break;
}
} else {
switch (freq) {
case 32000:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x1e08040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x30
+ */
+ cx18_av_write4(cx, 0x108, 0x300d040f);
+
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
- /* AUX_PLL_FRAC */
- /* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */
- cx18_av_write4(cx, 0x110, 0x012a0863);
+ /* AUX_PLL Fraction = 0x176740c */
+ /* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0176740c);
/* src1_ctl */
/* 0x1.0000 = 32000/32000 */
@@ -134,27 +201,34 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08020000);
cx18_av_write4(cx, 0x90c, 0x08020000);
- /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
- cx18_av_write(cx, 0x127, 0x54);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */
+ cx18_av_write(cx, 0x127, 0x70);
/* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x11201fff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
* ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa10d2ef8);
+ cx18_av_write4(cx, 0x128, 0xa00d2ef8);
break;
case 44100:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x1809040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x24
+ */
+ cx18_av_write4(cx, 0x108, 0x240e040f);
+
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
- /* AUX_PLL_FRAC */
- /* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */
- cx18_av_write4(cx, 0x110, 0x00ec6bce);
+ /* AUX_PLL Fraction = 0x062a1f2 */
+ /* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0062a1f2);
/* src1_ctl */
/* 0x1.60cd = 44100/32000 */
@@ -166,24 +240,34 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08017385);
cx18_av_write4(cx, 0x90c, 0x08017385);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x24 */
+ cx18_av_write(cx, 0x127, 0x64);
+
/* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x112061ff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
* ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa11d4bf8);
+ cx18_av_write4(cx, 0x128, 0xa01d4bf8);
break;
case 48000:
- /* VID_PLL and AUX_PLL */
- cx18_av_write4(cx, 0x108, 0x180a040f);
+ /*
+ * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+ * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
+ */
+ cx18_av_write4(cx, 0x108, 0x200d040f);
- /* AUX_PLL_FRAC */
- /* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */
- cx18_av_write4(cx, 0x110, 0x0098d6dd);
+ /* VID_PLL Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+ cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+ /* AUX_PLL Fraction = 0x176740c */
+ /* xtal * 0xd.bb3a060/0x20 = 48000 * 256: 393 MHz p-pd*/
+ cx18_av_write4(cx, 0x110, 0x0176740c);
/* src1_ctl */
/* 0x1.8000 = 48000/32000 */
@@ -195,15 +279,18 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
cx18_av_write4(cx, 0x904, 0x08015555);
cx18_av_write4(cx, 0x90c, 0x08015555);
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
+ cx18_av_write(cx, 0x127, 0x60);
+
/* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */
cx18_av_write4(cx, 0x12c, 0x11203fff);
/*
- * EN_AV_LOCK = 1
+ * EN_AV_LOCK = 0
* VID_COUNT = 0x1193f8 = 143999.000 * 8 =
* ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
*/
- cx18_av_write4(cx, 0x128, 0xa11193f8);
+ cx18_av_write4(cx, 0x128, 0xa01193f8);
break;
}
}
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c
index 40ea6fde6..0b1c84b4d 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.c
+++ b/linux/drivers/media/video/cx18/cx18-av-core.c
@@ -271,7 +271,7 @@ void cx18_av_std_setup(struct cx18 *cx)
if (pll_post) {
int fin, fsc, pll;
- pll = (28636364L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
+ pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
pll /= pll_post;
CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
pll / 1000000, pll % 1000000);
diff --git a/linux/drivers/media/video/cx18/cx18-firmware.c b/linux/drivers/media/video/cx18/cx18-firmware.c
index e74f76d47..1fa95da15 100644
--- a/linux/drivers/media/video/cx18/cx18-firmware.c
+++ b/linux/drivers/media/video/cx18/cx18-firmware.c
@@ -26,6 +26,7 @@
#include "cx18-irq.h"
#include "cx18-firmware.h"
#include "cx18-cards.h"
+#include "cx18-av-core.h"
#include <linux/firmware.h>
#define CX18_PROC_SOFT_RESET 0xc70010
@@ -224,7 +225,45 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
0x00000000, 0x00020002);
- /* The fast clock is at 200/245 MHz */
+ /*
+ * The PLL parameters are based on the external crystal frequency that
+ * would ideally be:
+ *
+ * NTSC Color subcarrier freq * 8 =
+ * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+ *
+ * The accidents of history and rationale that explain from where this
+ * combination of magic numbers originate can be found in:
+ *
+ * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
+ * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
+ *
+ * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
+ * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
+ *
+ * As Mike Bradley has rightly pointed out, it's not the exact crystal
+ * frequency that matters, only that all parts of the driver and
+ * firmware are using the same value (close to the ideal value).
+ *
+ * Since I have a strong suspicion that, if the firmware ever assumes a
+ * crystal value at all, it will assume 28.636360 MHz, the crystal
+ * freq used in calculations in this driver will be:
+ *
+ * xtal_freq = 28.636360 MHz
+ *
+ * an error of less than 0.13 ppm which is way, way better than any off
+ * the shelf crystal will have for accuracy anyway.
+ *
+ * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+ *
+ * Many thanks to Jeff Campbell and Mike Bradley for their extensive
+ * investigation, experimentation, testing, and suggested solutions of
+ * of audio/video sync problems with SVideo and CVBS captures.
+ */
+
+ /* the fast clock is at 200/245 MHz */
+ /* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/
+ /* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/
cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
CX18_FAST_CLOCK_PLL_FRAC);
@@ -234,16 +273,36 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
/* set slow clock to 125/120 MHz */
- cx18_write_reg(cx, lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
- cx18_write_reg(cx, lowpwr ? 0xEBAF05 : 0x18618A8,
+ /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
+ /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */
+ cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT);
+ cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F,
CX18_SLOW_CLOCK_PLL_FRAC);
- cx18_write_reg(cx, 4, CX18_SLOW_CLOCK_PLL_POST);
+ cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);
/* mpeg clock pll 54MHz */
+ /* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */
cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
- cx18_write_reg(cx, 0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
+ cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
+ /*
+ * VDCLK Integer = 0x0f, Post Divider = 0x04
+ * AIMCLK Integer = 0x0e, Post Divider = 0x16
+ */
+ cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+
+ /* VDCLK Fraction = 0x2be2fe */
+ /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+ cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+
+ /* AIMCLK Fraction = 0x05227ad */
+ /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz before post-divide */
+ cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+ cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+
/* Defaults */
/* APU = SC or SC/2 = 125/62.5 */
/* EPU = SC = 125 */
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index f62b05eae..2c975ffa4 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -621,10 +621,19 @@ int em28xx_capture_start(struct em28xx *dev, int start)
return rc;
}
-int em28xx_outfmt_set_yuv422(struct em28xx *dev)
+int em28xx_set_outfmt(struct em28xx *dev)
{
- em28xx_write_reg(dev, EM28XX_R27_OUTFMT, 0x34);
- em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10);
+ int ret;
+
+ ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
+ dev->format->reg | 0x20, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10);
+ if (ret < 0)
+ return ret;
+
return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x11);
}
@@ -686,7 +695,7 @@ int em28xx_resolution_set(struct em28xx *dev)
width = norm_maxw(dev);
height = norm_maxh(dev) >> 1;
- em28xx_outfmt_set_yuv422(dev);
+ em28xx_set_outfmt(dev);
em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index 78eb335a5..7531a20f7 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -96,6 +96,16 @@ MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
static unsigned long em28xx_devused;
+/* supported video standards */
+static struct em28xx_fmt format[] = {
+ {
+ .name = "16bpp YUY2, 4:2:2, packed",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .reg = 0x14,
+ },
+};
+
/* supported controls */
/* Common to all boards */
static struct v4l2_queryctrl em28xx_qctrl[] = {
@@ -390,16 +400,18 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
struct em28xx *dev = fh->dev;
struct v4l2_frequency f;
- *size = 16 * fh->dev->width * fh->dev->height >> 3;
+ *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
+
if (0 == *count)
*count = EM28XX_DEF_BUF;
if (*count < EM28XX_MIN_BUF)
*count = EM28XX_MIN_BUF;
- /* Ask tuner to go to analog mode */
+ /* Ask tuner to go to analog or radio mode */
memset(&f, 0, sizeof(f));
f.frequency = dev->ctl_freq;
+ f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
@@ -442,9 +454,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct em28xx *dev = fh->dev;
int rc = 0, urb_init = 0;
- /* FIXME: It assumes depth = 16 */
- /* The only currently supported format is 16 bits/pixel */
- buf->vb.size = 16 * dev->width * dev->height >> 3;
+ buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
@@ -541,7 +551,7 @@ static int em28xx_config(struct em28xx *dev)
dev->mute = 1; /* maybe not the right place... */
dev->volume = 0x1f;
- em28xx_outfmt_set_yuv422(dev);
+ em28xx_set_outfmt(dev);
em28xx_colorlevels_set_default(dev);
em28xx_compression_disable(dev);
@@ -709,8 +719,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- f->fmt.pix.bytesperline = dev->width * 2;
+ f->fmt.pix.pixelformat = dev->format->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
@@ -722,6 +732,17 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
+static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(format); i++)
+ if (format[i].fourcc == fourcc)
+ return &format[i];
+
+ return NULL;
+}
+
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -732,6 +753,14 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
unsigned int maxw = norm_maxw(dev);
unsigned int maxh = norm_maxh(dev);
unsigned int hscale, vscale;
+ struct em28xx_fmt *fmt;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
/* width must even because of the YUYV format
height must be even because of interlacing */
@@ -770,9 +799,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = width;
f->fmt.pix.height = height;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- f->fmt.pix.bytesperline = width * 2;
- f->fmt.pix.sizeimage = width * 2 * height;
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
@@ -785,6 +814,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
int rc;
+ struct em28xx_fmt *fmt;
rc = check_dev(dev);
if (rc < 0)
@@ -794,6 +824,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
vidioc_try_fmt_vid_cap(file, priv, f);
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ rc = -EINVAL;
+ goto out;
+ }
+
if (videobuf_queue_is_busy(&fh->vb_vidq)) {
em28xx_errdev("%s queue busy\n", __func__);
rc = -EBUSY;
@@ -809,6 +845,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
/* set new image size */
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
+ dev->format = fmt;
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
em28xx_set_alternate(dev);
@@ -1032,18 +1069,14 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
rc = check_dev(dev);
if (rc < 0)
return rc;
+ rc = 0;
mutex_lock(&dev->lock);
- if (!dev->board.has_msp34xx)
- rc = em28xx_get_ctrl(dev, ctrl);
- else
- rc = -EINVAL;
-
- if (rc == -EINVAL) {
+ if (dev->board.has_msp34xx)
em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
- rc = 0;
- }
+ else
+ rc = em28xx_get_ctrl(dev, ctrl);
mutex_unlock(&dev->lock);
return rc;
@@ -1282,10 +1315,8 @@ static int vidioc_streamon(struct file *file, void *priv,
mutex_lock(&dev->lock);
rc = res_get(fh);
- if (unlikely(rc < 0))
- return rc;
-
- rc = videobuf_streamon(&fh->vb_vidq);
+ if (likely(rc >= 0))
+ rc = videobuf_streamon(&fh->vb_vidq);
mutex_unlock(&dev->lock);
@@ -1346,15 +1377,13 @@ static int vidioc_querycap(struct file *file, void *priv,
}
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *fmtd)
+ struct v4l2_fmtdesc *f)
{
- if (fmtd->index != 0)
+ if (unlikely(f->index >= ARRAY_SIZE(format)))
return -EINVAL;
- fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(fmtd->description, "Packed YUY2");
- fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
- memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+ strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ f->pixelformat = format[f->index].fourcc;
return 0;
}
@@ -2143,6 +2172,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->em28xx_write_regs_req = em28xx_write_regs_req;
dev->em28xx_read_reg_req = em28xx_read_reg_req;
dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800;
+ dev->format = &format[0];
em28xx_pre_card_setup(dev);
@@ -2564,3 +2594,4 @@ static void __exit em28xx_module_exit(void)
module_init(em28xx_module_init);
module_exit(em28xx_module_exit);
+
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index 4de9a8190..ae511ed7e 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -210,9 +210,12 @@ struct em28xx_usb_isoc_ctl {
};
+/* Struct to enumberate video formats */
struct em28xx_fmt {
char *name;
u32 fourcc; /* v4l2 format id */
+ int depth;
+ int reg;
};
/* buffer for one video frame */
@@ -439,6 +442,8 @@ struct em28xx {
unsigned int has_audio_class:1;
unsigned int has_alsa_audio:1;
+ struct em28xx_fmt *format;
+
struct em28xx_IR *ir;
/* Some older em28xx chips needs a waiting time after writing */
@@ -577,7 +582,7 @@ int em28xx_audio_setup(struct em28xx *dev);
int em28xx_colorlevels_set_default(struct em28xx *dev);
int em28xx_capture_start(struct em28xx *dev, int start);
-int em28xx_outfmt_set_yuv422(struct em28xx *dev);
+int em28xx_set_outfmt(struct em28xx *dev);
int em28xx_resolution_set(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
int em28xx_init_isoc(struct em28xx *dev, int max_packets,
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index 74a7402f2..8d1f8bebf 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -737,6 +737,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
t->mode = mode;
if (check_mode(t, cmd) == -EINVAL) {
+ tuner_dbg("Tuner doesn't support this mode. "
+ "Putting tuner to sleep\n");
t->mode = T_STANDBY;
if (analog_ops->standby)
analog_ops->standby(&t->fe);
@@ -797,6 +799,8 @@ static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby)
struct tuner *t = to_tuner(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ tuner_dbg("Putting tuner to sleep\n");
+
if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
return 0;
t->mode = T_STANDBY;
@@ -929,6 +933,11 @@ static int tuner_ioctl(struct v4l2_subdev *sd, int cmd, void *arg)
}
return -ENOIOCTLCMD;
}
+#else
+static int tuner_ioctl(struct v4l2_subdev *sd, int cmd, void *arg)
+{
+ return -ENOIOCTLCMD;
+}
#endif
static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg)
diff --git a/linux/drivers/media/video/v4l2-compat-ioctl32.c b/linux/drivers/media/video/v4l2-compat-ioctl32.c
index 171f1ccd1..c9cb73a06 100644
--- a/linux/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/linux/drivers/media/video/v4l2-compat-ioctl32.c
@@ -7,12 +7,14 @@
* Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
* Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
* Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
+ * Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
*
* These routines maintain argument size conversion between 32bit and 64bit
* ioctls.
*/
#include <linux/compat.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/module.h>
@@ -59,55 +61,6 @@ static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user
return 0;
}
-#if 0 /*FIXME */
-struct video_audio32 {
- compat_int_t audio;
- __u16 volume;
- __u16 bass, treble;
- __u32 flags;
- __u8 name[16];
- __u16 mode;
- __u16 balance;
- __u16 step;
-};
-
-static int get_video_audio32(struct video_audio *kp,
- struct video_audio32 __user *up)
-{
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_audio32)) ||
- get_user(kp->audio, &up->audio) ||
- get_user(kp->volume, &up->volume) ||
- get_user(kp->bass, &up->bass) ||
- get_user(kp->treble, &up->treble) ||
- get_user(kp->flags, &up->flags) ||
- copy_from_user(kp->name, up->name, sizeof(up->name)) ||
- get_user(kp->mode, &up->mode) ||
- get_user(kp->balance, &up->balance) ||
- get_user(kp->step, &up->step))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_video_audio32(struct video_audio *kp,
- struct video_audio32 __user *up)
-{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_audio32)) ||
- put_user(kp->audio, &up->audio) ||
- put_user(kp->volume, &up->volume) ||
- put_user(kp->bass, &up->bass) ||
- put_user(kp->treble, &up->treble) ||
- put_user(kp->flags, &up->flags) ||
- copy_to_user(kp->name, up->name, sizeof(up->name)) ||
- put_user(kp->mode, &up->mode) ||
- put_user(kp->balance, &up->balance) ||
- put_user(kp->step, &up->step))
- return -EFAULT;
-
- return 0;
-}
-#endif
-
struct video_buffer32 {
compat_caddr_t base;
compat_int_t height, width, depth, bytesperline;
@@ -148,7 +101,7 @@ static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __u
}
struct video_clip32 {
- s32 x, y, width, height; /* Its really s32 in videodev.h */
+ s32 x, y, width, height; /* It's really s32 in videodev.h */
compat_caddr_t next;
};
@@ -157,29 +110,72 @@ struct video_window32 {
compat_caddr_t clips;
compat_int_t clipcount;
};
-#endif
-static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static int get_video_window32(struct video_window *kp, struct video_window32 __user *up)
{
- int ret = -ENOIOCTLCMD;
+ struct video_clip __user *uclips;
+ struct video_clip __user *kclips;
+ compat_caddr_t p;
+ int nclips;
- if (file->f_op->unlocked_ioctl)
- ret = file->f_op->unlocked_ioctl(file, cmd, arg);
- else if (file->f_op->ioctl) {
- lock_kernel();
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
- ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
-#else
- ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
-#endif
- unlock_kernel();
+ if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
+ return -EFAULT;
+
+ if (get_user(nclips, &up->clipcount))
+ return -EFAULT;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)) ||
+ get_user(kp->x, &up->x) ||
+ get_user(kp->y, &up->y) ||
+ get_user(kp->width, &up->width) ||
+ get_user(kp->height, &up->height) ||
+ get_user(kp->chromakey, &up->chromakey) ||
+ get_user(kp->flags, &up->flags) ||
+ get_user(kp->clipcount, &up->clipcount))
+ return -EFAULT;
+
+ nclips = kp->clipcount;
+ kp->clips = NULL;
+
+ if (nclips == 0)
+ return 0;
+ if (get_user(p, &up->clips))
+ return -EFAULT;
+ uclips = compat_ptr(p);
+
+ /* If nclips < 0, then it is a clipping bitmap of size
+ VIDEO_CLIPMAP_SIZE */
+ if (nclips < 0) {
+ if (!access_ok(VERIFY_READ, uclips, VIDEO_CLIPMAP_SIZE))
+ return -EFAULT;
+ kp->clips = compat_alloc_user_space(VIDEO_CLIPMAP_SIZE);
+ if (copy_in_user(kp->clips, uclips, VIDEO_CLIPMAP_SIZE))
+ return -EFAULT;
+ return 0;
}
- return ret;
-}
+ /* Otherwise it is an array of video_clip structs. */
+ if (!access_ok(VERIFY_READ, uclips, nclips * sizeof(struct video_clip)))
+ return -EFAULT;
+ kp->clips = compat_alloc_user_space(nclips * sizeof(struct video_clip));
+ kclips = kp->clips;
+ while (nclips--) {
+ int err;
+
+ err = copy_in_user(&kclips->x, &uclips->x, sizeof(kclips->x));
+ err |= copy_in_user(&kclips->y, &uclips->y, sizeof(kclips->y));
+ err |= copy_in_user(&kclips->width, &uclips->width, sizeof(kclips->width));
+ err |= copy_in_user(&kclips->height, &uclips->height, sizeof(kclips->height));
+ kclips->next = NULL;
+ if (err)
+ return -EFAULT;
+ kclips++;
+ uclips++;
+ }
+ return 0;
+}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
/* You get back everything except the clips... */
static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
{
@@ -194,8 +190,59 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u
return -EFAULT;
return 0;
}
+
+struct video_code32 {
+ char loadwhat[16]; /* name or tag of file being passed */
+ compat_int_t datasize;
+ unsigned char *data;
+};
+
+static int get_microcode32(struct video_code *kp, struct video_code32 __user *up)
+{
+ if (!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
+ copy_from_user(kp->loadwhat, up->loadwhat, sizeof(up->loadwhat)) ||
+ get_user(kp->datasize, &up->datasize) ||
+ copy_from_user(kp->data, up->data, up->datasize))
+ return -EFAULT;
+ return 0;
+}
+
+#define VIDIOCGTUNER32 _IOWR('v', 4, struct video_tuner32)
+#define VIDIOCSTUNER32 _IOW('v', 5, struct video_tuner32)
+#define VIDIOCGWIN32 _IOR('v', 9, struct video_window32)
+#define VIDIOCSWIN32 _IOW('v', 10, struct video_window32)
+#define VIDIOCGFBUF32 _IOR('v', 11, struct video_buffer32)
+#define VIDIOCSFBUF32 _IOW('v', 12, struct video_buffer32)
+#define VIDIOCGFREQ32 _IOR('v', 14, u32)
+#define VIDIOCSFREQ32 _IOW('v', 15, u32)
+#define VIDIOCSMICROCODE32 _IOW('v', 27, struct video_code32)
+
+#define VIDIOCCAPTURE32 _IOW('v', 8, s32)
+#define VIDIOCSYNC32 _IOW('v', 18, s32)
+#define VIDIOCSWRITEMODE32 _IOW('v', 25, s32)
+
#endif
+static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOIOCTLCMD;
+
+ if (file->f_op->unlocked_ioctl)
+ ret = file->f_op->unlocked_ioctl(file, cmd, arg);
+ else if (file->f_op->ioctl) {
+ lock_kernel();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
+#else
+ ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
+#endif
+ unlock_kernel();
+ }
+
+ return ret;
+}
+
+
struct v4l2_clip32 {
struct v4l2_rect c;
compat_caddr_t next;
@@ -282,12 +329,27 @@ static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vb
return 0;
}
+static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+{
+ if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+ return -EFAULT;
+ return 0;
+}
+
+static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+{
+ if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
+ return -EFAULT;
+ return 0;
+}
+
struct v4l2_format32 {
enum v4l2_buf_type type;
union {
- struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
- struct v4l2_window32 win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
- struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
+ struct v4l2_pix_format pix;
+ struct v4l2_window32 win;
+ struct v4l2_vbi_format vbi;
+ struct v4l2_sliced_vbi_format sliced;
__u8 raw_data[200]; /* user-defined */
} fmt;
};
@@ -299,15 +361,27 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
return -EFAULT;
switch (kp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
+ return -EFAULT;
+ return 0;
+ case 0:
+ return -EINVAL;
default:
- printk(KERN_INFO "compat_ioctl: unexpected VIDIOC_FMT type %d\n",
+ printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
kp->type);
- return -ENXIO;
+ return -EINVAL;
}
}
@@ -318,31 +392,30 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
return -EFAULT;
switch (kp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
+ return -EFAULT;
+ return 0;
+ case 0:
+ return -EINVAL;
default:
- return -ENXIO;
+ printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+ kp->type);
+ return -EINVAL;
}
}
-static inline int get_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
-{
- if (copy_from_user(kp, up, sizeof(struct v4l2_standard)))
- return -EFAULT;
- return 0;
-
-}
-
-static inline int put_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
-{
- if (copy_to_user(up, kp, sizeof(struct v4l2_standard)))
- return -EFAULT;
- return 0;
-}
-
struct v4l2_standard32 {
__u32 index;
__u32 id[2]; /* __u64 would get the alignment wrong */
@@ -374,21 +447,6 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32
return 0;
}
-static inline int get_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
-{
- if (copy_from_user(kp, up, sizeof(struct v4l2_tuner)))
- return -EFAULT;
- return 0;
-
-}
-
-static inline int put_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
-{
- if (copy_to_user(up, kp, sizeof(struct v4l2_tuner)))
- return -EFAULT;
- return 0;
-}
-
struct v4l2_buffer32 {
__u32 index;
enum v4l2_buf_type type;
@@ -512,149 +570,145 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame
return 0;
}
-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
-{
- if (copy_from_user(kp, up, sizeof(struct v4l2_input) - 4))
- return -EFAULT;
- return 0;
-}
-
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
+struct v4l2_input32 {
+ __u32 index; /* Which input */
+ __u8 name[32]; /* Label */
+ __u32 type; /* Type of input */
+ __u32 audioset; /* Associated audios (bitfield) */
+ __u32 tuner; /* Associated tuner */
+ v4l2_std_id std;
+ __u32 status;
+ __u32 reserved[4];
+} __attribute__ ((packed));
+
+/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
+ Otherwise it is identical to the 32-bit version. */
+static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
{
- if (copy_to_user(up, kp, sizeof(struct v4l2_input) - 4))
+ if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
return -EFAULT;
return 0;
}
-static inline int get_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
+static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
{
- if (copy_from_user(kp, up, sizeof(struct v4l2_input)))
+ if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
return -EFAULT;
return 0;
}
-static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
-{
- if (copy_to_user(up, kp, sizeof(struct v4l2_input)))
- return -EFAULT;
- return 0;
-}
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-struct video_code32 {
- char loadwhat[16]; /* name or tag of file being passed */
- compat_int_t datasize;
- unsigned char *data;
+struct v4l2_ext_controls32 {
+ __u32 ctrl_class;
+ __u32 count;
+ __u32 error_idx;
+ __u32 reserved[2];
+ compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
};
-static inline int microcode32(struct video_code *kp, struct video_code32 __user *up)
+static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
- copy_from_user(kp->loadwhat, up->loadwhat, sizeof(up->loadwhat)) ||
- get_user(kp->datasize, &up->datasize) ||
- copy_from_user(kp->data, up->data, up->datasize))
+ struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control __user *kcontrols;
+ int n;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
+ get_user(kp->ctrl_class, &up->ctrl_class) ||
+ get_user(kp->count, &up->count) ||
+ get_user(kp->error_idx, &up->error_idx) ||
+ copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+ return -EFAULT;
+ n = kp->count;
+ if (n == 0) {
+ kp->controls = NULL;
+ return 0;
+ }
+ if (get_user(p, &up->controls))
+ return -EFAULT;
+ ucontrols = compat_ptr(p);
+ if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
+ return -EFAULT;
+ kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
+ kp->controls = kcontrols;
+ while (--n >= 0) {
+ if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
return -EFAULT;
+ if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
+ return -EFAULT;
+ /* Note: if the void * part of the union ever becomes relevant
+ then we need to know the type of the control in order to do
+ the right thing here. Luckily, that is not yet an issue. */
+ if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
+ return -EFAULT;
+ ucontrols++;
+ kcontrols++;
+ }
return 0;
}
-#define VIDIOCGTUNER32 _IOWR('v', 4, struct video_tuner32)
-#define VIDIOCSTUNER32 _IOW('v', 5, struct video_tuner32)
-#define VIDIOCGWIN32 _IOR('v', 9, struct video_window32)
-#define VIDIOCSWIN32 _IOW('v', 10, struct video_window32)
-#define VIDIOCGFBUF32 _IOR('v', 11, struct video_buffer32)
-#define VIDIOCSFBUF32 _IOW('v', 12, struct video_buffer32)
-#define VIDIOCGFREQ32 _IOR('v', 14, u32)
-#define VIDIOCSFREQ32 _IOW('v', 15, u32)
-#define VIDIOCSMICROCODE32 _IOW('v', 27, struct video_code32)
-
-#endif
-
-/* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */
-#define VIDIOC_ENUMINPUT32 (VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4))
-#define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32)
-#define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32)
-#define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32)
-#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
-#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
-/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
-#define VIDIOC_OVERLAY32 _IOWR ('V', 14, compat_int_t)
-#define VIDIOC_QBUF32 _IOWR ('V', 15, struct v4l2_buffer32)
-#define VIDIOC_DQBUF32 _IOWR ('V', 17, struct v4l2_buffer32)
-#define VIDIOC_STREAMON32 _IOW ('V', 18, compat_int_t)
-#define VIDIOC_STREAMOFF32 _IOW ('V', 19, compat_int_t)
-#define VIDIOC_ENUMSTD32 _IOWR ('V', 25, struct v4l2_standard32)
-/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
-#define VIDIOC_S_CTRL32 _IOW ('V', 28, struct v4l2_control)
-#define VIDIOC_G_INPUT32 _IOR ('V', 38, compat_int_t)
-#define VIDIOC_S_INPUT32 _IOWR ('V', 39, compat_int_t)
-#define VIDIOC_TRY_FMT32 _IOWR ('V', 64, struct v4l2_format32)
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-enum {
- MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
-};
-
-static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
+static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- struct video_window32 __user *up = compat_ptr(arg);
- struct video_window __user *vw;
- struct video_clip __user *p;
- int nclips;
- u32 n;
-
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
- return -EFAULT;
+ struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control __user *kcontrols = kp->controls;
+ int n = kp->count;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
+ put_user(kp->ctrl_class, &up->ctrl_class) ||
+ put_user(kp->count, &up->count) ||
+ put_user(kp->error_idx, &up->error_idx) ||
+ copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+ return -EFAULT;
+ if (!kp->count)
+ return 0;
- if (get_user(nclips, &up->clipcount))
+ if (get_user(p, &up->controls))
return -EFAULT;
-
- /* Peculiar interface... */
- if (nclips < 0)
- nclips = VIDEO_CLIPMAP_SIZE;
-
- if (nclips > MaxClips)
- return -ENOMEM;
-
- vw = compat_alloc_user_space(sizeof(struct video_window) +
- nclips * sizeof(struct video_clip));
-
- p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
-
- if (get_user(n, &up->x) || put_user(n, &vw->x) ||
- get_user(n, &up->y) || put_user(n, &vw->y) ||
- get_user(n, &up->width) || put_user(n, &vw->width) ||
- get_user(n, &up->height) || put_user(n, &vw->height) ||
- get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
- get_user(n, &up->flags) || put_user(n, &vw->flags) ||
- get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
- get_user(n, &up->clips) || put_user(p, &vw->clips))
+ ucontrols = compat_ptr(p);
+ if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
return -EFAULT;
- if (nclips) {
- struct video_clip32 __user *u = compat_ptr(n);
- int i;
- if (!u)
- return -EINVAL;
- for (i = 0; i < nclips; i++, u++, p++) {
- s32 v;
- if (!access_ok(VERIFY_READ, u, sizeof(struct video_clip32)) ||
- !access_ok(VERIFY_WRITE, p, sizeof(struct video_clip32)) ||
- get_user(v, &u->x) ||
- put_user(v, &p->x) ||
- get_user(v, &u->y) ||
- put_user(v, &p->y) ||
- get_user(v, &u->width) ||
- put_user(v, &p->width) ||
- get_user(v, &u->height) ||
- put_user(v, &p->height) ||
- put_user(NULL, &p->next))
- return -EFAULT;
- }
+ while (--n >= 0) {
+ if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
+ return -EFAULT;
+ if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
+ sizeof(ucontrols->reserved2)))
+ return -EFAULT;
+ /* Note: if the void * part of the union ever becomes relevant
+ then we need to know the type of the control in order to do
+ the right thing here. Luckily, that is not yet an issue. */
+ if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
+ return -EFAULT;
+ ucontrols++;
+ kcontrols++;
}
-
- return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
+ return 0;
}
+
+#define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32)
+#define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32)
+#define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32)
+#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
+#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
+#define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32)
+#define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32)
+#define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32)
+#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
+#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
+#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
+#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
+#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
+
+#define VIDIOC_OVERLAY32 _IOW ('V', 14, s32)
+#ifdef __OLD_VIDIOC_
+#define VIDIOC_OVERLAY32_OLD _IOWR('V', 14, s32)
#endif
+#define VIDIOC_STREAMON32 _IOW ('V', 18, s32)
+#define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32)
+#define VIDIOC_G_INPUT32 _IOR ('V', 38, s32)
+#define VIDIOC_S_INPUT32 _IOWR('V', 39, s32)
+#define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
+#define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -669,45 +723,53 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
struct v4l2_format v2f;
struct v4l2_buffer v2b;
struct v4l2_framebuffer v2fb;
- struct v4l2_standard v2s;
struct v4l2_input v2i;
- struct v4l2_tuner v2t;
+ struct v4l2_standard v2s;
+ struct v4l2_ext_controls v2ecs;
unsigned long vx;
+ int vi;
} karg;
void __user *up = compat_ptr(arg);
int compatible_arg = 1;
int err = 0;
- int realcmd = cmd;
/* First, convert the command. */
switch (cmd) {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGTUNER32: realcmd = cmd = VIDIOCGTUNER; break;
- case VIDIOCSTUNER32: realcmd = cmd = VIDIOCSTUNER; break;
- case VIDIOCGWIN32: realcmd = cmd = VIDIOCGWIN; break;
- case VIDIOCGFBUF32: realcmd = cmd = VIDIOCGFBUF; break;
- case VIDIOCSFBUF32: realcmd = cmd = VIDIOCSFBUF; break;
- case VIDIOCGFREQ32: realcmd = cmd = VIDIOCGFREQ; break;
- case VIDIOCSFREQ32: realcmd = cmd = VIDIOCSFREQ; break;
- case VIDIOCSMICROCODE32: realcmd = cmd = VIDIOCSMICROCODE; break;
+ case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+ case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+ case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+ case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
+ case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+ case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+ case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+ case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+ case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
+#endif
+ case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
+ case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
+ case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
+ case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
+ case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
+ case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
+ case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
+ case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
+ case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
+ case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
+ case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
+ case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
+ case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
+ case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
+#ifdef __OLD_VIDIOC_
+ case VIDIOC_OVERLAY32_OLD: cmd = VIDIOC_OVERLAY; break;
#endif
- case VIDIOC_G_FMT32: realcmd = cmd = VIDIOC_G_FMT; break;
- case VIDIOC_S_FMT32: realcmd = cmd = VIDIOC_S_FMT; break;
- case VIDIOC_QUERYBUF32: realcmd = cmd = VIDIOC_QUERYBUF; break;
- case VIDIOC_QBUF32: realcmd = cmd = VIDIOC_QBUF; break;
- case VIDIOC_DQBUF32: realcmd = cmd = VIDIOC_DQBUF; break;
- case VIDIOC_STREAMON32: realcmd = cmd = VIDIOC_STREAMON; break;
- case VIDIOC_STREAMOFF32: realcmd = cmd = VIDIOC_STREAMOFF; break;
- case VIDIOC_G_FBUF32: realcmd = cmd = VIDIOC_G_FBUF; break;
- case VIDIOC_S_FBUF32: realcmd = cmd = VIDIOC_S_FBUF; break;
- case VIDIOC_OVERLAY32: realcmd = cmd = VIDIOC_OVERLAY; break;
- case VIDIOC_ENUMSTD32: realcmd = VIDIOC_ENUMSTD; break;
- case VIDIOC_ENUMINPUT32: realcmd = VIDIOC_ENUMINPUT; break;
- case VIDIOC_S_CTRL32: realcmd = cmd = VIDIOC_S_CTRL; break;
- case VIDIOC_G_INPUT32: realcmd = cmd = VIDIOC_G_INPUT; break;
- case VIDIOC_S_INPUT32: realcmd = cmd = VIDIOC_S_INPUT; break;
- case VIDIOC_TRY_FMT32: realcmd = cmd = VIDIOC_TRY_FMT; break;
- };
+ case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
+ case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
+ case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
+ case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
+ case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
+ case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
+ }
switch (cmd) {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -715,7 +777,6 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case VIDIOCGTUNER:
err = get_video_tuner32(&karg.vt, up);
compatible_arg = 0;
-
break;
case VIDIOCSFBUF:
@@ -723,25 +784,42 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
compatible_arg = 0;
break;
-#if 0 /*FIXME*/
- case VIDIOCSAUDIO:
- err = get_video_audio32(&karg.va, up);
+ case VIDIOCSWIN:
+ err = get_video_window32(&karg.vw, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOCGWIN:
+ case VIDIOCGFBUF:
+ case VIDIOCGFREQ:
+ compatible_arg = 0;
+ break;
+
+ case VIDIOCSMICROCODE:
+ err = get_microcode32(&karg.vc, up);
compatible_arg = 0;
break;
-#endif
case VIDIOCSFREQ:
+ err = get_user(karg.vx, (u32 __user *)up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOCCAPTURE:
+ case VIDIOCSYNC:
+ case VIDIOCSWRITEMODE:
#endif
- case VIDIOC_S_INPUT:
case VIDIOC_OVERLAY:
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
- err = get_user(karg.vx, (u32 __user *)up);
- compatible_arg = 1;
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_OUTPUT:
+ err = get_user(karg.vi, (s32 __user *)up);
+ compatible_arg = 0;
break;
- case VIDIOC_S_FBUF:
- err = get_v4l2_framebuffer32(&karg.v2fb, up);
+ case VIDIOC_G_INPUT:
+ case VIDIOC_G_OUTPUT:
compatible_arg = 0;
break;
@@ -759,127 +837,108 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
compatible_arg = 0;
break;
- case VIDIOC_ENUMSTD:
- err = get_v4l2_standard(&karg.v2s, up);
+ case VIDIOC_S_FBUF:
+ err = get_v4l2_framebuffer32(&karg.v2fb, up);
compatible_arg = 0;
break;
- case VIDIOC_ENUMSTD32:
- err = get_v4l2_standard32(&karg.v2s, up);
+ case VIDIOC_G_FBUF:
compatible_arg = 0;
break;
- case VIDIOC_ENUMINPUT:
- err = get_v4l2_input(&karg.v2i, up);
+ case VIDIOC_ENUMSTD:
+ err = get_v4l2_standard32(&karg.v2s, up);
compatible_arg = 0;
break;
- case VIDIOC_ENUMINPUT32:
+ case VIDIOC_ENUMINPUT:
err = get_v4l2_input32(&karg.v2i, up);
compatible_arg = 0;
break;
- case VIDIOC_G_TUNER:
- case VIDIOC_S_TUNER:
- err = get_v4l2_tuner(&karg.v2t, up);
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ err = get_v4l2_ext_controls32(&karg.v2ecs, up);
compatible_arg = 0;
break;
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGWIN:
- case VIDIOCGFBUF:
- case VIDIOCGFREQ:
-#endif
- case VIDIOC_G_FBUF:
- case VIDIOC_G_INPUT:
- compatible_arg = 0;
- break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCSMICROCODE:
- err = microcode32(&karg.vc, up);
- compatible_arg = 0;
- break;
-#endif
- };
+ }
if (err)
- goto out;
+ return err;
if (compatible_arg)
- err = native_ioctl(file, realcmd, (unsigned long)up);
+ err = native_ioctl(file, cmd, (unsigned long)up);
else {
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
- err = native_ioctl(file, realcmd, (unsigned long)&karg);
+ err = native_ioctl(file, cmd, (unsigned long)&karg);
set_fs(old_fs);
}
- if (err == 0) {
- switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGTUNER:
- err = put_video_tuner32(&karg.vt, up);
- break;
-
- case VIDIOCGWIN:
- err = put_video_window32(&karg.vw, up);
- break;
-
- case VIDIOCGFBUF:
- err = put_video_buffer32(&karg.vb, up);
- break;
-#if 0 /*FIXME*/
- case VIDIOCGAUDIO:
- err = put_video_audio32(&karg.va, up);
- break;
-#endif
-#endif
- case VIDIOC_G_FBUF:
- err = put_v4l2_framebuffer32(&karg.v2fb, up);
- break;
-
- case VIDIOC_G_FMT:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT:
- err = put_v4l2_format32(&karg.v2f, up);
- break;
-
- case VIDIOC_QUERYBUF:
- case VIDIOC_QBUF:
- case VIDIOC_DQBUF:
- err = put_v4l2_buffer32(&karg.v2b, up);
- break;
-
- case VIDIOC_ENUMSTD:
- err = put_v4l2_standard(&karg.v2s, up);
- break;
-
- case VIDIOC_ENUMSTD32:
- err = put_v4l2_standard32(&karg.v2s, up);
- break;
-
- case VIDIOC_G_TUNER:
- case VIDIOC_S_TUNER:
- err = put_v4l2_tuner(&karg.v2t, up);
- break;
-
- case VIDIOC_ENUMINPUT:
- err = put_v4l2_input(&karg.v2i, up);
- break;
-
- case VIDIOC_ENUMINPUT32:
- err = put_v4l2_input32(&karg.v2i, up);
- break;
+ /* Special case: even after an error we need to put the
+ results back for these ioctls since the error_idx will
+ contain information on which control failed. */
+ switch (cmd) {
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ if (put_v4l2_ext_controls32(&karg.v2ecs, up))
+ err = -EFAULT;
+ break;
+ }
+ if (err)
+ return err;
+ switch (cmd) {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGFREQ:
+ case VIDIOCGTUNER:
+ err = put_video_tuner32(&karg.vt, up);
+ break;
+
+ case VIDIOCGWIN:
+ err = put_video_window32(&karg.vw, up);
+ break;
+
+ case VIDIOCGFBUF:
+ err = put_video_buffer32(&karg.vb, up);
+ break;
+
+ case VIDIOCGFREQ:
+ err = put_user(((u32)karg.vx), (u32 __user *)up);
+ break;
#endif
- case VIDIOC_G_INPUT:
- err = put_user(((u32)karg.vx), (u32 __user *)up);
- break;
- };
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_OUTPUT:
+ case VIDIOC_G_INPUT:
+ case VIDIOC_G_OUTPUT:
+ err = put_user(((s32)karg.vi), (s32 __user *)up);
+ break;
+
+ case VIDIOC_G_FBUF:
+ err = put_v4l2_framebuffer32(&karg.v2fb, up);
+ break;
+
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ err = put_v4l2_format32(&karg.v2f, up);
+ break;
+
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+ err = put_v4l2_buffer32(&karg.v2b, up);
+ break;
+
+ case VIDIOC_ENUMSTD:
+ err = put_v4l2_standard32(&karg.v2s, up);
+ break;
+
+ case VIDIOC_ENUMINPUT:
+ err = put_v4l2_input32(&karg.v2i, up);
+ break;
}
-out:
return err;
}
@@ -892,26 +951,48 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCSWIN32:
- ret = do_set_window(file, cmd, arg);
- break;
+ case VIDIOCGCAP:
+ case VIDIOCGCHAN:
+ case VIDIOCSCHAN:
case VIDIOCGTUNER32:
case VIDIOCSTUNER32:
+ case VIDIOCGPICT:
+ case VIDIOCSPICT:
+ case VIDIOCCAPTURE32:
case VIDIOCGWIN32:
+ case VIDIOCSWIN32:
case VIDIOCGFBUF32:
case VIDIOCSFBUF32:
+ case VIDIOCKEY:
case VIDIOCGFREQ32:
case VIDIOCSFREQ32:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
+ case VIDIOCSYNC32:
+ case VIDIOCMCAPTURE:
+ case VIDIOCGMBUF:
+ case VIDIOCGUNIT:
+ case VIDIOCGCAPTURE:
+ case VIDIOCSCAPTURE:
+ case VIDIOCSPLAYMODE:
+ case VIDIOCSWRITEMODE32:
+ case VIDIOCGPLAYINFO:
+ case VIDIOCSMICROCODE32:
case VIDIOCGVBIFMT:
case VIDIOCSVBIFMT:
#endif
+#ifdef __OLD_VIDIOC_
+ case VIDIOC_OVERLAY32_OLD:
+ case VIDIOC_S_PARM_OLD:
+ case VIDIOC_S_CTRL_OLD:
+ case VIDIOC_G_AUDIO_OLD:
+ case VIDIOC_G_AUDOUT_OLD:
+ case VIDIOC_CROPCAP_OLD:
+#endif
case VIDIOC_QUERYCAP:
+ case VIDIOC_RESERVED:
case VIDIOC_ENUM_FMT:
case VIDIOC_G_FMT32:
- case VIDIOC_CROPCAP:
- case VIDIOC_S_CROP:
case VIDIOC_S_FMT32:
case VIDIOC_REQBUFS:
case VIDIOC_QUERYBUF32:
@@ -926,43 +1007,56 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_S_PARM:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
- case VIDIOC_G_TUNER:
- case VIDIOC_S_TUNER:
- case VIDIOC_ENUMSTD:
case VIDIOC_ENUMSTD32:
- case VIDIOC_ENUMINPUT:
case VIDIOC_ENUMINPUT32:
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
- case VIDIOC_S_CTRL32:
- case VIDIOC_S_FREQUENCY:
- case VIDIOC_G_FREQUENCY:
+ case VIDIOC_G_TUNER:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_S_AUDIO:
case VIDIOC_QUERYCTRL:
+ case VIDIOC_QUERYMENU:
case VIDIOC_G_INPUT32:
case VIDIOC_S_INPUT32:
+ case VIDIOC_G_OUTPUT32:
+ case VIDIOC_S_OUTPUT32:
+ case VIDIOC_ENUMOUTPUT:
+ case VIDIOC_G_AUDOUT:
+ case VIDIOC_S_AUDOUT:
+ case VIDIOC_G_MODULATOR:
+ case VIDIOC_S_MODULATOR:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_CROPCAP:
+ case VIDIOC_G_CROP:
+ case VIDIOC_S_CROP:
+ case VIDIOC_G_JPEGCOMP:
+ case VIDIOC_S_JPEGCOMP:
+ case VIDIOC_QUERYSTD:
case VIDIOC_TRY_FMT32:
- case VIDIOC_S_HW_FREQ_SEEK:
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_ENUMAUDOUT:
+ case VIDIOC_G_PRIORITY:
+ case VIDIOC_S_PRIORITY:
+ case VIDIOC_G_SLICED_VBI_CAP:
+ case VIDIOC_LOG_STATUS:
+ case VIDIOC_G_EXT_CTRLS32:
+ case VIDIOC_S_EXT_CTRLS32:
+ case VIDIOC_TRY_EXT_CTRLS32:
case VIDIOC_ENUM_FRAMESIZES:
case VIDIOC_ENUM_FRAMEINTERVALS:
+ case VIDIOC_G_ENC_INDEX:
+ case VIDIOC_ENCODER_CMD:
+ case VIDIOC_TRY_ENCODER_CMD:
+ case VIDIOC_DBG_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_G_CHIP_IDENT:
+ case VIDIOC_S_HW_FREQ_SEEK:
ret = do_video_ioctl(file, cmd, arg);
break;
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* Little v, the video4linux ioctls (conflict?) */
- case VIDIOCGCAP:
- case VIDIOCGCHAN:
- case VIDIOCSCHAN:
- case VIDIOCGPICT:
- case VIDIOCSPICT:
- case VIDIOCCAPTURE:
- case VIDIOCKEY:
- case VIDIOCSYNC:
- case VIDIOCMCAPTURE:
- case VIDIOCGMBUF:
- case VIDIOCGUNIT:
- case VIDIOCGCAPTURE:
- case VIDIOCSCAPTURE:
-
/* BTTV specific... */
case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]):
case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]):
diff --git a/linux/include/linux/videodev2.h b/linux/include/linux/videodev2.h
index 96624e29f..f64a3f780 100644
--- a/linux/include/linux/videodev2.h
+++ b/linux/include/linux/videodev2.h
@@ -1465,6 +1465,8 @@ struct v4l2_chip_ident {
#define VIDIOC_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_chip_ident)
#endif
#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek)
+/* Reminder: when adding new ioctls please add support for them to
+ drivers/media/video/v4l2-compat-ioctl32.c as well! */
#ifdef __OLD_VIDIOC_
/* for compatibility, will go away some day */