diff options
32 files changed, 2738 insertions, 2071 deletions
diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig index bee1bf3c9..7847a8320 100644 --- a/linux/drivers/media/dvb/dvb-usb/Kconfig +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig @@ -76,6 +76,7 @@ config DVB_USB_DIB0700 select DVB_DIB3000MC select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The @@ -107,6 +108,7 @@ config DVB_USB_CXUSB select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -121,6 +123,7 @@ config DVB_USB_M920X select DVB_MT352 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE help Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. Currently, only devices with a product id of diff --git a/linux/drivers/media/dvb/frontends/stv0299.c b/linux/drivers/media/dvb/frontends/stv0299.c index 17556183e..35435bef8 100644 --- a/linux/drivers/media/dvb/frontends/stv0299.c +++ b/linux/drivers/media/dvb/frontends/stv0299.c @@ -63,6 +63,7 @@ struct stv0299_state { u32 symbol_rate; fe_code_rate_t fec_inner; int errmode; + u32 ucblocks; }; #define STATUS_BER 0 @@ -501,8 +502,10 @@ static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) { struct stv0299_state* state = fe->demodulator_priv; - if (state->errmode != STATUS_BER) return 0; - *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); + if (state->errmode != STATUS_BER) + return -ENOSYS; + + *ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8); return 0; } @@ -540,8 +543,12 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { struct stv0299_state* state = fe->demodulator_priv; - if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0; - else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); + if (state->errmode != STATUS_UCBLOCKS) + return -ENOSYS; + + state->ucblocks += stv0299_readreg(state, 0x1e); + state->ucblocks += (stv0299_readreg(state, 0x1d) << 8); + *ucblocks = state->ucblocks; return 0; } diff --git a/linux/drivers/media/dvb/frontends/tda10023.c b/linux/drivers/media/dvb/frontends/tda10023.c index ec9d772c4..ccc63f064 100644 --- a/linux/drivers/media/dvb/frontends/tda10023.c +++ b/linux/drivers/media/dvb/frontends/tda10023.c @@ -74,9 +74,12 @@ static u8 tda10023_readreg (struct tda10023_state* state, u8 reg) int ret; ret = i2c_transfer (state->i2c, msg, 2); - if (ret != 2) - printk("DVB: TDA10023: %s: readreg error (ret == %i)\n", - __func__, ret); + if (ret != 2) { + int num = state->frontend.dvb ? state->frontend.dvb->num : -1; + printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error " + "(reg == 0x%02x, ret == %i)\n", + num, __func__, reg, ret); + } return b1[0]; } @@ -87,11 +90,12 @@ static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data) int ret; ret = i2c_transfer (state->i2c, &msg, 1); - if (ret != 1) - printk("DVB: TDA10023(%d): %s, writereg error " + if (ret != 1) { + int num = state->frontend.dvb ? state->frontend.dvb->num : -1; + printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error " "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", - state->frontend.dvb->num, __func__, reg, data, ret); - + num, __func__, reg, data, ret); + } return (ret != 1) ? -EREMOTEIO : 0; } @@ -485,7 +489,7 @@ struct dvb_frontend *tda10023_attach(const struct tda10023_config *config, struct tda10023_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c index 073ed350f..cc25b3380 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.c +++ b/linux/drivers/media/dvb/ttpci/av7110.c @@ -1198,7 +1198,6 @@ static int start_ts_capture(struct av7110 *budget) if (budget->feeding1) return ++budget->feeding1; memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH); - budget->tsf = 0xff; budget->ttbp = 0; SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ diff --git a/linux/drivers/media/dvb/ttpci/av7110.h b/linux/drivers/media/dvb/ttpci/av7110.h index 290ffc188..6cbf79c3e 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.h +++ b/linux/drivers/media/dvb/ttpci/av7110.h @@ -200,7 +200,6 @@ struct av7110 { struct dvb_net dvb_net1; spinlock_t feedlock1; int feeding1; - u8 tsf; u32 ttbp; unsigned char *grabbing; struct saa7146_pgtable pt; diff --git a/linux/drivers/media/dvb/ttpci/av7110_hw.c b/linux/drivers/media/dvb/ttpci/av7110_hw.c index ec049bb6e..afae0266a 100644 --- a/linux/drivers/media/dvb/ttpci/av7110_hw.c +++ b/linux/drivers/media/dvb/ttpci/av7110_hw.c @@ -427,6 +427,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) if (err) { printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", __func__, type); + av7110->arm_errors++; return -ETIMEDOUT; } msleep(1); @@ -853,10 +854,8 @@ static osd_raw_window_t bpp2bit[8] = { static inline int WaitUntilBmpLoaded(struct av7110 *av7110) { - int ret = wait_event_interruptible_timeout(av7110->bmpq, + int ret = wait_event_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, 10*HZ); - if (ret == -ERESTARTSYS) - return ret; if (ret == 0) { printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", ret, av7110->bmp_state); diff --git a/linux/drivers/media/dvb/ttpci/av7110_hw.h b/linux/drivers/media/dvb/ttpci/av7110_hw.h index 74d940f75..ca99e5c1f 100644 --- a/linux/drivers/media/dvb/ttpci/av7110_hw.h +++ b/linux/drivers/media/dvb/ttpci/av7110_hw.h @@ -305,7 +305,6 @@ enum av7110_command_type { #define IRQ_STATE (DPRAM_BASE + 0x0F4) #define IRQ_STATE_EXT (DPRAM_BASE + 0x0F6) #define MSGSTATE (DPRAM_BASE + 0x0F8) -#define FILT_STATE (DPRAM_BASE + 0x0FA) #define COMMAND (DPRAM_BASE + 0x0FC) #define COM_BUFF (DPRAM_BASE + 0x100) #define COM_BUFF_SIZE 0x20 @@ -332,8 +331,6 @@ enum av7110_command_type { /* firmware status area */ #define STATUS_BASE (DPRAM_BASE + 0x1FC0) -#define STATUS_SCR (STATUS_BASE + 0x00) -#define STATUS_MODES (STATUS_BASE + 0x04) #define STATUS_LOOPS (STATUS_BASE + 0x08) #define STATUS_MPEG_WIDTH (STATUS_BASE + 0x0C) diff --git a/linux/drivers/media/dvb/ttpci/budget-ci.c b/linux/drivers/media/dvb/ttpci/budget-ci.c index 19ce91db9..c254ff242 100644 --- a/linux/drivers/media/dvb/ttpci/budget-ci.c +++ b/linux/drivers/media/dvb/ttpci/budget-ci.c @@ -237,6 +237,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) break; case 0x1010: case 0x1017: + case 0x101a: /* for the Technotrend 1500 bundled remote */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_tt_1500); diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c index c35eb53a3..90857bedc 100644 --- a/linux/drivers/media/video/cx18/cx18-cards.c +++ b/linux/drivers/media/video/cx18/cx18-cards.c @@ -27,6 +27,8 @@ #include "cx18-i2c.h" #include <media/cs5345.h> +#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM) + /********************** card configuration *******************************/ /* usual i2c tuner addresses to probe */ @@ -67,10 +69,10 @@ static const struct cx18_card cx18_card_hvr1600_esmt = { { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL, CS5345_IN_2 }, { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL, CS5345_IN_2 }, + CX18_AV_AUDIO_SERIAL, CS5345_IN_3 }, }, .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL, 0 }, + CX18_AV_AUDIO_SERIAL, CS5345_IN_4 }, .ddr = { /* ESMT M13S128324A-5B memory */ .chip_config = 0x003, @@ -82,6 +84,11 @@ static const struct cx18_card cx18_card_hvr1600_esmt = { }, .gpio_init.initial_value = 0x3001, .gpio_init.direction = 0x3001, + .gpio_i2c_slave_reset = { + .active_lo_mask = 0x3001, + .msecs_asserted = 10, + .msecs_recovery = 40, + }, .i2c = &cx18_i2c_std, }; @@ -107,10 +114,10 @@ static const struct cx18_card cx18_card_hvr1600_samsung = { { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL, CS5345_IN_2 }, { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL, CS5345_IN_2 }, + CX18_AV_AUDIO_SERIAL, CS5345_IN_3 }, }, .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL, 0 }, + CX18_AV_AUDIO_SERIAL, CS5345_IN_4 }, .ddr = { /* Samsung K4D263238G-VC33 memory */ .chip_config = 0x003, @@ -122,6 +129,11 @@ static const struct cx18_card cx18_card_hvr1600_samsung = { }, .gpio_init.initial_value = 0x3001, .gpio_init.direction = 0x3001, + .gpio_i2c_slave_reset = { + .active_lo_mask = 0x3001, + .msecs_asserted = 10, + .msecs_recovery = 40, + }, .i2c = &cx18_i2c_std, }; @@ -184,23 +196,26 @@ 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 = "Not yet supported!\n", - .v4l2_capabilities = 0, + .comment = "Some Composite and S-Video inputs are currently working.\n", + .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_all = CX18_HW_TUNER, .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, + { 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 }, + { CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 }, }, .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO8, 0 }, - { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL, 0 }, + { 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 }, }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL, 0 }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL, 0 }, .tuners = { /* XC3028 tuner */ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, @@ -219,11 +234,64 @@ static const struct cx18_card cx18_card_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_AUDIO_SERIAL, 1 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL, 0 }, + { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL, 0 }, + }, + .tuners = { + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + }, + .ddr = { + /* MT 46V16M16 memory */ + .chip_config = 0x50306, + .refresh = 0x753, + .timing1 = 0x33220953, + .timing2 = 0x09, + .tune_lane = 0, + .initial_emrs = 0, + }, + .gpio_init.initial_value = 0x02, + .gpio_init.direction = 0x02, + .gpio_audio_input = { .mask = 0x02, .tuner = 0x02, .linein = 0x00 }, + .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/linux/drivers/media/video/cx18/cx18-cards.h b/linux/drivers/media/video/cx18/cx18-cards.h index 3c2c0b929..26ac41de2 100644 --- a/linux/drivers/media/video/cx18/cx18-cards.h +++ b/linux/drivers/media/video/cx18/cx18-cards.h @@ -78,6 +78,20 @@ struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */ u32 initial_value; }; +struct cx18_gpio_i2c_slave_reset { + u32 active_lo_mask; /* GPIO outputs that reset i2c chips when low */ + 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 */ +}; + +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 { v4l2_std_id std; /* standard for which the tuner is suitable */ int tuner; /* tuner ID (from tuner.h) */ @@ -114,7 +128,9 @@ struct cx18_card { /* GPIO card-specific settings */ u8 xceive_pin; /* XCeive tuner GPIO reset pin */ - struct cx18_gpio_init gpio_init; + 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/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c index 87cf41021..6eae75f4e 100644 --- a/linux/drivers/media/video/cx18/cx18-controls.c +++ b/linux/drivers/media/video/cx18/cx18-controls.c @@ -51,8 +51,9 @@ 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); @@ -91,19 +92,28 @@ 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; + CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); qctrl.id = qmenu->id; - cx18_queryctrl(cx, &qctrl); + cx18_queryctrl(file, fh, &qctrl); return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); } -static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +int cx18_s_ctrl(struct file *file, void *fh, struct v4l2_control *vctrl) { + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; s32 v = vctrl->value; + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; + CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); switch (vctrl->id) { @@ -129,8 +139,10 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) return 0; } -static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +int cx18_g_ctrl(struct file *file, void *fh, struct v4l2_control *vctrl) { + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); switch (vctrl->id) { @@ -194,113 +206,100 @@ 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(file, fh, &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; + } + CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); + 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(file, fh, &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; } + 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), + 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; - } - 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; - } - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; - - 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 (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); + } + 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; +} - default: - return -EINVAL; - } - return 0; +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), + c, VIDIOC_TRY_EXT_CTRLS); + return -EINVAL; } diff --git a/linux/drivers/media/video/cx18/cx18-controls.h b/linux/drivers/media/video/cx18/cx18-controls.h index 6e985cf42..81b8996e5 100644 --- a/linux/drivers/media/video/cx18/cx18-controls.h +++ b/linux/drivers/media/video/cx18/cx18-controls.h @@ -21,4 +21,11 @@ * 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_ctrl(struct file *file, void *fh, struct v4l2_control *a); +int cx18_s_ctrl(struct file *file, void *fh, struct v4l2_control *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/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index d9178843e..71bb04ab9 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/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"); @@ -435,7 +436,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 = 0; init_waitqueue_head(&cx->cap_w); init_waitqueue_head(&cx->mb_apu_waitq); init_waitqueue_head(&cx->mb_cpu_waitq); @@ -818,6 +819,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 +873,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/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index 576358873..e4f1accd2 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -77,7 +77,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 @@ -96,6 +97,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 =========== */ diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c index c9744173f..cae38985b 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.c +++ b/linux/drivers/media/video/cx18/cx18-dvb.c @@ -69,11 +69,21 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) struct dvb_demux *demux = feed->demux; struct cx18_stream *stream = (struct cx18_stream *) demux->priv; struct cx18 *cx = stream->cx; - int ret = -EINVAL; + int ret; u32 v; CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n", feed->pid, feed->index); + + mutex_lock(&cx->serialize_lock); + ret = cx18_init_on_first_open(cx); + mutex_unlock(&cx->serialize_lock); + if (ret) { + CX18_ERR("Failed to initialize firmware starting DVB feed\n"); + return ret; + } + ret = -EINVAL; + switch (cx->card->type) { case CX18_CARD_HVR_1600_ESMT: case CX18_CARD_HVR_1600_SAMSUNG: @@ -101,6 +111,11 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) if (stream->dvb.feeding++ == 0) { CX18_DEBUG_INFO("Starting Transport DMA\n"); ret = cx18_start_v4l2_encode_stream(stream); + if (ret < 0) { + CX18_DEBUG_INFO( + "Failed to start Transport DMA\n"); + stream->dvb.feeding--; + } } else ret = 0; mutex_unlock(&stream->dvb.feedlock); diff --git a/linux/drivers/media/video/cx18/cx18-gpio.c b/linux/drivers/media/video/cx18/cx18-gpio.c index ceb63653c..089bad6d8 100644 --- a/linux/drivers/media/video/cx18/cx18-gpio.c +++ b/linux/drivers/media/video/cx18/cx18-gpio.c @@ -53,10 +53,34 @@ static void gpio_write(struct cx18 *cx) write_reg(((dir & 0xffff) << 16) | (val & 0xffff), CX18_REG_GPIO_OUT1); write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2); - write_reg((dir & 0xffff0000) | ((val & 0xffff0000) >> 16), + write_reg_sync((dir & 0xffff0000) | ((val & 0xffff0000) >> 16), CX18_REG_GPIO_OUT2); } +void cx18_reset_i2c_slaves_gpio(struct cx18 *cx) +{ + const struct cx18_gpio_i2c_slave_reset *p; + + p = &cx->card->gpio_i2c_slave_reset; + + if ((p->active_lo_mask | p->active_hi_mask) == 0) + return; + + /* Assuming that the masks are a subset of the bits in gpio_dir */ + + /* Assert */ + cx->gpio_val = + (cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask); + gpio_write(cx); + schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted)); + + /* Deassert */ + cx->gpio_val = + (cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask); + gpio_write(cx); + schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery)); +} + void cx18_gpio_init(struct cx18 *cx) { cx->gpio_dir = cx->card->gpio_init.direction; @@ -98,3 +122,37 @@ int cx18_reset_tuner_gpio(void *dev, int cmd, int value) 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) { + cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask); + gpio_write(cx); + } + return 0; +} diff --git a/linux/drivers/media/video/cx18/cx18-gpio.h b/linux/drivers/media/video/cx18/cx18-gpio.h index 41bac8856..7447fed35 100644 --- a/linux/drivers/media/video/cx18/cx18-gpio.h +++ b/linux/drivers/media/video/cx18/cx18-gpio.h @@ -21,4 +21,6 @@ */ void cx18_gpio_init(struct cx18 *cx); +void cx18_reset_i2c_slaves_gpio(struct cx18 *cx); 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/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c index 30ec26a61..5b8550e0e 100644 --- a/linux/drivers/media/video/cx18/cx18-i2c.c +++ b/linux/drivers/media/video/cx18/cx18-i2c.c @@ -339,8 +339,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); @@ -378,6 +382,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 */ @@ -386,6 +392,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)); @@ -435,6 +453,8 @@ int init_cx18_i2c(struct cx18 *cx) cx18_setscl(&cx->i2c_algo_cb_data[1], 1); cx18_setsda(&cx->i2c_algo_cb_data[1], 1); + cx18_reset_i2c_slaves_gpio(cx); + return i2c_bit_add_bus(&cx->i2c_adap[0]) || i2c_bit_add_bus(&cx->i2c_adap[1]); } diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c index f008604f9..90712f4cd 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.c +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c @@ -100,6 +100,7 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) } } +#if 0 static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) { int f, l; @@ -113,6 +114,7 @@ static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) } return set != 0; } +#endif u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) { @@ -126,35 +128,6 @@ 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_cxc(struct cx18 *cx, unsigned int cmd, void *arg) { struct v4l2_register *regs = arg; @@ -174,692 +147,802 @@ 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; - - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - { - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - 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)); - - cx18_av_cmd(cx, VIDIOC_G_FMT, fmt); - vbifmt->service_set = cx18_get_service_set(vbifmt); - break; - } - default: - return -EINVAL; +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_try_or_set_fmt(struct cx18 *cx, int streamtype, - struct v4l2_format *fmt, int set_fmt) +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; + + CX18_DEBUG_IOCTL("VIDIOC_G_FMT: V4L2_BUF_TYPE_VBI_CAPTURE\n"); + + 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) { +#if 0 + /* Supported by the cx23418 but not yet implemented. */ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - u16 set; - - /* set window size */ - if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; - - 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; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) - if (cx->params.width != 720 || cx->params.height != (cx->is_50hz ? 576 : 480)) - cx->params.video_temporal_filter = 0; - else - cx->params.video_temporal_filter = 8; + + CX18_DEBUG_IOCTL("VIDIOC_G_FMT: V4L2_BUF_TYPE_SLICED_VBI_CAPTURE\n"); + + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); + + cx18_av_cmd(cx, VIDIOC_G_FMT, fmt); + vbifmt->service_set = cx18_get_service_set(vbifmt); + return 0; +#else + return -EINVAL; #endif +} - 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); - } +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; - /* 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); - } + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; - /* any else but sliced VBI capture is an error */ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; + CX18_DEBUG_IOCTL("VIDIOC_TRY_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); - /* TODO: implement sliced VBI, for now silently return 0 */ + 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) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + + CX18_DEBUG_IOCTL("VIDIOC_TRY_FMT: V4L2_BUF_TYPE_VBI_CAPTURE\n"); + + 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) +{ +#if 0 + /* Supported by the cx23418 but not yet implemented. */ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + + CX18_DEBUG_IOCTL("VIDIOC_TRY_FMT: V4L2_BUF_TYPE_SLICED_VBI_CAPTURE\n"); - /* set sliced VBI capture format */ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; if (vbifmt->service_set) cx18_expand_service_set(vbifmt, cx->is_50hz); - set = check_service_set(vbifmt, cx->is_50hz); + check_service_set(vbifmt, cx->is_50hz); vbifmt->service_set = cx18_get_service_set(vbifmt); + return 0; +#else + return -EINVAL; +#endif +} - if (!set_fmt) +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; + + CX18_DEBUG_IOCTL("VIDIOC_S_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); + + 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 (set == 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; + + CX18_DEBUG_IOCTL("VIDIOC_S_FMT: V4L2_BUF_TYPE_VBI_CAPTURE\n"); + + 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) +{ +#if 0 + /* Supported by the cx23418 but not yet implemented. */ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; + + CX18_DEBUG_IOCTL("VIDIOC_S_FMT: V4L2_BUF_TYPE_SLICED_VBI_CAPTURE\n"); + + ret = cx18_try_fmt_sliced_vbi_cap(file, fh, fmt); + if (ret) + return ret; + + if (check_service_set(vbifmt, cx->is_50hz) == 0) return -EINVAL; - if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0) + + 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)); return 0; +#else + return -EINVAL; +#endif } -static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) +static int cx18_g_chip_ident(struct file *file, void *fh, + struct v4l2_chip_ident *chip) { - 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; + CX18_DEBUG_IOCTL("VIDIOC_G_CHIP_IDENT\n"); + + 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; +} - case VIDIOC_INT_S_AUDIO_ROUTING: { - struct v4l2_routing *route = arg; +static int cx18_g_register(struct file *file, void *fh, + struct v4l2_register *reg) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - cx18_audio_set_route(cx, route); - break; - } + CX18_DEBUG_IOCTL("VIDIOC_DBG_G_REGISTER\n"); - default: - return -EINVAL; - } + 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); +} + +static int cx18_s_register(struct file *file, void *fh, + struct v4l2_register *reg) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + + CX18_DEBUG_IOCTL("VIDIOC_DBG_S_REGISTER\n"); + + 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); +} + +static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + + CX18_DEBUG_IOCTL("VIDIOC_G_PRIORITY\n"); + + *p = v4l2_prio_max(&cx->prio); return 0; } -int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg) +static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio) { - struct cx18_open_id *id = NULL; + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; - if (filp) - id = (struct cx18_open_id *)filp->private_data; + CX18_DEBUG_IOCTL("VIDIOC_S_PRIORITY\n"); - switch (cmd) { - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; + return v4l2_prio_change(&cx->prio, &id->prio, prio); +} - *p = v4l2_prio_max(&cx->prio); - break; - } +static int cx18_querycap(struct file *file, void *fh, + struct v4l2_capability *vcap) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; + CX18_DEBUG_IOCTL("VIDIOC_QUERYCAP\n"); - return v4l2_prio_change(&cx->prio, &id->prio, *prio); - } + 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; +} - case VIDIOC_QUERYCAP:{ - struct v4l2_capability *vcap = arg; +static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - 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 */ + CX18_DEBUG_IOCTL("VIDIOC_ENUMAUDIO\n"); - /* reserved.. must set to 0! */ - vcap->reserved[0] = vcap->reserved[1] = - vcap->reserved[2] = vcap->reserved[3] = 0; - break; - } + return cx18_get_audio_input(cx, vin->index, vin); +} - case VIDIOC_ENUMAUDIO:{ - struct v4l2_audio *vin = arg; +static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - return cx18_get_audio_input(cx, vin->index, vin); - } + CX18_DEBUG_IOCTL("VIDIOC_G_AUDIO\n"); - case VIDIOC_G_AUDIO:{ - struct v4l2_audio *vin = arg; + vin->index = cx->audio_input; + return cx18_get_audio_input(cx, vin->index, vin); +} - vin->index = cx->audio_input; - return cx18_get_audio_input(cx, vin->index, vin); - } +static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - case VIDIOC_S_AUDIO:{ - struct v4l2_audio *vout = arg; + CX18_DEBUG_IOCTL("VIDIOC_S_AUDIO\n"); - if (vout->index >= cx->nof_audio_inputs) - return -EINVAL; - cx->audio_input = vout->index; - cx18_audio_set_io(cx); - break; - } + if (vout->index >= cx->nof_audio_inputs) + return -EINVAL; + cx->audio_input = vout->index; + cx18_audio_set_io(cx); + return 0; +} - case VIDIOC_ENUMINPUT:{ - struct v4l2_input *vin = arg; +static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - /* set it to defaults from our table */ - return cx18_get_input(cx, vin->index, vin); - } + CX18_DEBUG_IOCTL("VIDIOC_ENUMINPUT\n"); - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: { - struct v4l2_format *fmt = arg; + /* set it to defaults from our table */ + return cx18_get_input(cx, vin->index, vin); +} - return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT); - } +static int cx18_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cropcap) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - case VIDIOC_G_FMT: { - struct v4l2_format *fmt = arg; - int type = fmt->type; + CX18_DEBUG_IOCTL("VIDIOC_CROPCAP\n"); - memset(fmt, 0, sizeof(*fmt)); - fmt->type = type; - return cx18_get_fmt(cx, id->type, fmt); - } + 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; +} - 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; - } +static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct cx18_open_id *id = fh; + struct cx18 *cx = id->cx; + int ret; - case VIDIOC_S_CROP: { - struct v4l2_crop *crop = arg; + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return cx18_av_cmd(cx, VIDIOC_S_CROP, arg); - } + CX18_DEBUG_IOCTL("VIDIOC_S_CROP\n"); - case VIDIOC_G_CROP: { - struct v4l2_crop *crop = arg; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_S_CROP, crop); +} - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return cx18_av_cmd(cx, VIDIOC_G_CROP, arg); - } +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_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; + CX18_DEBUG_IOCTL("VIDIOC_G_CROP\n"); + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_G_CROP, crop); +} + +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 } } - if (fmt->index > 1) - return -EINVAL; - *fmt = formats[fmt->index]; - fmt->type = type; + }; + + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + + CX18_DEBUG_IOCTL("VIDIOC_ENUM_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); + + if (fmt->index > 1) + return -EINVAL; + *fmt = formats[fmt->index]; + return 0; +} + +static int cx18_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + + CX18_DEBUG_IOCTL("VIDIOC_G_INPUT\n"); + + *i = cx->active_input; + return 0; +} + +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; + + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; + + CX18_DEBUG_IOCTL("VIDIOC_S_INPUT\n"); + + if (inp < 0 || inp >= cx->nof_inputs) + return -EINVAL; + + if (inp == cx->active_input) { + CX18_DEBUG_INFO("Input unchanged\n"); return 0; } - case VIDIOC_G_INPUT:{ - *(int *)arg = cx->active_input; - break; - } + CX18_DEBUG_INFO("Changing input from %d to %d\n", + cx->active_input, inp); - case VIDIOC_S_INPUT:{ - int inp = *(int *)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; - if (inp < 0 || inp >= cx->nof_inputs) - return -EINVAL; + /* 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; +} - 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); +static int cx18_g_frequency(struct file *file, void *fh, + struct v4l2_frequency *vf) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - 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; + CX18_DEBUG_IOCTL("VIDIOC_G_FREQUENCY\n"); - /* 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 (vf->tuner != 0) + return -EINVAL; - case VIDIOC_G_FREQUENCY:{ - struct v4l2_frequency *vf = arg; + cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf); + return 0; +} - if (vf->tuner != 0) - return -EINVAL; - cx18_call_i2c_clients(cx, cmd, arg); - break; - } +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; - 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; + CX18_DEBUG_IOCTL("VIDIOC_S_FREQUENCY\n"); - 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; - } + if (vf->tuner != 0) + return -EINVAL; - case VIDIOC_ENUMSTD:{ - struct v4l2_standard *vs = arg; - int idx = vs->index; + 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; +} - if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) - return -EINVAL; +static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) +{ + 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; - } + CX18_DEBUG_IOCTL("VIDIOC_G_STD\n"); - case VIDIOC_G_STD:{ - *(v4l2_std_id *) arg = cx->std; - break; - } + *std = cx->std; + return 0; +} + +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; - case VIDIOC_S_STD: { - v4l2_std_id std = *(v4l2_std_id *) arg; + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; - if ((std & V4L2_STD_ALL) == 0) - return -EINVAL; + CX18_DEBUG_IOCTL("VIDIOC_S_STD\n"); - if (std == cx->std) - break; + if ((*std & V4L2_STD_ALL) == 0) + 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; - } + if (*std == cx->std) + return 0; - 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); - 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_S_TUNER: { /* Setting tuner can only set audio mode */ - struct v4l2_tuner *vt = 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 (vt->index != 0) - return -EINVAL; +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; - cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt); - break; - } + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; - case VIDIOC_G_TUNER: { - struct v4l2_tuner *vt = arg; + CX18_DEBUG_IOCTL("VIDIOC_S_TUNER\n"); - if (vt->index != 0) - return -EINVAL; + if (vt->index != 0) + return -EINVAL; - memset(vt, 0, sizeof(*vt)); - cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt); + /* Setting tuner can only set audio mode */ + cx18_call_i2c_clients(cx, VIDIOC_S_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; - } - break; + return 0; +} + +static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + + CX18_DEBUG_IOCTL("VIDIOC_G_TUNER\n"); + + if (vt->index != 0) + return -EINVAL; + + 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_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; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - enum v4l2_buf_type type = cap->type; -#else - enum v4l2_buf_type type = VIDIOC_G_SLICED_VBI_CAP; -#endif + return 0; +} - memset(cap, 0, sizeof(*cap)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - cap->type = type; -#endif - 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; - } +static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_sliced_vbi_cap *cap) +{ +#if 0 + /* Supported by the cx23418 but not yet implemented. */ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; + int f, l; + + CX18_DEBUG_IOCTL("VIDIOC_G_SLICED_VBI_CAP\n"); + + if (cap->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; } - return -EINVAL; + return 0; } +#endif + return -EINVAL; +} +static int cx18_g_enc_index(struct file *file, void *fh, + struct v4l2_enc_idx *idx) +{ #if 0 - case VIDIOC_G_ENC_INDEX: { - struct v4l2_enc_idx *idx = arg; - int i; - - idx->entries = (cx->pgm_info_write_idx + CX18_MAX_PGM_INDEX - cx->pgm_info_read_idx) % - CX18_MAX_PGM_INDEX; - if (idx->entries > V4L2_ENC_IDX_ENTRIES) - idx->entries = V4L2_ENC_IDX_ENTRIES; - for (i = 0; i < idx->entries; i++) - idx->entry[i] = cx->pgm_info[(cx->pgm_info_read_idx + i) % CX18_MAX_PGM_INDEX]; - cx->pgm_info_read_idx = (cx->pgm_info_read_idx + idx->entries) % CX18_MAX_PGM_INDEX; - break; - } + /* Supported by the cx23418 but not yet implemented. */ + struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + int i; + + CX18_DEBUG_IOCTL("VIDIOC_G_ENC_INDEX\n"); + + idx->entries = (cx->pgm_info_write_idx + CX18_MAX_PGM_INDEX + - cx->pgm_info_read_idx) % CX18_MAX_PGM_INDEX; + if (idx->entries > V4L2_ENC_IDX_ENTRIES) + idx->entries = V4L2_ENC_IDX_ENTRIES; + for (i = 0; i < idx->entries; i++) + idx->entry[i] = cx->pgm_info [(cx->pgm_info_read_idx + i) + % CX18_MAX_PGM_INDEX]; + cx->pgm_info_read_idx = + (cx->pgm_info_read_idx + idx->entries) % CX18_MAX_PGM_INDEX; + return 0; +#else + return -EINVAL; #endif - 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); +} + +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; + + CX18_DEBUG_IOCTL("VIDIOC_ENCODER_CMD:\n"); + + 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 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 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; - } + 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; + + default: + CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); + return -EINVAL; } + return 0; +} - case VIDIOC_LOG_STATUS: - { - struct v4l2_input vidin; - struct v4l2_audio audin; - int i; +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; - CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); - if (cx->hw_flags & CX18_HW_TVEEPROM) { - struct tveeprom tv; + CX18_DEBUG_IOCTL("VIDIOC_TRY_ENCDOER_CMD:\n"); - 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); + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + break; + + case V4L2_ENC_CMD_STOP: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + break; + + case V4L2_ENC_CMD_PAUSE: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + break; + + 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; - /* 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; - } + CX18_DEBUG_IOCTL("VIDIOC_LOG_STATUS\n"); + 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); + CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n", + cx->gpio_dir, cx->gpio_val); + 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; 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: + 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; + } + case VIDIOC_INT_RESET: { + u32 val = *(u32 *)arg; + CX18_DEBUG_IOCTL("VIDIOC_INT_RESET (%#10x)\n", val); + /* No op right now */ + /* cx18_av_cmd(cx, cmd, arg) */ + /* cx18_call_i2c_clients(cx, cmd, arg) */ + break; + } + default: if (cx18_debug & CX18_DBGFLG_IOCTL) { - printk(KERN_INFO "cx18%d ioctl: ", cx->num); + printk(KERN_INFO "cx18%d ioctl: unsupported cmd: ", + cx->num); v4l_printk_ioctl(cmd); + printk("\n"); } - return cx18_control_ioctls(cx, cmd, arg); - - case 0x00005401: /* Handle isatty() calls */ return -EINVAL; - default: - return v4l_compat_translate_ioctl(inode, filp, cmd, arg, - cx18_v4l2_do_ioctl); } return 0; } @@ -872,7 +955,55 @@ int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, int res; mutex_lock(&cx->serialize_lock); - res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl); + res = video_ioctl2(inode, filp, cmd, arg); 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; + vdev->vidioc_g_register = cx18_g_register; + vdev->vidioc_s_register = cx18_s_register; + vdev->vidioc_default = cx18_default; + vdev->vidioc_queryctrl = cx18_queryctrl; + vdev->vidioc_querymenu = cx18_querymenu; + vdev->vidioc_g_ctrl = cx18_g_ctrl; + vdev->vidioc_s_ctrl = cx18_s_ctrl; + 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/linux/drivers/media/video/cx18/cx18-ioctl.h b/linux/drivers/media/video/cx18/cx18-ioctl.h index 9f4c7eb28..2222f679d 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.h +++ b/linux/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/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 7f695f36a..177cd7c3a 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/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, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) .compat_ioctl = v4l_compat_ioctl32, @@ -198,7 +199,8 @@ static int cx18_prep_dev(struct cx18 *cx, int type) 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; } diff --git a/linux/drivers/media/video/ivtv/ivtv-controls.c b/linux/drivers/media/video/ivtv/ivtv-controls.c index c7e449f63..06723bac9 100644 --- a/linux/drivers/media/video/ivtv/ivtv-controls.c +++ b/linux/drivers/media/video/ivtv/ivtv-controls.c @@ -47,8 +47,10 @@ static const u32 *ctrl_classes[] = { NULL }; -static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl) + +int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) { + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; const char *name; IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); @@ -87,17 +89,20 @@ static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl) return 0; } -static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu) +int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu) { + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; struct v4l2_queryctrl qctrl; + IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); qctrl.id = qmenu->id; - ivtv_queryctrl(itv, &qctrl); + ivtv_queryctrl(file, fh, &qctrl); return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); } -static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) +int ivtv_s_ctrl(struct file *file, void *fh, struct v4l2_control *vctrl) { + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; s32 v = vctrl->value; IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); @@ -125,8 +130,10 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) return 0; } -static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) +int ivtv_g_ctrl(struct file *file, void *fh, struct v4l2_control *vctrl) { + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); switch (vctrl->id) { @@ -191,119 +198,96 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm return 0; } -int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) +int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) { + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; struct v4l2_control ctrl; - switch (cmd) { - case VIDIOC_QUERYMENU: - IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); - return ivtv_querymenu(itv, arg); - - case VIDIOC_QUERYCTRL: - return ivtv_queryctrl(itv, arg); - - case VIDIOC_S_CTRL: - return ivtv_s_ctrl(itv, arg); - - case VIDIOC_G_CTRL: - return ivtv_g_ctrl(itv, 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 = ivtv_s_ctrl(itv, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } - } - return err; - } - IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - static u32 freqs[3] = { 44100, 48000, 32000 }; - struct cx2341x_mpeg_params p = itv->params; - int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd); - unsigned idx; - - if (err) - return err; - - if (p.video_encoding != itv->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 = itv->params.width / (is_mpeg1 ? 2 : 1); - fmt.fmt.pix.height = itv->params.height; - itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt); - } - err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); - if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) { - err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_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 = ivtv_g_ctrl(file, fh, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; } - itv->params = p; - itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; - idx = p.audio_properties & 0x03; - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (idx < sizeof(freqs)) - ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]); - return err; } - return -EINVAL; + return err; } + IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&itv->params, 0, c, VIDIOC_G_EXT_CTRLS); + return -EINVAL; +} - 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 = ivtv_g_ctrl(itv, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } +int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_control ctrl; + + 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 = ivtv_s_ctrl(file, fh, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; } - return err; } - IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd); - return -EINVAL; + return err; } + IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + static u32 freqs[3] = { 44100, 48000, 32000 }; + struct cx2341x_mpeg_params p = itv->params; + int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), c, VIDIOC_S_EXT_CTRLS); + unsigned idx; + + if (err) + return err; - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; + if (p.video_encoding != itv->params.video_encoding) { + int is_mpeg1 = p.video_encoding == + V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_format fmt; - IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd); - return -EINVAL; + /* fix videodecoder resolution */ + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); + fmt.fmt.pix.height = itv->params.height; + itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt); + } + err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); + if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) + err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt); + itv->params = p; + itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; + idx = p.audio_properties & 0x03; + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (idx < sizeof(freqs)) + ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]); + return err; } + return -EINVAL; +} - default: - return -EINVAL; - } - return 0; +int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), c, VIDIOC_TRY_EXT_CTRLS); + return -EINVAL; } diff --git a/linux/drivers/media/video/ivtv/ivtv-controls.h b/linux/drivers/media/video/ivtv/ivtv-controls.h index bb8a6a5ed..304204be6 100644 --- a/linux/drivers/media/video/ivtv/ivtv-controls.h +++ b/linux/drivers/media/video/ivtv/ivtv-controls.h @@ -21,6 +21,12 @@ #ifndef IVTV_CONTROLS_H #define IVTV_CONTROLS_H -int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg); +int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); +int ivtv_g_ctrl(struct file *file, void *fh, struct v4l2_control *a); +int ivtv_s_ctrl(struct file *file, void *fh, struct v4l2_control *a); +int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); +int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); +int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); +int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a); #endif diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c index 094f5524f..284610c3c 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.c +++ b/linux/drivers/media/video/ivtv/ivtv-driver.c @@ -1266,9 +1266,13 @@ err: int ivtv_init_on_first_open(struct ivtv *itv) { struct v4l2_frequency vf; + /* Needed to call ioctls later */ + struct ivtv_open_id fh; int fw_retry_count = 3; int video_input; + fh.itv = itv; + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) return -ENXIO; @@ -1316,18 +1320,18 @@ int ivtv_init_on_first_open(struct ivtv *itv) video_input = itv->active_input; itv->active_input++; /* Force update of input */ - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); + ivtv_s_input(NULL, &fh, video_input); /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code in one place. */ itv->std++; /* Force full standard initialization */ itv->std_out = itv->std; - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); + ivtv_s_frequency(NULL, &fh, &vf); if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { ivtv_init_mpeg_decoder(itv); } - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); + ivtv_s_std(NULL, &fh, &itv->tuner_std); /* On a cx23416 this seems to be able to enable DMA to the chip? */ if (!itv->has_cx23415) diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index db813e071..7ec5c99f9 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -582,6 +582,19 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c ivtv_queue_init(&q); set_bit(IVTV_F_S_APPL_IO, &s->s_flags); + /* Start decoder (returns 0 if already started) */ + mutex_lock(&itv->serialize_lock); + rc = ivtv_start_decoding(id, itv->speed); + mutex_unlock(&itv->serialize_lock); + if (rc) { + IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); + + /* failure, clean up */ + clear_bit(IVTV_F_S_STREAMING, &s->s_flags); + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + return rc; + } + retry: /* If possible, just DMA the entire frame - Check the data transfer size since we may get here before the stream has been fully set-up */ @@ -664,18 +677,6 @@ retry: ivtv_enqueue(s, buf, &s->q_full); } - /* Start decoder (returns 0 if already started) */ - mutex_lock(&itv->serialize_lock); - rc = ivtv_start_decoding(id, itv->speed); - mutex_unlock(&itv->serialize_lock); - if (rc) { - IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); - - /* failure, clean up */ - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return rc; - } if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { if (s->q_full.length >= itv->dma_data_req_size) { int got_sig; diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index 7101a0ea5..aa222056d 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -128,37 +128,6 @@ u16 ivtv_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 ivtv_std_60hz = -{ - .frameperiod = {.numerator = 1001, .denominator = 30000}, - .framelines = 525, -}; - -static const struct v4l2_standard ivtv_std_50hz = -{ - .frameperiod = {.numerator = 1, .denominator = 25}, - .framelines = 625, -}; - void ivtv_set_osd_alpha(struct ivtv *itv) { ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, @@ -373,1057 +342,1182 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) return 0; } -static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt) +static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) { - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - fmt->fmt.pix.width = itv->main_rect.width; - fmt->fmt.pix.height = itv->main_rect.height; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { - case IVTV_YUV_MODE_INTERLACED: - fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? - V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; - break; - case IVTV_YUV_MODE_PROGRESSIVE: - fmt->fmt.pix.field = V4L2_FIELD_NONE; - break; - default: - fmt->fmt.pix.field = V4L2_FIELD_ANY; - break; - } - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; - fmt->fmt.pix.bytesperline = 720; - fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w; - fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h; - /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ - fmt->fmt.pix.sizeimage = - 1080 * ((fmt->fmt.pix.height + 31) & ~31); - } else if (streamtype == IVTV_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; + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - fmt->fmt.pix.width = itv->params.width; - fmt->fmt.pix.height = itv->params.height; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (streamtype == IVTV_ENC_STREAM_TYPE_YUV || - streamtype == IVTV_DEC_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; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) + return -EINVAL; + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + if (itv->is_60hz) { + vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; + } else { + vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; + vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; + } + vbifmt->service_set = ivtv_get_service_set(vbifmt); + return 0; +} - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - fmt->fmt.win.chromakey = itv->osd_chroma_key; - fmt->fmt.win.global_alpha = itv->osd_global_alpha; - break; +static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + pixfmt->width = itv->params.width; + pixfmt->height = itv->params.height; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + pixfmt->priv = 0; + if (id->type == IVTV_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; +} - case V4L2_BUF_TYPE_VBI_CAPTURE: - fmt->fmt.vbi.sampling_rate = 27000000; - fmt->fmt.vbi.offset = 248; - fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4; - fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - fmt->fmt.vbi.start[0] = itv->vbi.start[0]; - fmt->fmt.vbi.start[1] = itv->vbi.start[1]; - fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count; - break; +static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; + + vbifmt->sampling_rate = 27000000; + vbifmt->offset = 248; + vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4; + vbifmt->sample_format = V4L2_PIX_FMT_GREY; + vbifmt->start[0] = itv->vbi.start[0]; + vbifmt->start[1] = itv->vbi.start[1]; + vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count; + vbifmt->flags = 0; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + return 0; +} - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - { - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; +static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) - return -EINVAL; - 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)); - if (itv->is_60hz) { - vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } else { - vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; - vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; - } - vbifmt->service_set = ivtv_get_service_set(vbifmt); - break; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + + if (id->type == IVTV_DEC_STREAM_TYPE_VBI) { + vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : + V4L2_SLICED_VBI_525; + ivtv_expand_service_set(vbifmt, itv->is_50hz); + return 0; } - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - { - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + itv->video_dec_func(itv, VIDIOC_G_FMT, fmt); + vbifmt->service_set = ivtv_get_service_set(vbifmt); + return 0; +} - 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 ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { - vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : - V4L2_SLICED_VBI_525; - ivtv_expand_service_set(vbifmt, itv->is_50hz); + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + pixfmt->width = itv->main_rect.width; + pixfmt->height = itv->main_rect.height; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + pixfmt->priv = 0; + if (id->type == IVTV_DEC_STREAM_TYPE_YUV) { + switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { + case IVTV_YUV_MODE_INTERLACED: + pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? + V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; + break; + case IVTV_YUV_MODE_PROGRESSIVE: + pixfmt->field = V4L2_FIELD_NONE; + break; + default: + pixfmt->field = V4L2_FIELD_ANY; break; } - - itv->video_dec_func(itv, VIDIOC_G_FMT, fmt); - vbifmt->service_set = ivtv_get_service_set(vbifmt); - break; + pixfmt->pixelformat = V4L2_PIX_FMT_HM12; + pixfmt->bytesperline = 720; + pixfmt->width = itv->yuv_info.v4l2_src_w; + pixfmt->height = itv->yuv_info.v4l2_src_h; + /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ + pixfmt->sizeimage = + 1080 * ((pixfmt->height + 31) & ~31); + } else { + pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; + pixfmt->sizeimage = 128 * 1024; + pixfmt->bytesperline = 0; } - case V4L2_BUF_TYPE_VBI_OUTPUT: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - default: + return 0; +} + +static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_window *winfmt = &fmt->fmt.win; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; - } + winfmt->chromakey = itv->osd_chroma_key; + winfmt->global_alpha = itv->osd_global_alpha; + winfmt->field = V4L2_FIELD_INTERLACED; + winfmt->clips = NULL; + winfmt->clipcount = 0; + winfmt->bitmap = NULL; + winfmt->w.top = winfmt->w.left = 0; + winfmt->w.width = itv->osd_rect.width; + winfmt->w.height = itv->osd_rect.height; return 0; } -static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, - struct v4l2_format *fmt, int set_fmt) +static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); +} + +static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + + w = min(w, 720); + w = max(w, 1); + h = min(h, itv->is_50hz ? 576 : 480); + h = max(h, 2); + ivtv_g_fmt_vid_cap(file, fh, fmt); + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + return 0; +} + +static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + return ivtv_g_fmt_vbi_cap(file, fh, fmt); +} + +static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct yuv_playback_info *yi = &itv->yuv_info; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - u16 set; + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - struct v4l2_rect r; - int field; + if (id->type == IVTV_DEC_STREAM_TYPE_VBI) + return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - field = fmt->fmt.pix.field; - r.top = 0; - r.left = 0; - r.width = fmt->fmt.pix.width; - r.height = fmt->fmt.pix.height; - ivtv_get_fmt(itv, streamtype, fmt); - fmt->fmt.pix.width = r.width; - fmt->fmt.pix.height = r.height; - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - fmt->fmt.pix.field = field; - if (fmt->fmt.pix.width < 2) - fmt->fmt.pix.width = 2; - if (fmt->fmt.pix.width > 720) - fmt->fmt.pix.width = 720; - if (fmt->fmt.pix.height < 2) - fmt->fmt.pix.height = 2; - if (fmt->fmt.pix.height > 576) - fmt->fmt.pix.height = 576; - } - if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - /* Return now if we already have some frame data */ - if (yi->stream_size) - return -EBUSY; + /* set sliced VBI capture format */ + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; - yi->v4l2_src_w = r.width; - yi->v4l2_src_h = r.height; + if (vbifmt->service_set) + ivtv_expand_service_set(vbifmt, itv->is_50hz); + check_service_set(vbifmt, itv->is_50hz); + vbifmt->service_set = ivtv_get_service_set(vbifmt); + return 0; +} - switch (field) { - case V4L2_FIELD_NONE: - yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; - break; - case V4L2_FIELD_ANY: - yi->lace_mode = IVTV_YUV_MODE_AUTO; - break; - case V4L2_FIELD_INTERLACED_BT: - yi->lace_mode = - IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; - break; - case V4L2_FIELD_INTERLACED_TB: - default: - yi->lace_mode = IVTV_YUV_MODE_INTERLACED; - break; - } - yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; +static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh; + s32 w, h; + int field; + int ret; - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - itv->dma_data_req_size = - 1080 * ((yi->v4l2_src_h + 31) & ~31); + w = fmt->fmt.pix.width; + h = fmt->fmt.pix.height; + field = fmt->fmt.pix.field; + ret = ivtv_g_fmt_vid_out(file, fh, fmt); + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + if (!ret && id->type == IVTV_DEC_STREAM_TYPE_YUV) { + fmt->fmt.pix.field = field; + if (fmt->fmt.pix.width < 2) + fmt->fmt.pix.width = 2; + if (fmt->fmt.pix.width > 720) + fmt->fmt.pix.width = 720; + if (fmt->fmt.pix.height < 2) + fmt->fmt.pix.height = 2; + if (fmt->fmt.pix.height > 576) + fmt->fmt.pix.height = 576; + } + return ret; +} - /* Force update of yuv registers */ - yi->yuv_forced_update = 1; - return 0; - } - return 0; - } +static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + u32 chromakey = fmt->fmt.win.chromakey; + u8 global_alpha = fmt->fmt.win.global_alpha; - if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) { - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - if (set_fmt) { - itv->osd_chroma_key = fmt->fmt.win.chromakey; - itv->osd_global_alpha = fmt->fmt.win.global_alpha; - ivtv_set_osd_alpha(itv); - } - return 0; - } + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + ivtv_g_fmt_vid_out_overlay(file, fh, fmt); + fmt->fmt.win.chromakey = chromakey; + fmt->fmt.win.global_alpha = global_alpha; + return 0; +} - /* set window size */ - if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - struct cx2341x_mpeg_params *p = &itv->params; - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; - - if (w > 720) w = 720; - else if (w < 1) w = 1; - if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480); - else if (h < 2) h = 2; - ivtv_get_fmt(itv, streamtype, fmt); - fmt->fmt.pix.width = w; - fmt->fmt.pix.height = h; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) - if (p->width != 720 || p->height != (itv->is_50hz ? 576 : 480)) - p->video_temporal_filter = 0; - else - p->video_temporal_filter = 8; -#endif +static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); +} - if (!set_fmt || (p->width == w && p->height == h)) - return 0; - if (atomic_read(&itv->capturing) > 0) - return -EBUSY; +static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct cx2341x_mpeg_params *p = &itv->params; + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); - p->width = w; - p->height = h; - if (w != 720 || h != (itv->is_50hz ? 576 : 480)) - p->video_temporal_filter = 0; - else - p->video_temporal_filter = 8; - if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) - fmt->fmt.pix.width /= 2; - itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); - return ivtv_get_fmt(itv, streamtype, fmt); - } + if (ret) + return ret; - /* set raw VBI format */ - if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (set_fmt && atomic_read(&itv->capturing) > 0) { - return -EBUSY; - } - if (set_fmt) { - itv->vbi.sliced_in->service_set = 0; - itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); - } - return ivtv_get_fmt(itv, streamtype, fmt); - } + if (p->width == w && p->height == h) + return 0; - /* set sliced VBI output - In principle the user could request that only certain - VBI types are output and that the others are ignored. - I.e., suppress CC in the even fields or only output - WSS and no VPS. Currently though there is no choice. */ - if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) - return ivtv_get_fmt(itv, streamtype, fmt); + if (atomic_read(&itv->capturing) > 0) + return -EBUSY; - /* any else but sliced VBI capture is an error */ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; + p->width = w; + p->height = h; + if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + fmt->fmt.pix.width /= 2; + itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); + return ivtv_g_fmt_vid_cap(file, fh, fmt); +} - if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) - return ivtv_get_fmt(itv, streamtype, fmt); +static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - /* set sliced VBI capture format */ - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); + itv->vbi.sliced_in->service_set = 0; + itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); + return ivtv_g_fmt_vbi_cap(file, fh, fmt); +} - if (vbifmt->service_set) - ivtv_expand_service_set(vbifmt, itv->is_50hz); - set = check_service_set(vbifmt, itv->is_50hz); - vbifmt->service_set = ivtv_get_service_set(vbifmt); +static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt); - if (!set_fmt) - return 0; - if (set == 0) + if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI) + return ret; + + if (check_service_set(vbifmt, itv->is_50hz) == 0) return -EINVAL; - if (atomic_read(&itv->capturing) > 0) { + if (atomic_read(&itv->capturing) > 0) return -EBUSY; - } itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in)); return 0; } -static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) +static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; + struct ivtv_open_id *id = fh; struct ivtv *itv = id->itv; - struct v4l2_register *reg = arg; + struct yuv_playback_info *yi = &itv->yuv_info; + int ret = ivtv_try_fmt_vid_out(file, fh, fmt); - 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 ivtv_itvc(itv, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); - return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); - - case VIDIOC_DBG_S_REGISTER: - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return ivtv_itvc(itv, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); - return ivtv_call_i2c_client(itv, 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)) - chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; - return 0; - } - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) - return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); - return -EINVAL; - } + if (ret) + return ret; - case VIDIOC_INT_S_AUDIO_ROUTING: { - struct v4l2_routing *route = arg; + if (id->type != IVTV_DEC_STREAM_TYPE_YUV) + return 0; - ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); - break; - } + /* Return now if we already have some frame data */ + if (yi->stream_size) + return -EBUSY; - case VIDIOC_INT_RESET: { - u32 val = *(u32 *)arg; + yi->v4l2_src_w = fmt->fmt.pix.width; + yi->v4l2_src_h = fmt->fmt.pix.height; - if ((val == 0 && itv->options.newi2c) || (val & 0x01)) { - ivtv_reset_ir_gpio(itv); - } - if (val & 0x02) { - itv->video_dec_func(itv, cmd, NULL); - } + switch (fmt->fmt.pix.field) { + case V4L2_FIELD_NONE: + yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; break; - } - + case V4L2_FIELD_ANY: + yi->lace_mode = IVTV_YUV_MODE_AUTO; + break; + case V4L2_FIELD_INTERLACED_BT: + yi->lace_mode = + IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; + break; + case V4L2_FIELD_INTERLACED_TB: default: - return -EINVAL; + yi->lace_mode = IVTV_YUV_MODE_INTERLACED; + break; } + yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; + + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + itv->dma_data_req_size = + 1080 * ((yi->v4l2_src_h + 31) & ~31); + + /* Force update of yuv registers */ + yi->yuv_forced_update = 1; return 0; } -int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg) +static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = NULL; - struct yuv_playback_info *yi = &itv->yuv_info; - u32 data[CX2341X_MBOX_MAX_DATA]; - int streamtype = 0; + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt); - if (filp) { - id = (struct ivtv_open_id *)filp->private_data; - streamtype = id->type; + if (ret == 0) { + itv->osd_chroma_key = fmt->fmt.win.chromakey; + itv->osd_global_alpha = fmt->fmt.win.global_alpha; + ivtv_set_osd_alpha(itv); } + return ret; +} - switch (cmd) { - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; +static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_chip_ident *chip) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - *p = v4l2_prio_max(&itv->prio); - break; + 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 = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; + return 0; } + if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return ivtv_i2c_id(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip); + if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR) + return ivtv_call_i2c_client(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip); + return -EINVAL; +} - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; +static int ivtv_g_register(struct file *file, void *fh, struct v4l2_register *reg) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - return v4l2_prio_change(&itv->prio, &id->prio, *prio); - } + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg); + return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg); +} - case VIDIOC_QUERYCAP:{ - struct v4l2_capability *vcap = arg; +static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *reg) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - memset(vcap, 0, sizeof(*vcap)); - strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); - strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); - strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info)); - vcap->version = IVTV_DRIVER_VERSION; /* version */ - vcap->capabilities = itv->v4l2_cap; /* capabilities */ + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg); + return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg); +} - /* reserved.. must set to 0! */ - vcap->reserved[0] = vcap->reserved[1] = - vcap->reserved[2] = vcap->reserved[3] = 0; - break; - } +static int ivtv_g_priority(struct file *file, void *fh, enum v4l2_priority *p) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_ENUMAUDIO:{ - struct v4l2_audio *vin = arg; + *p = v4l2_prio_max(&itv->prio); - return ivtv_get_audio_input(itv, vin->index, vin); - } + return 0; +} - case VIDIOC_G_AUDIO:{ - struct v4l2_audio *vin = arg; +static int ivtv_s_priority(struct file *file, void *fh, enum v4l2_priority prio) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - vin->index = itv->audio_input; - return ivtv_get_audio_input(itv, vin->index, vin); - } + return v4l2_prio_change(&itv->prio, &id->prio, prio); +} - case VIDIOC_S_AUDIO:{ - struct v4l2_audio *vout = arg; +static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - if (vout->index >= itv->nof_audio_inputs) - return -EINVAL; - itv->audio_input = vout->index; - ivtv_audio_set_io(itv); - break; - } + strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); + strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info)); + vcap->version = IVTV_DRIVER_VERSION; /* version */ + vcap->capabilities = itv->v4l2_cap; /* capabilities */ + return 0; +} - case VIDIOC_ENUMAUDOUT:{ - struct v4l2_audioout *vin = arg; +static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - /* set it to defaults from our table */ - return ivtv_get_audio_output(itv, vin->index, vin); - } + return ivtv_get_audio_input(itv, vin->index, vin); +} - case VIDIOC_G_AUDOUT:{ - struct v4l2_audioout *vin = arg; +static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - vin->index = 0; - return ivtv_get_audio_output(itv, vin->index, vin); - } + vin->index = itv->audio_input; + return ivtv_get_audio_input(itv, vin->index, vin); +} - case VIDIOC_S_AUDOUT:{ - struct v4l2_audioout *vout = arg; +static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - return ivtv_get_audio_output(itv, vout->index, vout); - } + if (vout->index >= itv->nof_audio_inputs) + return -EINVAL; - case VIDIOC_ENUMINPUT:{ - struct v4l2_input *vin = arg; + itv->audio_input = vout->index; + ivtv_audio_set_io(itv); - /* set it to defaults from our table */ - return ivtv_get_input(itv, vin->index, vin); - } + return 0; +} - case VIDIOC_ENUMOUTPUT:{ - struct v4l2_output *vout = arg; +static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - return ivtv_get_output(itv, vout->index, vout); - } + /* set it to defaults from our table */ + return ivtv_get_audio_output(itv, vin->index, vin); +} - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: { - struct v4l2_format *fmt = arg; +static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT); - } + vin->index = 0; + return ivtv_get_audio_output(itv, vin->index, vin); +} - case VIDIOC_G_FMT: { - struct v4l2_format *fmt = arg; - int type = fmt->type; +static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - memset(fmt, 0, sizeof(*fmt)); - fmt->type = type; - return ivtv_get_fmt(itv, id->type, fmt); - } + return ivtv_get_audio_output(itv, vout->index, vout); +} - case VIDIOC_CROPCAP: { - struct v4l2_cropcap *cropcap = arg; +static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - cropcap->bounds.height = itv->is_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; - } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - if (yi->track_osd) { - cropcap->bounds.width = yi->osd_full_w; - cropcap->bounds.height = yi->osd_full_h; - } else { - cropcap->bounds.width = 720; - cropcap->bounds.height = - itv->is_out_50hz ? 576 : 480; - } - cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; + /* set it to defaults from our table */ + return ivtv_get_input(itv, vin->index, vin); +} + +static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + return ivtv_get_output(itv, vout->index, vout); +} + +static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int streamtype; + + streamtype = id->type; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + cropcap->bounds.height = itv->is_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; + } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + if (yi->track_osd) { + cropcap->bounds.width = yi->osd_full_w; + cropcap->bounds.height = yi->osd_full_h; } else { - cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; + cropcap->bounds.width = 720; + cropcap->bounds.height = + itv->is_out_50hz ? 576 : 480; } - cropcap->defrect = cropcap->bounds; - return 0; + cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; + } else { + cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; } + cropcap->defrect = cropcap->bounds; + return 0; +} + +static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int streamtype; - case VIDIOC_S_CROP: { - struct v4l2_crop *crop = arg; + streamtype = id->type; - if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - yi->main_rect = crop->c; + if (ivtv_debug & IVTV_DBGFLG_IOCTL) { + printk(KERN_INFO "ivtv%d ioctl: ", itv->num); + /* Should be replaced */ + /* v4l_printk_ioctl(VIDIOC_S_CROP); */ + } + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + yi->main_rect = crop->c; + return 0; + } else { + if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { + itv->main_rect = crop->c; return 0; - } else { - if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { - itv->main_rect = crop->c; - return 0; - } } - return -EINVAL; } return -EINVAL; } + return -EINVAL; +} + +static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int streamtype; - case VIDIOC_G_CROP: { - struct v4l2_crop *crop = arg; + streamtype = id->type; - if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) - crop->c = yi->main_rect; - else - crop->c = itv->main_rect; - return 0; + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) + crop->c = yi->main_rect; + else + crop->c = itv->main_rect; + return 0; + } + return -EINVAL; +} + +static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) +{ + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, + { 0, 0, 0, 0 } + }, + { 1, 0, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, + { 0, 0, 0, 0 } } + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 1) return -EINVAL; - } - case VIDIOC_ENUM_FMT: { - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "HM12 (YUV 4:2:0)", 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; + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; +} - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - break; - default: - return -EINVAL; +static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, + { 0, 0, 0, 0 } + }, + { 1, 0, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, + { 0, 0, 0, 0 } } - if (fmt->index > 1) - return -EINVAL; - *fmt = formats[fmt->index]; - fmt->type = type; + }; + enum v4l2_buf_type type = fmt->type; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + + if (fmt->index > 1) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + + return 0; +} + +static int ivtv_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + *i = itv->active_input; + + return 0; +} + +int ivtv_s_input(struct file *file, void *fh, unsigned int inp) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + if (inp < 0 || inp >= itv->nof_inputs) + return -EINVAL; + + if (inp == itv->active_input) { + IVTV_DEBUG_INFO("Input unchanged\n"); return 0; } - case VIDIOC_G_INPUT:{ - *(int *)arg = itv->active_input; - break; + if (atomic_read(&itv->capturing) > 0) { + return -EBUSY; } - case VIDIOC_S_INPUT:{ - int inp = *(int *)arg; + IVTV_DEBUG_INFO("Changing input from %d to %d\n", + itv->active_input, inp); - if (inp < 0 || inp >= itv->nof_inputs) - return -EINVAL; + itv->active_input = inp; + /* Set the audio input to whatever is appropriate for the + input type. */ + itv->audio_input = itv->card->video_inputs[inp].audio_index; - if (inp == itv->active_input) { - IVTV_DEBUG_INFO("Input unchanged\n"); - break; - } - if (atomic_read(&itv->capturing) > 0) { - return -EBUSY; - } - IVTV_DEBUG_INFO("Changing input from %d to %d\n", - itv->active_input, inp); + /* prevent others from messing with the streams until + we're finished changing inputs. */ + ivtv_mute(itv); + ivtv_video_set_io(itv); + ivtv_audio_set_io(itv); + ivtv_unmute(itv); - itv->active_input = inp; - /* Set the audio input to whatever is appropriate for the - input type. */ - itv->audio_input = itv->card->video_inputs[inp].audio_index; + return 0; +} - /* prevent others from messing with the streams until - we're finished changing inputs. */ - ivtv_mute(itv); - ivtv_video_set_io(itv); - ivtv_audio_set_io(itv); - ivtv_unmute(itv); - break; - } +static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_G_OUTPUT:{ - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - *(int *)arg = itv->active_output; - break; - } + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; - case VIDIOC_S_OUTPUT:{ - int outp = *(int *)arg; - struct v4l2_routing route; + *i = itv->active_output; - if (outp >= itv->card->nof_outputs) - return -EINVAL; + return 0; +} - if (outp == itv->active_output) { - IVTV_DEBUG_INFO("Output unchanged\n"); - break; - } - IVTV_DEBUG_INFO("Changing output from %d to %d\n", - itv->active_output, outp); +static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_routing route; - itv->active_output = outp; - route.input = SAA7127_INPUT_TYPE_NORMAL; - route.output = itv->card->video_outputs[outp].video_output; - ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - break; + if (outp >= itv->card->nof_outputs) + return -EINVAL; + + if (outp == itv->active_output) { + IVTV_DEBUG_INFO("Output unchanged\n"); + return 0; } + IVTV_DEBUG_INFO("Changing output from %d to %d\n", + itv->active_output, outp); - case VIDIOC_G_FREQUENCY:{ - struct v4l2_frequency *vf = arg; + itv->active_output = outp; + route.input = SAA7127_INPUT_TYPE_NORMAL; + route.output = itv->card->video_outputs[outp].video_output; + ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - if (vf->tuner != 0) - return -EINVAL; - ivtv_call_i2c_clients(itv, cmd, arg); - break; - } + return 0; +} - case VIDIOC_S_FREQUENCY:{ - struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; +static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - if (vf.tuner != 0) - return -EINVAL; + if (vf->tuner != 0) + return -EINVAL; - ivtv_mute(itv); - IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); - ivtv_call_i2c_clients(itv, cmd, &vf); - ivtv_unmute(itv); - break; - } + ivtv_call_i2c_clients(itv, VIDIOC_G_FREQUENCY, vf); + return 0; +} - case VIDIOC_ENUMSTD:{ - struct v4l2_standard *vs = arg; - int idx = vs->index; +int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) - return -EINVAL; + if (vf->tuner != 0) + return -EINVAL; - *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? - ivtv_std_60hz : ivtv_std_50hz; - vs->index = idx; - vs->id = enum_stds[idx].std; - strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); - break; - } + ivtv_mute(itv); + IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); + ivtv_call_i2c_clients(itv, VIDIOC_S_FREQUENCY, vf); + ivtv_unmute(itv); + return 0; +} - case VIDIOC_G_STD:{ - *(v4l2_std_id *) arg = itv->std; - break; - } +static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - case VIDIOC_S_STD: { - v4l2_std_id std = *(v4l2_std_id *) arg; + *std = itv->std; + return 0; +} - if ((std & V4L2_STD_ALL) == 0) - return -EINVAL; +int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct yuv_playback_info *yi = &itv->yuv_info; - if (std == itv->std) - break; + if ((*std & V4L2_STD_ALL) == 0) + return -EINVAL; - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || - atomic_read(&itv->capturing) > 0 || - atomic_read(&itv->decoding) > 0) { - /* Switching standard would turn off the radio or mess - with already running streams, prevent that by - returning EBUSY. */ - return -EBUSY; - } + if (*std == itv->std) + return 0; - itv->std = std; - itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; - itv->params.is_50hz = itv->is_50hz = !itv->is_60hz; - itv->params.width = 720; - itv->params.height = itv->is_50hz ? 576 : 480; - itv->vbi.count = itv->is_50hz ? 18 : 12; - itv->vbi.start[0] = itv->is_50hz ? 6 : 10; - itv->vbi.start[1] = itv->is_50hz ? 318 : 273; - if (itv->hw_flags & IVTV_HW_CX25840) { - itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; - } - IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std); - - /* Tuner */ - ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - /* set display standard */ - itv->std_out = std; - itv->is_out_60hz = itv->is_60hz; - itv->is_out_50hz = itv->is_50hz; - ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out); - ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); - itv->main_rect.left = itv->main_rect.top = 0; - itv->main_rect.width = 720; - itv->main_rect.height = itv->params.height; - ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - 720, itv->main_rect.height, 0, 0); - yi->main_rect = itv->main_rect; - if (!itv->osd_info) { - yi->osd_full_w = 720; - yi->osd_full_h = itv->is_out_50hz ? 576 : 480; - } + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || + atomic_read(&itv->capturing) > 0 || + atomic_read(&itv->decoding) > 0) { + /* Switching standard would turn off the radio or mess + with already running streams, prevent that by + returning EBUSY. */ + return -EBUSY; + } + + itv->std = *std; + itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + itv->params.is_50hz = itv->is_50hz = !itv->is_60hz; + itv->params.width = 720; + itv->params.height = itv->is_50hz ? 576 : 480; + itv->vbi.count = itv->is_50hz ? 18 : 12; + itv->vbi.start[0] = itv->is_50hz ? 6 : 10; + itv->vbi.start[1] = itv->is_50hz ? 318 : 273; + + if (itv->hw_flags & IVTV_HW_CX25840) + itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; + + IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std); + + /* Tuner */ + ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); + + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + /* set display standard */ + itv->std_out = *std; + itv->is_out_60hz = itv->is_60hz; + itv->is_out_50hz = itv->is_50hz; + ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out); + ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); + itv->main_rect.left = itv->main_rect.top = 0; + itv->main_rect.width = 720; + itv->main_rect.height = itv->params.height; + ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + 720, itv->main_rect.height, 0, 0); + yi->main_rect = itv->main_rect; + if (!itv->osd_info) { + yi->osd_full_w = 720; + yi->osd_full_h = itv->is_out_50hz ? 576 : 480; } - break; } + return 0; +} - case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ - struct v4l2_tuner *vt = arg; +static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - if (vt->index != 0) - return -EINVAL; + if (vt->index != 0) + return -EINVAL; - ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt); - break; - } + ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt); - case VIDIOC_G_TUNER: { - struct v4l2_tuner *vt = arg; + return 0; +} - if (vt->index != 0) - return -EINVAL; +static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - memset(vt, 0, sizeof(*vt)); - ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); + if (vt->index != 0) + return -EINVAL; - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_RADIO; - } else { - strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_ANALOG_TV; - } - break; + ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); + + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_RADIO; + } else { + strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_ANALOG_TV; } - case VIDIOC_G_SLICED_VBI_CAP: { - struct v4l2_sliced_vbi_cap *cap = arg; - int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; - int f, l; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - enum v4l2_buf_type type = cap->type; -#else - enum v4l2_buf_type type = VIDIOC_G_SLICED_VBI_CAP; -#endif - - memset(cap, 0, sizeof(*cap)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - cap->type = type; -#endif - 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, itv->is_50hz)) { - cap->service_lines[f][l] = set; - } - } + return 0; +} + +static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; + int f, l; + + if (cap->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, itv->is_50hz)) + cap->service_lines[f][l] = set; } - return 0; } - if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { - if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) - return -EINVAL; - if (itv->is_60hz) { - cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } else { - cap->service_lines[0][23] = V4L2_SLICED_WSS_625; - cap->service_lines[0][16] = V4L2_SLICED_VPS; - } - return 0; + return 0; + } + if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { + if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) + return -EINVAL; + if (itv->is_60hz) { + cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; + } else { + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; + cap->service_lines[0][16] = V4L2_SLICED_VPS; } - return -EINVAL; + return 0; } + return -EINVAL; +} - case VIDIOC_G_ENC_INDEX: { - struct v4l2_enc_idx *idx = arg; - struct v4l2_enc_idx_entry *e = idx->entry; - int entries; - int i; - - entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % - IVTV_MAX_PGM_INDEX; - if (entries > V4L2_ENC_IDX_ENTRIES) - entries = V4L2_ENC_IDX_ENTRIES; - idx->entries = 0; - for (i = 0; i < entries; i++) { - *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; - if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) { - idx->entries++; - e++; - } +static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct v4l2_enc_idx_entry *e = idx->entry; + int entries; + int i; + + entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % + IVTV_MAX_PGM_INDEX; + if (entries > V4L2_ENC_IDX_ENTRIES) + entries = V4L2_ENC_IDX_ENTRIES; + idx->entries = 0; + for (i = 0; i < entries; i++) { + *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; + if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) { + idx->entries++; + e++; } - itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; - break; } + itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; + 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: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); - enc->flags = 0; - if (try) - return 0; - return ivtv_start_capture(id); +static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - case V4L2_ENC_CMD_STOP: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - if (try) - return 0; - ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); + + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + return ivtv_start_capture(id); + + case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); + return 0; + + case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + + if (!atomic_read(&itv->capturing)) + return -EPERM; + if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) return 0; - case V4L2_ENC_CMD_PAUSE: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); - enc->flags = 0; - if (try) - return 0; - if (!atomic_read(&itv->capturing)) - return -EPERM; - if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - return 0; - ivtv_mute(itv); - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); - break; + ivtv_mute(itv); + ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); + break; - case V4L2_ENC_CMD_RESUME: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); - enc->flags = 0; - if (try) - return 0; - if (!atomic_read(&itv->capturing)) - return -EPERM; - if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - return 0; - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); - ivtv_unmute(itv); - break; - default: - IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); - return -EINVAL; - } + case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; + + if (!atomic_read(&itv->capturing)) + return -EPERM; + + if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) + return 0; + + ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); + ivtv_unmute(itv); break; + default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); + return -EINVAL; } - case VIDIOC_G_FBUF: { - struct v4l2_framebuffer *fb = arg; - int pixfmt; - static u32 pixel_format[16] = { - V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ - V4L2_PIX_FMT_RGB565, - V4L2_PIX_FMT_RGB555, - V4L2_PIX_FMT_RGB444, - V4L2_PIX_FMT_RGB32, - 0, - 0, - 0, - V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ - V4L2_PIX_FMT_YUV565, - V4L2_PIX_FMT_YUV555, - V4L2_PIX_FMT_YUV444, - V4L2_PIX_FMT_YUV32, - 0, - 0, - 0, - }; + return 0; +} - memset(fb, 0, sizeof(*fb)); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; - fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | - V4L2_FBUF_CAP_GLOBAL_ALPHA; - ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); - data[0] |= (read_reg(0x2a00) >> 7) & 0x40; - pixfmt = (data[0] >> 3) & 0xf; - fb->fmt.pixelformat = pixel_format[pixfmt]; - fb->fmt.width = itv->osd_rect.width; - fb->fmt.height = itv->osd_rect.height; - fb->base = (void *)itv->osd_video_pbase; - if (itv->osd_chroma_key_state) - fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; - if (itv->osd_global_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; - pixfmt &= 7; - /* no local alpha for RGB565 or unknown formats */ - if (pixfmt == 1 || pixfmt > 4) - break; +static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + return 0; + + case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + return 0; + + case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + return 0; + + case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; + return 0; + default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); + return -EINVAL; + } +} + +static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + u32 data[CX2341X_MBOX_MAX_DATA]; + struct yuv_playback_info *yi = &itv->yuv_info; + + int pixfmt; + static u32 pixel_format[16] = { + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB555, + V4L2_PIX_FMT_RGB444, + V4L2_PIX_FMT_RGB32, + 0, + 0, + 0, + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ + V4L2_PIX_FMT_YUV565, + V4L2_PIX_FMT_YUV555, + V4L2_PIX_FMT_YUV444, + V4L2_PIX_FMT_YUV32, + 0, + 0, + 0, + }; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + + fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | + V4L2_FBUF_CAP_GLOBAL_ALPHA; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; + pixfmt = (data[0] >> 3) & 0xf; + + fb->fmt.pixelformat = pixel_format[pixfmt]; + fb->fmt.width = itv->osd_rect.width; + fb->fmt.height = itv->osd_rect.height; + fb->fmt.field = V4L2_FIELD_INTERLACED; + fb->fmt.bytesperline = fb->fmt.width; + if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8) + fb->fmt.bytesperline *= 2; + if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 || + fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32) + fb->fmt.bytesperline *= 2; + fb->base = (void *)itv->osd_video_pbase; + fb->flags = 0; + + if (itv->osd_chroma_key_state) + fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; + + if (itv->osd_global_alpha_state) + fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; + + pixfmt &= 7; + + /* no local alpha for RGB565 or unknown formats */ + if (pixfmt == 1 || pixfmt > 4) + return 0; + + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + else + fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; + + if (itv->osd_local_alpha_state) { /* 16-bit formats have inverted local alpha */ if (pixfmt == 2 || pixfmt == 3) - fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; else - fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; - if (itv->osd_local_alpha_state) { - /* 16-bit formats have inverted local alpha */ - if (pixfmt == 2 || pixfmt == 3) - fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; - else - fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; - } - if (yi->track_osd) - fb->flags |= V4L2_FBUF_FLAG_OVERLAY; - break; + fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; } + if (yi->track_osd) + fb->flags |= V4L2_FBUF_FLAG_OVERLAY; - case VIDIOC_S_FBUF: { - struct v4l2_framebuffer *fb = arg; + return 0; +} - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; - itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; - itv->osd_local_alpha_state = - (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; - itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; - ivtv_set_osd_alpha(itv); - yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; - break; - } +static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; - case VIDIOC_OVERLAY: { - int *on = arg; + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0); - break; - } + itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; + itv->osd_local_alpha_state = + (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; + itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; + ivtv_set_osd_alpha(itv); + yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; + return ivtv_g_fbuf(file, fh, fb); +} - case VIDIOC_LOG_STATUS: - { - int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; - struct v4l2_input vidin; - struct v4l2_audio audin; - int i; +static int ivtv_overlay(struct file *file, void *fh, unsigned int on) +{ + struct ivtv_open_id *id = fh; + struct ivtv *itv = id->itv; - IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); - IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); - if (itv->hw_flags & IVTV_HW_TVEEPROM) { - struct tveeprom tv; + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; - ivtv_read_eeprom(itv, &tv); - } - ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); - ivtv_get_input(itv, itv->active_input, &vidin); - ivtv_get_audio_input(itv, itv->audio_input, &audin); - IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s%s\n", audin.name, - (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); - if (has_output) { - struct v4l2_output vidout; - struct v4l2_audioout audout; - int mode = itv->output_mode; - static const char * const output_modes[5] = { - "None", - "MPEG Streaming", - "YUV Streaming", - "YUV Frames", - "Passthrough", - }; - static const char * const audio_modes[5] = { - "Stereo", - "Left", - "Right", - "Mono", - "Swapped" - }; - static const char * const alpha_mode[4] = { - "None", - "Global", - "Local", - "Global and Local" - }; - static const char * const pixel_format[16] = { - "ARGB Indexed", - "RGB 5:6:5", - "ARGB 1:5:5:5", - "ARGB 1:4:4:4", - "ARGB 8:8:8:8", - "5", - "6", - "7", - "AYUV Indexed", - "YUV 5:6:5", - "AYUV 1:5:5:5", - "AYUV 1:4:4:4", - "AYUV 8:8:8:8", - "13", - "14", - "15", - }; - - ivtv_get_output(itv, itv->active_output, &vidout); - ivtv_get_audio_output(itv, 0, &audout); - IVTV_INFO("Video Output: %s\n", vidout.name); - IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, - audio_modes[itv->audio_stereo_mode], - audio_modes[itv->audio_bilingual_mode]); - if (mode < 0 || mode > OUT_PASSTHROUGH) - mode = OUT_NONE; - IVTV_INFO("Output Mode: %s\n", output_modes[mode]); - ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); - data[0] |= (read_reg(0x2a00) >> 7) & 0x40; - IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", - data[0] & 1 ? "On" : "Off", - alpha_mode[(data[0] >> 1) & 0x3], - pixel_format[(data[0] >> 3) & 0xf]); - } - IVTV_INFO("Tuner: %s\n", - test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); - cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); - for (i = 0; i < IVTV_MAX_STREAMS; i++) { - struct ivtv_stream *s = &itv->streams[i]; - - if (s->v4l2dev == NULL || s->buffers == 0) - continue; - IVTV_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); - } - IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); - IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); - break; + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0); + + return 0; +} + +static int ivtv_log_status(struct file *file, void *fh) +{ + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + u32 data[CX2341X_MBOX_MAX_DATA]; + + int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; + struct v4l2_input vidin; + struct v4l2_audio audin; + int i; + + IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); + IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); + if (itv->hw_flags & IVTV_HW_TVEEPROM) { + struct tveeprom tv; + + ivtv_read_eeprom(itv, &tv); + } + ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); + ivtv_get_input(itv, itv->active_input, &vidin); + ivtv_get_audio_input(itv, itv->audio_input, &audin); + IVTV_INFO("Video Input: %s\n", vidin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, + (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); + if (has_output) { + struct v4l2_output vidout; + struct v4l2_audioout audout; + int mode = itv->output_mode; + static const char * const output_modes[5] = { + "None", + "MPEG Streaming", + "YUV Streaming", + "YUV Frames", + "Passthrough", + }; + static const char * const audio_modes[5] = { + "Stereo", + "Left", + "Right", + "Mono", + "Swapped" + }; + static const char * const alpha_mode[4] = { + "None", + "Global", + "Local", + "Global and Local" + }; + static const char * const pixel_format[16] = { + "ARGB Indexed", + "RGB 5:6:5", + "ARGB 1:5:5:5", + "ARGB 1:4:4:4", + "ARGB 8:8:8:8", + "5", + "6", + "7", + "AYUV Indexed", + "YUV 5:6:5", + "AYUV 1:5:5:5", + "AYUV 1:4:4:4", + "AYUV 8:8:8:8", + "13", + "14", + "15", + }; + + ivtv_get_output(itv, itv->active_output, &vidout); + ivtv_get_audio_output(itv, 0, &audout); + IVTV_INFO("Video Output: %s\n", vidout.name); + IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, + audio_modes[itv->audio_stereo_mode], + audio_modes[itv->audio_bilingual_mode]); + if (mode < 0 || mode > OUT_PASSTHROUGH) + mode = OUT_NONE; + IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; + IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", + data[0] & 1 ? "On" : "Off", + alpha_mode[(data[0] >> 1) & 0x3], + pixel_format[(data[0] >> 3) & 0xf]); } + IVTV_INFO("Tuner: %s\n", + test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); + cx2341x_log_status(&itv->params, itv->name); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); + for (i = 0; i < IVTV_MAX_STREAMS; i++) { + struct ivtv_stream *s = &itv->streams[i]; - default: - return -EINVAL; + if (s->v4l2dev == NULL || s->buffers == 0) + continue; + IVTV_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); } + + IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); + IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); + return 0; } @@ -1445,7 +1539,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) return -EINVAL; if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL) return 0; - if (ivtv_claim_stream(id, id->type)) { + if (ivtv_start_decoding(id, id->type)) { return -EBUSY; } if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) { @@ -1619,121 +1713,30 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) return 0; } -static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, void *arg) +static int ivtv_default(struct file *file, void *fh, int cmd, void *arg) { - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - int ret; + struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - /* check priority */ switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - case VIDIOC_S_FMT: - case VIDIOC_S_CROP: - case VIDIOC_S_AUDIO: - case VIDIOC_S_AUDOUT: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_S_FBUF: - case VIDIOC_OVERLAY: - ret = v4l2_prio_check(&itv->prio, &id->prio); - if (ret) - return ret; - } - - 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 (ivtv_debug & IVTV_DBGFLG_IOCTL) { - printk(KERN_INFO "ivtv%d ioctl: ", itv->num); - v4l_printk_ioctl(cmd); - printk("\n"); - } - return ivtv_debug_ioctls(filp, cmd, arg); + case VIDIOC_INT_S_AUDIO_ROUTING: { + struct v4l2_routing *route = 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_ENUMOUTPUT: - case VIDIOC_G_OUTPUT: - case VIDIOC_S_OUTPUT: - 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_ENUMAUDOUT: - case VIDIOC_S_AUDOUT: - case VIDIOC_G_AUDOUT: - case VIDIOC_G_SLICED_VBI_CAP: - case VIDIOC_LOG_STATUS: - case VIDIOC_G_ENC_INDEX: - case VIDIOC_ENCODER_CMD: - case VIDIOC_TRY_ENCODER_CMD: - case VIDIOC_G_FBUF: - case VIDIOC_S_FBUF: - case VIDIOC_OVERLAY: - if (ivtv_debug & IVTV_DBGFLG_IOCTL) { - printk(KERN_INFO "ivtv%d ioctl: ", itv->num); - v4l_printk_ioctl(cmd); - printk("\n"); - } - return ivtv_v4l2_ioctls(itv, filp, cmd, arg); + ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); + break; + } - 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 (ivtv_debug & IVTV_DBGFLG_IOCTL) { - printk(KERN_INFO "ivtv%d ioctl: ", itv->num); - v4l_printk_ioctl(cmd); - printk("\n"); - } - return ivtv_control_ioctls(itv, cmd, arg); + case VIDIOC_INT_RESET: { + u32 val = *(u32 *)arg; - case IVTV_IOC_DMA_FRAME: - case VIDEO_GET_PTS: - case VIDEO_GET_FRAME_COUNT: - case VIDEO_GET_EVENT: - case VIDEO_PLAY: - case VIDEO_STOP: - case VIDEO_FREEZE: - case VIDEO_CONTINUE: - case VIDEO_COMMAND: - case VIDEO_TRY_COMMAND: - return ivtv_decoder_ioctls(filp, cmd, arg); + if ((val == 0 && itv->options.newi2c) || (val & 0x01)) + ivtv_reset_ir_gpio(itv); + if (val & 0x02) + itv->video_dec_func(itv, cmd, NULL); + break; + } - case 0x00005401: /* Handle isatty() calls */ - return -EINVAL; default: - return v4l_compat_translate_ioctl(inode, filp, cmd, arg, - ivtv_v4l2_do_ioctl); + return -EINVAL; } return 0; } @@ -1741,7 +1744,10 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - /* Filter dvb ioctls that cannot be handled by video_usercopy */ + struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; + int ret; + + /* Filter dvb ioctls that cannot be handled by the v4l ioctl framework */ switch (cmd) { case VIDEO_SELECT_SOURCE: IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n"); @@ -1770,10 +1776,49 @@ static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct f ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); return 0; + case IVTV_IOC_DMA_FRAME: + case VIDEO_GET_PTS: + case VIDEO_GET_FRAME_COUNT: + case VIDEO_GET_EVENT: + case VIDEO_PLAY: + case VIDEO_STOP: + case VIDEO_FREEZE: + case VIDEO_CONTINUE: + case VIDEO_COMMAND: + case VIDEO_TRY_COMMAND: + return ivtv_decoder_ioctls(filp, cmd, (void *)arg); + default: break; } - return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl); + + /* check priority */ + switch (cmd) { + case VIDIOC_S_CTRL: + case VIDIOC_S_STD: + case VIDIOC_S_INPUT: + case VIDIOC_S_OUTPUT: + case VIDIOC_S_TUNER: + case VIDIOC_S_FREQUENCY: + case VIDIOC_S_FMT: + case VIDIOC_S_CROP: + case VIDIOC_S_AUDIO: + case VIDIOC_S_AUDOUT: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: + ret = v4l2_prio_check(&itv->prio, &id->prio); + if (ret) + return ret; + } + + if (ivtv_debug & IVTV_DBGFLG_IOCTL) { + printk(KERN_INFO "ivtv%d ioctl: ", itv->num); + v4l_printk_ioctl(cmd); + printk("\n"); + } + + return video_ioctl2(inode, filp, cmd, arg); } int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, @@ -1788,3 +1833,70 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, mutex_unlock(&itv->serialize_lock); return res; } + +void ivtv_set_funcs(struct video_device *vdev) +{ + vdev->vidioc_querycap = ivtv_querycap; + vdev->vidioc_g_priority = ivtv_g_priority; + vdev->vidioc_s_priority = ivtv_s_priority; + vdev->vidioc_s_audio = ivtv_s_audio; + vdev->vidioc_g_audio = ivtv_g_audio; + vdev->vidioc_enumaudio = ivtv_enumaudio; + vdev->vidioc_s_audout = ivtv_s_audout; + vdev->vidioc_g_audout = ivtv_g_audout; + vdev->vidioc_enum_input = ivtv_enum_input; + vdev->vidioc_enum_output = ivtv_enum_output; + vdev->vidioc_enumaudout = ivtv_enumaudout; + vdev->vidioc_cropcap = ivtv_cropcap; + vdev->vidioc_s_crop = ivtv_s_crop; + vdev->vidioc_g_crop = ivtv_g_crop; + vdev->vidioc_g_input = ivtv_g_input; + vdev->vidioc_s_input = ivtv_s_input; + vdev->vidioc_g_output = ivtv_g_output; + vdev->vidioc_s_output = ivtv_s_output; + vdev->vidioc_g_frequency = ivtv_g_frequency; + vdev->vidioc_s_frequency = ivtv_s_frequency; + vdev->vidioc_s_tuner = ivtv_s_tuner; + vdev->vidioc_g_tuner = ivtv_g_tuner; + vdev->vidioc_g_enc_index = ivtv_g_enc_index; + vdev->vidioc_g_fbuf = ivtv_g_fbuf; + vdev->vidioc_s_fbuf = ivtv_s_fbuf; + vdev->vidioc_g_std = ivtv_g_std; + vdev->vidioc_s_std = ivtv_s_std; + vdev->vidioc_overlay = ivtv_overlay; + vdev->vidioc_log_status = ivtv_log_status; + vdev->vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap; + vdev->vidioc_encoder_cmd = ivtv_encoder_cmd; + vdev->vidioc_try_encoder_cmd = ivtv_try_encoder_cmd; + vdev->vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out; + vdev->vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap; + vdev->vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap; + vdev->vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap; + vdev->vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out; + vdev->vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay; + vdev->vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out; + vdev->vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap; + vdev->vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap; + vdev->vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap; + vdev->vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out; + vdev->vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay; + vdev->vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out; + vdev->vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap; + vdev->vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap; + vdev->vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap; + vdev->vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out; + vdev->vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay; + vdev->vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out; + vdev->vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap; + vdev->vidioc_g_chip_ident = ivtv_g_chip_ident; + vdev->vidioc_g_register = ivtv_g_register; + vdev->vidioc_s_register = ivtv_s_register; + vdev->vidioc_default = ivtv_default; + vdev->vidioc_queryctrl = ivtv_queryctrl; + vdev->vidioc_querymenu = ivtv_querymenu; + vdev->vidioc_g_ctrl = ivtv_g_ctrl; + vdev->vidioc_s_ctrl = ivtv_s_ctrl; + vdev->vidioc_g_ext_ctrls = ivtv_g_ext_ctrls; + vdev->vidioc_s_ext_ctrls = ivtv_s_ext_ctrls; + vdev->vidioc_try_ext_ctrls = ivtv_try_ext_ctrls; +} diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.h b/linux/drivers/media/video/ivtv/ivtv-ioctl.h index 4e67f0ed1..70188588b 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.h +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.h @@ -24,10 +24,13 @@ u16 ivtv_service2vbi(int type); void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt); -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg); void ivtv_set_osd_alpha(struct ivtv *itv); int ivtv_set_speed(struct ivtv *itv, int speed); +void ivtv_set_funcs(struct video_device *vdev); +int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std); +int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int ivtv_s_input(struct file *file, void *fh, unsigned int inp); +int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); #endif diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index 01f546083..d2dd89519 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -224,7 +224,8 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) s->v4l2dev->dev = &itv->dev->dev; s->v4l2dev->fops = ivtv_stream_info[type].fops; s->v4l2dev->release = video_device_release; - + s->v4l2dev->tvnorms = V4L2_STD_ALL; + ivtv_set_funcs(s->v4l2dev); return 0; } diff --git a/linux/drivers/media/video/videodev.c b/linux/drivers/media/video/videodev.c index d7059944b..da78f4578 100644 --- a/linux/drivers/media/video/videodev.c +++ b/linux/drivers/media/video/videodev.c @@ -55,12 +55,51 @@ #define VIDEO_NUM_DEVICES 256 #define VIDEO_NAME "video4linux" +struct std_descr { + v4l2_std_id std; + const char *descr; +}; + +static const struct std_descr standards[] = { + { V4L2_STD_NTSC, "NTSC" }, + { V4L2_STD_NTSC_M, "NTSC-M" }, + { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" }, + { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" }, + { V4L2_STD_NTSC_443, "NTSC-443" }, + { V4L2_STD_PAL, "PAL" }, + { V4L2_STD_PAL_BG, "PAL-BG" }, + { V4L2_STD_PAL_B, "PAL-B" }, + { V4L2_STD_PAL_B1, "PAL-B1" }, + { V4L2_STD_PAL_G, "PAL-G" }, + { V4L2_STD_PAL_H, "PAL-H" }, + { V4L2_STD_PAL_I, "PAL-I" }, + { V4L2_STD_PAL_DK, "PAL-DK" }, + { V4L2_STD_PAL_D, "PAL-D" }, + { V4L2_STD_PAL_D1, "PAL-D1" }, + { V4L2_STD_PAL_K, "PAL-K" }, + { V4L2_STD_PAL_M, "PAL-M" }, + { V4L2_STD_PAL_N, "PAL-N" }, + { V4L2_STD_PAL_Nc, "PAL-Nc" }, + { V4L2_STD_PAL_60, "PAL-60" }, + { V4L2_STD_SECAM, "SECAM" }, + { V4L2_STD_SECAM_B, "SECAM-B" }, + { V4L2_STD_SECAM_G, "SECAM-G" }, + { V4L2_STD_SECAM_H, "SECAM-H" }, + { V4L2_STD_SECAM_DK, "SECAM-DK" }, + { V4L2_STD_SECAM_D, "SECAM-D" }, + { V4L2_STD_SECAM_K, "SECAM-K" }, + { V4L2_STD_SECAM_K1, "SECAM-K1" }, + { V4L2_STD_SECAM_L, "SECAM-L" }, + { V4L2_STD_SECAM_LC, "SECAM-Lc" }, + { 0, "Unknown" } +}; + /* video4linux standard ID conversion to standard name */ -char *v4l2_norm_to_name(v4l2_std_id id) +const char *v4l2_norm_to_name(v4l2_std_id id) { - char *name; u32 myid = id; + int i; /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle 64 bit comparations. So, on that architecture, with some gcc @@ -68,110 +107,17 @@ char *v4l2_norm_to_name(v4l2_std_id id) */ BUG_ON(myid != id); - switch (myid) { - case V4L2_STD_PAL: - name = "PAL"; - break; - case V4L2_STD_PAL_BG: - name = "PAL-BG"; - break; - case V4L2_STD_PAL_DK: - name = "PAL-DK"; - break; - case V4L2_STD_PAL_B: - name = "PAL-B"; - break; - case V4L2_STD_PAL_B1: - name = "PAL-B1"; - break; - case V4L2_STD_PAL_G: - name = "PAL-G"; - break; - case V4L2_STD_PAL_H: - name = "PAL-H"; - break; - case V4L2_STD_PAL_I: - name = "PAL-I"; - break; - case V4L2_STD_PAL_D: - name = "PAL-D"; - break; - case V4L2_STD_PAL_D1: - name = "PAL-D1"; - break; - case V4L2_STD_PAL_K: - name = "PAL-K"; - break; - case V4L2_STD_PAL_M: - name = "PAL-M"; - break; - case V4L2_STD_PAL_N: - name = "PAL-N"; - break; - case V4L2_STD_PAL_Nc: - name = "PAL-Nc"; - break; - case V4L2_STD_PAL_60: - name = "PAL-60"; - break; - case V4L2_STD_NTSC: - name = "NTSC"; - break; - case V4L2_STD_NTSC_M: - name = "NTSC-M"; - break; - case V4L2_STD_NTSC_M_JP: - name = "NTSC-M-JP"; - break; - case V4L2_STD_NTSC_443: - name = "NTSC-443"; - break; - case V4L2_STD_NTSC_M_KR: - name = "NTSC-M-KR"; - break; - case V4L2_STD_SECAM: - name = "SECAM"; - break; - case V4L2_STD_SECAM_DK: - name = "SECAM-DK"; - break; - case V4L2_STD_SECAM_B: - name = "SECAM-B"; - break; - case V4L2_STD_SECAM_D: - name = "SECAM-D"; - break; - case V4L2_STD_SECAM_G: - name = "SECAM-G"; - break; - case V4L2_STD_SECAM_H: - name = "SECAM-H"; - break; - case V4L2_STD_SECAM_K: - name = "SECAM-K"; - break; - case V4L2_STD_SECAM_K1: - name = "SECAM-K1"; - break; - case V4L2_STD_SECAM_L: - name = "SECAM-L"; - break; - case V4L2_STD_SECAM_LC: - name = "SECAM-LC"; - break; - default: - name = "Unknown"; - break; - } - - return name; + for (i = 0; standards[i].std; i++) + if (myid == standards[i].std) + break; + return standards[i].descr; } EXPORT_SYMBOL(v4l2_norm_to_name); /* Fill in the fields of a v4l2_standard structure according to the 'id' and 'transmission' parameters. Returns negative on error. */ int v4l2_video_std_construct(struct v4l2_standard *vs, - int id, char *name) + int id, const char *name) { u32 index = vs->index; @@ -429,6 +375,14 @@ EXPORT_SYMBOL(v4l_printk_ioctl); * sysfs stuff */ +static ssize_t show_index(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); + return sprintf(buf, "%i\n", vfd->index); +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) static ssize_t show_name(struct class_device *cd, char *buf) #else @@ -487,6 +441,7 @@ static void video_release(struct device *cd) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) static struct device_attribute video_device_attrs[] = { __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR(index, S_IRUGO, show_index, NULL), __ATTR_NULL }; #endif @@ -1249,95 +1204,40 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_ENUMSTD: { struct v4l2_standard *p = arg; - v4l2_std_id id = vfd->tvnorms,curr_id=0; - unsigned int index = p->index,i; - - if (index<0) { - ret=-EINVAL; - break; - } - - /* Return norm array on a canonical way */ - for (i=0;i<= index && id; i++) { - if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) { - curr_id = V4L2_STD_PAL; - } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) { - curr_id = V4L2_STD_PAL_BG; - } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) { - curr_id = V4L2_STD_PAL_DK; - } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) { - curr_id = V4L2_STD_PAL_B; - } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) { - curr_id = V4L2_STD_PAL_B1; - } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) { - curr_id = V4L2_STD_PAL_G; - } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) { - curr_id = V4L2_STD_PAL_H; - } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) { - curr_id = V4L2_STD_PAL_I; - } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) { - curr_id = V4L2_STD_PAL_D; - } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) { - curr_id = V4L2_STD_PAL_D1; - } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) { - curr_id = V4L2_STD_PAL_K; - } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) { - curr_id = V4L2_STD_PAL_M; - } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) { - curr_id = V4L2_STD_PAL_N; - } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) { - curr_id = V4L2_STD_PAL_Nc; - } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) { - curr_id = V4L2_STD_PAL_60; - } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) { - curr_id = V4L2_STD_NTSC; - } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) { - curr_id = V4L2_STD_NTSC_M; - } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) { - curr_id = V4L2_STD_NTSC_M_JP; - } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) { - curr_id = V4L2_STD_NTSC_443; - } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) { - curr_id = V4L2_STD_NTSC_M_KR; - } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) { - curr_id = V4L2_STD_SECAM; - } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) { - curr_id = V4L2_STD_SECAM_DK; - } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) { - curr_id = V4L2_STD_SECAM_B; - } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) { - curr_id = V4L2_STD_SECAM_D; - } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) { - curr_id = V4L2_STD_SECAM_G; - } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) { - curr_id = V4L2_STD_SECAM_H; - } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) { - curr_id = V4L2_STD_SECAM_K; - } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) { - curr_id = V4L2_STD_SECAM_K1; - } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) { - curr_id = V4L2_STD_SECAM_L; - } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) { - curr_id = V4L2_STD_SECAM_LC; - } else { + v4l2_std_id id = vfd->tvnorms, curr_id = 0; + unsigned int index = p->index, i, j = 0; + const char *descr = ""; + + /* Return norm array in a canonical way */ + for (i = 0; i <= index && id; i++) { + /* last std value in the standards array is 0, so this + while always ends there since (id & 0) == 0. */ + while ((id & standards[j].std) != standards[j].std) + j++; + curr_id = standards[j].std; + descr = standards[j].descr; + j++; + if (curr_id == 0) break; - } - id &= ~curr_id; + if (curr_id != V4L2_STD_PAL && + curr_id != V4L2_STD_SECAM && + curr_id != V4L2_STD_NTSC) + id &= ~curr_id; } - if (i<=index) + if (i <= index) return -EINVAL; - v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id)); + v4l2_video_std_construct(p, curr_id, descr); p->index = index; - dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, " + dbgarg(cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, " "framelines=%d\n", p->index, (unsigned long long)p->id, p->name, p->frameperiod.numerator, p->frameperiod.denominator, p->framelines); - ret=0; + ret = 0; break; } case VIDIOC_G_STD: @@ -1749,26 +1649,26 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_ENCODER_CMD: { - struct v4l2_encoder_cmd *p=arg; + struct v4l2_encoder_cmd *p = arg; if (!vfd->vidioc_encoder_cmd) break; - ret=vfd->vidioc_encoder_cmd(file, fh, p); + memset(&p->raw, 0, sizeof(p->raw)); + ret = vfd->vidioc_encoder_cmd(file, fh, p); if (!ret) - dbgarg (cmd, "cmd=%d, flags=%d\n", - p->cmd,p->flags); + dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); break; } case VIDIOC_TRY_ENCODER_CMD: { - struct v4l2_encoder_cmd *p=arg; + struct v4l2_encoder_cmd *p = arg; if (!vfd->vidioc_try_encoder_cmd) break; - ret=vfd->vidioc_try_encoder_cmd(file, fh, p); + memset(&p->raw, 0, sizeof(p->raw)); + ret = vfd->vidioc_try_encoder_cmd(file, fh, p); if (!ret) - dbgarg (cmd, "cmd=%d, flags=%d\n", - p->cmd,p->flags); + dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); break; } case VIDIOC_G_PARM: @@ -1871,12 +1771,17 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_G_SLICED_VBI_CAP: { - struct v4l2_sliced_vbi_cap *p=arg; + struct v4l2_sliced_vbi_cap *p = arg; + __u32 type = p->type; + if (!vfd->vidioc_g_sliced_vbi_cap) break; - ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p); + memset(p, 0, sizeof(*p)); + p->type = type; + ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p); if (!ret) - dbgarg (cmd, "service_set=%d\n", p->service_set); + dbgarg(cmd, "type=%d, service_set=%d\n", + p->type, p->service_set); break; } case VIDIOC_LOG_STATUS: @@ -2042,8 +1947,82 @@ out: } EXPORT_SYMBOL(video_ioctl2); +struct index_info { + struct device *dev; + unsigned int used[VIDEO_NUM_DEVICES]; +}; + +static int __fill_index_info(struct device *cd, void *data) +{ + struct index_info *info = data; + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); + + if (info->dev == vfd->dev) + info->used[vfd->index] = 1; + + return 0; +} + +/** + * assign_index - assign stream number based on parent device + * @vdev: video_device to assign index number to, vdev->dev should be assigned + * @num: -1 if auto assign, requested number otherwise + * + * + * returns -ENFILE if num is already in use, a free index number if + * successful. + */ +static int get_index(struct video_device *vdev, int num) +{ + struct index_info *info; + int i; + int ret = 0; + + if (num >= VIDEO_NUM_DEVICES) + return -EINVAL; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = vdev->dev; + + ret = class_for_each_device(&video_class, info, + __fill_index_info); + + if (ret < 0) + goto out; + + if (num >= 0) { + if (!info->used[num]) + ret = num; + else + ret = -ENFILE; + + goto out; + } + + for (i = 0; i < VIDEO_NUM_DEVICES; i++) { + if (info->used[i]) + continue; + ret = i; + goto out; + } + +out: + kfree(info); + return ret; +} + static const struct file_operations video_fops; +int video_register_device(struct video_device *vfd, int type, int nr) +{ + return video_register_device_index(vfd, type, nr, -1); +} +EXPORT_SYMBOL(video_register_device); + /** * video_register_device - register video4linux devices * @vfd: video device structure we want to register @@ -2069,7 +2048,8 @@ static const struct file_operations video_fops; * %VFL_TYPE_RADIO - A radio card */ -int video_register_device(struct video_device *vfd, int type, int nr) +int video_register_device_index(struct video_device *vfd, int type, int nr, + int index) { int i=0; int base; @@ -2126,6 +2106,16 @@ int video_register_device(struct video_device *vfd, int type, int nr) } video_device[i]=vfd; vfd->minor=i; + + ret = get_index(vfd, index); + if (ret < 0) { + printk(KERN_ERR "%s: get_index failed\n", + __func__); + goto fail_minor; + } + + vfd->index = ret; + mutex_unlock(&videodev_lock); mutex_init(&vfd->lock); @@ -2188,7 +2178,7 @@ fail_minor: mutex_unlock(&videodev_lock); return ret; } -EXPORT_SYMBOL(video_register_device); +EXPORT_SYMBOL(video_register_device_index); /** * video_unregister_device - unregister a video4linux device diff --git a/linux/drivers/media/video/zoran_driver.c b/linux/drivers/media/video/zoran_driver.c index fdec02d98..c1ed32e99 100644 --- a/linux/drivers/media/video/zoran_driver.c +++ b/linux/drivers/media/video/zoran_driver.c @@ -97,7 +97,6 @@ V4L2_CAP_VIDEO_OVERLAY \ ) -#include <asm/byteorder.h> #if defined(CONFIG_VIDEO_V4L1_COMPAT) #define ZFMT(pal, fcc, cs) \ diff --git a/linux/include/media/v4l2-dev.h b/linux/include/media/v4l2-dev.h index 484090509..dff99a024 100644 --- a/linux/include/media/v4l2-dev.h +++ b/linux/include/media/v4l2-dev.h @@ -46,9 +46,9 @@ #define VFL_TYPE_VTX 3 /* Video standard functions */ -extern char *v4l2_norm_to_name(v4l2_std_id id); +extern const char *v4l2_norm_to_name(v4l2_std_id id); extern int v4l2_video_std_construct(struct v4l2_standard *vs, - int id, char *name); + int id, const char *name); /* Prints the ioctl in a human-readable format */ extern void v4l_printk_ioctl(unsigned int cmd); @@ -112,6 +112,8 @@ struct video_device int type; /* v4l1 */ int type2; /* v4l2 */ int minor; + /* attribute to diferentiate multiple indexs on one physical device */ + int index; int debug; /* Activates debug level*/ @@ -377,6 +379,8 @@ void *priv; /* Version 2 functions */ extern int video_register_device(struct video_device *vfd, int type, int nr); +int video_register_device_index(struct video_device *vfd, int type, int nr, + int index); void video_unregister_device(struct video_device *); extern int video_ioctl2(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); diff --git a/v4l/scripts/check_deps.pl b/v4l/scripts/check_deps.pl new file mode 100755 index 000000000..4071a9976 --- /dev/null +++ b/v4l/scripts/check_deps.pl @@ -0,0 +1,228 @@ +#!/usr/bin/perl + +# Copyright (C) 2008 Mauro Carvalho Chehab <mchehab@infradead.org> + + +use strict; +use File::Find; +use Fcntl ':mode'; +use FileHandle; + +my $debug=0; + +my $SRC = 'linux'; + +my %export; + +############# +# open_makefile were adapted from analyze_build.pl +# by Copyright (C) 2006 Trent Piepho <xyzzy@speakeasy.org> + +# Print out some extra checks of Makefile correctness +my $check = 0; + +# Root of source tree +my $root; + +# List of Makefile's opened +my %makefiles = (); + +# For each module that is made up of multiple source files, list of sources +my %multi = (); +my $multi_count = 0; + +my %config; + +my %associate; + +sub open_makefile($) { + my $file = shift; + + # only open a given Makefile once + return if exists $makefiles{$file}; + $makefiles{$file} = 1; + + $file =~ m|^(.*)/[^/]*$|; + my $dir = $1; + + print "opening $root$file (dir=$dir)\n" if ($debug > 2); + my $in = new FileHandle; + open $in, '<', "$root$file" or die "Unable to open Makefile '$root$file': $!"; + + while (<$in>) { + # print STDERR "Line: $_"; + # Skip comment and blank lines + next if (/^\s*(#.*)?$/); + m/^\s*\-?include/ and die "Can't handle includes! In $file"; + + # Handle line continuations + if (/\\\n$/) { + $_ .= <$in>; + redo; + } + # Eat line continuations in string we will parse + s/\s*\\\n\s*/ /g; + # Eat comments + s/#.*$//; + + if (/^\s*obj-(\S+)\s*([:+]?)=\s*(\S.*?)\s*$/) { + print STDERR "Should use '+=' in $file:$.\n$_\n" if ($check && $2 ne '+'); + my ($var,$targets) = ($1, $3); + if ($var =~ /\$\(CONFIG_(\S+)\)$/) { + $var = $1; + } elsif ($var !~ /^[ym]$/) { + print STDERR "Confused by obj assignment '$var' in $file:$.\n$_"; + } + foreach(split(/\s+/, $targets)) { + if (m|/$|) { # Ends in /, means it's a directory + open_makefile("$dir/$_".'Makefile'); + } elsif (/^(\S+)\.o$/) { + $config{"$dir/$1"} = $var; +# printf "%s -> %s\n", $var, $1 if $debug > 1; + } else { + print STDERR "Confused by target '$_' in $file:$.\n"; + } + } + next; + } + if (/(\S+)-objs\s*([:+]?)=\s*(\S.*?)\s*$/) { + my @files = split(/\s+/, $3); + map { s|^(.*)\.o$|$dir/\1| } @files; + if ($2 eq '+') { + # Adding to files + print STDERR "Should use ':=' in $file:$.\n$_\n" if ($check && !exists $multi{"$dir/$1"}); + push @files, @{$multi{"$dir/$1"}}; + } else { + print STDERR "Setting objects twice in $file:$.\n$_\n" if ($check && exists $multi{"$dir/$1"}); + } + $multi{"$dir/$1"} = \@files; + next; + } + if (/^\s*EXTRA_CFLAGS\s*([:+]?)=\s*(\S.*?)\s*$/) { + if ($check) { + sub allI { /^-I/ or return 0 foreach split(/\s+/, $_[0]);return 1; } + my $use = allI($2) ? ':' : '+'; + print STDERR "Should use '$use=' with EXTRA_CFLAGS in $file:$.\n$_\n" + if ($1 ne $use); + } + next; + } + print STDERR "Odd line $file:$.\n$_\n" if ($check); + } + close IN; +} + +# +############# + +sub associate_multi() +{ + foreach (keys %multi) { + my $name = $_; + my @files = @{$multi{$_}}; + map { s/^(.*)$/\1.c/ } @files; + + foreach (@files) { + my $file = $_; + my $var = $config{$name}; + $associate{$file} = $var; + printf "$var -> $file\n" if $debug > 1; + } + delete $config{$name}; + } + foreach my $file (keys %config) { + my $var = $config{$file}; + $file .= ".c"; + $associate{$file} = $var; + printf "$var -> $file\n" if $debug > 1; + } +} + +sub build_exported_symbol_list { + my $file = $File::Find::name; + + return if (!($file =~ /\.c$/)); + + open IN, $file; + while (<IN>) { + if (m/EXPORT_SYMBOL.*\(\s*([^\s\)]+)/) { + $export{$1} = $file; + printf "%s -> %s\n", $file , $1 if $debug > 1; + } + } + close IN; +} + + +sub find_usage_list { + my %depend; + my $file = $File::Find::name; + my $s; + + return if (!($file =~ /\.c$/)); + + open IN, $file; + printf "Checking symbols at $file\n" if $debug; + while (<IN>) { + foreach my $symbol (keys %export) { + my $symb_file = $export{$symbol}; + + # Doesn't search the symbol at the file that defines it + next if ($symb_file eq $file); + + if (m/($symbol)/) { + my $var = $associate{$symb_file}; + if (!$depend{$var}) { + printf "$symbol found at $file. It depends on %s\n", $associate{$symb_file} if $debug; + $depend{$var} = 1; + } + } + } + } + close IN; + + foreach (%depend) { $s .= "$_ && "; }; + $s =~ s/\&\&\ $//; + if ($s ne "") { + print $associate{$file}." depends on $s\n"; + } +} + +print <<EOL; +Dependency check tool for Kernel Symbols. + +Copyright(c) 2008 by Mauro Carvalho Chehab <mchehab\@infradead.org> +This code is licenced under the terms of GPLv2. + +This script seeks all .c files under linux/ for their exported symbols. For +each exported symbol, it will check what Kconfig symbol is associated. Then, it +will cross-check that symbol usage and output a Kconfig depencency table. + +WARNING: The result of this tool should be used just as a hint, since, due to +performance issues, and to simplify the tool, the checks will use a simple grep +for the symbol string at the .c files, instead of a real symbol cross-check. + +Also, the same symbol may appear twice with different dependencies. This is due +to the way it checks for symbols. The final dependency is the union (AND) of +all showed ones for that symbol. + +Further patches improving this tool are welcome. + +EOL + +print "Checking makefile rules..." if $debug; +open_makefile("$SRC/drivers/media/Makefile"); +print " ok\n" if $debug; + +print "Associating symbols with c files..." if $debug; +associate_multi(); +print " ok\n" if $debug; + +print "finding exported symbols at $SRC..." if $debug; +find({wanted => \&build_exported_symbol_list, no_chdir => 1}, $SRC); +print " ok\n" if $debug; + +print "finding usage of symbols at $SRC\n" if $debug; +find({wanted => \&find_usage_list, no_chdir => 1}, $SRC); +print "finished\n" if $debug; + |