From 8f33450a4c886774345d606d615cf6b50fa193b7 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Mon, 24 Oct 2011 00:41:27 +0100 Subject: [PATCH 001/144] [media] ivtv: Fix radio support Although the ivtv driver reports radio support through the V4L2 API, it fails to actually enable it. This patch fixes that. Signed-off-by: Ian Armstrong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 0fb75524484d..41108a9a195e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1180,6 +1180,8 @@ static int __devinit ivtv_probe(struct pci_dev *pdev, setup.addr = ADDR_UNSET; setup.type = itv->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + if (itv->options.radio > 0) + setup.mode_mask |= T_RADIO; setup.tuner_callback = (setup.type == TUNER_XC2028) ? ivtv_reset_tuner_gpio : NULL; ivtv_call_all(itv, tuner, s_type_addr, &setup); From c8c741b6eeb7c5c514a3177fd28225bff454b08f Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Mon, 24 Oct 2011 00:51:11 +0100 Subject: [PATCH 002/144] [media] cx18: Fix FM radio The cx18 driver was not setting up the analog tuner driver to enable FM radio. This change fixes that. Thanks go to Ian Armstrong for reporting and fixing the analogous problem in ivtv. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-driver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 9e2f870f4258..c6ff32a6137c 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -1085,6 +1085,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, setup.addr = ADDR_UNSET; setup.type = cx->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + if (cx->options.radio > 0) + setup.mode_mask |= T_RADIO; setup.tuner_callback = (setup.type == TUNER_XC2028) ? cx18_reset_tuner_gpio : NULL; cx18_call_all(cx, tuner, s_type_addr, &setup); From e92f9a56815d8566dcb6f98aa0ed118d66881a59 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 8 Sep 2011 07:44:15 +0100 Subject: [PATCH 003/144] [media] DVB: add MaxLinear MxL111SF DVB-T demodulator driver Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Makefile | 1 + drivers/media/dvb/dvb-usb/mxl111sf-demod.c | 604 +++++++++++++++++++++ drivers/media/dvb/dvb-usb/mxl111sf-demod.h | 55 ++ drivers/media/dvb/dvb-usb/mxl111sf.h | 2 +- 4 files changed, 661 insertions(+), 1 deletion(-) create mode 100644 drivers/media/dvb/dvb-usb/mxl111sf-demod.c create mode 100644 drivers/media/dvb/dvb-usb/mxl111sf-demod.h diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 7d0710bb1978..26c8b9e57050 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o +obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c new file mode 100644 index 000000000000..330774e346ab --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c @@ -0,0 +1,604 @@ +/* + * mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "mxl111sf-demod.h" +#include "mxl111sf-reg.h" + +/* debug */ +static int mxl111sf_demod_debug; +module_param_named(debug, mxl111sf_demod_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +#define mxl_dbg(fmt, arg...) \ + if (mxl111sf_demod_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +/* ------------------------------------------------------------------------ */ + +struct mxl111sf_demod_state { + struct mxl111sf_state *mxl_state; + + struct mxl111sf_demod_config *cfg; + + struct dvb_frontend fe; +}; + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state, + u8 addr, u8 *data) +{ + return (state->cfg->read_reg) ? + state->cfg->read_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state, + u8 addr, u8 data) +{ + return (state->cfg->write_reg) ? + state->cfg->write_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static +int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info) +{ + return (state->cfg->program_regs) ? + state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : + -EINVAL; +} + +/* ------------------------------------------------------------------------ */ +/* TPS */ + +static +int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state, + fe_code_rate_t *code_rate) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val); + /* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */ + if (mxl_fail(ret)) + goto fail; + + switch (val & V6_CODE_RATE_TPS_MASK) { + case 0: + *code_rate = FEC_1_2; + break; + case 1: + *code_rate = FEC_2_3; + break; + case 2: + *code_rate = FEC_3_4; + break; + case 3: + *code_rate = FEC_5_6; + break; + case 4: + *code_rate = FEC_7_8; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state, + fe_modulation_t *constellation) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); + /* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { + case 0: + *constellation = QPSK; + break; + case 1: + *constellation = QAM_16; + break; + case 2: + *constellation = QAM_64; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state, + fe_transmit_mode_t *fft_mode) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val); + /* FFT Mode, 00:2K, 01:8K, 10:4K */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) { + case 0: + *fft_mode = TRANSMISSION_MODE_2K; + break; + case 1: + *fft_mode = TRANSMISSION_MODE_8K; + break; + case 2: + *fft_mode = TRANSMISSION_MODE_4K; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state, + fe_guard_interval_t *guard) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val); + /* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_PARAM_GI_MASK) >> 4) { + case 0: + *guard = GUARD_INTERVAL_1_32; + break; + case 1: + *guard = GUARD_INTERVAL_1_16; + break; + case 2: + *guard = GUARD_INTERVAL_1_8; + break; + case 3: + *guard = GUARD_INTERVAL_1_4; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state, + fe_hierarchy_t *hierarchy) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val); + /* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) { + case 0: + *hierarchy = HIERARCHY_NONE; + break; + case 1: + *hierarchy = HIERARCHY_1; + break; + case 2: + *hierarchy = HIERARCHY_2; + break; + case 3: + *hierarchy = HIERARCHY_4; + break; + } +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ +/* LOCKS */ + +static +int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state, + int *sync_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val); + if (mxl_fail(ret)) + goto fail; + *sync_lock = (val & SYNC_LOCK_MASK) >> 4; +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state, + int *rs_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val); + if (mxl_fail(ret)) + goto fail; + *rs_lock = (val & RS_LOCK_DET_MASK) >> 3; +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state, + int *tps_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val); + if (mxl_fail(ret)) + goto fail; + *tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6; +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state, + int *fec_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val); + if (mxl_fail(ret)) + goto fail; + *fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4; +fail: + return ret; +} + +#if 0 +static +int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state, + int *cp_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val); + if (mxl_fail(ret)) + goto fail; + *cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2; +fail: + return ret; +} +#endif + +static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) +{ + return mxl111sf_demod_write_reg(state, 0x0e, 0xff); +} + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + int ret = 0; + + struct mxl111sf_reg_ctrl_info phy_pll_patch[] = { + {0x00, 0xff, 0x01}, /* change page to 1 */ + {0x40, 0xff, 0x05}, + {0x40, 0xff, 0x01}, + {0x41, 0xff, 0xca}, + {0x41, 0xff, 0xc0}, + {0x00, 0xff, 0x00}, /* change page to 0 */ + {0, 0, 0} + }; + + mxl_dbg("()"); + + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe, param); + if (mxl_fail(ret)) + goto fail; + msleep(50); + } + ret = mxl111sf_demod_program_regs(state, phy_pll_patch); + mxl_fail(ret); + msleep(50); + ret = mxl1x1sf_demod_reset_irq_status(state); + mxl_fail(ret); + msleep(100); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#if 0 +/* resets TS Packet error count */ +/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */ +static +int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state) +{ + struct mxl111sf_reg_ctrl_info reset_per_count[] = { + {0x20, 0x01, 0x01}, + {0x20, 0x01, 0x00}, + {0, 0, 0} + }; + return mxl111sf_demod_program_regs(state, reset_per_count); +} +#endif + +/* returns TS Packet error count */ +/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */ +static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + u32 fec_per_count, fec_per_scale; + u8 val; + int ret; + + *ucblocks = 0; + + /* FEC_PER_COUNT Register */ + ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val); + if (mxl_fail(ret)) + goto fail; + + fec_per_count = val; + + /* FEC_PER_SCALE Register */ + ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val); + if (mxl_fail(ret)) + goto fail; + + val &= V6_FEC_PER_SCALE_MASK; + val *= 4; + + fec_per_scale = 1 << val; + + fec_per_count *= fec_per_scale; + + *ucblocks = fec_per_count; +fail: + return ret; +} + +#define CALCULATE_BER(avg_errors, count) \ + ((u32)(avg_errors * 4)/(count*64*188*8)) +#define CALCULATE_SNR(data) \ + ((u32)((10 * (u32)data / 64) - 2.5)) + +static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + u8 val1, val2, val3; + int ret; + + *ber = 0; + + ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3); + if (mxl_fail(ret)) + goto fail; + + *ber = CALCULATE_BER((val1 | (val2 << 8)), val3); +fail: + return ret; +} + +static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state, + u16 *snr) +{ + u8 val1, val2; + int ret; + + *snr = 0; + + ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2); + if (mxl_fail(ret)) + goto fail; + + *snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8)); +fail: + return ret; +} + +static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + + int ret = mxl111sf_demod_calc_snr(state, snr); + if (mxl_fail(ret)) + goto fail; + + *snr /= 10; /* 0.1 dB */ +fail: + return ret; +} + +static int mxl111sf_demod_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + int ret, locked, cr_lock, sync_lock, fec_lock; + + *status = 0; + + ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock); + if (mxl_fail(ret)) + goto fail; + + if (locked) + *status |= FE_HAS_SIGNAL; + if (cr_lock) + *status |= FE_HAS_CARRIER; + if (sync_lock) + *status |= FE_HAS_SYNC; + if (fec_lock) /* false positives? */ + *status |= FE_HAS_VITERBI; + + if ((locked) && (cr_lock) && (sync_lock)) + *status |= FE_HAS_LOCK; +fail: + return ret; +} + +static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + fe_modulation_t constellation; + u16 snr; + + mxl111sf_demod_calc_snr(state, &snr); + mxl1x1sf_demod_get_tps_constellation(state, &constellation); + + switch (constellation) { + case QPSK: + *signal_strength = (snr >= 1300) ? + min(65535, snr * 44) : snr * 38; + break; + case QAM_16: + *signal_strength = (snr >= 1500) ? + min(65535, snr * 38) : snr * 33; + break; + case QAM_64: + *signal_strength = (snr >= 2000) ? + min(65535, snr * 29) : snr * 25; + break; + default: + *signal_strength = 0; + return -EINVAL; + } + + return 0; +} + +static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + + mxl_dbg("()"); +#if 0 + p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; +#endif + if (fe->ops.tuner_ops.get_bandwidth) + fe->ops.tuner_ops.get_bandwidth(fe, &p->u.ofdm.bandwidth); + if (fe->ops.tuner_ops.get_frequency) + fe->ops.tuner_ops.get_frequency(fe, &p->frequency); + mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_HP); + mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_LP); + mxl1x1sf_demod_get_tps_constellation(state, &p->u.ofdm.constellation); + mxl1x1sf_demod_get_tps_guard_fft_mode(state, + &p->u.ofdm.transmission_mode); + mxl1x1sf_demod_get_tps_guard_interval(state, + &p->u.ofdm.guard_interval); + mxl1x1sf_demod_get_tps_hierarchy(state, + &p->u.ofdm.hierarchy_information); + + return 0; +} + +static +int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void mxl111sf_demod_release(struct dvb_frontend *fe) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + mxl_dbg("()"); + kfree(state); + fe->demodulator_priv = NULL; +} + +static struct dvb_frontend_ops mxl111sf_demod_ops = { + + .info = { + .name = "MxL111SF DVB-T", + .type = FE_OFDM, + .frequency_min = 177000000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER + }, + .release = mxl111sf_demod_release, +#if 0 + .init = mxl111sf_init, + .i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl, +#endif + .set_frontend = mxl111sf_demod_set_frontend, + .get_frontend = mxl111sf_demod_get_frontend, + .get_tune_settings = mxl111sf_demod_get_tune_settings, + .read_status = mxl111sf_demod_read_status, + .read_signal_strength = mxl111sf_demod_read_signal_strength, + .read_ber = mxl111sf_demod_read_ber, + .read_snr = mxl111sf_demod_read_snr, + .read_ucblocks = mxl111sf_demod_read_ucblocks, +}; + +struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, + struct mxl111sf_demod_config *cfg) +{ + struct mxl111sf_demod_state *state = NULL; + + mxl_dbg("()"); + + state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->mxl_state = mxl_state; + state->cfg = cfg; + + memcpy(&state->fe.ops, &mxl111sf_demod_ops, + sizeof(struct dvb_frontend_ops)); + + state->fe.demodulator_priv = state; + return &state->fe; +} +EXPORT_SYMBOL_GPL(mxl111sf_demod_attach); + +MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h new file mode 100644 index 000000000000..432706ae5274 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h @@ -0,0 +1,55 @@ +/* + * mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MXL111SF_DEMOD_H__ +#define __MXL111SF_DEMOD_H__ + +#include "dvb_frontend.h" +#include "mxl111sf.h" + +struct mxl111sf_demod_config { + int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); + int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); + int (*program_regs)(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info); +}; + +#if defined(CONFIG_DVB_USB_MXL111SF) || \ + (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) +extern +struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, + struct mxl111sf_demod_config *cfg); +#else +static inline +struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, + struct mxl111sf_demod_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_USB_MXL111SF */ + +#endif /* __MXL111SF_DEMOD_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h index 5a2c7bb386cd..364d89f826bd 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.h +++ b/drivers/media/dvb/dvb-usb/mxl111sf.h @@ -133,7 +133,7 @@ extern int dvb_usb_mxl111sf_debug; /* The following allows the mxl_fail() macro defined below to work * in externel modules, such as mxl111sf-tuner.ko, even though * dvb_usb_mxl111sf_debug is not defined within those modules */ -#ifdef __MXL111SF_TUNER_H__ +#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__)) #define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG #else #define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug From 4f98480f32fb11af40de3947cc5d500ec9691726 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 15 Oct 2011 23:10:15 +0100 Subject: [PATCH 004/144] [media] mxl111sf: add DVB-T support Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/mxl111sf.c | 228 ++++++++++++++++++++++++++- 1 file changed, 225 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index 546ba5915a5b..b5c98da5d9e2 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c @@ -17,6 +17,7 @@ #include "mxl111sf-i2c.h" #include "mxl111sf-gpio.h" +#include "mxl111sf-demod.h" #include "mxl111sf-tuner.h" #include "lgdt3305.h" @@ -362,6 +363,22 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return ret; } +static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + int ret = 0; + + deb_info("%s(%d)\n", __func__, onoff); + + if (onoff) { + ret = mxl111sf_enable_usb_output(state); + mxl_fail(ret); + } + + return ret; +} + /* ------------------------------------------------------------------------ */ static struct lgdt3305_config hauppauge_lgdt3305_config = { @@ -438,6 +455,70 @@ fail: return ret; } +static struct mxl111sf_demod_config mxl_demod_config = { + .read_reg = mxl111sf_read_reg, + .write_reg = mxl111sf_write_reg, + .program_regs = mxl111sf_ctrl_program_regs, +}; + +static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + int fe_id = adap->num_frontends_initialized; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_DVBT; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_SOC_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + /* dont care if this fails */ + mxl111sf_init_port_expander(state); + + adap->fe_adap[fe_id].fe = dvb_attach(mxl111sf_demod_attach, state, + &mxl_demod_config); + if (adap->fe_adap[fe_id].fe) { + adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; + adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; + adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, int antpath) { @@ -567,7 +648,8 @@ struct i2c_algorithm mxl111sf_i2c_algo = { #endif }; -/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties; +static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties; static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties; static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties; @@ -580,8 +662,14 @@ static int mxl111sf_probe(struct usb_interface *intf, if (((dvb_usb_mxl111sf_isoc) && (0 == dvb_usb_device_init(intf, + &mxl111sf_dvbt_isoc_properties, + THIS_MODULE, &d, adapter_nr) || + 0 == dvb_usb_device_init(intf, &mxl111sf_atsc_isoc_properties, THIS_MODULE, &d, adapter_nr))) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_dvbt_bulk_properties, + THIS_MODULE, &d, adapter_nr) || 0 == dvb_usb_device_init(intf, &mxl111sf_atsc_bulk_properties, THIS_MODULE, &d, adapter_nr) || 0) { @@ -669,6 +757,36 @@ static struct usb_device_id mxl111sf_table[] = { MODULE_DEVICE_TABLE(usb, mxl111sf_table); +#define MXL111SF_EP4_BULK_STREAMING_CONFIG \ + .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ + .stream = { \ + .type = USB_BULK, \ + .count = 5, \ + .endpoint = 0x04, \ + .u = { \ + .bulk = { \ + .buffersize = 8192, \ + } \ + } \ + } + +/* FIXME: works for v6 but not v8 silicon */ +#define MXL111SF_EP4_ISOC_STREAMING_CONFIG \ + .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ + .stream = { \ + .type = USB_ISOC, \ + .count = 5, \ + .endpoint = 0x04, \ + .u = { \ + .isoc = { \ + .framesperurb = 96, \ + /* FIXME: v6 SILICON: */ \ + .framesize = 564, \ + .interval = 1, \ + } \ + } \ + } + #define MXL111SF_EP6_BULK_STREAMING_CONFIG \ .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ .stream = { \ @@ -712,7 +830,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \ .size_of_priv = sizeof(struct mxl111sf_state) -static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { +static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = { MXL111SF_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 1, @@ -723,10 +841,106 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { .fe = {{ .size_of_priv = sizeof(struct mxl111sf_adap_state), + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_BULK_STREAMING_CONFIG, + } }, + }, + }, + .num_device_descs = 4, + .devices = { + { "Hauppauge 126xxx DVBT (bulk)", + { NULL }, + { &mxl111sf_table[4], &mxl111sf_table[8], + NULL }, + }, + { "Hauppauge 117xxx DVBT (bulk)", + { NULL }, + { &mxl111sf_table[15], &mxl111sf_table[18], + NULL }, + }, + { "Hauppauge 138xxx DVBT (bulk)", + { NULL }, + { &mxl111sf_table[20], &mxl111sf_table[22], + &mxl111sf_table[24], &mxl111sf_table[26], + NULL }, + }, + { "Hauppauge 126xxx (tp-bulk)", + { NULL }, + { &mxl111sf_table[28], &mxl111sf_table[30], + NULL }, + }, + } +}; + +static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 1, + .fe = {{ + .size_of_priv = sizeof(struct mxl111sf_adap_state), + + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_ISOC_STREAMING_CONFIG, + } }, + }, + }, + .num_device_descs = 4, + .devices = { + { "Hauppauge 126xxx DVBT (isoc)", + { NULL }, + { &mxl111sf_table[4], &mxl111sf_table[8], + NULL }, + }, + { "Hauppauge 117xxx DVBT (isoc)", + { NULL }, + { &mxl111sf_table[15], &mxl111sf_table[18], + NULL }, + }, + { "Hauppauge 138xxx DVBT (isoc)", + { NULL }, + { &mxl111sf_table[20], &mxl111sf_table[22], + &mxl111sf_table[24], &mxl111sf_table[26], + NULL }, + }, + { "Hauppauge 126xxx (tp-isoc)", + { NULL }, + { &mxl111sf_table[28], &mxl111sf_table[30], + NULL }, + }, + } +}; + +static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 2, + .fe = {{ + .size_of_priv = sizeof(struct mxl111sf_adap_state), + .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP6_BULK_STREAMING_CONFIG, + }, + { + .size_of_priv = sizeof(struct mxl111sf_adap_state), + + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_BULK_STREAMING_CONFIG, }}, }, }, @@ -776,7 +990,7 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { .adapter = { { .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 1, + .num_frontends = 2, .fe = {{ .size_of_priv = sizeof(struct mxl111sf_adap_state), @@ -784,6 +998,14 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP6_ISOC_STREAMING_CONFIG, + }, + { + .size_of_priv = sizeof(struct mxl111sf_adap_state), + + .frontend_attach = mxl111sf_attach_demod, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP4_ISOC_STREAMING_CONFIG, }}, }, }, From 7e8d8f6df3e8f26547b3b986c3946b1f8a6bd6c1 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 20 Oct 2011 15:42:34 +0100 Subject: [PATCH 005/144] [media] mxl111sf: disable snr / ber calculations for DVB-T Leaving this code enabled breaks the build on some architectures, and we shouldn't have any floating point math in the kernel, anyway. These macros need to be re-written, but it's harmless to simply return zero for now. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/mxl111sf-demod.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c index 330774e346ab..25e75c1ae36e 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c @@ -370,10 +370,20 @@ fail: return ret; } +#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS +/* FIXME: leaving this enabled breaks the build on some architectures, + * and we shouldn't have any floating point math in the kernel, anyway. + * + * These macros need to be re-written, but it's harmless to simply + * return zero for now. */ #define CALCULATE_BER(avg_errors, count) \ ((u32)(avg_errors * 4)/(count*64*188*8)) #define CALCULATE_SNR(data) \ ((u32)((10 * (u32)data / 64) - 2.5)) +#else +#define CALCULATE_BER(avg_errors, count) 0 +#define CALCULATE_SNR(data) 0 +#endif static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber) { From 539b469518b45c0b5915bec3e258e21e03667084 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 23 Oct 2011 10:46:13 +0100 Subject: [PATCH 006/144] [media] mxl111sf: update demod_ops.info.name to "MaxLinear MxL111SF DVB-T demodulator" Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/mxl111sf-demod.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c index 25e75c1ae36e..d1f58371c711 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c @@ -553,11 +553,11 @@ static void mxl111sf_demod_release(struct dvb_frontend *fe) static struct dvb_frontend_ops mxl111sf_demod_ops = { .info = { - .name = "MxL111SF DVB-T", - .type = FE_OFDM, - .frequency_min = 177000000, - .frequency_max = 858000000, - .frequency_stepsize = 166666, + .name = "MaxLinear MxL111SF DVB-T demodulator", + .type = FE_OFDM, + .frequency_min = 177000000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | From 41b44e0418112e694f9b7beb8088efbb8c9c0053 Mon Sep 17 00:00:00 2001 From: Pierrick Hascoet Date: Mon, 31 Oct 2011 12:24:39 -0300 Subject: [PATCH 007/144] [media] staging: as102: Initial import from Abilis Changes by Devin Heitmueller: Import the original Abilis Systems as102 driver. The source is unmodified, with the only changes I've made so far were that I created a Kconfig and Makefile so that the code builds in a standard v4l-dvb tree. This driver requires firmware (which Abilis has provided with redistribution terms which will allow it to be bundled in the Linux distributions). The firmware can be downloaded from here: Thanks to Rainer Miethling from PCTV Systems for working to get the driver released (for use with the PCTV 74e) and Pierrick Hascoet from Abilis for authoring the driver. Changes by Piotr Chmura: - moved the driver from media/dvb to staging/media - removed Makefile/Kconfig - compilation fails in current tree [snjw23@gmail.com: edited changelog] Signed-off-by: Pierrick Hascoet Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/Kconfig | 7 + drivers/staging/media/as102/Makefile | 5 + drivers/staging/media/as102/as102_drv.c | 356 ++++++++++ drivers/staging/media/as102/as102_drv.h | 146 ++++ drivers/staging/media/as102/as102_fe.c | 647 ++++++++++++++++++ drivers/staging/media/as102/as102_fw.c | 236 +++++++ drivers/staging/media/as102/as102_fw.h | 42 ++ drivers/staging/media/as102/as102_usb_drv.c | 432 ++++++++++++ drivers/staging/media/as102/as102_usb_drv.h | 54 ++ drivers/staging/media/as102/as10x_cmd.c | 478 +++++++++++++ drivers/staging/media/as102/as10x_cmd.h | 540 +++++++++++++++ drivers/staging/media/as102/as10x_cmd_cfg.c | 239 +++++++ .../staging/media/as102/as10x_cmd_stream.c | 256 +++++++ drivers/staging/media/as102/as10x_handle.h | 58 ++ drivers/staging/media/as102/as10x_types.h | 198 ++++++ 15 files changed, 3694 insertions(+) create mode 100644 drivers/staging/media/as102/Kconfig create mode 100644 drivers/staging/media/as102/Makefile create mode 100644 drivers/staging/media/as102/as102_drv.c create mode 100644 drivers/staging/media/as102/as102_drv.h create mode 100644 drivers/staging/media/as102/as102_fe.c create mode 100644 drivers/staging/media/as102/as102_fw.c create mode 100644 drivers/staging/media/as102/as102_fw.h create mode 100644 drivers/staging/media/as102/as102_usb_drv.c create mode 100644 drivers/staging/media/as102/as102_usb_drv.h create mode 100644 drivers/staging/media/as102/as10x_cmd.c create mode 100644 drivers/staging/media/as102/as10x_cmd.h create mode 100644 drivers/staging/media/as102/as10x_cmd_cfg.c create mode 100644 drivers/staging/media/as102/as10x_cmd_stream.c create mode 100644 drivers/staging/media/as102/as10x_handle.h create mode 100644 drivers/staging/media/as102/as10x_types.h diff --git a/drivers/staging/media/as102/Kconfig b/drivers/staging/media/as102/Kconfig new file mode 100644 index 000000000000..5865029db0f6 --- /dev/null +++ b/drivers/staging/media/as102/Kconfig @@ -0,0 +1,7 @@ +config DVB_AS102 + tristate "Abilis AS102 DVB receiver" + depends on DVB_CORE && USB && I2C && INPUT + help + Choose Y or M here if you have a device containing an AS102 + + To compile this driver as a module, choose M here diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile new file mode 100644 index 000000000000..c2334c6c952e --- /dev/null +++ b/drivers/staging/media/as102/Makefile @@ -0,0 +1,5 @@ +dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o + +obj-$(CONFIG_DVB_AS102) += dvb-as102.o + +EXTRA_CFLAGS += -DLINUX -DCONFIG_AS102_USB -Idrivers/media/dvb/dvb-core diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c new file mode 100644 index 000000000000..c334bffa36e4 --- /dev/null +++ b/drivers/staging/media/as102/as102_drv.c @@ -0,0 +1,356 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* header file for Usb device driver*/ +#include "as102_drv.h" +#include "as102_fw.h" + +#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) +#include "dvbdev.h" +#else +#warning >>> DVB_CORE not defined !!! <<< +#endif + +int debug = 0; +module_param_named(debug, debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)"); + +int dual_tuner = 0; +module_param_named(dual_tuner, dual_tuner, int, 0644); +MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner configuration (default: off)"); + +static int fw_upload = 1; +module_param_named(fw_upload, fw_upload, int, 0644); +MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)"); + +static int pid_filtering = 0; +module_param_named(pid_filtering, pid_filtering, int, 0644); +MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)"); + +static int ts_auto_disable = 0; +module_param_named(ts_auto_disable, ts_auto_disable, int, 0644); +MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)"); + +int elna_enable = 1; +module_param_named(elna_enable, elna_enable, int, 0644); +MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)"); + +#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +#endif + +#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) +static void as102_stop_stream(struct as102_dev_t *dev) { + struct as102_bus_adapter_t *bus_adap; + + if (dev != NULL) + bus_adap = &dev->bus_adap; + else + return; + + if (bus_adap->ops->stop_stream != NULL) + bus_adap->ops->stop_stream(dev); + + if (ts_auto_disable) { + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return; + + if (as10x_cmd_stop_streaming(bus_adap) < 0) { + dprintk(debug, "as10x_cmd_stop_streaming failed\n"); + } + + mutex_unlock(&dev->bus_adap.lock); + } +} + +static int as102_start_stream(struct as102_dev_t *dev) { + + struct as102_bus_adapter_t *bus_adap; + int ret = -EFAULT; + + if (dev != NULL) + bus_adap = &dev->bus_adap; + else + return ret; + + if (bus_adap->ops->start_stream != NULL) { + ret = bus_adap->ops->start_stream(dev); + } + + if (ts_auto_disable) { + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EFAULT; + + ret = as10x_cmd_start_streaming(bus_adap); + + mutex_unlock(&dev->bus_adap.lock); + } + + return ret; +} + +static int as10x_pid_filter(struct as102_dev_t *dev, + int index, u16 pid, int onoff) { + + struct as102_bus_adapter_t *bus_adap = &dev->bus_adap; + int ret = -EFAULT; + + ENTER(); + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) { + dprintk(debug, "mutex_lock_interruptible(lock) failed !\n"); + return -EBUSY; + } + + switch(onoff) { + case 0: + ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); + dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", + index, pid, ret); + break; + case 1: + { + struct as10x_ts_filter filter; + + filter.type = TS_PID_TYPE_TS; + filter.idx = 0xFF; + filter.pid = pid; + + ret = as10x_cmd_add_PID_filter(bus_adap, &filter); + dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", + index, filter.idx, filter.pid, ret); + break; + } + } + + mutex_unlock(&dev->bus_adap.lock); + + LEAVE(); + return ret; +} + +static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) { + int ret = 0; + struct dvb_demux *demux = dvbdmxfeed->demux; + struct as102_dev_t *as102_dev = demux->priv; + + ENTER(); + + if (mutex_lock_interruptible(&as102_dev->sem)) + return -ERESTARTSYS; + + if (pid_filtering) { + as10x_pid_filter(as102_dev, + dvbdmxfeed->index, dvbdmxfeed->pid, 1); + } + + if (as102_dev->streaming++ == 0) { + ret = as102_start_stream(as102_dev); + } + + mutex_unlock(&as102_dev->sem); + LEAVE(); + return ret; +} + +static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { + struct dvb_demux *demux = dvbdmxfeed->demux; + struct as102_dev_t *as102_dev = demux->priv; + + ENTER(); + + if (mutex_lock_interruptible(&as102_dev->sem)) + return -ERESTARTSYS; + + if (--as102_dev->streaming == 0) { + as102_stop_stream(as102_dev); + } + + if (pid_filtering) { + as10x_pid_filter(as102_dev, + dvbdmxfeed->index, dvbdmxfeed->pid, 0); + } + + mutex_unlock(&as102_dev->sem); + LEAVE(); + return 0; +} +#endif + +int as102_dvb_register(struct as102_dev_t *as102_dev) { + int ret = 0; + ENTER(); + +#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) + ret = dvb_register_adapter(&as102_dev->dvb_adap, + DEVICE_FULL_NAME, + THIS_MODULE, +#if defined(CONFIG_AS102_USB) + &as102_dev->bus_adap.usb_dev->dev +#elif defined(CONFIG_AS102_SPI) + &as102_dev->bus_adap.spi_dev->dev +#else +#error >>> dvb_register_adapter <<< +#endif +#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR + , adapter_nr +#endif + ); + if (ret < 0) { + err("%s: dvb_register_adapter() failed (errno = %d)", + __FUNCTION__, ret); + goto failed; + } + + as102_dev->dvb_dmx.priv = as102_dev; + as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256; + as102_dev->dvb_dmx.feednum = 256; + as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed; + as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed; + + as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING | + DMX_SECTION_FILTERING; + + as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum; + as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx; + as102_dev->dvb_dmxdev.capabilities = 0; + + if ((ret = dvb_dmx_init(&as102_dev->dvb_dmx)) < 0) { + err("%s: dvb_dmx_init() failed (errno = %d)", + __FUNCTION__, ret); + goto failed; + } + + ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap); + if (ret < 0) { + err("%s: dvb_dmxdev_init() failed (errno = %d)", + __FUNCTION__, ret); + goto failed; + } + + ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe); + if (ret < 0) { + err("%s: as102_dvb_register_frontend() failed (errno = %d)", + __FUNCTION__, ret); + goto failed; + } +#endif + + /* init bus mutex for token locking */ + mutex_init(&as102_dev->bus_adap.lock); + + /* init start / stop stream mutex */ + mutex_init(&as102_dev->sem); + +#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) + /* + * try to load as102 firmware. If firmware upload failed, we'll be + * able to upload it later. + */ + if (fw_upload) + try_then_request_module(as102_fw_upload(&as102_dev->bus_adap), + "firmware_class"); +#endif + +failed: + LEAVE(); + /* FIXME: free dvb_XXX */ + return ret; +} + +void as102_dvb_unregister(struct as102_dev_t *as102_dev) { + ENTER(); + +#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) + /* unregister as102 frontend */ + as102_dvb_unregister_fe(&as102_dev->dvb_fe); + + /* unregister demux device */ + dvb_dmxdev_release(&as102_dev->dvb_dmxdev); + dvb_dmx_release(&as102_dev->dvb_dmx); + + /* unregister dvb adapter */ + dvb_unregister_adapter(&as102_dev->dvb_adap); +#endif + LEAVE(); +} + +static int __init as102_driver_init(void) { + int ret = 0; + + ENTER(); + + /* register this driver with the low level subsystem */ +#if defined(CONFIG_AS102_USB) + ret = usb_register(&as102_usb_driver); + if (ret) + err("usb_register failed (ret = %d)", ret); +#endif +#if defined(CONFIG_AS102_SPI) + ret = spi_register_driver(&as102_spi_driver); + if (ret) + printk(KERN_ERR "spi_register failed (ret = %d)", ret); +#endif + + LEAVE(); + return ret; +} + +/* + * Mandatory function : Adds a special section to the module indicating + * where initialisation function is defined + */ +module_init(as102_driver_init); + +/** + * \brief as102 driver exit point. This function is called when device has + * to be removed. + */ +static void __exit as102_driver_exit(void) { + ENTER(); + /* deregister this driver with the low level bus subsystem */ +#if defined(CONFIG_AS102_USB) + usb_deregister(&as102_usb_driver); +#endif +#if defined(CONFIG_AS102_SPI) + spi_unregister_driver(&as102_spi_driver); +#endif + LEAVE(); +} + +/* + * required function for unload: Adds a special section to the module + * indicating where unload function is defined + */ +module_exit(as102_driver_exit); +/* modinfo details */ +MODULE_DESCRIPTION(DRIVER_FULL_NAME); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pierrick Hascoet "); + +/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h new file mode 100644 index 000000000000..f50bb9f67fce --- /dev/null +++ b/drivers/staging/media/as102/as102_drv.h @@ -0,0 +1,146 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if defined(CONFIG_AS102_USB) +#include +extern struct usb_driver as102_usb_driver; +#endif + +#if defined(CONFIG_AS102_SPI) +#include +#include +#include + +extern struct spi_driver as102_spi_driver; +#endif + +#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dmxdev.h" +#endif + +#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" +#define DRIVER_NAME "as10x_usb" + +extern int debug; + +#define dprintk(debug, args...) \ + do { if (debug) { \ + printk(KERN_DEBUG "%s: ",__FUNCTION__); \ + printk(args); \ + } } while (0) + +#ifdef TRACE +#define ENTER() printk(">> enter %s\n", __FUNCTION__) +#define LEAVE() printk("<< leave %s\n", __FUNCTION__) +#else +#define ENTER() +#define LEAVE() +#endif + +#define AS102_DEVICE_MAJOR 192 + +#define AS102_USB_BUF_SIZE 512 +#define MAX_STREAM_URB 32 + +#include "as10x_cmd.h" + +#if defined(CONFIG_AS102_USB) +#include "as102_usb_drv.h" +#endif + +#if defined(CONFIG_AS102_SPI) +#include "as10x_spi_drv.h" +#endif + + +struct as102_bus_adapter_t { +#if defined(CONFIG_AS102_USB) + struct usb_device *usb_dev; +#elif defined(CONFIG_AS102_SPI) + struct spi_device *spi_dev; + struct cdev cdev; /* spidev raw device */ + + struct timer_list timer; + struct completion xfer_done; +#endif + /* bus token lock */ + struct mutex lock; + /* low level interface for bus adapter */ + union as10x_bus_token_t { +#if defined(CONFIG_AS102_USB) + /* usb token */ + struct as10x_usb_token_cmd_t usb; +#endif +#if defined(CONFIG_AS102_SPI) + /* spi token */ + struct as10x_spi_token_cmd_t spi; +#endif + } token; + + /* token cmd xfer id */ + uint16_t cmd_xid; + + /* as10x command and response for dvb interface*/ + struct as10x_cmd_t *cmd, *rsp; + + /* bus adapter private ops callback */ + struct as102_priv_ops_t *ops; +}; + +struct as102_dev_t { + struct as102_bus_adapter_t bus_adap; + struct list_head device_entry; + struct kref kref; + unsigned long minor; + +#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) + struct dvb_adapter dvb_adap; + struct dvb_frontend dvb_fe; + struct dvb_demux dvb_dmx; + struct dmxdev dvb_dmxdev; +#endif + + /* demodulator stats */ + struct as10x_demod_stats demod_stats; + /* signal strength */ + uint16_t signal_strength; + /* bit error rate */ + uint32_t ber; + + /* timer handle to trig ts stream download */ + struct timer_list timer_handle; + + struct mutex sem; + dma_addr_t dma_addr; + void *stream; + int streaming; + struct urb *stream_urb[MAX_STREAM_URB]; +}; + +int as102_dvb_register(struct as102_dev_t *dev); +void as102_dvb_unregister(struct as102_dev_t *dev); + +#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) +int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe); +int as102_dvb_unregister_fe(struct dvb_frontend *dev); +#endif + +/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c new file mode 100644 index 000000000000..3e6f497aed51 --- /dev/null +++ b/drivers/staging/media/as102/as102_fe.c @@ -0,0 +1,647 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#include "as102_drv.h" +#include "as10x_types.h" +#include "as10x_cmd.h" + +extern int elna_enable; + +#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) +static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, + struct as10x_tps *src); + +static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, + struct dvb_frontend_parameters *src); + +static void as102_fe_release(struct dvb_frontend *fe) { + struct as102_dev_t *dev; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return; + + /* send abilis command: TURN_OFF */ + as10x_cmd_turn_off(&dev->bus_adap); + + mutex_unlock(&dev->bus_adap.lock); +#endif + + /* release frontend callback ops */ + memset(&fe->ops, 0, sizeof(struct dvb_frontend_ops)); + + /* flush statistics */ + memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); + dev->signal_strength = 0; + dev->ber = -1; + + /* reset tuner private data */ +/* fe->tuner_priv = NULL; */ + + LEAVE(); +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) +static int as102_fe_init(struct dvb_frontend *fe) { + int ret = 0; + struct as102_dev_t *dev; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EBUSY; + + if (elna_enable) + ret = as10x_cmd_set_context(&dev->bus_adap, 1010, 0xC0); + + /* send abilis command: TURN_ON */ + ret = as10x_cmd_turn_on(&dev->bus_adap); + + mutex_unlock(&dev->bus_adap.lock); + + LEAVE(); + return (ret < 0) ? -EINVAL : 0; +} +#endif + +static int as102_fe_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { + int ret = 0; + struct as102_dev_t *dev; + struct as10x_tune_args tune_args = { 0 }; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EBUSY; + + as102_fe_copy_tune_parameters(&tune_args, params); + + /* send abilis command: SET_TUNE */ + ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); + if(ret != 0) { + dprintk(debug, "as10x_cmd_set_tune failed. (err = %d)\n", ret); + } + + mutex_unlock(&dev->bus_adap.lock); + + LEAVE(); + return (ret < 0) ? -EINVAL : 0; +} + +static int as102_fe_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { + int ret = 0; + struct as102_dev_t *dev; + struct as10x_tps tps = { 0 }; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return -EINVAL; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EBUSY; + + /* send abilis command: GET_TPS */ + ret = as10x_cmd_get_tps(&dev->bus_adap, &tps); + + if (ret == 0) + as10x_fe_copy_tps_parameters(p, &tps); + + mutex_unlock(&dev->bus_adap.lock); + + LEAVE(); + return (ret < 0) ? -EINVAL : 0; +} + +static int as102_fe_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *settings) { + ENTER(); + +#if 0 + dprintk(debug, "step_size = %d\n", settings->step_size); + dprintk(debug, "max_drift = %d\n", settings->max_drift); + dprintk(debug, "min_delay_ms = %d -> %d\n", settings->min_delay_ms, 1000); +#endif + + settings->min_delay_ms = 1000; + + LEAVE(); + return 0; +} + + +static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) { + int ret = 0; + struct as102_dev_t *dev; + struct as10x_tune_status tstate = { 0 }; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EBUSY; + + /* send abilis command: GET_TUNE_STATUS */ + ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate); + if (ret < 0) { + dprintk(debug, "as10x_cmd_get_tune_status failed (err = %d)\n", ret); + goto out; + } + + dev->signal_strength = tstate.signal_strength; + dev->ber = tstate.BER; + + switch(tstate.tune_state) { + case TUNE_STATUS_SIGNAL_DVB_OK: + *status = FE_HAS_SIGNAL | + FE_HAS_CARRIER; + break; + case TUNE_STATUS_STREAM_DETECTED: + *status = FE_HAS_SIGNAL | + FE_HAS_CARRIER | + FE_HAS_SYNC; + break; + case TUNE_STATUS_STREAM_TUNED: + *status = FE_HAS_SIGNAL | + FE_HAS_CARRIER | + FE_HAS_SYNC | + FE_HAS_LOCK; + break; + default: + *status = TUNE_STATUS_NOT_TUNED; + } + + dprintk(debug, "tuner status: 0x%02x , strength %d , per: %d , ber: %d\n", + tstate.tune_state, tstate.signal_strength, + tstate.PER, tstate.BER); + + if (*status & FE_HAS_LOCK) { + if (as10x_cmd_get_demod_stats(&dev->bus_adap, + (struct as10x_demod_stats *) &dev->demod_stats) < 0) { + memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); + dprintk(debug, "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); + } else { + dprintk(debug, "demod status: fc: 0x%08x , bad fc: 0x%08x , bytes corrected: 0x%08x , MER: 0x%04x\n", + dev->demod_stats.frame_count, + dev->demod_stats.bad_frame_count, + dev->demod_stats.bytes_fixed_by_rs, + dev->demod_stats.mer); + } + } else { + memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); + } + +out: + mutex_unlock(&dev->bus_adap.lock); + LEAVE(); + return ret; +} + +/* + * Note: + * - in AS102 SNR=MER + * - the SNR will be returned in linear terms, i.e. not in dB + * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB + * - the accuracy is >2dB for SNR values outside this range + */ +static int as102_fe_read_snr(struct dvb_frontend* fe, u16* snr) { + struct as102_dev_t *dev; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return -ENODEV; + + *snr = dev->demod_stats.mer; + + LEAVE(); + return 0; +} + +static int as102_fe_read_ber(struct dvb_frontend* fe, u32* ber) { + struct as102_dev_t *dev; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return -ENODEV; + + *ber = dev->ber; + + LEAVE(); + return 0; +} + +static int as102_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength) { + struct as102_dev_t *dev; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return -ENODEV; + + *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2); + + LEAVE(); + return 0; +} + +static int as102_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { + struct as102_dev_t *dev; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return -ENODEV; + + if (dev->demod_stats.has_started) + *ucblocks = dev->demod_stats.bad_frame_count; + else + *ucblocks = 0; + + LEAVE(); + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) +static int as102_fe_ts_bus_ctrl(struct dvb_frontend* fe, int acquire) { + struct as102_dev_t *dev; + int ret; + + ENTER(); + + if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EBUSY; + + if (acquire) { + if (elna_enable) + as10x_cmd_set_context(&dev->bus_adap, 1010, 0xC0); + + ret = as10x_cmd_turn_on(&dev->bus_adap); + } else { + ret = as10x_cmd_turn_off(&dev->bus_adap); + } + + mutex_unlock(&dev->bus_adap.lock); + + LEAVE(); + return ret; +} +#endif + +static struct dvb_frontend_ops as102_fe_ops = { + .info = { + .name = DEVICE_FULL_NAME, + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_INVERSION_AUTO + | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 + | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO + | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK + | FE_CAN_QAM_AUTO + | FE_CAN_TRANSMISSION_MODE_AUTO + | FE_CAN_GUARD_INTERVAL_AUTO + | FE_CAN_HIERARCHY_AUTO + | FE_CAN_RECOVER + | FE_CAN_MUTE_TS + }, + + .set_frontend = as102_fe_set_frontend, + .get_frontend = as102_fe_get_frontend, + .get_tune_settings = as102_fe_get_tune_settings, + + + .read_status = as102_fe_read_status, + .read_snr = as102_fe_read_snr, + .read_ber = as102_fe_read_ber, + .read_signal_strength = as102_fe_read_signal_strength, + .read_ucblocks = as102_fe_read_ucblocks, + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) + .ts_bus_ctrl = as102_fe_ts_bus_ctrl, +#else + .release = as102_fe_release, + .init = as102_fe_init, +#endif +}; + +int as102_dvb_unregister_fe(struct dvb_frontend *fe) { + + /* unregister frontend */ + dvb_unregister_frontend(fe); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) + /* detach frontend */ + dvb_frontend_detach(fe); +#endif + return 0; +} + +int as102_dvb_register_fe(struct as102_dev_t *as102_dev, struct dvb_frontend *dvb_fe) { + int errno; + struct dvb_adapter *dvb_adap; + + if(as102_dev == NULL) + return -EINVAL; + + /* extract dvb_adapter */ + dvb_adap = &as102_dev->dvb_adap; + + /* init frontend callback ops */ + memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); + + /* register dbvb frontend */ + errno = dvb_register_frontend(dvb_adap, dvb_fe); + if(errno == 0) + dvb_fe->tuner_priv = as102_dev; + + return errno; +} + +static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, + struct as10x_tps *as10x_tps) { + + struct dvb_ofdm_parameters *fe_tps = &dst->u.ofdm; + + /* extract consteallation */ + switch(as10x_tps->constellation) { + case CONST_QPSK: + fe_tps->constellation = QPSK; + break; + case CONST_QAM16: + fe_tps->constellation = QAM_16; + break; + case CONST_QAM64: + fe_tps->constellation = QAM_64; + break; + } + + /* extract hierarchy */ + switch(as10x_tps->hierarchy) { + case HIER_NONE: + fe_tps->hierarchy_information = HIERARCHY_NONE; + break; + case HIER_ALPHA_1: + fe_tps->hierarchy_information = HIERARCHY_1; + break; + case HIER_ALPHA_2: + fe_tps->hierarchy_information = HIERARCHY_2; + break; + case HIER_ALPHA_4: + fe_tps->hierarchy_information = HIERARCHY_4; + break; + } + + /* extract code rate HP */ + switch(as10x_tps->code_rate_HP) { + case CODE_RATE_1_2: + fe_tps->code_rate_HP = FEC_1_2; + break; + case CODE_RATE_2_3: + fe_tps->code_rate_HP = FEC_2_3; + break; + case CODE_RATE_3_4: + fe_tps->code_rate_HP = FEC_3_4; + break; + case CODE_RATE_5_6: + fe_tps->code_rate_HP = FEC_5_6; + break; + case CODE_RATE_7_8: + fe_tps->code_rate_HP = FEC_7_8; + break; + } + + /* extract code rate LP */ + switch(as10x_tps->code_rate_LP) { + case CODE_RATE_1_2: + fe_tps->code_rate_LP = FEC_1_2; + break; + case CODE_RATE_2_3: + fe_tps->code_rate_LP = FEC_2_3; + break; + case CODE_RATE_3_4: + fe_tps->code_rate_LP = FEC_3_4; + break; + case CODE_RATE_5_6: + fe_tps->code_rate_LP = FEC_5_6; + break; + case CODE_RATE_7_8: + fe_tps->code_rate_LP = FEC_7_8; + break; + } + + /* extract guard interval */ + switch(as10x_tps->guard_interval) { + case GUARD_INT_1_32: + fe_tps->guard_interval = GUARD_INTERVAL_1_32; + break; + case GUARD_INT_1_16: + fe_tps->guard_interval = GUARD_INTERVAL_1_16; + break; + case GUARD_INT_1_8: + fe_tps->guard_interval = GUARD_INTERVAL_1_8; + break; + case GUARD_INT_1_4: + fe_tps->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + /* extract transmission mode */ + switch(as10x_tps->transmission_mode) { + case TRANS_MODE_2K: + fe_tps->transmission_mode = TRANSMISSION_MODE_2K; + break; + case TRANS_MODE_8K: + fe_tps->transmission_mode = TRANSMISSION_MODE_8K; + break; + } +} + +static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) { + uint8_t c; + + switch(arg) { + case FEC_1_2: + c = CODE_RATE_1_2; + break; + case FEC_2_3: + c = CODE_RATE_2_3; + break; + case FEC_3_4: + c = CODE_RATE_3_4; + break; + case FEC_5_6: + c = CODE_RATE_5_6; + break; + case FEC_7_8: + c = CODE_RATE_7_8; + break; + default: + c = CODE_RATE_UNKNOWN; + break; + } + + return c; +} + +static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, + struct dvb_frontend_parameters *params) { + + /* set frequency */ + tune_args->freq = params->frequency / 1000; + + /* fix interleaving_mode */ + tune_args->interleaving_mode = INTLV_NATIVE; + + switch(params->u.ofdm.bandwidth) { + case BANDWIDTH_8_MHZ: + tune_args->bandwidth = BW_8_MHZ; + break; + case BANDWIDTH_7_MHZ: + tune_args->bandwidth = BW_7_MHZ; + break; + case BANDWIDTH_6_MHZ: + tune_args->bandwidth = BW_6_MHZ; + break; + default: + tune_args->bandwidth = BW_8_MHZ; + } + + switch(params->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: + tune_args->guard_interval = GUARD_INT_1_32; + break; + case GUARD_INTERVAL_1_16: + tune_args->guard_interval = GUARD_INT_1_16; + break; + case GUARD_INTERVAL_1_8: + tune_args->guard_interval = GUARD_INT_1_8; + break; + case GUARD_INTERVAL_1_4: + tune_args->guard_interval = GUARD_INT_1_4; + break; + case GUARD_INTERVAL_AUTO: + default: + tune_args->guard_interval = GUARD_UNKNOWN; + break; + } + + switch(params->u.ofdm.constellation) { + case QPSK: + tune_args->constellation = CONST_QPSK; + break; + case QAM_16: + tune_args->constellation = CONST_QAM16; + break; + case QAM_64: + tune_args->constellation = CONST_QAM64; + break; + default: + tune_args->constellation = CONST_UNKNOWN; + break; + } + + switch(params->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: + tune_args->transmission_mode = TRANS_MODE_2K; + break; + case TRANSMISSION_MODE_8K: + tune_args->transmission_mode = TRANS_MODE_8K; + break; + default: + tune_args->transmission_mode = TRANS_MODE_UNKNOWN; + } + + switch(params->u.ofdm.hierarchy_information) { + case HIERARCHY_NONE: + tune_args->hierarchy = HIER_NONE; + break; + case HIERARCHY_1: + tune_args->hierarchy = HIER_ALPHA_1; + break; + case HIERARCHY_2: + tune_args->hierarchy = HIER_ALPHA_2; + break; + case HIERARCHY_4: + tune_args->hierarchy = HIER_ALPHA_4; + break; + case HIERARCHY_AUTO: + tune_args->hierarchy = HIER_UNKNOWN; + break; + } + + dprintk(debug, "tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", + params->frequency, + tune_args->bandwidth, + tune_args->guard_interval); + + /* + * Detect a hierarchy selection + * if HP/LP are both set to FEC_NONE, HP will be selected. + */ + if ((tune_args->hierarchy != HIER_NONE) && + ((params->u.ofdm.code_rate_LP == FEC_NONE) || + (params->u.ofdm.code_rate_HP == FEC_NONE))) { + + if (params->u.ofdm.code_rate_LP == FEC_NONE) { + tune_args->hier_select = HIER_HIGH_PRIORITY; + tune_args->code_rate = + as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); + } + + if (params->u.ofdm.code_rate_HP == FEC_NONE) { + tune_args->hier_select = HIER_LOW_PRIORITY; + tune_args->code_rate = + as102_fe_get_code_rate(params->u.ofdm.code_rate_LP); + } + + dprintk(debug, "\thierarchy: 0x%02x " + "selected: %s code_rate_%s: 0x%02x\n", + tune_args->hierarchy, + tune_args->hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", + tune_args->hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", + tune_args->code_rate); + } else { + tune_args->code_rate = as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); + } +} +#endif + +/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c new file mode 100644 index 000000000000..d921a6fd6953 --- /dev/null +++ b/drivers/staging/media/as102/as102_fw.c @@ -0,0 +1,236 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include + +#include "as102_drv.h" +#include "as102_fw.h" + +#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) +char as102_st_fw1[] = "as102_data1_st.hex"; +char as102_st_fw2[] = "as102_data2_st.hex"; +char as102_dt_fw1[] = "as102_data1_dt.hex"; +char as102_dt_fw2[] = "as102_data2_dt.hex"; + +static unsigned char atohx(unsigned char *dst, char *src) { + unsigned char value = 0; + + char msb = tolower(*src) - '0'; + char lsb = tolower(*(src +1)) - '0'; + + if (msb > 9 ) + msb -= 7; + if (lsb > 9 ) + lsb -= 7; + + *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF); + return value; +} + +/* + * Parse INTEL HEX firmware file to extract address and data. + */ +static int parse_hex_line(unsigned char *fw_data, unsigned char *addr, + unsigned char *data, int *dataLength, + unsigned char *addr_has_changed) { + + int count = 0; + unsigned char *src, dst; + + if (*fw_data++ != ':') { + printk(KERN_ERR "invalid firmware file\n"); + return -EFAULT; + } + + /* locate end of line */ + for (src=fw_data; *src != '\n'; src += 2) { + atohx(&dst, src); + /* parse line to split addr / data */ + switch (count) { + case 0: + *dataLength = dst; + break; + case 1: + addr[2] = dst; + break; + case 2: + addr[3] = dst; + break; + case 3: + /* check if data is an address */ + if (dst == 0x04) + *addr_has_changed = 1; + else + *addr_has_changed = 0; + break; + case 4: + case 5: + if (*addr_has_changed) { + addr[(count - 4)] = dst; + } else { + data[(count - 4)] = dst; + } + break; + default: + data[(count - 4)] = dst; + break; + } + count++; + } + + /* return read value + ':' + '\n' */ + return ((count * 2) + 2); +} + +static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap, + unsigned char *cmd, + const struct firmware *firmware) { + + struct as10x_fw_pkt_t fw_pkt; + int total_read_bytes = 0, errno = 0; + unsigned char addr_has_changed = 0; + + ENTER(); + + for (total_read_bytes = 0; total_read_bytes < firmware->size; ) { + int read_bytes = 0, data_len = 0; + + /* parse intel hex line */ + read_bytes = parse_hex_line( + (u8 *) (firmware->data + total_read_bytes), + fw_pkt.raw.address, + fw_pkt.raw.data, + &data_len, + &addr_has_changed); + + if (read_bytes <= 0) { + goto error; + } + + /* detect the end of file */ + if ((total_read_bytes += read_bytes) == firmware->size) { + fw_pkt.u.request[0] = 0x00; + fw_pkt.u.request[1] = 0x03; + + /* send EOF command */ + if ((errno = bus_adap->ops->upload_fw_pkt(bus_adap,(uint8_t *) &fw_pkt, 2, 0)) < 0) + goto error; + } else { + if (!addr_has_changed) { + /* prepare command to send */ + fw_pkt.u.request[0] = 0x00; + fw_pkt.u.request[1] = 0x01; + + data_len += sizeof(fw_pkt.u.request); + data_len += sizeof(fw_pkt.raw.address); + + /* send cmd to device */ + if ((errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) &fw_pkt, data_len, 0)) < 0) + goto error; + } + } + } +error: + LEAVE(); + return (errno == 0) ? total_read_bytes : errno; +} + +int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) { + int errno = -EFAULT; + const struct firmware *firmware; + unsigned char *cmd_buf = NULL; + char *fw1, *fw2; + +#if defined(CONFIG_AS102_USB) + struct usb_device *dev = bus_adap->usb_dev; +#endif +#if defined(CONFIG_AS102_SPI) + struct spi_device *dev = bus_adap->spi_dev; +#endif + ENTER(); + + /* select fw file to upload */ + if (dual_tuner) { + fw1 = as102_dt_fw1; + fw2 = as102_dt_fw2; + } else { + fw1 = as102_st_fw1; + fw2 = as102_st_fw2; + } + +#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) + /* allocate buffer to store firmware upload command and data */ + if ((cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL)) == NULL) { + errno = -ENOMEM; + goto error; + } + + /* request kernel to locate firmware file: part1 */ + if ((errno = request_firmware(&firmware, fw1, &dev->dev)) < 0) { + printk(KERN_ERR "%s: unable to locate firmware file: %s\n", + DRIVER_NAME, fw1); + goto error; + } + + /* initiate firmware upload */ + if ((errno = as102_firmware_upload(bus_adap, cmd_buf, firmware)) < 0) { + printk(KERN_ERR "%s: error during firmware upload part1\n", + DRIVER_NAME); + goto error; + } + + printk(KERN_INFO "%s: fimrware: %s loaded with success\n", + DRIVER_NAME, fw1); + release_firmware(firmware); + + /* wait for boot to complete */ + mdelay(100); + + /* request kernel to locate firmware file: part2 */ + if ((errno = request_firmware(&firmware, fw2, &dev->dev)) < 0) { + printk(KERN_ERR "%s: unable to locate firmware file: %s\n", + DRIVER_NAME, fw2); + goto error; + } + + /* initiate firmware upload */ + if ((errno = as102_firmware_upload(bus_adap, cmd_buf, firmware)) < 0) { + printk(KERN_ERR "%s: error during firmware upload part2\n", + DRIVER_NAME); + goto error; + } + + printk(KERN_INFO "%s: fimrware: %s loaded with success\n", + DRIVER_NAME, fw2); +error: + /* free data buffer */ + kfree(cmd_buf); + /* release firmware if needed */ + if (firmware != NULL) + release_firmware(firmware); +#endif + LEAVE(); + return errno; +} +#endif + +/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fw.h b/drivers/staging/media/as102/as102_fw.h new file mode 100644 index 000000000000..27e5347e2e19 --- /dev/null +++ b/drivers/staging/media/as102/as102_fw.h @@ -0,0 +1,42 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#define MAX_FW_PKT_SIZE 64 + +extern int dual_tuner; + +#pragma pack(1) +struct as10x_raw_fw_pkt { + unsigned char address[4]; + unsigned char data[MAX_FW_PKT_SIZE - 6]; +}; + +struct as10x_fw_pkt_t { + union { + unsigned char request[2]; + unsigned char length[2]; + } u; + struct as10x_raw_fw_pkt raw; +}; +#pragma pack() + +#ifdef __KERNEL__ +int as102_fw_upload(struct as102_bus_adapter_t *bus_adap); +#endif + +/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c new file mode 100644 index 000000000000..ee993960731a --- /dev/null +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -0,0 +1,432 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include + +#include "as102_drv.h" +#include "as102_usb_drv.h" +#include "as102_fw.h" + +static void as102_usb_disconnect(struct usb_interface *interface); +static int as102_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id); + +static int as102_usb_start_stream(struct as102_dev_t *dev); +static void as102_usb_stop_stream(struct as102_dev_t *dev); + +static int as102_open(struct inode *inode, struct file *file); +static int as102_release(struct inode *inode, struct file *file); + +static struct usb_device_id as102_usb_id_table[] = { + { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) }, + { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, + { } /* Terminating entry */ +}; + +struct usb_driver as102_usb_driver = { + .name = DRIVER_FULL_NAME, + .probe = as102_usb_probe, + .disconnect = as102_usb_disconnect, + .id_table = as102_usb_id_table +}; + +struct file_operations as102_dev_fops = { + .owner = THIS_MODULE, + .open = as102_open, + .release = as102_release, +}; + +static struct usb_class_driver as102_usb_class_driver = { + .name = "aton2-%d", + .fops = &as102_dev_fops, + .minor_base = AS102_DEVICE_MAJOR, +}; + +static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap, + unsigned char *send_buf, int send_buf_len, + unsigned char *recv_buf, int recv_buf_len) { + + int ret = 0; + ENTER(); + + if(send_buf != NULL) { + ret = usb_control_msg(bus_adap->usb_dev, + usb_sndctrlpipe(bus_adap->usb_dev, 0), + AS102_USB_DEVICE_TX_CTRL_CMD, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + bus_adap->cmd_xid, /* value */ + 0, /* index */ + send_buf, send_buf_len, + USB_CTRL_SET_TIMEOUT /* 200 */); + if(ret < 0) { + dprintk(debug, "usb_control_msg(send) failed, err %i\n", + ret); + return ret; + } + + if(ret != send_buf_len) { + dprintk(debug, "only wrote %d of %d bytes\n", + ret, send_buf_len); + return -1; + } + } + + if(recv_buf != NULL) { +#ifdef TRACE + dprintk(debug, "want to read: %d bytes\n", recv_buf_len); +#endif + ret = usb_control_msg(bus_adap->usb_dev, + usb_rcvctrlpipe(bus_adap->usb_dev, 0), + AS102_USB_DEVICE_RX_CTRL_CMD, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + bus_adap->cmd_xid, /* value */ + 0, /* index */ + recv_buf, recv_buf_len, + USB_CTRL_GET_TIMEOUT /* 200 */); + if(ret < 0) { + dprintk(debug, "usb_control_msg(recv) failed, err %i\n", + ret); + return ret; + } +#ifdef TRACE + dprintk(debug, "read %d bytes\n", recv_buf_len); +#endif + } + + LEAVE(); + return ret; +} + +static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap, + unsigned char *send_buf, + int send_buf_len, + int swap32) { + + int ret = 0, actual_len; + + ret = usb_bulk_msg(bus_adap->usb_dev, usb_sndbulkpipe(bus_adap->usb_dev, 1), + send_buf, send_buf_len, &actual_len, 200); + if(ret) { + dprintk(debug, "usb_bulk_msg(send) failed, err %i\n", ret); + return ret; + } + + if(actual_len != send_buf_len) { + dprintk(debug, "only wrote %d of %d bytes\n", + actual_len, send_buf_len); + return -1; + } + return ret ? ret : actual_len; +} + +static int as102_read_ep2(struct as102_bus_adapter_t *bus_adap, + unsigned char *recv_buf, int recv_buf_len) { + + int ret = 0, actual_len; + + if(recv_buf == NULL) + return -EINVAL; + + ret = usb_bulk_msg(bus_adap->usb_dev, usb_rcvbulkpipe(bus_adap->usb_dev, 2), + recv_buf, recv_buf_len, &actual_len, 200); + if(ret) { + dprintk(debug, "usb_bulk_msg(recv) failed, err %i\n", ret); + return ret; + } + + if(actual_len != recv_buf_len) { + dprintk(debug, "only read %d of %d bytes\n", + actual_len, recv_buf_len); + return -1; + } + return ret ? ret : actual_len; +} + +struct as102_priv_ops_t as102_priv_ops = { + .upload_fw_pkt = as102_send_ep1, + .xfer_cmd = as102_usb_xfer_cmd, + .as102_read_ep2 = as102_read_ep2, + .start_stream = as102_usb_start_stream, + .stop_stream = as102_usb_stop_stream, +}; + +static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) { + int err; + + usb_fill_bulk_urb(urb, + dev->bus_adap.usb_dev, + usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2), + urb->transfer_buffer, + AS102_USB_BUF_SIZE, + as102_urb_stream_irq, + dev); + + if ((err = usb_submit_urb(urb, GFP_ATOMIC))) + dprintk(debug, "%s: usb_submit_urb failed\n", __FUNCTION__); + + return err; +} + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)) +void as102_urb_stream_irq(struct urb *urb, struct pt_regs *regs) +#else +void as102_urb_stream_irq(struct urb *urb) +#endif +{ + struct as102_dev_t *as102_dev = urb->context; + + if (urb->actual_length > 0) { +#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) + dvb_dmx_swfilter(&as102_dev->dvb_dmx, + urb->transfer_buffer, + urb->actual_length); +#else + /* do nothing ? */ +#endif + } else { + if(urb->actual_length == 0) + memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE); + } + + /* is not stopped, re-submit urb */ + if (as102_dev->streaming) + as102_submit_urb_stream(as102_dev, urb); +} + +static void as102_free_usb_stream_buffer(struct as102_dev_t *dev) { + int i; + + ENTER(); + + for (i = 0; i < MAX_STREAM_URB; i++) + usb_free_urb(dev->stream_urb[i]); + + usb_buffer_free(dev->bus_adap.usb_dev, + MAX_STREAM_URB * AS102_USB_BUF_SIZE, + dev->stream, + dev->dma_addr); + LEAVE(); +} + +static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) { + int i, ret = 0; + + ENTER(); + + dev->stream = usb_buffer_alloc(dev->bus_adap.usb_dev, + MAX_STREAM_URB * AS102_USB_BUF_SIZE, + GFP_KERNEL, + &dev->dma_addr); + if (!dev->stream) { + dprintk(debug, "%s: usb_buffer_alloc failed\n", __FUNCTION__); + return -ENOMEM; + } + + memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE); + + /* init urb buffers */ + for (i = 0; i < MAX_STREAM_URB; i++) { + struct urb *urb; + + if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) { + dprintk(debug, "%s: usb_alloc_urb failed\n", __FUNCTION__); + as102_free_usb_stream_buffer(dev); + return -ENOMEM; + } + + urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE); + urb->transfer_buffer_length = AS102_USB_BUF_SIZE; + + dev->stream_urb[i] = urb; + } + LEAVE(); + return ret; +} + +static void as102_usb_stop_stream(struct as102_dev_t *dev) { + int i; + + for (i = 0; i < MAX_STREAM_URB; i++) + usb_kill_urb(dev->stream_urb[i]); +} + +static int as102_usb_start_stream(struct as102_dev_t *dev) { + int i, ret = 0; + + for (i = 0; i < MAX_STREAM_URB; i++) { + if ((ret = as102_submit_urb_stream(dev, dev->stream_urb[i]))) { + as102_usb_stop_stream(dev); + return ret; + } + } + + return 0; +} + +static void as102_usb_release(struct kref *kref) { + struct as102_dev_t *as102_dev; + + ENTER(); + + as102_dev = container_of(kref, struct as102_dev_t, kref); + if (as102_dev != NULL) { + usb_put_dev(as102_dev->bus_adap.usb_dev); + kfree(as102_dev); + } + + LEAVE(); +} + +static void as102_usb_disconnect(struct usb_interface *intf) { + struct as102_dev_t *as102_dev; + + ENTER(); + + /* extract as102_dev_t from usb_device private data */ + as102_dev = usb_get_intfdata(intf); + + /* unregister dvb layer */ + as102_dvb_unregister(as102_dev); + + /* free usb buffers */ + as102_free_usb_stream_buffer(as102_dev); + + usb_set_intfdata(intf, NULL); + + /* usb unregister device */ + usb_deregister_dev(intf, &as102_usb_class_driver); + + /* decrement usage counter */ + kref_put(&as102_dev->kref, as102_usb_release); + + printk(KERN_INFO "%s: device has been disconnected\n", DRIVER_NAME); + + LEAVE(); +} + +static int as102_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) { + int ret; + struct as102_dev_t *as102_dev; + + ENTER(); + + if(!(as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL))) { + err("%s: kzalloc failed", __FUNCTION__); + return -ENOMEM; + } + + /* set private callback functions */ + as102_dev->bus_adap.ops = &as102_priv_ops; + + /* init cmd token for usb bus */ + as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c; + as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r; + + /* init kernel device reference */ + kref_init(&as102_dev->kref); + + /* store as102 device to usb_device private data */ + usb_set_intfdata(intf, (void *) as102_dev); + + /* store in as102 device the usb_device pointer */ + as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf)); + + /* we can register the device now, as it is ready */ + if((ret = usb_register_dev(intf, &as102_usb_class_driver)) < 0) {; + /* something prevented us from registering this driver */ + err("%s: usb_register_dev() failed (errno = %d)", + __FUNCTION__, ret); + goto failed; + } + + printk(KERN_INFO "%s: device has been detected\n", DRIVER_NAME); + + /* request buffer allocation for streaming */ + if ((ret = as102_alloc_usb_stream_buffer(as102_dev)) != 0) + goto failed; + + /* register dvb layer */ + ret = as102_dvb_register(as102_dev); + + LEAVE(); + return ret; + +failed: + usb_set_intfdata(intf, NULL); + kfree(as102_dev); + return ret; +} + +static int as102_open(struct inode *inode, struct file *file) { + int ret = 0, minor = 0; + struct usb_interface *intf = NULL; + struct as102_dev_t *dev = NULL; + + ENTER(); + + /* read minor from inode */ + minor = iminor(inode); + + /* fetch device from usb interface */ + if((intf = usb_find_interface(&as102_usb_driver, minor)) == NULL) { + printk(KERN_ERR "%s: can't find device for minor %d\n", + __FUNCTION__, minor); + ret = -ENODEV; + goto exit; + } + + /* get our device */ + if((dev = usb_get_intfdata(intf)) == NULL) { + ret = -EFAULT; + goto exit; + } + + /* save our device object in the file's private structure */ + file->private_data = dev; + + /* increment our usage count for the device */ + kref_get(&dev->kref); + +exit: + LEAVE(); + return ret; +} + +static int as102_release(struct inode *inode, struct file *file) { + int ret = 0; + struct as102_dev_t *dev = NULL; + + ENTER(); + + if((dev = file->private_data) != NULL ) { + /* decrement the count on our device */ + kref_put(&dev->kref, as102_usb_release); + } + + LEAVE(); + return ret; +} + +MODULE_DEVICE_TABLE(usb, as102_usb_id_table); + +/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h new file mode 100644 index 000000000000..abb858ececbe --- /dev/null +++ b/drivers/staging/media/as102/as102_usb_drv.h @@ -0,0 +1,54 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#ifndef _AS102_USB_DRV_H_ +#define _AS102_USB_DRV_H_ + +#define AS102_USB_DEVICE_TX_CTRL_CMD 0xF1 +#define AS102_USB_DEVICE_RX_CTRL_CMD 0xF2 + +/* define these values to match the supported devices */ + +/* Abilis system: "TITAN" */ +#define AS102_USB_DEVICE_VENDOR_ID 0x1BA6 +#define AS102_USB_DEVICE_PID_0001 0x0001 + +/* PCTV Systems: PCTV picoStick (74e) */ +#define DEVICE_FULL_NAME "PCTV Systems : PCTV picoStick (74e)" +#define PCTV_74E_USB_VID 0x2013 +#define PCTV_74E_USB_PID 0x0246 + +extern struct file_operations as102_dev_fops; + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)) +void as102_urb_stream_irq(struct urb *urb, struct pt_regs *regs); +#else +void as102_urb_stream_irq(struct urb *urb); +#endif + + +struct as10x_usb_token_cmd_t { + /* token cmd */ + struct as10x_cmd_t c; + /* token response */ + struct as10x_cmd_t r; +}; +#endif +/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c new file mode 100644 index 000000000000..cecb809a51a0 --- /dev/null +++ b/drivers/staging/media/as102/as10x_cmd.c @@ -0,0 +1,478 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */ +#include +#include "as102_drv.h" +#elif defined(WIN32) + #if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) /* win32 ddk implementation */ + #include "wdm.h" + #include "Device.h" + #include "endian_mgmt.h" /* FIXME */ + #else /* win32 sdk implementation */ + #include + #include "types.h" + #include "util.h" + #include "as10x_handle.h" + #include "endian_mgmt.h" + #endif +#else /* all other cases */ + #include + #include "types.h" + #include "util.h" + #include "as10x_handle.h" + #include "endian_mgmt.h" /* FIXME */ +#endif /* __KERNEL__ */ + +#include "as10x_types.h" +#include "as10x_cmd.h" + +/** + \brief send turn on command to AS10x + \param phandle: pointer to AS10x handle + \return 0 when no error, < 0 in case of error. + \callgraph +*/ +int as10x_cmd_turn_on(as10x_handle_t *phandle) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd,(++phandle->cmd_xid), sizeof(pcmd->body.turn_on.req)); + + /* fill command */ + pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON); + + /* send command */ + if(phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd( + phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.turn_on.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.turn_on.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP); + +out: + LEAVE(); + return(error); +} + +/** + \brief send turn off command to AS10x + \param phandle: pointer to AS10x handle + \return 0 when no error, < 0 in case of error. + \callgraph +*/ +int as10x_cmd_turn_off(as10x_handle_t *phandle) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd,(++phandle->cmd_xid),sizeof(pcmd->body.turn_off.req)); + + /* fill command */ + pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF); + + /* send command */ + if(phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd( + phandle, (uint8_t *) pcmd, + sizeof(pcmd->body.turn_off.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP); + +out: + LEAVE(); + return(error); +} + +/** + \brief send set tune command to AS10x + \param phandle: pointer to AS10x handle + \param ptune: tune parameters + \return 0 when no error, < 0 in case of error. + \callgraph + */ +int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) +{ + int error; + struct as10x_cmd_t *preq, *prsp; + + ENTER(); + + preq = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(preq,(++phandle->cmd_xid),sizeof(preq->body.set_tune.req)); + + /* fill command */ + preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE); + preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq); + preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; + preq->body.set_tune.req.args.hier_select = ptune->hier_select; + preq->body.set_tune.req.args.constellation = ptune->constellation; + preq->body.set_tune.req.args.hierarchy = ptune->hierarchy; + preq->body.set_tune.req.args.interleaving_mode = ptune->interleaving_mode; + preq->body.set_tune.req.args.code_rate = ptune->code_rate; + preq->body.set_tune.req.args.guard_interval = ptune->guard_interval; + preq->body.set_tune.req.args.transmission_mode = ptune->transmission_mode; + + /* send command */ + if(phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) preq, + sizeof(preq->body.set_tune.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.set_tune.rsp) + HEADER_SIZE); + } else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP); + +out: + LEAVE(); + return(error); +} + +/** + \brief send get tune status command to AS10x + \param phandle: pointer to AS10x handle + \param pstatus: pointer to updated status structure of the current tune + \return 0 when no error, < 0 in case of error. + \callgraph + */ +int as10x_cmd_get_tune_status(as10x_handle_t *phandle, struct as10x_tune_status *pstatus) +{ + int error; + struct as10x_cmd_t *preq, *prsp; + + ENTER(); + + preq = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(preq,(++phandle->cmd_xid), + sizeof(preq->body.get_tune_status.req)); + + /* fill command */ + preq->body.get_tune_status.req.proc_id = + cpu_to_le16(CONTROL_PROC_GETTUNESTAT); + + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd( + phandle, + (uint8_t *) preq, + sizeof(preq->body.get_tune_status.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if (error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP); + if (error < 0) { + goto out; + } + + /* Response OK -> get response data */ + pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state; + pstatus->signal_strength = + le16_to_cpu(prsp->body.get_tune_status.rsp.sts.signal_strength); + pstatus->PER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.PER); + pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER); + +out: + LEAVE(); + return(error); +} + +/** + \brief send get TPS command to AS10x + \param phandle: pointer to AS10x handle + \param ptps: pointer to TPS parameters structure + \return 0 when no error, < 0 in case of error. + \callgraph + */ +int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) +{ + + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid),sizeof(pcmd->body.get_tps.req)); + + /* fill command */ + pcmd->body.get_tune_status.req.proc_id = cpu_to_le16(CONTROL_PROC_GETTPS); + + /* send command */ + if(phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, sizeof(pcmd->body.get_tps.req) + HEADER_SIZE, + (uint8_t *) prsp, sizeof(prsp->body.get_tps.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP); + if (error < 0) { + goto out; + } + + /* Response OK -> get response data */ + ptps->constellation = prsp->body.get_tps.rsp.tps.constellation; + ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy; + ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode; + ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP; + ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP; + ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval; + ptps->transmission_mode = prsp->body.get_tps.rsp.tps.transmission_mode; + ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP; + ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP; + ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID); + +out: + LEAVE(); + return(error); +} + +/** + \brief send get demod stats command to AS10x + \param phandle: pointer to AS10x handle + \param pdemod_stats: pointer to demod stats parameters structure + \return 0 when no error, < 0 in case of error. + \callgraph +*/ +int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, + struct as10x_demod_stats *pdemod_stats) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.get_demod_stats.req)); + + /* fill command */ + pcmd->body.get_demod_stats.req.proc_id = + cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS); + + /* send command */ + if(phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_demod_stats.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_demod_stats.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp,CONTROL_PROC_GET_DEMOD_STATS_RSP); + if (error < 0) { + goto out; + } + + /* Response OK -> get response data */ + pdemod_stats->frame_count = + le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.frame_count); + pdemod_stats->bad_frame_count = + le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bad_frame_count); + pdemod_stats->bytes_fixed_by_rs = + le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs); + pdemod_stats->mer = + le16_to_cpu(prsp->body.get_demod_stats.rsp.stats.mer); + pdemod_stats->has_started = + prsp->body.get_demod_stats.rsp.stats.has_started; + +out: + LEAVE(); + return(error); +} + +/** + \brief send get impulse response command to AS10x + \param phandle: pointer to AS10x handle + \param is_ready: pointer to value indicating when impulse + response data is ready + \return 0 when no error, < 0 in case of error. + \callgraph +*/ +int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, + uint8_t *is_ready) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.get_impulse_rsp.req)); + + /* fill command */ + pcmd->body.get_impulse_rsp.req.proc_id = + cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP); + + /* send command */ + if(phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_impulse_rsp.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_impulse_rsp.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp,CONTROL_PROC_GET_IMPULSE_RESP_RSP); + if (error < 0) { + goto out; + } + + /* Response OK -> get response data */ + *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready; + +out: + LEAVE(); + return(error); +} + + + +/** + \brief build AS10x command header + \param pcmd: pointer to AS10x command buffer + \param xid: sequence id of the command + \param cmd_len: lenght of the command + \return - + \callgraph +*/ +void as10x_cmd_build(struct as10x_cmd_t *pcmd, + uint16_t xid, uint16_t cmd_len) +{ + pcmd->header.req_id = cpu_to_le16(xid); + pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID); + pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION); + pcmd->header.data_len = cpu_to_le16(cmd_len); +} + +/** + \brief Parse command response + \param pcmd: pointer to AS10x command buffer + \param cmd_seqid: sequence id of the command + \param cmd_len: lenght of the command + \return 0 when no error, < 0 in case of error + \callgraph +*/ +int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) +{ + int error; + + /* extract command error code */ + error = prsp->body.common.rsp.error; + + if((error == 0) && (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) { + return 0; + } + + return AS10X_CMD_ERROR; +} + + diff --git a/drivers/staging/media/as102/as10x_cmd.h b/drivers/staging/media/as102/as10x_cmd.h new file mode 100644 index 000000000000..01a716380e0a --- /dev/null +++ b/drivers/staging/media/as102/as10x_cmd.h @@ -0,0 +1,540 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _AS10X_CMD_H_ +#define _AS10X_CMD_H_ + +#ifdef __KERNEL__ +#include +#endif + +#include "as10x_types.h" + +/*********************************/ +/* MACRO DEFINITIONS */ +/*********************************/ +#define AS10X_CMD_ERROR -1 + +#define SERVICE_PROG_ID 0x0002 +#define SERVICE_PROG_VERSION 0x0001 + +#define HIER_NONE 0x00 +#define HIER_LOW_PRIORITY 0x01 + +#define HEADER_SIZE (sizeof(struct as10x_cmd_header_t)) + +/* context request types */ +#define GET_CONTEXT_DATA 1 +#define SET_CONTEXT_DATA 2 + +/* ODSP suspend modes */ +#define CFG_MODE_ODSP_RESUME 0 +#define CFG_MODE_ODSP_SUSPEND 1 + +/* Dump memory size */ +#define DUMP_BLOCK_SIZE_MAX 0x20 + +/*********************************/ +/* TYPE DEFINITION */ +/*********************************/ +typedef enum { + CONTROL_PROC_TURNON = 0x0001, + CONTROL_PROC_TURNON_RSP = 0x0100, + CONTROL_PROC_SET_REGISTER = 0x0002, + CONTROL_PROC_SET_REGISTER_RSP = 0x0200, + CONTROL_PROC_GET_REGISTER = 0x0003, + CONTROL_PROC_GET_REGISTER_RSP = 0x0300, + CONTROL_PROC_SETTUNE = 0x000A, + CONTROL_PROC_SETTUNE_RSP = 0x0A00, + CONTROL_PROC_GETTUNESTAT = 0x000B, + CONTROL_PROC_GETTUNESTAT_RSP = 0x0B00, + CONTROL_PROC_GETTPS = 0x000D, + CONTROL_PROC_GETTPS_RSP = 0x0D00, + CONTROL_PROC_SETFILTER = 0x000E, + CONTROL_PROC_SETFILTER_RSP = 0x0E00, + CONTROL_PROC_REMOVEFILTER = 0x000F, + CONTROL_PROC_REMOVEFILTER_RSP = 0x0F00, + CONTROL_PROC_GET_IMPULSE_RESP = 0x0012, + CONTROL_PROC_GET_IMPULSE_RESP_RSP = 0x1200, + CONTROL_PROC_START_STREAMING = 0x0013, + CONTROL_PROC_START_STREAMING_RSP = 0x1300, + CONTROL_PROC_STOP_STREAMING = 0x0014, + CONTROL_PROC_STOP_STREAMING_RSP = 0x1400, + CONTROL_PROC_GET_DEMOD_STATS = 0x0015, + CONTROL_PROC_GET_DEMOD_STATS_RSP = 0x1500, + CONTROL_PROC_ELNA_CHANGE_MODE = 0x0016, + CONTROL_PROC_ELNA_CHANGE_MODE_RSP = 0x1600, + CONTROL_PROC_ODSP_CHANGE_MODE = 0x0017, + CONTROL_PROC_ODSP_CHANGE_MODE_RSP = 0x1700, + CONTROL_PROC_AGC_CHANGE_MODE = 0x0018, + CONTROL_PROC_AGC_CHANGE_MODE_RSP = 0x1800, + + CONTROL_PROC_CONTEXT = 0x00FC, + CONTROL_PROC_CONTEXT_RSP = 0xFC00, + CONTROL_PROC_DUMP_MEMORY = 0x00FD, + CONTROL_PROC_DUMP_MEMORY_RSP = 0xFD00, + CONTROL_PROC_DUMPLOG_MEMORY = 0x00FE, + CONTROL_PROC_DUMPLOG_MEMORY_RSP = 0xFE00, + CONTROL_PROC_TURNOFF = 0x00FF, + CONTROL_PROC_TURNOFF_RSP = 0xFF00 +} control_proc; + + +#pragma pack(1) +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} TURN_ON; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t err; + } rsp; +} TURN_OFF; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* tune params */ + struct as10x_tune_args args; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } rsp; +} SET_TUNE; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* tune status */ + struct as10x_tune_status sts; + } rsp; +} GET_TUNE_STATUS; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* tps details */ + struct as10x_tps tps; + } rsp; +} GET_TPS; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } rsp; +} COMMON; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* PID to filter */ + uint16_t pid; + /* stream type (MPE, PSI/SI or PES )*/ + uint8_t stream_type; + /* PID index in filter table */ + uint8_t idx; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* Filter id */ + uint8_t filter_id; + } rsp; +} ADD_PID_FILTER; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* PID to remove */ + uint16_t pid; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } rsp; +} DEL_PID_FILTER; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} START_STREAMING; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} STOP_STREAMING; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* demod stats */ + struct as10x_demod_stats stats; + } rsp; +} GET_DEMOD_STATS; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* impulse response ready */ + uint8_t is_ready; + } rsp; +} GET_IMPULSE_RESP; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* value to write (for set context)*/ + struct as10x_register_value reg_val; + /* context tag */ + uint16_t tag; + /* context request type */ + uint16_t type; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* value read (for get context) */ + struct as10x_register_value reg_val; + /* context request type */ + uint16_t type; + /* error */ + uint8_t error; + } rsp; +} FW_CONTEXT; + +typedef union { + /* request */ + struct { + /* response identifier */ + uint16_t proc_id; + /* register description */ + struct as10x_register_addr reg_addr; + /* register content */ + struct as10x_register_value reg_val; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} SET_REGISTER; + +typedef union { + /* request */ + struct { + /* response identifier */ + uint16_t proc_id; + /* register description */ + struct as10x_register_addr reg_addr; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* register content */ + struct as10x_register_value reg_val; + } rsp; +} GET_REGISTER; + +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* mode */ + uint8_t mode; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} CFG_CHANGE_MODE; + +struct as10x_cmd_header_t { + uint16_t req_id; + uint16_t prog; + uint16_t version; + uint16_t data_len; +}; + +#define DUMP_BLOCK_SIZE 16 +typedef union { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* dump memory type request */ + uint8_t dump_req; + /* register description */ + struct as10x_register_addr reg_addr; + /* nb blocks to read */ + uint16_t num_blocks; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* dump response */ + uint8_t dump_rsp; + /* data */ + union { + uint8_t data8[DUMP_BLOCK_SIZE]; + uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)]; + uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)]; + } u; + } rsp; +} DUMP_MEMORY; + +typedef union { + struct { + /* request identifier */ + uint16_t proc_id; + /* dump memory type request */ + uint8_t dump_req; + } req; + struct { + /* request identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* dump response */ + uint8_t dump_rsp; + /* dump data */ + uint8_t data[DUMP_BLOCK_SIZE]; + } rsp; +} DUMPLOG_MEMORY; + +typedef union { + /* request */ + struct { + uint16_t proc_id; + uint8_t data[64 - sizeof(struct as10x_cmd_header_t) -2 /* proc_id */]; + } req; + /* response */ + struct { + uint16_t proc_id; + uint8_t error; + uint8_t data[64 - sizeof(struct as10x_cmd_header_t) /* header */ + - 2 /* proc_id */ - 1 /* rc */]; + } rsp; +} RAW_DATA; + +struct as10x_cmd_t { + /* header */ + struct as10x_cmd_header_t header; + /* body */ + union { + TURN_ON turn_on; + TURN_OFF turn_off; + SET_TUNE set_tune; + GET_TUNE_STATUS get_tune_status; + GET_TPS get_tps; + COMMON common; + ADD_PID_FILTER add_pid_filter; + DEL_PID_FILTER del_pid_filter; + START_STREAMING start_streaming; + STOP_STREAMING stop_streaming; + GET_DEMOD_STATS get_demod_stats; + GET_IMPULSE_RESP get_impulse_rsp; + FW_CONTEXT context; + SET_REGISTER set_register; + GET_REGISTER get_register; + CFG_CHANGE_MODE cfg_change_mode; + DUMP_MEMORY dump_memory; + DUMPLOG_MEMORY dumplog_memory; + RAW_DATA raw_data; + } body; +}; + +struct as10x_token_cmd_t { + /* token cmd */ + struct as10x_cmd_t c; + /* token response */ + struct as10x_cmd_t r; +}; +#pragma pack() + + +/**************************/ +/* FUNCTION DECLARATION */ +/**************************/ + +void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id, + uint16_t cmd_len); +int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id); + +#ifdef __cplusplus +extern "C" { +#endif + +/* as10x cmd */ +int as10x_cmd_turn_on(as10x_handle_t *phandle); +int as10x_cmd_turn_off(as10x_handle_t *phandle); + +int as10x_cmd_set_tune(as10x_handle_t *phandle, + struct as10x_tune_args *ptune); + +int as10x_cmd_get_tune_status(as10x_handle_t *phandle, + struct as10x_tune_status *pstatus); + +int as10x_cmd_get_tps(as10x_handle_t *phandle, + struct as10x_tps *ptps); + +int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, + struct as10x_demod_stats *pdemod_stats); + +int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, + uint8_t *is_ready); + +/* as10x cmd stream */ +int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, + struct as10x_ts_filter *filter); +int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, + uint16_t pid_value); + +int as10x_cmd_start_streaming(as10x_handle_t *phandle); +int as10x_cmd_stop_streaming(as10x_handle_t *phandle); + +/* as10x cmd cfg */ +int as10x_cmd_set_context(as10x_handle_t *phandle, + uint16_t tag, + uint32_t value); +int as10x_cmd_get_context(as10x_handle_t *phandle, + uint16_t tag, + uint32_t *pvalue); + +int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode); +int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id); +#ifdef __cplusplus +} +#endif +#endif +/* EOF - vim: set textwidth=80 ts=3 sw=3 sts=3 et: */ diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c new file mode 100644 index 000000000000..e3a0f90936d4 --- /dev/null +++ b/drivers/staging/media/as102/as10x_cmd_cfg.c @@ -0,0 +1,239 @@ +/** + + \file as10x_cmd_cfg.c + + \version $Id$ + + \author: S. Martinelli + + ----------------------------------------------------------------------------\n + (c) Copyright Abilis Systems SARL 2005-2009 All rigths reserved \n + www.abilis.com \n + ----------------------------------------------------------------------------\n + + \brief AS10x API, configuration services + + AS10x cmd management: build command buffer, send command through + selected port and wait for the response when required. + +*/ + +#if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */ +#include +#include "as102_drv.h" +#elif defined(WIN32) + #if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) /* win32 ddk implementation */ + #include "wdm.h" + #include "Device.h" + #include "endian_mgmt.h" /* FIXME */ + #else /* win32 sdk implementation */ + #include + #include "types.h" + #include "util.h" + #include "as10x_handle.h" + #include "endian_mgmt.h" + #endif +#else /* all other cases */ + #include + #include "types.h" + #include "util.h" + #include "as10x_handle.h" + #include "endian_mgmt.h" /* FIXME */ +#endif /* __KERNEL__ */ + +#include "as10x_types.h" +#include "as10x_cmd.h" + +/***************************/ +/* FUNCTION DEFINITION */ +/***************************/ + +/** + \brief send get context command to AS10x + \param phandle: pointer to AS10x handle + \param tag: context tag + \param pvalue: pointer where to store context value read + \return 0 when no error, < 0 in case of error. + \callgraph +*/ +int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, + uint32_t *pvalue) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.context.req)); + + /* fill command */ + pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); + pcmd->body.context.req.tag = cpu_to_le16(tag); + pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA); + + /* send command */ + if(phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response: context command do not follow the common response */ + /* structure -> specific handling response parse required */ + error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); + + if(error == 0) { + /* Response OK -> get response data */ + *pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32); + /* value returned is always a 32-bit value */ + } + +out: + LEAVE(); + return(error); +} + +/** + \brief send set context command to AS10x + \param phandle: pointer to AS10x handle + \param tag: context tag + \param value: value to set in context + \return 0 when no error, < 0 in case of error. + \callgraph +*/ +int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, + uint32_t value) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd,(++phandle->cmd_xid),sizeof(pcmd->body.context.req)); + + /* fill command */ + pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); + /* pcmd->body.context.req.reg_val.mode initialization is not required */ + pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value); + pcmd->body.context.req.tag = cpu_to_le16(tag); + pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); + + /* send command */ + if(phandle->ops->xfer_cmd){ + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response: context command do not follow the common response */ + /* structure -> specific handling response parse required */ + error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); + +out: + LEAVE(); + return(error); +} + +/** + \brief send eLNA change mode command to AS10x + \param phandle: pointer to AS10x handle + \param tag: context tag + \param mode: mode selected: + - ON : 0x0 => eLNA always ON + - OFF : 0x1 => eLNA always OFF + - AUTO : 0x2 => eLNA follow hysteresis parameters to be + ON or OFF + \return 0 when no error, < 0 in case of error. + \callgraph +*/ +int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.cfg_change_mode.req)); + + /* fill command */ + pcmd->body.cfg_change_mode.req.proc_id = + cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE); + pcmd->body.cfg_change_mode.req.mode = mode; + + /* send command */ + if(phandle->ops->xfer_cmd){ + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.cfg_change_mode.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.cfg_change_mode.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP); + +out: + LEAVE(); + return(error); +} + +/** + \brief Parse context command response. Since this command does not follow + the common response, a specific parse function is required. + \param prsp: pointer to AS10x command response buffer + \param proc_id: id of the command + \return 0 when no error, < 0 in case of error. + ABILIS_RC_NOK + \callgraph +*/ +int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) { + + int err; + + err = prsp->body.context.rsp.error; + + if((err == 0) && + (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) { + return 0; + } + return AS10X_CMD_ERROR; +} diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c new file mode 100644 index 000000000000..4dfacf464ed1 --- /dev/null +++ b/drivers/staging/media/as102/as10x_cmd_stream.c @@ -0,0 +1,256 @@ +/** + + \file as10x_cmd_stream.c + + \version $Id$ + + \author: S. Martinelli + + ----------------------------------------------------------------------------\n + (c) Copyright Abilis Systems SARL 2005-2009 All rigths reserved \n + www.abilis.com \n + ----------------------------------------------------------------------------\n + + \brief AS10x CMD, stream services + + AS10x CMD management: build command buffer, send command through + selected port and wait for the response when required. + +*/ + + +#if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */ +#include +#include "as102_drv.h" +#elif defined(WIN32) + #if defined(DDK) /* win32 ddk implementation */ + #include "wdm.h" + #include "Device.h" + #include "endian_mgmt.h" /* FIXME */ + #else /* win32 sdk implementation */ + #include + #include "types.h" + #include "util.h" + #include "as10x_handle.h" + #include "endian_mgmt.h" + #endif +#else /* all other cases */ + #include + #include "types.h" + #include "util.h" + #include "as10x_handle.h" + #include "endian_mgmt.h" /* FIXME */ +#endif /* __KERNEL__ */ + +#include "as10x_cmd.h" + + +/** + \brief send add filter command to AS10x + \param phandle: pointer to AS10x handle + \param filter: TSFilter filter for DVB-T + \param pfilter_handle: pointer where to store filter handle + \return 0 when no error, < 0 in case of error. + \callgraph +*/ +int as10x_cmd_add_PID_filter(as10x_handle_t* phandle, + struct as10x_ts_filter *filter) { + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.add_pid_filter.req)); + + /* fill command */ + pcmd->body.add_pid_filter.req.proc_id = cpu_to_le16(CONTROL_PROC_SETFILTER); + pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid); + pcmd->body.add_pid_filter.req.stream_type = filter->type; + + if(filter->idx < 16) + pcmd->body.add_pid_filter.req.idx = filter->idx; + else + pcmd->body.add_pid_filter.req.idx = 0xFF; + + /* send command */ + if(phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.add_pid_filter.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.add_pid_filter.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP); + + if(error == 0) { + /* Response OK -> get response data */ + filter->idx = prsp->body.add_pid_filter.rsp.filter_id; + } + +out: + LEAVE(); + return(error); +} + +/** + \brief Send delete filter command to AS10x + \param phandle: pointer to AS10x handle + \param filter_handle: filter handle + \return 0 when no error, < 0 in case of error. + \callgraph +*/ +int as10x_cmd_del_PID_filter(as10x_handle_t* phandle, + uint16_t pid_value) +{ + + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.del_pid_filter.req)); + + /* fill command */ + pcmd->body.del_pid_filter.req.proc_id = cpu_to_le16(CONTROL_PROC_REMOVEFILTER); + pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value); + + /* send command */ + if(phandle->ops->xfer_cmd){ + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.del_pid_filter.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.del_pid_filter.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP); + +out: + LEAVE(); + return(error); +} + +/** + \brief Send start streaming command to AS10x + \param phandle: pointer to AS10x handle + \return 0 when no error, < 0 in case of error.  + \callgraph +*/ +int as10x_cmd_start_streaming(as10x_handle_t* phandle) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.start_streaming.req)); + + /* fill command */ + pcmd->body.start_streaming.req.proc_id = + cpu_to_le16(CONTROL_PROC_START_STREAMING); + + /* send command */ + if(phandle->ops->xfer_cmd){ + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.start_streaming.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.start_streaming.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP); + +out: + LEAVE(); + return(error); +} + +/** + \brief Send stop streaming command to AS10x + \param phandle: pointer to AS10x handle + \return 0 when no error, < 0 in case of error.  + \callgraph +*/ +int as10x_cmd_stop_streaming(as10x_handle_t* phandle) +{ + int8_t error; + struct as10x_cmd_t *pcmd, *prsp; + + ENTER(); + + pcmd = phandle->cmd; + prsp = phandle->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.stop_streaming.req)); + + /* fill command */ + pcmd->body.stop_streaming.req.proc_id = + cpu_to_le16(CONTROL_PROC_STOP_STREAMING); + + /* send command */ + if(phandle->ops->xfer_cmd){ + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.stop_streaming.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.stop_streaming.rsp) + HEADER_SIZE); + } + else{ + error = AS10X_CMD_ERROR; + } + + if(error < 0) { + goto out; + } + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP); + +out: + LEAVE(); + return(error); +} + + diff --git a/drivers/staging/media/as102/as10x_handle.h b/drivers/staging/media/as102/as10x_handle.h new file mode 100644 index 000000000000..4f01a76e9829 --- /dev/null +++ b/drivers/staging/media/as102/as10x_handle.h @@ -0,0 +1,58 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifdef __KERNEL__ +struct as102_bus_adapter_t; +struct as102_dev_t; + +#define as10x_handle_t struct as102_bus_adapter_t +#include "as10x_cmd.h" + +/* values for "mode" field */ +#define REGMODE8 8 +#define REGMODE16 16 +#define REGMODE32 32 + +struct as102_priv_ops_t { + int (*upload_fw_pkt) (struct as102_bus_adapter_t *bus_adap, + unsigned char *buf, int buflen, int swap32); + + int (*send_cmd) (struct as102_bus_adapter_t *bus_adap, + unsigned char *buf, int buflen); + + int (*xfer_cmd) (struct as102_bus_adapter_t *bus_adap, + unsigned char *send_buf, int send_buf_len, + unsigned char *recv_buf, int recv_buf_len); +/* + int (*pid_filter) (struct as102_bus_adapter_t *bus_adap, + int index, u16 pid, int onoff); +*/ + int (*start_stream) (struct as102_dev_t *dev); + void (*stop_stream) (struct as102_dev_t *dev); + + int (*reset_target) (struct as102_bus_adapter_t *bus_adap); + + int (*read_write)(struct as102_bus_adapter_t *bus_adap, uint8_t mode, + uint32_t rd_addr, uint16_t rd_len, + uint32_t wr_addr, uint16_t wr_len); + + int (*as102_read_ep2) (struct as102_bus_adapter_t *bus_adap, + unsigned char *recv_buf, + int recv_buf_len); +}; +#endif diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/staging/media/as102/as10x_types.h new file mode 100644 index 000000000000..3dedb3c1420a --- /dev/null +++ b/drivers/staging/media/as102/as10x_types.h @@ -0,0 +1,198 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _AS10X_TYPES_H_ +#define _AS10X_TYPES_H_ + +#include "as10x_handle.h" + +/*********************************/ +/* MACRO DEFINITIONS */ +/*********************************/ + +/* bandwidth constant values */ +#define BW_5_MHZ 0x00 +#define BW_6_MHZ 0x01 +#define BW_7_MHZ 0x02 +#define BW_8_MHZ 0x03 + +/* hierarchy priority selection values */ +#define HIER_NO_PRIORITY 0x00 +#define HIER_LOW_PRIORITY 0x01 +#define HIER_HIGH_PRIORITY 0x02 + +/* constellation available values */ +#define CONST_QPSK 0x00 +#define CONST_QAM16 0x01 +#define CONST_QAM64 0x02 +#define CONST_UNKNOWN 0xFF + +/* hierarchy available values */ +#define HIER_NONE 0x00 +#define HIER_ALPHA_1 0x01 +#define HIER_ALPHA_2 0x02 +#define HIER_ALPHA_4 0x03 +#define HIER_UNKNOWN 0xFF + +/* interleaving available values */ +#define INTLV_NATIVE 0x00 +#define INTLV_IN_DEPTH 0x01 +#define INTLV_UNKNOWN 0xFF + +/* code rate available values */ +#define CODE_RATE_1_2 0x00 +#define CODE_RATE_2_3 0x01 +#define CODE_RATE_3_4 0x02 +#define CODE_RATE_5_6 0x03 +#define CODE_RATE_7_8 0x04 +#define CODE_RATE_UNKNOWN 0xFF + +/* guard interval available values */ +#define GUARD_INT_1_32 0x00 +#define GUARD_INT_1_16 0x01 +#define GUARD_INT_1_8 0x02 +#define GUARD_INT_1_4 0x03 +#define GUARD_UNKNOWN 0xFF + +/* transmission mode available values */ +#define TRANS_MODE_2K 0x00 +#define TRANS_MODE_8K 0x01 +#define TRANS_MODE_4K 0x02 +#define TRANS_MODE_UNKNOWN 0xFF + +/* DVBH signalling available values */ +#define TIMESLICING_PRESENT 0x01 +#define MPE_FEC_PRESENT 0x02 + +/* tune state available */ +#define TUNE_STATUS_NOT_TUNED 0x00 +#define TUNE_STATUS_IDLE 0x01 +#define TUNE_STATUS_LOCKING 0x02 +#define TUNE_STATUS_SIGNAL_DVB_OK 0x03 +#define TUNE_STATUS_STREAM_DETECTED 0x04 +#define TUNE_STATUS_STREAM_TUNED 0x05 +#define TUNE_STATUS_ERROR 0xFF + +/* available TS FID filter types */ +#define TS_PID_TYPE_TS 0 +#define TS_PID_TYPE_PSI_SI 1 +#define TS_PID_TYPE_MPE 2 + +/* number of echos available */ +#define MAX_ECHOS 15 + +/* Context types */ +#define CONTEXT_LNA 1010 +#define CONTEXT_ELNA_HYSTERESIS 4003 +#define CONTEXT_ELNA_GAIN 4004 +#define CONTEXT_MER_THRESHOLD 5005 +#define CONTEXT_MER_OFFSET 5006 +#define CONTEXT_IR_STATE 7000 +#define CONTEXT_TSOUT_MSB_FIRST 7004 +#define CONTEXT_TSOUT_FALLING_EDGE 7005 + +/* Configuration modes */ +#define CFG_MODE_ON 0 +#define CFG_MODE_OFF 1 +#define CFG_MODE_AUTO 2 + +#pragma pack(1) +struct as10x_tps { + uint8_t constellation; + uint8_t hierarchy; + uint8_t interleaving_mode; + uint8_t code_rate_HP; + uint8_t code_rate_LP; + uint8_t guard_interval; + uint8_t transmission_mode; + uint8_t DVBH_mask_HP; + uint8_t DVBH_mask_LP; + uint16_t cell_ID; +}; + +struct as10x_tune_args { + /* frequency */ + uint32_t freq; + /* bandwidth */ + uint8_t bandwidth; + /* hierarchy selection */ + uint8_t hier_select; + /* constellation */ + uint8_t constellation; + /* hierarchy */ + uint8_t hierarchy; + /* interleaving mode */ + uint8_t interleaving_mode; + /* code rate */ + uint8_t code_rate; + /* guard interval */ + uint8_t guard_interval; + /* transmission mode */ + uint8_t transmission_mode; +}; + +struct as10x_tune_status { + /* tune status */ + uint8_t tune_state; + /* signal strength */ + int16_t signal_strength; + /* packet error rate 10^-4 */ + uint16_t PER; + /* bit error rate 10^-4 */ + uint16_t BER; +}; + +struct as10x_demod_stats { + /* frame counter */ + uint32_t frame_count; + /* Bad frame counter */ + uint32_t bad_frame_count; + /* Number of wrong bytes fixed by Reed-Solomon */ + uint32_t bytes_fixed_by_rs; + /* Averaged MER */ + uint16_t mer; + /* statistics calculation state indicator (started or not) */ + uint8_t has_started; +}; + +struct as10x_ts_filter { + uint16_t pid; /** valid PID value 0x00 : 0x2000 */ + uint8_t type; /** Red TS_PID_TYPE_ values */ + uint8_t idx; /** index in filtering table */ +}; + +struct as10x_register_value { + uint8_t mode; + union { + uint8_t value8; /* 8 bit value */ + uint16_t value16; /* 16 bit value */ + uint32_t value32; /* 32 bit value */ + }u; +}; + +#pragma pack() + +struct as10x_register_addr { + /* register addr */ + uint32_t addr; + /* register mode access */ + uint8_t mode; +}; + + +#endif From c6ccdca9801604e9e2797677f1a78c2c534b2f1f Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 31 Oct 2011 12:24:40 -0300 Subject: [PATCH 008/144] [media] staging: as102: Fix CodingStyle errors in file as102_drv.c Fix Linux kernel coding style (whitespace and indentation) errors in file as102_drv.c. Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_drv.c | 96 +++++++++++++------------ 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c index c334bffa36e4..9e5d81bb3432 100644 --- a/drivers/staging/media/as102/as102_drv.c +++ b/drivers/staging/media/as102/as102_drv.c @@ -1,6 +1,7 @@ /* * Abilis Systems Single DVB-T Receiver * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,23 +37,23 @@ #warning >>> DVB_CORE not defined !!! <<< #endif -int debug = 0; +int debug; module_param_named(debug, debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)"); -int dual_tuner = 0; +int dual_tuner; module_param_named(dual_tuner, dual_tuner, int, 0644); -MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner configuration (default: off)"); +MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)"); static int fw_upload = 1; module_param_named(fw_upload, fw_upload, int, 0644); MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)"); -static int pid_filtering = 0; +static int pid_filtering; module_param_named(pid_filtering, pid_filtering, int, 0644); MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)"); -static int ts_auto_disable = 0; +static int ts_auto_disable; module_param_named(ts_auto_disable, ts_auto_disable, int, 0644); MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)"); @@ -65,7 +66,8 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #endif #if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) -static void as102_stop_stream(struct as102_dev_t *dev) { +static void as102_stop_stream(struct as102_dev_t *dev) +{ struct as102_bus_adapter_t *bus_adap; if (dev != NULL) @@ -80,16 +82,15 @@ static void as102_stop_stream(struct as102_dev_t *dev) { if (mutex_lock_interruptible(&dev->bus_adap.lock)) return; - if (as10x_cmd_stop_streaming(bus_adap) < 0) { + if (as10x_cmd_stop_streaming(bus_adap) < 0) dprintk(debug, "as10x_cmd_stop_streaming failed\n"); - } mutex_unlock(&dev->bus_adap.lock); } } -static int as102_start_stream(struct as102_dev_t *dev) { - +static int as102_start_stream(struct as102_dev_t *dev) +{ struct as102_bus_adapter_t *bus_adap; int ret = -EFAULT; @@ -98,9 +99,8 @@ static int as102_start_stream(struct as102_dev_t *dev) { else return ret; - if (bus_adap->ops->start_stream != NULL) { + if (bus_adap->ops->start_stream != NULL) ret = bus_adap->ops->start_stream(dev); - } if (ts_auto_disable) { if (mutex_lock_interruptible(&dev->bus_adap.lock)) @@ -127,25 +127,25 @@ static int as10x_pid_filter(struct as102_dev_t *dev, return -EBUSY; } - switch(onoff) { - case 0: - ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); - dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", - index, pid, ret); - break; - case 1: - { - struct as10x_ts_filter filter; + switch (onoff) { + case 0: + ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); + dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", + index, pid, ret); + break; + case 1: + { + struct as10x_ts_filter filter; - filter.type = TS_PID_TYPE_TS; - filter.idx = 0xFF; - filter.pid = pid; + filter.type = TS_PID_TYPE_TS; + filter.idx = 0xFF; + filter.pid = pid; - ret = as10x_cmd_add_PID_filter(bus_adap, &filter); - dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", - index, filter.idx, filter.pid, ret); - break; - } + ret = as10x_cmd_add_PID_filter(bus_adap, &filter); + dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", + index, filter.idx, filter.pid, ret); + break; + } } mutex_unlock(&dev->bus_adap.lock); @@ -154,7 +154,8 @@ static int as10x_pid_filter(struct as102_dev_t *dev, return ret; } -static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) { +static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ int ret = 0; struct dvb_demux *demux = dvbdmxfeed->demux; struct as102_dev_t *as102_dev = demux->priv; @@ -169,16 +170,16 @@ static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) { dvbdmxfeed->index, dvbdmxfeed->pid, 1); } - if (as102_dev->streaming++ == 0) { + if (as102_dev->streaming++ == 0) ret = as102_start_stream(as102_dev); - } mutex_unlock(&as102_dev->sem); LEAVE(); return ret; } -static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { +static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ struct dvb_demux *demux = dvbdmxfeed->demux; struct as102_dev_t *as102_dev = demux->priv; @@ -187,9 +188,8 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { if (mutex_lock_interruptible(&as102_dev->sem)) return -ERESTARTSYS; - if (--as102_dev->streaming == 0) { + if (--as102_dev->streaming == 0) as102_stop_stream(as102_dev); - } if (pid_filtering) { as10x_pid_filter(as102_dev, @@ -202,7 +202,8 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { } #endif -int as102_dvb_register(struct as102_dev_t *as102_dev) { +int as102_dvb_register(struct as102_dev_t *as102_dev) +{ int ret = 0; ENTER(); @@ -223,7 +224,7 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) { ); if (ret < 0) { err("%s: dvb_register_adapter() failed (errno = %d)", - __FUNCTION__, ret); + __func__, ret); goto failed; } @@ -240,23 +241,23 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) { as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx; as102_dev->dvb_dmxdev.capabilities = 0; - if ((ret = dvb_dmx_init(&as102_dev->dvb_dmx)) < 0) { - err("%s: dvb_dmx_init() failed (errno = %d)", - __FUNCTION__, ret); + ret = dvb_dmx_init(&as102_dev->dvb_dmx); + if (ret < 0) { + err("%s: dvb_dmx_init() failed (errno = %d)", __func__, ret); goto failed; } ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap); if (ret < 0) { - err("%s: dvb_dmxdev_init() failed (errno = %d)", - __FUNCTION__, ret); + err("%s: dvb_dmxdev_init() failed (errno = %d)", __func__, + ret); goto failed; } ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe); if (ret < 0) { err("%s: as102_dvb_register_frontend() failed (errno = %d)", - __FUNCTION__, ret); + __func__, ret); goto failed; } #endif @@ -283,7 +284,8 @@ failed: return ret; } -void as102_dvb_unregister(struct as102_dev_t *as102_dev) { +void as102_dvb_unregister(struct as102_dev_t *as102_dev) +{ ENTER(); #if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) @@ -300,7 +302,8 @@ void as102_dvb_unregister(struct as102_dev_t *as102_dev) { LEAVE(); } -static int __init as102_driver_init(void) { +static int __init as102_driver_init(void) +{ int ret = 0; ENTER(); @@ -331,7 +334,8 @@ module_init(as102_driver_init); * \brief as102 driver exit point. This function is called when device has * to be removed. */ -static void __exit as102_driver_exit(void) { +static void __exit as102_driver_exit(void) +{ ENTER(); /* deregister this driver with the low level bus subsystem */ #if defined(CONFIG_AS102_USB) From e54d081dacdcdee7d10c1f87bacce89044519c5c Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 31 Oct 2011 12:24:41 -0300 Subject: [PATCH 009/144] [media] staging: as102: Fix CodingStyle errors in file as102_fw.c Fix Linux kernel coding style (whitespace and indentation) errors in file as102_fw.c. No functional changes. Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_fw.c | 101 ++++++++++++++----------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c index d921a6fd6953..c019df933cc9 100644 --- a/drivers/staging/media/as102/as102_fw.c +++ b/drivers/staging/media/as102/as102_fw.c @@ -1,6 +1,7 @@ /* * Abilis Systems Single DVB-T Receiver * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,15 +32,16 @@ char as102_st_fw2[] = "as102_data2_st.hex"; char as102_dt_fw1[] = "as102_data1_dt.hex"; char as102_dt_fw2[] = "as102_data2_dt.hex"; -static unsigned char atohx(unsigned char *dst, char *src) { +static unsigned char atohx(unsigned char *dst, char *src) +{ unsigned char value = 0; char msb = tolower(*src) - '0'; - char lsb = tolower(*(src +1)) - '0'; + char lsb = tolower(*(src + 1)) - '0'; - if (msb > 9 ) + if (msb > 9) msb -= 7; - if (lsb > 9 ) + if (lsb > 9) lsb -= 7; *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF); @@ -62,43 +64,42 @@ static int parse_hex_line(unsigned char *fw_data, unsigned char *addr, } /* locate end of line */ - for (src=fw_data; *src != '\n'; src += 2) { + for (src = fw_data; *src != '\n'; src += 2) { atohx(&dst, src); /* parse line to split addr / data */ switch (count) { - case 0: - *dataLength = dst; - break; - case 1: - addr[2] = dst; - break; - case 2: - addr[3] = dst; - break; - case 3: - /* check if data is an address */ - if (dst == 0x04) - *addr_has_changed = 1; - else - *addr_has_changed = 0; - break; - case 4: - case 5: - if (*addr_has_changed) { - addr[(count - 4)] = dst; - } else { - data[(count - 4)] = dst; - } - break; - default: + case 0: + *dataLength = dst; + break; + case 1: + addr[2] = dst; + break; + case 2: + addr[3] = dst; + break; + case 3: + /* check if data is an address */ + if (dst == 0x04) + *addr_has_changed = 1; + else + *addr_has_changed = 0; + break; + case 4: + case 5: + if (*addr_has_changed) + addr[(count - 4)] = dst; + else data[(count - 4)] = dst; - break; + break; + default: + data[(count - 4)] = dst; + break; } count++; } /* return read value + ':' + '\n' */ - return ((count * 2) + 2); + return (count * 2) + 2; } static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap, @@ -122,17 +123,20 @@ static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap, &data_len, &addr_has_changed); - if (read_bytes <= 0) { + if (read_bytes <= 0) goto error; - } /* detect the end of file */ - if ((total_read_bytes += read_bytes) == firmware->size) { + total_read_bytes += read_bytes; + if (total_read_bytes == firmware->size) { fw_pkt.u.request[0] = 0x00; fw_pkt.u.request[1] = 0x03; /* send EOF command */ - if ((errno = bus_adap->ops->upload_fw_pkt(bus_adap,(uint8_t *) &fw_pkt, 2, 0)) < 0) + errno = bus_adap->ops->upload_fw_pkt(bus_adap, + (uint8_t *) + &fw_pkt, 2, 0); + if (errno < 0) goto error; } else { if (!addr_has_changed) { @@ -144,7 +148,12 @@ static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap, data_len += sizeof(fw_pkt.raw.address); /* send cmd to device */ - if ((errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) &fw_pkt, data_len, 0)) < 0) + errno = bus_adap->ops->upload_fw_pkt(bus_adap, + (uint8_t *) + &fw_pkt, + data_len, + 0); + if (errno < 0) goto error; } } @@ -154,7 +163,8 @@ error: return (errno == 0) ? total_read_bytes : errno; } -int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) { +int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) +{ int errno = -EFAULT; const struct firmware *firmware; unsigned char *cmd_buf = NULL; @@ -179,20 +189,23 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) { #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) /* allocate buffer to store firmware upload command and data */ - if ((cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL)) == NULL) { + cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL); + if (cmd_buf == NULL) { errno = -ENOMEM; goto error; } /* request kernel to locate firmware file: part1 */ - if ((errno = request_firmware(&firmware, fw1, &dev->dev)) < 0) { + errno = request_firmware(&firmware, fw1, &dev->dev); + if (errno < 0) { printk(KERN_ERR "%s: unable to locate firmware file: %s\n", DRIVER_NAME, fw1); goto error; } /* initiate firmware upload */ - if ((errno = as102_firmware_upload(bus_adap, cmd_buf, firmware)) < 0) { + errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); + if (errno < 0) { printk(KERN_ERR "%s: error during firmware upload part1\n", DRIVER_NAME); goto error; @@ -206,14 +219,16 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) { mdelay(100); /* request kernel to locate firmware file: part2 */ - if ((errno = request_firmware(&firmware, fw2, &dev->dev)) < 0) { + errno = request_firmware(&firmware, fw2, &dev->dev); + if (errno < 0) { printk(KERN_ERR "%s: unable to locate firmware file: %s\n", DRIVER_NAME, fw2); goto error; } /* initiate firmware upload */ - if ((errno = as102_firmware_upload(bus_adap, cmd_buf, firmware)) < 0) { + errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); + if (errno < 0) { printk(KERN_ERR "%s: error during firmware upload part2\n", DRIVER_NAME); goto error; From 9cc08121f177e9618fe9108b0f5e2fb690d4df33 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 31 Oct 2011 12:24:42 -0300 Subject: [PATCH 010/144] [media] staging: as102: Fix CodingStyle errors in file as10x_cmd.c Fix Linux kernel coding style (whitespace and indentation) errors in file as10x_cmd.c. No functional changes. Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as10x_cmd.c | 505 ++++++++++++------------ 1 file changed, 254 insertions(+), 251 deletions(-) diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c index cecb809a51a0..222e7032ded2 100644 --- a/drivers/staging/media/as102/as10x_cmd.c +++ b/drivers/staging/media/as102/as10x_cmd.c @@ -1,6 +1,7 @@ /* * Abilis Systems Single DVB-T Receiver * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,7 +22,8 @@ #include #include "as102_drv.h" #elif defined(WIN32) - #if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) /* win32 ddk implementation */ + #if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) + /* win32 ddk implementation */ #include "wdm.h" #include "Device.h" #include "endian_mgmt.h" /* FIXME */ @@ -51,43 +53,42 @@ */ int as10x_cmd_turn_on(as10x_handle_t *phandle) { - int error; - struct as10x_cmd_t *pcmd, *prsp; + int error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd,(++phandle->cmd_xid), sizeof(pcmd->body.turn_on.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.turn_on.req)); - /* fill command */ - pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON); + /* fill command */ + pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON); - /* send command */ - if(phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd( - phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.turn_on.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.turn_on.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + sizeof(pcmd->body.turn_on.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.turn_on.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP); + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP); out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -98,42 +99,41 @@ out: */ int as10x_cmd_turn_off(as10x_handle_t *phandle) { - int error; - struct as10x_cmd_t *pcmd, *prsp; + int error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd,(++phandle->cmd_xid),sizeof(pcmd->body.turn_off.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.turn_off.req)); - /* fill command */ - pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF); + /* fill command */ + pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF); - /* send command */ - if(phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd( + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd( phandle, (uint8_t *) pcmd, sizeof(pcmd->body.turn_off.req) + HEADER_SIZE, - (uint8_t *) prsp, + (uint8_t *) prsp, sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP); + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP); out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -145,50 +145,54 @@ out: */ int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) { - int error; - struct as10x_cmd_t *preq, *prsp; + int error; + struct as10x_cmd_t *preq, *prsp; - ENTER(); + ENTER(); - preq = phandle->cmd; - prsp = phandle->rsp; + preq = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(preq,(++phandle->cmd_xid),sizeof(preq->body.set_tune.req)); + /* prepare command */ + as10x_cmd_build(preq, (++phandle->cmd_xid), + sizeof(preq->body.set_tune.req)); - /* fill command */ - preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE); - preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq); - preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; - preq->body.set_tune.req.args.hier_select = ptune->hier_select; - preq->body.set_tune.req.args.constellation = ptune->constellation; - preq->body.set_tune.req.args.hierarchy = ptune->hierarchy; - preq->body.set_tune.req.args.interleaving_mode = ptune->interleaving_mode; - preq->body.set_tune.req.args.code_rate = ptune->code_rate; - preq->body.set_tune.req.args.guard_interval = ptune->guard_interval; - preq->body.set_tune.req.args.transmission_mode = ptune->transmission_mode; + /* fill command */ + preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE); + preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq); + preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; + preq->body.set_tune.req.args.hier_select = ptune->hier_select; + preq->body.set_tune.req.args.constellation = ptune->constellation; + preq->body.set_tune.req.args.hierarchy = ptune->hierarchy; + preq->body.set_tune.req.args.interleaving_mode = + ptune->interleaving_mode; + preq->body.set_tune.req.args.code_rate = ptune->code_rate; + preq->body.set_tune.req.args.guard_interval = ptune->guard_interval; + preq->body.set_tune.req.args.transmission_mode = + ptune->transmission_mode; - /* send command */ - if(phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) preq, - sizeof(preq->body.set_tune.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.set_tune.rsp) + HEADER_SIZE); - } else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) preq, + sizeof(preq->body.set_tune.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.set_tune.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP); + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP); out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -198,57 +202,55 @@ out: \return 0 when no error, < 0 in case of error. \callgraph */ -int as10x_cmd_get_tune_status(as10x_handle_t *phandle, struct as10x_tune_status *pstatus) +int as10x_cmd_get_tune_status(as10x_handle_t *phandle, + struct as10x_tune_status *pstatus) { - int error; - struct as10x_cmd_t *preq, *prsp; + int error; + struct as10x_cmd_t *preq, *prsp; - ENTER(); + ENTER(); - preq = phandle->cmd; - prsp = phandle->rsp; + preq = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(preq,(++phandle->cmd_xid), - sizeof(preq->body.get_tune_status.req)); + /* prepare command */ + as10x_cmd_build(preq, (++phandle->cmd_xid), + sizeof(preq->body.get_tune_status.req)); - /* fill command */ - preq->body.get_tune_status.req.proc_id = - cpu_to_le16(CONTROL_PROC_GETTUNESTAT); + /* fill command */ + preq->body.get_tune_status.req.proc_id = + cpu_to_le16(CONTROL_PROC_GETTUNESTAT); - /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd( + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd( phandle, (uint8_t *) preq, sizeof(preq->body.get_tune_status.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + } else { + error = AS10X_CMD_ERROR; + } - if (error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP); - if (error < 0) { - goto out; - } + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP); + if (error < 0) + goto out; - /* Response OK -> get response data */ - pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state; - pstatus->signal_strength = - le16_to_cpu(prsp->body.get_tune_status.rsp.sts.signal_strength); - pstatus->PER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.PER); - pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER); + /* Response OK -> get response data */ + pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state; + pstatus->signal_strength = + le16_to_cpu(prsp->body.get_tune_status.rsp.sts.signal_strength); + pstatus->PER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.PER); + pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER); out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -260,56 +262,58 @@ out: */ int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) { + int error; + struct as10x_cmd_t *pcmd, *prsp; - int error; - struct as10x_cmd_t *pcmd, *prsp; + ENTER(); - ENTER(); + pcmd = phandle->cmd; + prsp = phandle->rsp; - pcmd = phandle->cmd; - prsp = phandle->rsp; + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.get_tps.req)); - /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid),sizeof(pcmd->body.get_tps.req)); + /* fill command */ + pcmd->body.get_tune_status.req.proc_id = + cpu_to_le16(CONTROL_PROC_GETTPS); - /* fill command */ - pcmd->body.get_tune_status.req.proc_id = cpu_to_le16(CONTROL_PROC_GETTPS); + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_tps.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_tps.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - /* send command */ - if(phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, sizeof(pcmd->body.get_tps.req) + HEADER_SIZE, - (uint8_t *) prsp, sizeof(prsp->body.get_tps.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + if (error < 0) + goto out; - if(error < 0) { - goto out; - } + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP); + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP); - if (error < 0) { - goto out; - } - - /* Response OK -> get response data */ - ptps->constellation = prsp->body.get_tps.rsp.tps.constellation; - ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy; - ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode; - ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP; - ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP; - ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval; - ptps->transmission_mode = prsp->body.get_tps.rsp.tps.transmission_mode; - ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP; - ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP; - ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID); + /* Response OK -> get response data */ + ptps->constellation = prsp->body.get_tps.rsp.tps.constellation; + ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy; + ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode; + ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP; + ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP; + ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval; + ptps->transmission_mode = prsp->body.get_tps.rsp.tps.transmission_mode; + ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP; + ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP; + ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID); out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -322,59 +326,58 @@ out: int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, struct as10x_demod_stats *pdemod_stats) { - int error; - struct as10x_cmd_t *pcmd, *prsp; + int error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), - sizeof(pcmd->body.get_demod_stats.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.get_demod_stats.req)); - /* fill command */ - pcmd->body.get_demod_stats.req.proc_id = - cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS); + /* fill command */ + pcmd->body.get_demod_stats.req.proc_id = + cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS); - /* send command */ - if(phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.get_demod_stats.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.get_demod_stats.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_demod_stats.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_demod_stats.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp,CONTROL_PROC_GET_DEMOD_STATS_RSP); - if (error < 0) { - goto out; - } + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP); + if (error < 0) + goto out; - /* Response OK -> get response data */ - pdemod_stats->frame_count = - le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.frame_count); - pdemod_stats->bad_frame_count = - le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bad_frame_count); - pdemod_stats->bytes_fixed_by_rs = - le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs); - pdemod_stats->mer = - le16_to_cpu(prsp->body.get_demod_stats.rsp.stats.mer); - pdemod_stats->has_started = - prsp->body.get_demod_stats.rsp.stats.has_started; + /* Response OK -> get response data */ + pdemod_stats->frame_count = + le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.frame_count); + pdemod_stats->bad_frame_count = + le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bad_frame_count); + pdemod_stats->bytes_fixed_by_rs = + le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs); + pdemod_stats->mer = + le16_to_cpu(prsp->body.get_demod_stats.rsp.stats.mer); + pdemod_stats->has_started = + prsp->body.get_demod_stats.rsp.stats.has_started; out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -388,50 +391,49 @@ out: int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, uint8_t *is_ready) { - int error; - struct as10x_cmd_t *pcmd, *prsp; + int error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), - sizeof(pcmd->body.get_impulse_rsp.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.get_impulse_rsp.req)); - /* fill command */ - pcmd->body.get_impulse_rsp.req.proc_id = - cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP); + /* fill command */ + pcmd->body.get_impulse_rsp.req.proc_id = + cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP); - /* send command */ - if(phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.get_impulse_rsp.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.get_impulse_rsp.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_impulse_rsp.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_impulse_rsp.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp,CONTROL_PROC_GET_IMPULSE_RESP_RSP); - if (error < 0) { - goto out; - } + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP); + if (error < 0) + goto out; - /* Response OK -> get response data */ - *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready; + /* Response OK -> get response data */ + *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready; out: - LEAVE(); - return(error); + LEAVE(); + return error; } @@ -447,10 +449,10 @@ out: void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t xid, uint16_t cmd_len) { - pcmd->header.req_id = cpu_to_le16(xid); - pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID); - pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION); - pcmd->header.data_len = cpu_to_le16(cmd_len); + pcmd->header.req_id = cpu_to_le16(xid); + pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID); + pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION); + pcmd->header.data_len = cpu_to_le16(cmd_len); } /** @@ -463,16 +465,17 @@ void as10x_cmd_build(struct as10x_cmd_t *pcmd, */ int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) { - int error; + int error; - /* extract command error code */ - error = prsp->body.common.rsp.error; + /* extract command error code */ + error = prsp->body.common.rsp.error; - if((error == 0) && (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) { - return 0; - } + if ((error == 0) && + (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) { + return 0; + } - return AS10X_CMD_ERROR; + return AS10X_CMD_ERROR; } From 79848e9afbdb47a230d55d29af1a6fada718427c Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 31 Oct 2011 12:24:43 -0300 Subject: [PATCH 011/144] [media] staging: as102: Fix CodingStyle errors in file as10x_cmd_stream.c Fix Linux kernel coding style (whitespace and indentation) errors in file as10x_cmd_stream.c. No functional changes. Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/as102/as10x_cmd_stream.c | 262 +++++++++--------- 1 file changed, 127 insertions(+), 135 deletions(-) diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c index 4dfacf464ed1..8705894d51c7 100644 --- a/drivers/staging/media/as102/as10x_cmd_stream.c +++ b/drivers/staging/media/as102/as10x_cmd_stream.c @@ -2,8 +2,6 @@ \file as10x_cmd_stream.c - \version $Id$ - \author: S. Martinelli ----------------------------------------------------------------------------\n @@ -53,57 +51,57 @@ \return 0 when no error, < 0 in case of error. \callgraph */ -int as10x_cmd_add_PID_filter(as10x_handle_t* phandle, - struct as10x_ts_filter *filter) { - int error; - struct as10x_cmd_t *pcmd, *prsp; +int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, + struct as10x_ts_filter *filter) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), - sizeof(pcmd->body.add_pid_filter.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.add_pid_filter.req)); - /* fill command */ - pcmd->body.add_pid_filter.req.proc_id = cpu_to_le16(CONTROL_PROC_SETFILTER); - pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid); - pcmd->body.add_pid_filter.req.stream_type = filter->type; + /* fill command */ + pcmd->body.add_pid_filter.req.proc_id = + cpu_to_le16(CONTROL_PROC_SETFILTER); + pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid); + pcmd->body.add_pid_filter.req.stream_type = filter->type; - if(filter->idx < 16) - pcmd->body.add_pid_filter.req.idx = filter->idx; - else - pcmd->body.add_pid_filter.req.idx = 0xFF; + if (filter->idx < 16) + pcmd->body.add_pid_filter.req.idx = filter->idx; + else + pcmd->body.add_pid_filter.req.idx = 0xFF; - /* send command */ - if(phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.add_pid_filter.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.add_pid_filter.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + sizeof(pcmd->body.add_pid_filter.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.add_pid_filter.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP); + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP); - if(error == 0) { - /* Response OK -> get response data */ - filter->idx = prsp->body.add_pid_filter.rsp.filter_id; - } + if (error == 0) { + /* Response OK -> get response data */ + filter->idx = prsp->body.add_pid_filter.rsp.filter_id; + } out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -113,144 +111,138 @@ out: \return 0 when no error, < 0 in case of error. \callgraph */ -int as10x_cmd_del_PID_filter(as10x_handle_t* phandle, +int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, uint16_t pid_value) { + int error; + struct as10x_cmd_t *pcmd, *prsp; - int error; - struct as10x_cmd_t *pcmd, *prsp; + ENTER(); - ENTER(); + pcmd = phandle->cmd; + prsp = phandle->rsp; - pcmd = phandle->cmd; - prsp = phandle->rsp; + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.del_pid_filter.req)); - /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), - sizeof(pcmd->body.del_pid_filter.req)); + /* fill command */ + pcmd->body.del_pid_filter.req.proc_id = + cpu_to_le16(CONTROL_PROC_REMOVEFILTER); + pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value); - /* fill command */ - pcmd->body.del_pid_filter.req.proc_id = cpu_to_le16(CONTROL_PROC_REMOVEFILTER); - pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value); + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + sizeof(pcmd->body.del_pid_filter.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.del_pid_filter.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - /* send command */ - if(phandle->ops->xfer_cmd){ - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.del_pid_filter.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.del_pid_filter.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + if (error < 0) + goto out; - if(error < 0) { - goto out; - } - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP); + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP); out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** \brief Send start streaming command to AS10x \param phandle: pointer to AS10x handle - \return 0 when no error, < 0 in case of error.  + \return 0 when no error, < 0 in case of error. \callgraph */ -int as10x_cmd_start_streaming(as10x_handle_t* phandle) +int as10x_cmd_start_streaming(as10x_handle_t *phandle) { - int error; - struct as10x_cmd_t *pcmd, *prsp; + int error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), - sizeof(pcmd->body.start_streaming.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.start_streaming.req)); - /* fill command */ - pcmd->body.start_streaming.req.proc_id = - cpu_to_le16(CONTROL_PROC_START_STREAMING); + /* fill command */ + pcmd->body.start_streaming.req.proc_id = + cpu_to_le16(CONTROL_PROC_START_STREAMING); - /* send command */ - if(phandle->ops->xfer_cmd){ - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.start_streaming.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.start_streaming.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + sizeof(pcmd->body.start_streaming.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.start_streaming.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP); + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP); out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** \brief Send stop streaming command to AS10x \param phandle: pointer to AS10x handle - \return 0 when no error, < 0 in case of error.  + \return 0 when no error, < 0 in case of error. \callgraph */ -int as10x_cmd_stop_streaming(as10x_handle_t* phandle) +int as10x_cmd_stop_streaming(as10x_handle_t *phandle) { - int8_t error; - struct as10x_cmd_t *pcmd, *prsp; + int8_t error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), - sizeof(pcmd->body.stop_streaming.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.stop_streaming.req)); - /* fill command */ - pcmd->body.stop_streaming.req.proc_id = - cpu_to_le16(CONTROL_PROC_STOP_STREAMING); + /* fill command */ + pcmd->body.stop_streaming.req.proc_id = + cpu_to_le16(CONTROL_PROC_STOP_STREAMING); - /* send command */ - if(phandle->ops->xfer_cmd){ - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.stop_streaming.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.stop_streaming.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + sizeof(pcmd->body.stop_streaming.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.stop_streaming.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP); + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP); out: - LEAVE(); - return(error); + LEAVE(); + return error; } From 87ad567e257523ea8857507eaaed866ba5d20d5d Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 31 Oct 2011 12:24:44 -0300 Subject: [PATCH 012/144] [media] staging: as102: Fix CodingStyle errors in file as102_fe.c Fix Linux kernel coding style (whitespace and indentation) errors in file as102_fe.c. No functional changes. Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_fe.c | 476 +++++++++++++------------ 1 file changed, 252 insertions(+), 224 deletions(-) diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c index 3e6f497aed51..e9f7188ee44c 100644 --- a/drivers/staging/media/as102/as102_fe.c +++ b/drivers/staging/media/as102/as102_fe.c @@ -1,6 +1,7 @@ /* * Abilis Systems Single DVB-T Receiver * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,12 +32,14 @@ static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, struct dvb_frontend_parameters *src); -static void as102_fe_release(struct dvb_frontend *fe) { +static void as102_fe_release(struct dvb_frontend *fe) +{ struct as102_dev_t *dev; ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return; #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) @@ -64,13 +67,15 @@ static void as102_fe_release(struct dvb_frontend *fe) { } #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) -static int as102_fe_init(struct dvb_frontend *fe) { +static int as102_fe_init(struct dvb_frontend *fe) +{ int ret = 0; struct as102_dev_t *dev; ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return -ENODEV; if (mutex_lock_interruptible(&dev->bus_adap.lock)) @@ -90,14 +95,16 @@ static int as102_fe_init(struct dvb_frontend *fe) { #endif static int as102_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) { + struct dvb_frontend_parameters *params) +{ int ret = 0; struct as102_dev_t *dev; struct as10x_tune_args tune_args = { 0 }; ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return -ENODEV; if (mutex_lock_interruptible(&dev->bus_adap.lock)) @@ -107,9 +114,8 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe, /* send abilis command: SET_TUNE */ ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); - if(ret != 0) { + if (ret != 0) dprintk(debug, "as10x_cmd_set_tune failed. (err = %d)\n", ret); - } mutex_unlock(&dev->bus_adap.lock); @@ -117,7 +123,7 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe, return (ret < 0) ? -EINVAL : 0; } -static int as102_fe_get_frontend(struct dvb_frontend* fe, +static int as102_fe_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { int ret = 0; struct as102_dev_t *dev; @@ -125,7 +131,8 @@ static int as102_fe_get_frontend(struct dvb_frontend* fe, ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return -EINVAL; if (mutex_lock_interruptible(&dev->bus_adap.lock)) @@ -150,7 +157,8 @@ static int as102_fe_get_tune_settings(struct dvb_frontend *fe, #if 0 dprintk(debug, "step_size = %d\n", settings->step_size); dprintk(debug, "max_drift = %d\n", settings->max_drift); - dprintk(debug, "min_delay_ms = %d -> %d\n", settings->min_delay_ms, 1000); + dprintk(debug, "min_delay_ms = %d -> %d\n", settings->min_delay_ms, + 1000); #endif settings->min_delay_ms = 1000; @@ -160,14 +168,16 @@ static int as102_fe_get_tune_settings(struct dvb_frontend *fe, } -static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) { +static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ int ret = 0; struct as102_dev_t *dev; struct as10x_tune_status tstate = { 0 }; ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return -ENODEV; if (mutex_lock_interruptible(&dev->bus_adap.lock)) @@ -176,48 +186,47 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) { /* send abilis command: GET_TUNE_STATUS */ ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate); if (ret < 0) { - dprintk(debug, "as10x_cmd_get_tune_status failed (err = %d)\n", ret); + dprintk(debug, "as10x_cmd_get_tune_status failed (err = %d)\n", + ret); goto out; } dev->signal_strength = tstate.signal_strength; dev->ber = tstate.BER; - switch(tstate.tune_state) { - case TUNE_STATUS_SIGNAL_DVB_OK: - *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER; - break; - case TUNE_STATUS_STREAM_DETECTED: - *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_SYNC; - break; - case TUNE_STATUS_STREAM_TUNED: - *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_SYNC | - FE_HAS_LOCK; - break; - default: - *status = TUNE_STATUS_NOT_TUNED; + switch (tstate.tune_state) { + case TUNE_STATUS_SIGNAL_DVB_OK: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + break; + case TUNE_STATUS_STREAM_DETECTED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; + break; + case TUNE_STATUS_STREAM_TUNED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | + FE_HAS_LOCK; + break; + default: + *status = TUNE_STATUS_NOT_TUNED; } - dprintk(debug, "tuner status: 0x%02x , strength %d , per: %d , ber: %d\n", + dprintk(debug, "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", tstate.tune_state, tstate.signal_strength, tstate.PER, tstate.BER); if (*status & FE_HAS_LOCK) { if (as10x_cmd_get_demod_stats(&dev->bus_adap, - (struct as10x_demod_stats *) &dev->demod_stats) < 0) { + (struct as10x_demod_stats *) &dev->demod_stats) < 0) { memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - dprintk(debug, "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); + dprintk(debug, "as10x_cmd_get_demod_stats failed " + "(probably not tuned)\n"); } else { - dprintk(debug, "demod status: fc: 0x%08x , bad fc: 0x%08x , bytes corrected: 0x%08x , MER: 0x%04x\n", - dev->demod_stats.frame_count, - dev->demod_stats.bad_frame_count, - dev->demod_stats.bytes_fixed_by_rs, - dev->demod_stats.mer); + dprintk(debug, + "demod status: fc: 0x%08x, bad fc: 0x%08x, " + "bytes corrected: 0x%08x , MER: 0x%04x\n", + dev->demod_stats.frame_count, + dev->demod_stats.bad_frame_count, + dev->demod_stats.bytes_fixed_by_rs, + dev->demod_stats.mer); } } else { memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); @@ -236,12 +245,14 @@ out: * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB * - the accuracy is >2dB for SNR values outside this range */ -static int as102_fe_read_snr(struct dvb_frontend* fe, u16* snr) { +static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ struct as102_dev_t *dev; ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return -ENODEV; *snr = dev->demod_stats.mer; @@ -250,12 +261,14 @@ static int as102_fe_read_snr(struct dvb_frontend* fe, u16* snr) { return 0; } -static int as102_fe_read_ber(struct dvb_frontend* fe, u32* ber) { +static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ struct as102_dev_t *dev; ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return -ENODEV; *ber = dev->ber; @@ -264,12 +277,15 @@ static int as102_fe_read_ber(struct dvb_frontend* fe, u32* ber) { return 0; } -static int as102_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength) { +static int as102_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ struct as102_dev_t *dev; ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return -ENODEV; *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2); @@ -278,12 +294,14 @@ static int as102_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength) return 0; } -static int as102_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { +static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ struct as102_dev_t *dev; ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return -ENODEV; if (dev->demod_stats.has_started) @@ -296,13 +314,15 @@ static int as102_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) -static int as102_fe_ts_bus_ctrl(struct dvb_frontend* fe, int acquire) { +static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ struct as102_dev_t *dev; int ret; ENTER(); - if ((dev = (struct as102_dev_t *) fe->tuner_priv) == NULL) + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) return -ENODEV; if (mutex_lock_interruptible(&dev->bus_adap.lock)) @@ -362,8 +382,8 @@ static struct dvb_frontend_ops as102_fe_ops = { #endif }; -int as102_dvb_unregister_fe(struct dvb_frontend *fe) { - +int as102_dvb_unregister_fe(struct dvb_frontend *fe) +{ /* unregister frontend */ dvb_unregister_frontend(fe); @@ -374,11 +394,13 @@ int as102_dvb_unregister_fe(struct dvb_frontend *fe) { return 0; } -int as102_dvb_register_fe(struct as102_dev_t *as102_dev, struct dvb_frontend *dvb_fe) { +int as102_dvb_register_fe(struct as102_dev_t *as102_dev, + struct dvb_frontend *dvb_fe) +{ int errno; struct dvb_adapter *dvb_adap; - if(as102_dev == NULL) + if (as102_dev == NULL) return -EINVAL; /* extract dvb_adapter */ @@ -389,140 +411,143 @@ int as102_dvb_register_fe(struct as102_dev_t *as102_dev, struct dvb_frontend *dv /* register dbvb frontend */ errno = dvb_register_frontend(dvb_adap, dvb_fe); - if(errno == 0) + if (errno == 0) dvb_fe->tuner_priv = as102_dev; return errno; } static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, - struct as10x_tps *as10x_tps) { + struct as10x_tps *as10x_tps) +{ struct dvb_ofdm_parameters *fe_tps = &dst->u.ofdm; /* extract consteallation */ - switch(as10x_tps->constellation) { - case CONST_QPSK: - fe_tps->constellation = QPSK; - break; - case CONST_QAM16: - fe_tps->constellation = QAM_16; - break; - case CONST_QAM64: - fe_tps->constellation = QAM_64; - break; + switch (as10x_tps->constellation) { + case CONST_QPSK: + fe_tps->constellation = QPSK; + break; + case CONST_QAM16: + fe_tps->constellation = QAM_16; + break; + case CONST_QAM64: + fe_tps->constellation = QAM_64; + break; } /* extract hierarchy */ - switch(as10x_tps->hierarchy) { - case HIER_NONE: - fe_tps->hierarchy_information = HIERARCHY_NONE; - break; - case HIER_ALPHA_1: - fe_tps->hierarchy_information = HIERARCHY_1; - break; - case HIER_ALPHA_2: - fe_tps->hierarchy_information = HIERARCHY_2; - break; - case HIER_ALPHA_4: - fe_tps->hierarchy_information = HIERARCHY_4; - break; + switch (as10x_tps->hierarchy) { + case HIER_NONE: + fe_tps->hierarchy_information = HIERARCHY_NONE; + break; + case HIER_ALPHA_1: + fe_tps->hierarchy_information = HIERARCHY_1; + break; + case HIER_ALPHA_2: + fe_tps->hierarchy_information = HIERARCHY_2; + break; + case HIER_ALPHA_4: + fe_tps->hierarchy_information = HIERARCHY_4; + break; } /* extract code rate HP */ - switch(as10x_tps->code_rate_HP) { - case CODE_RATE_1_2: - fe_tps->code_rate_HP = FEC_1_2; - break; - case CODE_RATE_2_3: - fe_tps->code_rate_HP = FEC_2_3; - break; - case CODE_RATE_3_4: - fe_tps->code_rate_HP = FEC_3_4; - break; - case CODE_RATE_5_6: - fe_tps->code_rate_HP = FEC_5_6; - break; - case CODE_RATE_7_8: - fe_tps->code_rate_HP = FEC_7_8; - break; + switch (as10x_tps->code_rate_HP) { + case CODE_RATE_1_2: + fe_tps->code_rate_HP = FEC_1_2; + break; + case CODE_RATE_2_3: + fe_tps->code_rate_HP = FEC_2_3; + break; + case CODE_RATE_3_4: + fe_tps->code_rate_HP = FEC_3_4; + break; + case CODE_RATE_5_6: + fe_tps->code_rate_HP = FEC_5_6; + break; + case CODE_RATE_7_8: + fe_tps->code_rate_HP = FEC_7_8; + break; } /* extract code rate LP */ - switch(as10x_tps->code_rate_LP) { - case CODE_RATE_1_2: - fe_tps->code_rate_LP = FEC_1_2; - break; - case CODE_RATE_2_3: - fe_tps->code_rate_LP = FEC_2_3; - break; - case CODE_RATE_3_4: - fe_tps->code_rate_LP = FEC_3_4; - break; - case CODE_RATE_5_6: - fe_tps->code_rate_LP = FEC_5_6; - break; - case CODE_RATE_7_8: - fe_tps->code_rate_LP = FEC_7_8; - break; + switch (as10x_tps->code_rate_LP) { + case CODE_RATE_1_2: + fe_tps->code_rate_LP = FEC_1_2; + break; + case CODE_RATE_2_3: + fe_tps->code_rate_LP = FEC_2_3; + break; + case CODE_RATE_3_4: + fe_tps->code_rate_LP = FEC_3_4; + break; + case CODE_RATE_5_6: + fe_tps->code_rate_LP = FEC_5_6; + break; + case CODE_RATE_7_8: + fe_tps->code_rate_LP = FEC_7_8; + break; } /* extract guard interval */ - switch(as10x_tps->guard_interval) { - case GUARD_INT_1_32: - fe_tps->guard_interval = GUARD_INTERVAL_1_32; - break; - case GUARD_INT_1_16: - fe_tps->guard_interval = GUARD_INTERVAL_1_16; - break; - case GUARD_INT_1_8: - fe_tps->guard_interval = GUARD_INTERVAL_1_8; - break; - case GUARD_INT_1_4: - fe_tps->guard_interval = GUARD_INTERVAL_1_4; - break; + switch (as10x_tps->guard_interval) { + case GUARD_INT_1_32: + fe_tps->guard_interval = GUARD_INTERVAL_1_32; + break; + case GUARD_INT_1_16: + fe_tps->guard_interval = GUARD_INTERVAL_1_16; + break; + case GUARD_INT_1_8: + fe_tps->guard_interval = GUARD_INTERVAL_1_8; + break; + case GUARD_INT_1_4: + fe_tps->guard_interval = GUARD_INTERVAL_1_4; + break; } /* extract transmission mode */ - switch(as10x_tps->transmission_mode) { - case TRANS_MODE_2K: - fe_tps->transmission_mode = TRANSMISSION_MODE_2K; - break; - case TRANS_MODE_8K: - fe_tps->transmission_mode = TRANSMISSION_MODE_8K; - break; + switch (as10x_tps->transmission_mode) { + case TRANS_MODE_2K: + fe_tps->transmission_mode = TRANSMISSION_MODE_2K; + break; + case TRANS_MODE_8K: + fe_tps->transmission_mode = TRANSMISSION_MODE_8K; + break; } } -static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) { +static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) +{ uint8_t c; - switch(arg) { - case FEC_1_2: - c = CODE_RATE_1_2; - break; - case FEC_2_3: - c = CODE_RATE_2_3; - break; - case FEC_3_4: - c = CODE_RATE_3_4; - break; - case FEC_5_6: - c = CODE_RATE_5_6; - break; - case FEC_7_8: - c = CODE_RATE_7_8; - break; - default: - c = CODE_RATE_UNKNOWN; - break; + switch (arg) { + case FEC_1_2: + c = CODE_RATE_1_2; + break; + case FEC_2_3: + c = CODE_RATE_2_3; + break; + case FEC_3_4: + c = CODE_RATE_3_4; + break; + case FEC_5_6: + c = CODE_RATE_5_6; + break; + case FEC_7_8: + c = CODE_RATE_7_8; + break; + default: + c = CODE_RATE_UNKNOWN; + break; } return c; } static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, - struct dvb_frontend_parameters *params) { + struct dvb_frontend_parameters *params) +{ /* set frequency */ tune_args->freq = params->frequency / 1000; @@ -530,81 +555,81 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, /* fix interleaving_mode */ tune_args->interleaving_mode = INTLV_NATIVE; - switch(params->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: - tune_args->bandwidth = BW_8_MHZ; - break; - case BANDWIDTH_7_MHZ: - tune_args->bandwidth = BW_7_MHZ; - break; - case BANDWIDTH_6_MHZ: - tune_args->bandwidth = BW_6_MHZ; - break; - default: - tune_args->bandwidth = BW_8_MHZ; + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_8_MHZ: + tune_args->bandwidth = BW_8_MHZ; + break; + case BANDWIDTH_7_MHZ: + tune_args->bandwidth = BW_7_MHZ; + break; + case BANDWIDTH_6_MHZ: + tune_args->bandwidth = BW_6_MHZ; + break; + default: + tune_args->bandwidth = BW_8_MHZ; } - switch(params->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_32: - tune_args->guard_interval = GUARD_INT_1_32; - break; - case GUARD_INTERVAL_1_16: - tune_args->guard_interval = GUARD_INT_1_16; - break; - case GUARD_INTERVAL_1_8: - tune_args->guard_interval = GUARD_INT_1_8; - break; - case GUARD_INTERVAL_1_4: - tune_args->guard_interval = GUARD_INT_1_4; - break; - case GUARD_INTERVAL_AUTO: - default: - tune_args->guard_interval = GUARD_UNKNOWN; - break; + switch (params->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: + tune_args->guard_interval = GUARD_INT_1_32; + break; + case GUARD_INTERVAL_1_16: + tune_args->guard_interval = GUARD_INT_1_16; + break; + case GUARD_INTERVAL_1_8: + tune_args->guard_interval = GUARD_INT_1_8; + break; + case GUARD_INTERVAL_1_4: + tune_args->guard_interval = GUARD_INT_1_4; + break; + case GUARD_INTERVAL_AUTO: + default: + tune_args->guard_interval = GUARD_UNKNOWN; + break; } - switch(params->u.ofdm.constellation) { - case QPSK: - tune_args->constellation = CONST_QPSK; - break; - case QAM_16: - tune_args->constellation = CONST_QAM16; - break; - case QAM_64: - tune_args->constellation = CONST_QAM64; - break; - default: - tune_args->constellation = CONST_UNKNOWN; - break; + switch (params->u.ofdm.constellation) { + case QPSK: + tune_args->constellation = CONST_QPSK; + break; + case QAM_16: + tune_args->constellation = CONST_QAM16; + break; + case QAM_64: + tune_args->constellation = CONST_QAM64; + break; + default: + tune_args->constellation = CONST_UNKNOWN; + break; } - switch(params->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: - tune_args->transmission_mode = TRANS_MODE_2K; - break; - case TRANSMISSION_MODE_8K: - tune_args->transmission_mode = TRANS_MODE_8K; - break; - default: - tune_args->transmission_mode = TRANS_MODE_UNKNOWN; + switch (params->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: + tune_args->transmission_mode = TRANS_MODE_2K; + break; + case TRANSMISSION_MODE_8K: + tune_args->transmission_mode = TRANS_MODE_8K; + break; + default: + tune_args->transmission_mode = TRANS_MODE_UNKNOWN; } - switch(params->u.ofdm.hierarchy_information) { - case HIERARCHY_NONE: - tune_args->hierarchy = HIER_NONE; - break; - case HIERARCHY_1: - tune_args->hierarchy = HIER_ALPHA_1; - break; - case HIERARCHY_2: - tune_args->hierarchy = HIER_ALPHA_2; - break; - case HIERARCHY_4: - tune_args->hierarchy = HIER_ALPHA_4; - break; - case HIERARCHY_AUTO: - tune_args->hierarchy = HIER_UNKNOWN; - break; + switch (params->u.ofdm.hierarchy_information) { + case HIERARCHY_NONE: + tune_args->hierarchy = HIER_NONE; + break; + case HIERARCHY_1: + tune_args->hierarchy = HIER_ALPHA_1; + break; + case HIERARCHY_2: + tune_args->hierarchy = HIER_ALPHA_2; + break; + case HIERARCHY_4: + tune_args->hierarchy = HIER_ALPHA_4; + break; + case HIERARCHY_AUTO: + tune_args->hierarchy = HIER_UNKNOWN; + break; } dprintk(debug, "tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", @@ -623,23 +648,26 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, if (params->u.ofdm.code_rate_LP == FEC_NONE) { tune_args->hier_select = HIER_HIGH_PRIORITY; tune_args->code_rate = - as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); + as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); } if (params->u.ofdm.code_rate_HP == FEC_NONE) { tune_args->hier_select = HIER_LOW_PRIORITY; tune_args->code_rate = - as102_fe_get_code_rate(params->u.ofdm.code_rate_LP); + as102_fe_get_code_rate(params->u.ofdm.code_rate_LP); } dprintk(debug, "\thierarchy: 0x%02x " "selected: %s code_rate_%s: 0x%02x\n", tune_args->hierarchy, - tune_args->hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", - tune_args->hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", + tune_args->hier_select == HIER_HIGH_PRIORITY ? + "HP" : "LP", + tune_args->hier_select == HIER_HIGH_PRIORITY ? + "HP" : "LP", tune_args->code_rate); } else { - tune_args->code_rate = as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); + tune_args->code_rate = + as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); } } #endif From c7a6c00194c05a30fecc84e101d4b9c8d44cffc9 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 31 Oct 2011 12:24:45 -0300 Subject: [PATCH 013/144] [media] staging: as102: Fix CodingStyle errors in file as102_usb_drv.c Fix Linux kernel coding style (whitespace and indentation) errors in file as102_usb_drv.c. No functional changes. Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_usb_drv.c | 118 ++++++++++++-------- drivers/staging/media/as102/as102_usb_drv.h | 3 +- 2 files changed, 72 insertions(+), 49 deletions(-) diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index ee993960731a..6e7971994492 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -1,6 +1,7 @@ /* * Abilis Systems Single DVB-T Receiver * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,7 +50,7 @@ struct usb_driver as102_usb_driver = { .id_table = as102_usb_id_table }; -struct file_operations as102_dev_fops = { +static const struct file_operations as102_dev_fops = { .owner = THIS_MODULE, .open = as102_open, .release = as102_release, @@ -63,46 +64,48 @@ static struct usb_class_driver as102_usb_class_driver = { static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap, unsigned char *send_buf, int send_buf_len, - unsigned char *recv_buf, int recv_buf_len) { - + unsigned char *recv_buf, int recv_buf_len) +{ int ret = 0; ENTER(); - if(send_buf != NULL) { + if (send_buf != NULL) { ret = usb_control_msg(bus_adap->usb_dev, usb_sndctrlpipe(bus_adap->usb_dev, 0), AS102_USB_DEVICE_TX_CTRL_CMD, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, bus_adap->cmd_xid, /* value */ 0, /* index */ send_buf, send_buf_len, USB_CTRL_SET_TIMEOUT /* 200 */); - if(ret < 0) { + if (ret < 0) { dprintk(debug, "usb_control_msg(send) failed, err %i\n", ret); return ret; } - if(ret != send_buf_len) { + if (ret != send_buf_len) { dprintk(debug, "only wrote %d of %d bytes\n", ret, send_buf_len); return -1; } } - if(recv_buf != NULL) { + if (recv_buf != NULL) { #ifdef TRACE dprintk(debug, "want to read: %d bytes\n", recv_buf_len); #endif ret = usb_control_msg(bus_adap->usb_dev, usb_rcvctrlpipe(bus_adap->usb_dev, 0), AS102_USB_DEVICE_RX_CTRL_CMD, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, bus_adap->cmd_xid, /* value */ 0, /* index */ recv_buf, recv_buf_len, USB_CTRL_GET_TIMEOUT /* 200 */); - if(ret < 0) { + if (ret < 0) { dprintk(debug, "usb_control_msg(recv) failed, err %i\n", ret); return ret; @@ -119,18 +122,19 @@ static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap, static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap, unsigned char *send_buf, int send_buf_len, - int swap32) { - + int swap32) +{ int ret = 0, actual_len; - ret = usb_bulk_msg(bus_adap->usb_dev, usb_sndbulkpipe(bus_adap->usb_dev, 1), + ret = usb_bulk_msg(bus_adap->usb_dev, + usb_sndbulkpipe(bus_adap->usb_dev, 1), send_buf, send_buf_len, &actual_len, 200); - if(ret) { + if (ret) { dprintk(debug, "usb_bulk_msg(send) failed, err %i\n", ret); return ret; } - if(actual_len != send_buf_len) { + if (actual_len != send_buf_len) { dprintk(debug, "only wrote %d of %d bytes\n", actual_len, send_buf_len); return -1; @@ -139,21 +143,22 @@ static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap, } static int as102_read_ep2(struct as102_bus_adapter_t *bus_adap, - unsigned char *recv_buf, int recv_buf_len) { - + unsigned char *recv_buf, int recv_buf_len) +{ int ret = 0, actual_len; - if(recv_buf == NULL) + if (recv_buf == NULL) return -EINVAL; - ret = usb_bulk_msg(bus_adap->usb_dev, usb_rcvbulkpipe(bus_adap->usb_dev, 2), + ret = usb_bulk_msg(bus_adap->usb_dev, + usb_rcvbulkpipe(bus_adap->usb_dev, 2), recv_buf, recv_buf_len, &actual_len, 200); - if(ret) { + if (ret) { dprintk(debug, "usb_bulk_msg(recv) failed, err %i\n", ret); return ret; } - if(actual_len != recv_buf_len) { + if (actual_len != recv_buf_len) { dprintk(debug, "only read %d of %d bytes\n", actual_len, recv_buf_len); return -1; @@ -169,7 +174,8 @@ struct as102_priv_ops_t as102_priv_ops = { .stop_stream = as102_usb_stop_stream, }; -static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) { +static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) +{ int err; usb_fill_bulk_urb(urb, @@ -180,8 +186,9 @@ static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) { as102_urb_stream_irq, dev); - if ((err = usb_submit_urb(urb, GFP_ATOMIC))) - dprintk(debug, "%s: usb_submit_urb failed\n", __FUNCTION__); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + dprintk(debug, "%s: usb_submit_urb failed\n", __func__); return err; } @@ -203,7 +210,7 @@ void as102_urb_stream_irq(struct urb *urb) /* do nothing ? */ #endif } else { - if(urb->actual_length == 0) + if (urb->actual_length == 0) memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE); } @@ -212,7 +219,8 @@ void as102_urb_stream_irq(struct urb *urb) as102_submit_urb_stream(as102_dev, urb); } -static void as102_free_usb_stream_buffer(struct as102_dev_t *dev) { +static void as102_free_usb_stream_buffer(struct as102_dev_t *dev) +{ int i; ENTER(); @@ -227,7 +235,8 @@ static void as102_free_usb_stream_buffer(struct as102_dev_t *dev) { LEAVE(); } -static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) { +static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) +{ int i, ret = 0; ENTER(); @@ -237,7 +246,7 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) { GFP_KERNEL, &dev->dma_addr); if (!dev->stream) { - dprintk(debug, "%s: usb_buffer_alloc failed\n", __FUNCTION__); + dprintk(debug, "%s: usb_buffer_alloc failed\n", __func__); return -ENOMEM; } @@ -247,8 +256,9 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) { for (i = 0; i < MAX_STREAM_URB; i++) { struct urb *urb; - if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) { - dprintk(debug, "%s: usb_alloc_urb failed\n", __FUNCTION__); + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (urb == NULL) { + dprintk(debug, "%s: usb_alloc_urb failed\n", __func__); as102_free_usb_stream_buffer(dev); return -ENOMEM; } @@ -262,18 +272,21 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) { return ret; } -static void as102_usb_stop_stream(struct as102_dev_t *dev) { +static void as102_usb_stop_stream(struct as102_dev_t *dev) +{ int i; for (i = 0; i < MAX_STREAM_URB; i++) usb_kill_urb(dev->stream_urb[i]); } -static int as102_usb_start_stream(struct as102_dev_t *dev) { +static int as102_usb_start_stream(struct as102_dev_t *dev) +{ int i, ret = 0; for (i = 0; i < MAX_STREAM_URB; i++) { - if ((ret = as102_submit_urb_stream(dev, dev->stream_urb[i]))) { + ret = as102_submit_urb_stream(dev, dev->stream_urb[i]); + if (ret) { as102_usb_stop_stream(dev); return ret; } @@ -282,7 +295,8 @@ static int as102_usb_start_stream(struct as102_dev_t *dev) { return 0; } -static void as102_usb_release(struct kref *kref) { +static void as102_usb_release(struct kref *kref) +{ struct as102_dev_t *as102_dev; ENTER(); @@ -296,7 +310,8 @@ static void as102_usb_release(struct kref *kref) { LEAVE(); } -static void as102_usb_disconnect(struct usb_interface *intf) { +static void as102_usb_disconnect(struct usb_interface *intf) +{ struct as102_dev_t *as102_dev; ENTER(); @@ -324,14 +339,16 @@ static void as102_usb_disconnect(struct usb_interface *intf) { } static int as102_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) { + const struct usb_device_id *id) +{ int ret; struct as102_dev_t *as102_dev; ENTER(); - if(!(as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL))) { - err("%s: kzalloc failed", __FUNCTION__); + as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); + if (as102_dev == NULL) { + err("%s: kzalloc failed", __func__); return -ENOMEM; } @@ -352,17 +369,19 @@ static int as102_usb_probe(struct usb_interface *intf, as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf)); /* we can register the device now, as it is ready */ - if((ret = usb_register_dev(intf, &as102_usb_class_driver)) < 0) {; + ret = usb_register_dev(intf, &as102_usb_class_driver); + if (ret < 0) { /* something prevented us from registering this driver */ err("%s: usb_register_dev() failed (errno = %d)", - __FUNCTION__, ret); + __func__, ret); goto failed; } printk(KERN_INFO "%s: device has been detected\n", DRIVER_NAME); /* request buffer allocation for streaming */ - if ((ret = as102_alloc_usb_stream_buffer(as102_dev)) != 0) + ret = as102_alloc_usb_stream_buffer(as102_dev); + if (ret != 0) goto failed; /* register dvb layer */ @@ -377,7 +396,8 @@ failed: return ret; } -static int as102_open(struct inode *inode, struct file *file) { +static int as102_open(struct inode *inode, struct file *file) +{ int ret = 0, minor = 0; struct usb_interface *intf = NULL; struct as102_dev_t *dev = NULL; @@ -388,15 +408,17 @@ static int as102_open(struct inode *inode, struct file *file) { minor = iminor(inode); /* fetch device from usb interface */ - if((intf = usb_find_interface(&as102_usb_driver, minor)) == NULL) { + intf = usb_find_interface(&as102_usb_driver, minor); + if (intf == NULL) { printk(KERN_ERR "%s: can't find device for minor %d\n", - __FUNCTION__, minor); + __func__, minor); ret = -ENODEV; goto exit; } /* get our device */ - if((dev = usb_get_intfdata(intf)) == NULL) { + dev = usb_get_intfdata(intf); + if (dev == NULL) { ret = -EFAULT; goto exit; } @@ -412,13 +434,15 @@ exit: return ret; } -static int as102_release(struct inode *inode, struct file *file) { +static int as102_release(struct inode *inode, struct file *file) +{ int ret = 0; struct as102_dev_t *dev = NULL; ENTER(); - if((dev = file->private_data) != NULL ) { + dev = file->private_data; + if (dev != NULL) { /* decrement the count on our device */ kref_put(&dev->kref, as102_usb_release); } diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h index abb858ececbe..3abab6cc2386 100644 --- a/drivers/staging/media/as102/as102_usb_drv.h +++ b/drivers/staging/media/as102/as102_usb_drv.h @@ -1,6 +1,7 @@ /* * Abilis Systems Single DVB-T Receiver * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,8 +36,6 @@ #define PCTV_74E_USB_VID 0x2013 #define PCTV_74E_USB_PID 0x0246 -extern struct file_operations as102_dev_fops; - #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)) void as102_urb_stream_irq(struct urb *urb, struct pt_regs *regs); #else From e2e02ca48878e78393f09a47918501a3a4b374b4 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 31 Oct 2011 12:24:46 -0300 Subject: [PATCH 014/144] [media] staging: as102: Fix CodingStyle errors in file as10x_cmd_cfg.c Fix Linux kernel coding style (whitespace and indentation) errors in file as10x_cmd_cfg.c. No functional changes. Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as10x_cmd_cfg.c | 218 ++++++++++---------- 1 file changed, 108 insertions(+), 110 deletions(-) diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c index e3a0f90936d4..7b22e190c701 100644 --- a/drivers/staging/media/as102/as10x_cmd_cfg.c +++ b/drivers/staging/media/as102/as10x_cmd_cfg.c @@ -2,8 +2,6 @@ \file as10x_cmd_cfg.c - \version $Id$ - \author: S. Martinelli ----------------------------------------------------------------------------\n @@ -22,7 +20,8 @@ #include #include "as102_drv.h" #elif defined(WIN32) - #if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) /* win32 ddk implementation */ + #if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) + /* win32 ddk implementation */ #include "wdm.h" #include "Device.h" #include "endian_mgmt.h" /* FIXME */ @@ -59,52 +58,52 @@ int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, uint32_t *pvalue) { - int error; - struct as10x_cmd_t *pcmd, *prsp; + int error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), - sizeof(pcmd->body.context.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.context.req)); - /* fill command */ - pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); - pcmd->body.context.req.tag = cpu_to_le16(tag); - pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA); + /* fill command */ + pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); + pcmd->body.context.req.tag = cpu_to_le16(tag); + pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA); - /* send command */ - if(phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.context.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.context.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response: context command do not follow the common response */ - /* structure -> specific handling response parse required */ - error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); + /* parse response: context command do not follow the common response */ + /* structure -> specific handling response parse required */ + error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); - if(error == 0) { - /* Response OK -> get response data */ - *pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32); - /* value returned is always a 32-bit value */ - } + if (error == 0) { + /* Response OK -> get response data */ + *pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32); + /* value returned is always a 32-bit value */ + } out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -118,47 +117,48 @@ out: int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, uint32_t value) { - int error; - struct as10x_cmd_t *pcmd, *prsp; + int error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd,(++phandle->cmd_xid),sizeof(pcmd->body.context.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.context.req)); - /* fill command */ - pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); - /* pcmd->body.context.req.reg_val.mode initialization is not required */ - pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value); - pcmd->body.context.req.tag = cpu_to_le16(tag); - pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); + /* fill command */ + pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); + /* pcmd->body.context.req.reg_val.mode initialization is not required */ + pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value); + pcmd->body.context.req.tag = cpu_to_le16(tag); + pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); - /* send command */ - if(phandle->ops->xfer_cmd){ - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.context.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.context.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response: context command do not follow the common response */ - /* structure -> specific handling response parse required */ - error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); + /* parse response: context command do not follow the common response */ + /* structure -> specific handling response parse required */ + error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -175,45 +175,43 @@ out: */ int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode) { - int error; - struct as10x_cmd_t *pcmd, *prsp; + int error; + struct as10x_cmd_t *pcmd, *prsp; - ENTER(); + ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = phandle->cmd; + prsp = phandle->rsp; - /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), - sizeof(pcmd->body.cfg_change_mode.req)); + /* prepare command */ + as10x_cmd_build(pcmd, (++phandle->cmd_xid), + sizeof(pcmd->body.cfg_change_mode.req)); - /* fill command */ - pcmd->body.cfg_change_mode.req.proc_id = - cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE); - pcmd->body.cfg_change_mode.req.mode = mode; + /* fill command */ + pcmd->body.cfg_change_mode.req.proc_id = + cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE); + pcmd->body.cfg_change_mode.req.mode = mode; - /* send command */ - if(phandle->ops->xfer_cmd){ - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.cfg_change_mode.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.cfg_change_mode.rsp) + HEADER_SIZE); - } - else{ - error = AS10X_CMD_ERROR; - } + /* send command */ + if (phandle->ops->xfer_cmd) { + error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + sizeof(pcmd->body.cfg_change_mode.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.cfg_change_mode.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } - if(error < 0) { - goto out; - } + if (error < 0) + goto out; - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP); + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP); out: - LEAVE(); - return(error); + LEAVE(); + return error; } /** @@ -225,15 +223,15 @@ out: ABILIS_RC_NOK \callgraph */ -int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) { +int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) +{ + int err; - int err; + err = prsp->body.context.rsp.error; - err = prsp->body.context.rsp.error; - - if((err == 0) && - (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) { - return 0; - } - return AS10X_CMD_ERROR; + if ((err == 0) && + (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) { + return 0; + } + return AS10X_CMD_ERROR; } From 5f9745b2c942b2ab220831b2c51a18c3f1374249 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 31 Oct 2011 12:24:47 -0300 Subject: [PATCH 015/144] [media] staging: as102: Add Elgato EyeTV DTT Deluxe Add support for the Elgato EyeTV DTT Deluxe. Note that the product name field has not yet been abstracted out, so it will still identify itself as a PCTV 74e. The driver was originally built by the chipset manufacturer so that the product vendor can specify the device name via a #define, but wasn't setup to support multiple products from the same build of the driver. Thanks to Joerg Unglaub for suggesting this change. Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_usb_drv.c | 1 + drivers/staging/media/as102/as102_usb_drv.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index 6e7971994492..d749e0630ffd 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -40,6 +40,7 @@ static int as102_release(struct inode *inode, struct file *file); static struct usb_device_id as102_usb_id_table[] = { { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) }, { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, + { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h index 3abab6cc2386..a81a895aa058 100644 --- a/drivers/staging/media/as102/as102_usb_drv.h +++ b/drivers/staging/media/as102/as102_usb_drv.h @@ -36,6 +36,11 @@ #define PCTV_74E_USB_VID 0x2013 #define PCTV_74E_USB_PID 0x0246 +/* Elgato: EyeTV DTT Deluxe */ +#define ELGATO_EYETV_DTT_NAME "Elgato EyeTV DTT Deluxe" +#define ELGATO_EYETV_DTT_USB_VID 0x0fd9 +#define ELGATO_EYETV_DTT_USB_PID 0x002c + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)) void as102_urb_stream_irq(struct urb *urb, struct pt_regs *regs); #else From 4f7b7c01fd2ca12c6c2d9eaa2a63e1c534f372ae Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 31 Oct 2011 12:24:48 -0300 Subject: [PATCH 016/144] [media] staging: as102: Properly handle multiple product names Properly handle the case where the driver can be associated with multiple different products (as opposed to always saying the device is named after the value in a #define). Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_drv.c | 2 +- drivers/staging/media/as102/as102_drv.h | 1 + drivers/staging/media/as102/as102_fe.c | 4 ++- drivers/staging/media/as102/as102_usb_drv.c | 27 +++++++++++++++++++++ drivers/staging/media/as102/as102_usb_drv.h | 5 ++-- 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c index 9e5d81bb3432..e1e32be22ce7 100644 --- a/drivers/staging/media/as102/as102_drv.c +++ b/drivers/staging/media/as102/as102_drv.c @@ -209,7 +209,7 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) #if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) ret = dvb_register_adapter(&as102_dev->dvb_adap, - DEVICE_FULL_NAME, + as102_dev->name, THIS_MODULE, #if defined(CONFIG_AS102_USB) &as102_dev->bus_adap.usb_dev->dev diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h index f50bb9f67fce..cd11b1628f44 100644 --- a/drivers/staging/media/as102/as102_drv.h +++ b/drivers/staging/media/as102/as102_drv.h @@ -106,6 +106,7 @@ struct as102_bus_adapter_t { }; struct as102_dev_t { + const char *name; struct as102_bus_adapter_t bus_adap; struct list_head device_entry; struct kref kref; diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c index e9f7188ee44c..049548677111 100644 --- a/drivers/staging/media/as102/as102_fe.c +++ b/drivers/staging/media/as102/as102_fe.c @@ -346,7 +346,7 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) static struct dvb_frontend_ops as102_fe_ops = { .info = { - .name = DEVICE_FULL_NAME, + .name = "Unknown AS102 device", .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, @@ -408,6 +408,8 @@ int as102_dvb_register_fe(struct as102_dev_t *as102_dev, /* init frontend callback ops */ memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); + strncpy(dvb_fe->ops.info.name, as102_dev->name, + sizeof(dvb_fe->ops.info.name)); /* register dbvb frontend */ errno = dvb_register_frontend(dvb_adap, dvb_fe); diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index d749e0630ffd..3a3dd777f70a 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -44,6 +44,15 @@ static struct usb_device_id as102_usb_id_table[] = { { } /* Terminating entry */ }; +/* Note that this table must always have the same number of entries as the + as102_usb_id_table struct */ +static const char *as102_device_names[] = { + AS102_REFERENCE_DESIGN, + AS102_PCTV_74E, + AS102_ELGATO_EYETV_DTT_NAME, + NULL /* Terminating entry */ +}; + struct usb_driver as102_usb_driver = { .name = DRIVER_FULL_NAME, .probe = as102_usb_probe, @@ -344,6 +353,7 @@ static int as102_usb_probe(struct usb_interface *intf, { int ret; struct as102_dev_t *as102_dev; + int i; ENTER(); @@ -353,6 +363,23 @@ static int as102_usb_probe(struct usb_interface *intf, return -ENOMEM; } + /* This should never actually happen */ + if ((sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)) != + (sizeof(as102_device_names) / sizeof(const char *))) { + printk(KERN_ERR "Device names table invalid size"); + return -EINVAL; + } + + /* Assign the user-friendly device name */ + for (i = 0; i < (sizeof(as102_usb_id_table) / + sizeof(struct usb_device_id)); i++) { + if (id == &as102_usb_id_table[i]) + as102_dev->name = as102_device_names[i]; + } + + if (as102_dev->name == NULL) + as102_dev->name = "Unknown AS102 device"; + /* set private callback functions */ as102_dev->bus_adap.ops = &as102_priv_ops; diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h index a81a895aa058..a74146277fbd 100644 --- a/drivers/staging/media/as102/as102_usb_drv.h +++ b/drivers/staging/media/as102/as102_usb_drv.h @@ -28,16 +28,17 @@ /* define these values to match the supported devices */ /* Abilis system: "TITAN" */ +#define AS102_REFERENCE_DESIGN "Abilis Systems DVB-Titan" #define AS102_USB_DEVICE_VENDOR_ID 0x1BA6 #define AS102_USB_DEVICE_PID_0001 0x0001 /* PCTV Systems: PCTV picoStick (74e) */ -#define DEVICE_FULL_NAME "PCTV Systems : PCTV picoStick (74e)" +#define AS102_PCTV_74E "PCTV Systems picoStick (74e)" #define PCTV_74E_USB_VID 0x2013 #define PCTV_74E_USB_PID 0x0246 /* Elgato: EyeTV DTT Deluxe */ -#define ELGATO_EYETV_DTT_NAME "Elgato EyeTV DTT Deluxe" +#define AS102_ELGATO_EYETV_DTT_NAME "Elgato EyeTV DTT Deluxe" #define ELGATO_EYETV_DTT_USB_VID 0x0fd9 #define ELGATO_EYETV_DTT_USB_PID 0x002c From 315cadc446714c5c1a406afff6f53aa80d1e267e Mon Sep 17 00:00:00 2001 From: Pierrick Hascoet Date: Mon, 31 Oct 2011 12:24:49 -0300 Subject: [PATCH 017/144] [media] staging: as102: Fix licensing oversight Fix a couple of files which were supposed by be relicensed as GPL but were overlooked. Signed-off-by: Pierrick Hascoet Signed-off-by: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as10x_cmd_cfg.c | 35 +++++++++--------- .../staging/media/as102/as10x_cmd_stream.c | 37 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c index 7b22e190c701..0635797232e5 100644 --- a/drivers/staging/media/as102/as10x_cmd_cfg.c +++ b/drivers/staging/media/as102/as10x_cmd_cfg.c @@ -1,20 +1,21 @@ -/** - - \file as10x_cmd_cfg.c - - \author: S. Martinelli - - ----------------------------------------------------------------------------\n - (c) Copyright Abilis Systems SARL 2005-2009 All rigths reserved \n - www.abilis.com \n - ----------------------------------------------------------------------------\n - - \brief AS10x API, configuration services - - AS10x cmd management: build command buffer, send command through - selected port and wait for the response when required. - -*/ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */ #include diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c index 8705894d51c7..b5e6254ade48 100644 --- a/drivers/staging/media/as102/as10x_cmd_stream.c +++ b/drivers/staging/media/as102/as10x_cmd_stream.c @@ -1,22 +1,21 @@ -/** - - \file as10x_cmd_stream.c - - \author: S. Martinelli - - ----------------------------------------------------------------------------\n - (c) Copyright Abilis Systems SARL 2005-2009 All rigths reserved \n - www.abilis.com \n - ----------------------------------------------------------------------------\n - - \brief AS10x CMD, stream services - - AS10x CMD management: build command buffer, send command through - selected port and wait for the response when required. - -*/ - - +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */ #include #include "as102_drv.h" From f080c2ef542b0d3c78eb2f98a4450a8e22b471af Mon Sep 17 00:00:00 2001 From: Piotr Chmura Date: Mon, 31 Oct 2011 12:24:50 -0300 Subject: [PATCH 018/144] [media] staging: as102: Remove non-linux headers inclusion Remove inclusion of Windows and other not linux related headers. [snjw23@gmail.com: edited changelog, folded long line in Makefile] Cc: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/Makefile | 5 +++-- drivers/staging/media/as102/as10x_cmd.c | 22 ------------------- drivers/staging/media/as102/as10x_cmd_cfg.c | 22 ------------------- .../staging/media/as102/as10x_cmd_stream.c | 22 +------------------ 4 files changed, 4 insertions(+), 67 deletions(-) diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile index c2334c6c952e..e7dbb6f814d5 100644 --- a/drivers/staging/media/as102/Makefile +++ b/drivers/staging/media/as102/Makefile @@ -1,5 +1,6 @@ -dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o +dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \ + as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o obj-$(CONFIG_DVB_AS102) += dvb-as102.o -EXTRA_CFLAGS += -DLINUX -DCONFIG_AS102_USB -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -DCONFIG_AS102_USB -Idrivers/media/dvb/dvb-core diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c index 222e7032ded2..77aae3964fa2 100644 --- a/drivers/staging/media/as102/as10x_cmd.c +++ b/drivers/staging/media/as102/as10x_cmd.c @@ -18,30 +18,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */ #include #include "as102_drv.h" -#elif defined(WIN32) - #if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) - /* win32 ddk implementation */ - #include "wdm.h" - #include "Device.h" - #include "endian_mgmt.h" /* FIXME */ - #else /* win32 sdk implementation */ - #include - #include "types.h" - #include "util.h" - #include "as10x_handle.h" - #include "endian_mgmt.h" - #endif -#else /* all other cases */ - #include - #include "types.h" - #include "util.h" - #include "as10x_handle.h" - #include "endian_mgmt.h" /* FIXME */ -#endif /* __KERNEL__ */ - #include "as10x_types.h" #include "as10x_cmd.h" diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c index 0635797232e5..dca2cbf3bbdb 100644 --- a/drivers/staging/media/as102/as10x_cmd_cfg.c +++ b/drivers/staging/media/as102/as10x_cmd_cfg.c @@ -17,30 +17,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */ #include #include "as102_drv.h" -#elif defined(WIN32) - #if defined(__BUILDMACHINE__) && (__BUILDMACHINE__ == WinDDK) - /* win32 ddk implementation */ - #include "wdm.h" - #include "Device.h" - #include "endian_mgmt.h" /* FIXME */ - #else /* win32 sdk implementation */ - #include - #include "types.h" - #include "util.h" - #include "as10x_handle.h" - #include "endian_mgmt.h" - #endif -#else /* all other cases */ - #include - #include "types.h" - #include "util.h" - #include "as10x_handle.h" - #include "endian_mgmt.h" /* FIXME */ -#endif /* __KERNEL__ */ - #include "as10x_types.h" #include "as10x_cmd.h" diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c index b5e6254ade48..e8c668cff981 100644 --- a/drivers/staging/media/as102/as10x_cmd_stream.c +++ b/drivers/staging/media/as102/as10x_cmd_stream.c @@ -16,29 +16,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(LINUX) && defined(__KERNEL__) /* linux kernel implementation */ + #include #include "as102_drv.h" -#elif defined(WIN32) - #if defined(DDK) /* win32 ddk implementation */ - #include "wdm.h" - #include "Device.h" - #include "endian_mgmt.h" /* FIXME */ - #else /* win32 sdk implementation */ - #include - #include "types.h" - #include "util.h" - #include "as10x_handle.h" - #include "endian_mgmt.h" - #endif -#else /* all other cases */ - #include - #include "types.h" - #include "util.h" - #include "as10x_handle.h" - #include "endian_mgmt.h" /* FIXME */ -#endif /* __KERNEL__ */ - #include "as10x_cmd.h" From 3b4544a3a48b113d09610f2188954f4276047781 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 31 Oct 2011 12:24:51 -0300 Subject: [PATCH 019/144] [media] staging: as102: Convert the comments to kernel-doc style Also amend some mismatched comments. Cc: Devin Heitmueller Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_drv.c | 5 +- drivers/staging/media/as102/as10x_cmd.c | 105 ++++++++---------- drivers/staging/media/as102/as10x_cmd_cfg.c | 65 ++++++----- .../staging/media/as102/as10x_cmd_stream.c | 48 ++++---- 4 files changed, 106 insertions(+), 117 deletions(-) diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c index e1e32be22ce7..27a1571e1aee 100644 --- a/drivers/staging/media/as102/as102_drv.c +++ b/drivers/staging/media/as102/as102_drv.c @@ -331,8 +331,9 @@ static int __init as102_driver_init(void) module_init(as102_driver_init); /** - * \brief as102 driver exit point. This function is called when device has - * to be removed. + * as102_driver_exit - as102 driver exit point + * + * This function is called when device has to be removed. */ static void __exit as102_driver_exit(void) { diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c index 77aae3964fa2..0dcba8065780 100644 --- a/drivers/staging/media/as102/as10x_cmd.c +++ b/drivers/staging/media/as102/as10x_cmd.c @@ -24,11 +24,11 @@ #include "as10x_cmd.h" /** - \brief send turn on command to AS10x - \param phandle: pointer to AS10x handle - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_turn_on - send turn on command to AS10x + * @phandle: pointer to AS10x handle + * + * Return 0 when no error, < 0 in case of error. + */ int as10x_cmd_turn_on(as10x_handle_t *phandle) { int error; @@ -70,11 +70,11 @@ out: } /** - \brief send turn off command to AS10x - \param phandle: pointer to AS10x handle - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_turn_off - send turn off command to AS10x + * @phandle: pointer to AS10x handle + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_turn_off(as10x_handle_t *phandle) { int error; @@ -115,11 +115,11 @@ out: } /** - \brief send set tune command to AS10x - \param phandle: pointer to AS10x handle - \param ptune: tune parameters - \return 0 when no error, < 0 in case of error. - \callgraph + * as10x_cmd_set_tune - send set tune command to AS10x + * @phandle: pointer to AS10x handle + * @ptune: tune parameters + * + * Return 0 on success or negative value in case of error. */ int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) { @@ -174,11 +174,11 @@ out: } /** - \brief send get tune status command to AS10x - \param phandle: pointer to AS10x handle - \param pstatus: pointer to updated status structure of the current tune - \return 0 when no error, < 0 in case of error. - \callgraph + * as10x_cmd_get_tune_status - send get tune status command to AS10x + * @phandle: pointer to AS10x handle + * @pstatus: pointer to updated status structure of the current tune + * + * Return 0 on success or negative value in case of error. */ int as10x_cmd_get_tune_status(as10x_handle_t *phandle, struct as10x_tune_status *pstatus) @@ -232,11 +232,11 @@ out: } /** - \brief send get TPS command to AS10x - \param phandle: pointer to AS10x handle - \param ptps: pointer to TPS parameters structure - \return 0 when no error, < 0 in case of error. - \callgraph + * send get TPS command to AS10x + * @phandle: pointer to AS10x handle + * @ptps: pointer to TPS parameters structure + * + * Return 0 on success or negative value in case of error. */ int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) { @@ -295,12 +295,12 @@ out: } /** - \brief send get demod stats command to AS10x - \param phandle: pointer to AS10x handle - \param pdemod_stats: pointer to demod stats parameters structure - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_get_demod_stats - send get demod stats command to AS10x + * @phandle: pointer to AS10x handle + * @pdemod_stats: pointer to demod stats parameters structure + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, struct as10x_demod_stats *pdemod_stats) { @@ -359,13 +359,13 @@ out: } /** - \brief send get impulse response command to AS10x - \param phandle: pointer to AS10x handle - \param is_ready: pointer to value indicating when impulse - response data is ready - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x + * @phandle: pointer to AS10x handle + * @is_ready: pointer to value indicating when impulse + * response data is ready + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, uint8_t *is_ready) { @@ -414,16 +414,12 @@ out: return error; } - - /** - \brief build AS10x command header - \param pcmd: pointer to AS10x command buffer - \param xid: sequence id of the command - \param cmd_len: lenght of the command - \return - - \callgraph -*/ + * as10x_cmd_build - build AS10x command header + * @pcmd: pointer to AS10x command buffer + * @xid: sequence id of the command + * @cmd_len: length of the command + */ void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t xid, uint16_t cmd_len) { @@ -434,13 +430,12 @@ void as10x_cmd_build(struct as10x_cmd_t *pcmd, } /** - \brief Parse command response - \param pcmd: pointer to AS10x command buffer - \param cmd_seqid: sequence id of the command - \param cmd_len: lenght of the command - \return 0 when no error, < 0 in case of error - \callgraph -*/ + * as10x_rsp_parse - Parse command response + * @prsp: pointer to AS10x command buffer + * @proc_id: id of the command + * + * Return 0 on success or negative value in case of error. + */ int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) { int error; @@ -455,5 +450,3 @@ int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) return AS10X_CMD_ERROR; } - - diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c index dca2cbf3bbdb..ec6f69fcf399 100644 --- a/drivers/staging/media/as102/as10x_cmd_cfg.c +++ b/drivers/staging/media/as102/as10x_cmd_cfg.c @@ -27,13 +27,13 @@ /***************************/ /** - \brief send get context command to AS10x - \param phandle: pointer to AS10x handle - \param tag: context tag - \param pvalue: pointer where to store context value read - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_get_context - Send get context command to AS10x + * @phandle: pointer to AS10x handle + * @tag: context tag + * @pvalue: pointer where to store context value read + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, uint32_t *pvalue) { @@ -86,13 +86,13 @@ out: } /** - \brief send set context command to AS10x - \param phandle: pointer to AS10x handle - \param tag: context tag - \param value: value to set in context - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_set_context - send set context command to AS10x + * @phandle: pointer to AS10x handle + * @tag: context tag + * @value: value to set in context + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, uint32_t value) { @@ -141,17 +141,16 @@ out: } /** - \brief send eLNA change mode command to AS10x - \param phandle: pointer to AS10x handle - \param tag: context tag - \param mode: mode selected: - - ON : 0x0 => eLNA always ON - - OFF : 0x1 => eLNA always OFF - - AUTO : 0x2 => eLNA follow hysteresis parameters to be - ON or OFF - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x + * @phandle: pointer to AS10x handle + * @mode: mode selected: + * - ON : 0x0 => eLNA always ON + * - OFF : 0x1 => eLNA always OFF + * - AUTO : 0x2 => eLNA follow hysteresis parameters + * to be ON or OFF + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode) { int error; @@ -194,14 +193,14 @@ out: } /** - \brief Parse context command response. Since this command does not follow - the common response, a specific parse function is required. - \param prsp: pointer to AS10x command response buffer - \param proc_id: id of the command - \return 0 when no error, < 0 in case of error. - ABILIS_RC_NOK - \callgraph -*/ + * as10x_context_rsp_parse - Parse context command response + * @prsp: pointer to AS10x command response buffer + * @proc_id: id of the command + * + * Since the contex command reponse does not follow the common + * response, a specific parse function is required. + * Return 0 on success or negative value in case of error. + */ int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) { int err; diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c index e8c668cff981..045c70683193 100644 --- a/drivers/staging/media/as102/as10x_cmd_stream.c +++ b/drivers/staging/media/as102/as10x_cmd_stream.c @@ -21,15 +21,13 @@ #include "as102_drv.h" #include "as10x_cmd.h" - /** - \brief send add filter command to AS10x - \param phandle: pointer to AS10x handle - \param filter: TSFilter filter for DVB-T - \param pfilter_handle: pointer where to store filter handle - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_add_PID_filter - send add filter command to AS10x + * @phandle: pointer to AS10x handle + * @filter: TSFilter filter for DVB-T + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, struct as10x_ts_filter *filter) { @@ -84,12 +82,12 @@ out: } /** - \brief Send delete filter command to AS10x - \param phandle: pointer to AS10x handle - \param filter_handle: filter handle - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_del_PID_filter - Send delete filter command to AS10x + * @phandle: pointer to AS10x handle + * @pid_value: PID to delete + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, uint16_t pid_value) { @@ -133,11 +131,11 @@ out: } /** - \brief Send start streaming command to AS10x - \param phandle: pointer to AS10x handle - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_start_streaming - Send start streaming command to AS10x + * @phandle: pointer to AS10x handle + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_start_streaming(as10x_handle_t *phandle) { int error; @@ -179,11 +177,11 @@ out: } /** - \brief Send stop streaming command to AS10x - \param phandle: pointer to AS10x handle - \return 0 when no error, < 0 in case of error. - \callgraph -*/ + * as10x_cmd_stop_streaming - Send stop streaming command to AS10x + * @phandle: pointer to AS10x handle + * + * Return 0 on success or negative value in case of error. + */ int as10x_cmd_stop_streaming(as10x_handle_t *phandle) { int8_t error; @@ -223,5 +221,3 @@ out: LEAVE(); return error; } - - From 9d8e18b1e966e43729a08421a29510f49f931b60 Mon Sep 17 00:00:00 2001 From: Piotr Chmura Date: Mon, 31 Oct 2011 12:24:52 -0300 Subject: [PATCH 020/144] [media] staging: as102: Enable compilation Fix compilation errors in the USB driver by replacing usb_buffer_free(), usb_buffer_alloc() with usb_free_coherent() and usb_alloc_coherent(). Add entries for the driver in parent Makefile and Kconfig. [snjw23@gmail.com: minor edit to changelog] Cc: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/Kconfig | 2 ++ drivers/staging/Makefile | 1 + drivers/staging/media/as102/as102_usb_drv.c | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index d132c27dfb3f..0e1bc6dccccb 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -144,4 +144,6 @@ source "drivers/staging/mei/Kconfig" source "drivers/staging/nvec/Kconfig" +source "drivers/staging/media/as102/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 936b7c22e18e..51999860b0f6 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -63,3 +63,4 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ obj-$(CONFIG_DRM_PSB) += gma500/ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_MFD_NVEC) += nvec/ +obj-$(CONFIG_DVB_AS102) += media/as102/ diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index 3a3dd777f70a..2586d5537498 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -238,7 +238,7 @@ static void as102_free_usb_stream_buffer(struct as102_dev_t *dev) for (i = 0; i < MAX_STREAM_URB; i++) usb_free_urb(dev->stream_urb[i]); - usb_buffer_free(dev->bus_adap.usb_dev, + usb_free_coherent(dev->bus_adap.usb_dev, MAX_STREAM_URB * AS102_USB_BUF_SIZE, dev->stream, dev->dma_addr); @@ -251,7 +251,7 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) ENTER(); - dev->stream = usb_buffer_alloc(dev->bus_adap.usb_dev, + dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev, MAX_STREAM_URB * AS102_USB_BUF_SIZE, GFP_KERNEL, &dev->dma_addr); From 8be62e73e5c088fb4a1c928bdaeac1b27d776043 Mon Sep 17 00:00:00 2001 From: Piotr Chmura Date: Mon, 31 Oct 2011 12:24:53 -0300 Subject: [PATCH 021/144] [media] staging: as102: Add nBox Tuner Dongle support Add support for nBox Tuner Dongle based on the same chip. Cc: Devin Heitmueller Signed-off-by: Piotr Chmura Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_usb_drv.c | 2 ++ drivers/staging/media/as102/as102_usb_drv.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index 2586d5537498..70b21f342408 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -41,6 +41,7 @@ static struct usb_device_id as102_usb_id_table[] = { { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) }, { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, + { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) }, { } /* Terminating entry */ }; @@ -50,6 +51,7 @@ static const char *as102_device_names[] = { AS102_REFERENCE_DESIGN, AS102_PCTV_74E, AS102_ELGATO_EYETV_DTT_NAME, + AS102_NBOX_DVBT_DONGLE_NAME, NULL /* Terminating entry */ }; diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h index a74146277fbd..da34d32c55aa 100644 --- a/drivers/staging/media/as102/as102_usb_drv.h +++ b/drivers/staging/media/as102/as102_usb_drv.h @@ -42,6 +42,11 @@ #define ELGATO_EYETV_DTT_USB_VID 0x0fd9 #define ELGATO_EYETV_DTT_USB_PID 0x002c +/* nBox: nBox DVB-T Dongle */ +#define AS102_NBOX_DVBT_DONGLE_NAME "nBox DVB-T Dongle" +#define NBOX_DVBT_DONGLE_USB_VID 0x0b89 +#define NBOX_DVBT_DONGLE_USB_PID 0x0007 + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)) void as102_urb_stream_irq(struct urb *urb, struct pt_regs *regs); #else From ff7029f5e8fbf682ace0455f6452d840831a3bc2 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 31 Oct 2011 12:24:54 -0300 Subject: [PATCH 022/144] [media] staging: as102: Unconditionally compile code dependent on DVB_CORE The driver depends on DVB_CORE so there is no need for conditional compilation of parts of the code depending on CONFIG_DVB_CORE as the driver is never compiled with CONFIG_DVB_CORE* disabled. Cc: Devin Heitmueller Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_drv.c | 12 +----------- drivers/staging/media/as102/as102_drv.h | 6 ------ drivers/staging/media/as102/as102_fe.c | 2 -- drivers/staging/media/as102/as102_usb_drv.c | 4 ---- 4 files changed, 1 insertion(+), 23 deletions(-) diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c index 27a1571e1aee..d335c7d6fa0f 100644 --- a/drivers/staging/media/as102/as102_drv.c +++ b/drivers/staging/media/as102/as102_drv.c @@ -30,12 +30,7 @@ /* header file for Usb device driver*/ #include "as102_drv.h" #include "as102_fw.h" - -#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) #include "dvbdev.h" -#else -#warning >>> DVB_CORE not defined !!! <<< -#endif int debug; module_param_named(debug, debug, int, 0644); @@ -65,7 +60,6 @@ MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #endif -#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) static void as102_stop_stream(struct as102_dev_t *dev) { struct as102_bus_adapter_t *bus_adap; @@ -200,14 +194,12 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) LEAVE(); return 0; } -#endif int as102_dvb_register(struct as102_dev_t *as102_dev) { int ret = 0; ENTER(); -#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) ret = dvb_register_adapter(&as102_dev->dvb_adap, as102_dev->name, THIS_MODULE, @@ -260,7 +252,6 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) __func__, ret); goto failed; } -#endif /* init bus mutex for token locking */ mutex_init(&as102_dev->bus_adap.lock); @@ -288,7 +279,6 @@ void as102_dvb_unregister(struct as102_dev_t *as102_dev) { ENTER(); -#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) /* unregister as102 frontend */ as102_dvb_unregister_fe(&as102_dev->dvb_fe); @@ -298,7 +288,7 @@ void as102_dvb_unregister(struct as102_dev_t *as102_dev) /* unregister dvb adapter */ dvb_unregister_adapter(&as102_dev->dvb_adap); -#endif + LEAVE(); } diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h index cd11b1628f44..bcda635b5a99 100644 --- a/drivers/staging/media/as102/as102_drv.h +++ b/drivers/staging/media/as102/as102_drv.h @@ -30,11 +30,9 @@ extern struct usb_driver as102_usb_driver; extern struct spi_driver as102_spi_driver; #endif -#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) #include "dvb_demux.h" #include "dvb_frontend.h" #include "dmxdev.h" -#endif #define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" #define DRIVER_NAME "as10x_usb" @@ -112,12 +110,10 @@ struct as102_dev_t { struct kref kref; unsigned long minor; -#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) struct dvb_adapter dvb_adap; struct dvb_frontend dvb_fe; struct dvb_demux dvb_dmx; struct dmxdev dvb_dmxdev; -#endif /* demodulator stats */ struct as10x_demod_stats demod_stats; @@ -139,9 +135,7 @@ struct as102_dev_t { int as102_dvb_register(struct as102_dev_t *dev); void as102_dvb_unregister(struct as102_dev_t *dev); -#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe); int as102_dvb_unregister_fe(struct dvb_frontend *dev); -#endif /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c index 049548677111..874c698e80a8 100644 --- a/drivers/staging/media/as102/as102_fe.c +++ b/drivers/staging/media/as102/as102_fe.c @@ -25,7 +25,6 @@ extern int elna_enable; -#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, struct as10x_tps *src); @@ -672,6 +671,5 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); } } -#endif /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index 70b21f342408..ae1d38db2fee 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -214,13 +214,9 @@ void as102_urb_stream_irq(struct urb *urb) struct as102_dev_t *as102_dev = urb->context; if (urb->actual_length > 0) { -#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE) dvb_dmx_swfilter(&as102_dev->dvb_dmx, urb->transfer_buffer, urb->actual_length); -#else - /* do nothing ? */ -#endif } else { if (urb->actual_length == 0) memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE); From 92e9d1b70f7dd41576b9a890bc34a14f4cc2185b Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 31 Oct 2011 12:24:55 -0300 Subject: [PATCH 023/144] [media] staging: as102: Remove conditional compilation based on kernel version Remove #if's related to kernel version and the code not applicable to 3.2+ kernels. Cc: Devin Heitmueller Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_fe.c | 74 +-------------------- drivers/staging/media/as102/as102_usb_drv.c | 4 -- drivers/staging/media/as102/as102_usb_drv.h | 5 -- 3 files changed, 1 insertion(+), 82 deletions(-) diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c index 874c698e80a8..3550f905367e 100644 --- a/drivers/staging/media/as102/as102_fe.c +++ b/drivers/staging/media/as102/as102_fe.c @@ -31,68 +31,6 @@ static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, struct dvb_frontend_parameters *src); -static void as102_fe_release(struct dvb_frontend *fe) -{ - struct as102_dev_t *dev; - - ENTER(); - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return; - - /* send abilis command: TURN_OFF */ - as10x_cmd_turn_off(&dev->bus_adap); - - mutex_unlock(&dev->bus_adap.lock); -#endif - - /* release frontend callback ops */ - memset(&fe->ops, 0, sizeof(struct dvb_frontend_ops)); - - /* flush statistics */ - memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - dev->signal_strength = 0; - dev->ber = -1; - - /* reset tuner private data */ -/* fe->tuner_priv = NULL; */ - - LEAVE(); -} - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) -static int as102_fe_init(struct dvb_frontend *fe) -{ - int ret = 0; - struct as102_dev_t *dev; - - ENTER(); - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - if (elna_enable) - ret = as10x_cmd_set_context(&dev->bus_adap, 1010, 0xC0); - - /* send abilis command: TURN_ON */ - ret = as10x_cmd_turn_on(&dev->bus_adap); - - mutex_unlock(&dev->bus_adap.lock); - - LEAVE(); - return (ret < 0) ? -EINVAL : 0; -} -#endif - static int as102_fe_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { @@ -312,7 +250,6 @@ static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) { struct as102_dev_t *dev; @@ -341,7 +278,6 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) LEAVE(); return ret; } -#endif static struct dvb_frontend_ops as102_fe_ops = { .info = { @@ -366,19 +302,12 @@ static struct dvb_frontend_ops as102_fe_ops = { .get_frontend = as102_fe_get_frontend, .get_tune_settings = as102_fe_get_tune_settings, - .read_status = as102_fe_read_status, .read_snr = as102_fe_read_snr, .read_ber = as102_fe_read_ber, .read_signal_strength = as102_fe_read_signal_strength, .read_ucblocks = as102_fe_read_ucblocks, - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) .ts_bus_ctrl = as102_fe_ts_bus_ctrl, -#else - .release = as102_fe_release, - .init = as102_fe_init, -#endif }; int as102_dvb_unregister_fe(struct dvb_frontend *fe) @@ -386,10 +315,9 @@ int as102_dvb_unregister_fe(struct dvb_frontend *fe) /* unregister frontend */ dvb_unregister_frontend(fe); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) /* detach frontend */ dvb_frontend_detach(fe); -#endif + return 0; } diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index ae1d38db2fee..264be2dbd2a4 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -205,11 +205,7 @@ static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) return err; } -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)) -void as102_urb_stream_irq(struct urb *urb, struct pt_regs *regs) -#else void as102_urb_stream_irq(struct urb *urb) -#endif { struct as102_dev_t *as102_dev = urb->context; diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h index da34d32c55aa..fb1fc41dcd79 100644 --- a/drivers/staging/media/as102/as102_usb_drv.h +++ b/drivers/staging/media/as102/as102_usb_drv.h @@ -47,12 +47,7 @@ #define NBOX_DVBT_DONGLE_USB_VID 0x0b89 #define NBOX_DVBT_DONGLE_USB_PID 0x0007 -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)) -void as102_urb_stream_irq(struct urb *urb, struct pt_regs *regs); -#else void as102_urb_stream_irq(struct urb *urb); -#endif - struct as10x_usb_token_cmd_t { /* token cmd */ From d6ce55de3abcc4910fef1d79212a17480c154704 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 1 Nov 2011 23:31:14 -0200 Subject: [PATCH 024/144] [media] move cx25821 out of staging This driver had the major issues already fixed. Move it out of staging. Acked-by: Greg Kroah-Hartman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 ++ drivers/media/video/Makefile | 1 + drivers/{staging => media/video}/cx25821/Kconfig | 0 drivers/{staging => media/video}/cx25821/Makefile | 0 drivers/{staging => media/video}/cx25821/cx25821-alsa.c | 0 .../video}/cx25821/cx25821-audio-upstream.c | 0 .../video}/cx25821/cx25821-audio-upstream.h | 0 drivers/{staging => media/video}/cx25821/cx25821-audio.h | 0 drivers/{staging => media/video}/cx25821/cx25821-biffuncs.h | 0 drivers/{staging => media/video}/cx25821/cx25821-cards.c | 0 drivers/{staging => media/video}/cx25821/cx25821-core.c | 0 drivers/{staging => media/video}/cx25821/cx25821-gpio.c | 0 drivers/{staging => media/video}/cx25821/cx25821-i2c.c | 0 .../video}/cx25821/cx25821-medusa-defines.h | 0 .../{staging => media/video}/cx25821/cx25821-medusa-reg.h | 0 .../{staging => media/video}/cx25821/cx25821-medusa-video.c | 0 .../{staging => media/video}/cx25821/cx25821-medusa-video.h | 0 drivers/{staging => media/video}/cx25821/cx25821-reg.h | 0 drivers/{staging => media/video}/cx25821/cx25821-sram.h | 0 .../video}/cx25821/cx25821-video-upstream-ch2.c | 0 .../video}/cx25821/cx25821-video-upstream-ch2.h | 0 .../video}/cx25821/cx25821-video-upstream.c | 0 .../video}/cx25821/cx25821-video-upstream.h | 0 drivers/{staging => media/video}/cx25821/cx25821-video.c | 0 drivers/{staging => media/video}/cx25821/cx25821-video.h | 0 drivers/{staging => media/video}/cx25821/cx25821.h | 0 drivers/staging/Kconfig | 2 -- drivers/staging/Makefile | 1 - drivers/staging/cx25821/README | 6 ------ 29 files changed, 3 insertions(+), 9 deletions(-) rename drivers/{staging => media/video}/cx25821/Kconfig (100%) rename drivers/{staging => media/video}/cx25821/Makefile (100%) rename drivers/{staging => media/video}/cx25821/cx25821-alsa.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-audio-upstream.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-audio-upstream.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-audio.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-biffuncs.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-cards.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-core.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-gpio.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-i2c.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-medusa-defines.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-medusa-reg.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-medusa-video.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-medusa-video.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-reg.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-sram.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-video-upstream-ch2.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-video-upstream-ch2.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-video-upstream.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-video-upstream.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821-video.c (100%) rename drivers/{staging => media/video}/cx25821/cx25821-video.h (100%) rename drivers/{staging => media/video}/cx25821/cx25821.h (100%) delete mode 100644 drivers/staging/cx25821/README diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d285c8c92819..d471d1e5a744 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -736,6 +736,8 @@ source "drivers/media/video/cx88/Kconfig" source "drivers/media/video/cx23885/Kconfig" +source "drivers/media/video/cx25821/Kconfig" + source "drivers/media/video/au0828/Kconfig" source "drivers/media/video/ivtv/Kconfig" diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 11fff97e7196..faba1e333110 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -104,6 +104,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ +obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ diff --git a/drivers/staging/cx25821/Kconfig b/drivers/media/video/cx25821/Kconfig similarity index 100% rename from drivers/staging/cx25821/Kconfig rename to drivers/media/video/cx25821/Kconfig diff --git a/drivers/staging/cx25821/Makefile b/drivers/media/video/cx25821/Makefile similarity index 100% rename from drivers/staging/cx25821/Makefile rename to drivers/media/video/cx25821/Makefile diff --git a/drivers/staging/cx25821/cx25821-alsa.c b/drivers/media/video/cx25821/cx25821-alsa.c similarity index 100% rename from drivers/staging/cx25821/cx25821-alsa.c rename to drivers/media/video/cx25821/cx25821-alsa.c diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.c b/drivers/media/video/cx25821/cx25821-audio-upstream.c similarity index 100% rename from drivers/staging/cx25821/cx25821-audio-upstream.c rename to drivers/media/video/cx25821/cx25821-audio-upstream.c diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.h b/drivers/media/video/cx25821/cx25821-audio-upstream.h similarity index 100% rename from drivers/staging/cx25821/cx25821-audio-upstream.h rename to drivers/media/video/cx25821/cx25821-audio-upstream.h diff --git a/drivers/staging/cx25821/cx25821-audio.h b/drivers/media/video/cx25821/cx25821-audio.h similarity index 100% rename from drivers/staging/cx25821/cx25821-audio.h rename to drivers/media/video/cx25821/cx25821-audio.h diff --git a/drivers/staging/cx25821/cx25821-biffuncs.h b/drivers/media/video/cx25821/cx25821-biffuncs.h similarity index 100% rename from drivers/staging/cx25821/cx25821-biffuncs.h rename to drivers/media/video/cx25821/cx25821-biffuncs.h diff --git a/drivers/staging/cx25821/cx25821-cards.c b/drivers/media/video/cx25821/cx25821-cards.c similarity index 100% rename from drivers/staging/cx25821/cx25821-cards.c rename to drivers/media/video/cx25821/cx25821-cards.c diff --git a/drivers/staging/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c similarity index 100% rename from drivers/staging/cx25821/cx25821-core.c rename to drivers/media/video/cx25821/cx25821-core.c diff --git a/drivers/staging/cx25821/cx25821-gpio.c b/drivers/media/video/cx25821/cx25821-gpio.c similarity index 100% rename from drivers/staging/cx25821/cx25821-gpio.c rename to drivers/media/video/cx25821/cx25821-gpio.c diff --git a/drivers/staging/cx25821/cx25821-i2c.c b/drivers/media/video/cx25821/cx25821-i2c.c similarity index 100% rename from drivers/staging/cx25821/cx25821-i2c.c rename to drivers/media/video/cx25821/cx25821-i2c.c diff --git a/drivers/staging/cx25821/cx25821-medusa-defines.h b/drivers/media/video/cx25821/cx25821-medusa-defines.h similarity index 100% rename from drivers/staging/cx25821/cx25821-medusa-defines.h rename to drivers/media/video/cx25821/cx25821-medusa-defines.h diff --git a/drivers/staging/cx25821/cx25821-medusa-reg.h b/drivers/media/video/cx25821/cx25821-medusa-reg.h similarity index 100% rename from drivers/staging/cx25821/cx25821-medusa-reg.h rename to drivers/media/video/cx25821/cx25821-medusa-reg.h diff --git a/drivers/staging/cx25821/cx25821-medusa-video.c b/drivers/media/video/cx25821/cx25821-medusa-video.c similarity index 100% rename from drivers/staging/cx25821/cx25821-medusa-video.c rename to drivers/media/video/cx25821/cx25821-medusa-video.c diff --git a/drivers/staging/cx25821/cx25821-medusa-video.h b/drivers/media/video/cx25821/cx25821-medusa-video.h similarity index 100% rename from drivers/staging/cx25821/cx25821-medusa-video.h rename to drivers/media/video/cx25821/cx25821-medusa-video.h diff --git a/drivers/staging/cx25821/cx25821-reg.h b/drivers/media/video/cx25821/cx25821-reg.h similarity index 100% rename from drivers/staging/cx25821/cx25821-reg.h rename to drivers/media/video/cx25821/cx25821-reg.h diff --git a/drivers/staging/cx25821/cx25821-sram.h b/drivers/media/video/cx25821/cx25821-sram.h similarity index 100% rename from drivers/staging/cx25821/cx25821-sram.h rename to drivers/media/video/cx25821/cx25821-sram.h diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c similarity index 100% rename from drivers/staging/cx25821/cx25821-video-upstream-ch2.c rename to drivers/media/video/cx25821/cx25821-video-upstream-ch2.c diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.h b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.h similarity index 100% rename from drivers/staging/cx25821/cx25821-video-upstream-ch2.h rename to drivers/media/video/cx25821/cx25821-video-upstream-ch2.h diff --git a/drivers/staging/cx25821/cx25821-video-upstream.c b/drivers/media/video/cx25821/cx25821-video-upstream.c similarity index 100% rename from drivers/staging/cx25821/cx25821-video-upstream.c rename to drivers/media/video/cx25821/cx25821-video-upstream.c diff --git a/drivers/staging/cx25821/cx25821-video-upstream.h b/drivers/media/video/cx25821/cx25821-video-upstream.h similarity index 100% rename from drivers/staging/cx25821/cx25821-video-upstream.h rename to drivers/media/video/cx25821/cx25821-video-upstream.h diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c similarity index 100% rename from drivers/staging/cx25821/cx25821-video.c rename to drivers/media/video/cx25821/cx25821-video.c diff --git a/drivers/staging/cx25821/cx25821-video.h b/drivers/media/video/cx25821/cx25821-video.h similarity index 100% rename from drivers/staging/cx25821/cx25821-video.h rename to drivers/media/video/cx25821/cx25821-video.h diff --git a/drivers/staging/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h similarity index 100% rename from drivers/staging/cx25821/cx25821.h rename to drivers/media/video/cx25821/cx25821.h diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 0e1bc6dccccb..39df8597d310 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -32,8 +32,6 @@ source "drivers/staging/slicoss/Kconfig" source "drivers/staging/go7007/Kconfig" -source "drivers/staging/cx25821/Kconfig" - source "drivers/staging/cxd2099/Kconfig" source "drivers/staging/usbip/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 51999860b0f6..cd1bcc1f0e66 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -7,7 +7,6 @@ obj-y += serial/ obj-$(CONFIG_ET131X) += et131x/ obj-$(CONFIG_SLICOSS) += slicoss/ obj-$(CONFIG_VIDEO_GO7007) += go7007/ -obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_USBIP_CORE) += usbip/ diff --git a/drivers/staging/cx25821/README b/drivers/staging/cx25821/README deleted file mode 100644 index a9ba50b9888b..000000000000 --- a/drivers/staging/cx25821/README +++ /dev/null @@ -1,6 +0,0 @@ -Todo: - - checkpatch.pl cleanups - - sparse cleanups - -Please send patches to linux-media@vger.kernel.org - From 4860c73804c6e7ef8e69f98958489bb2bea6f6d2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 1 Nov 2011 22:23:55 -0200 Subject: [PATCH 025/144] staging: Move media drivers to staging/media In practice, it is being hard to distinguish when a patch should go to staging tree or to the media tree. Better to distinguish it, by putting the media drivers at a separate staging directory. Newer staging drivers that include anything with "dvb*.h", "v4l2*.h" or "videodev2.h" should go to the drivers/staging/media tree. Acked-by: Greg Kroah-Hartman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ddbridge/Makefile | 2 +- drivers/media/dvb/ngene/Makefile | 2 +- drivers/staging/Kconfig | 14 +------ drivers/staging/Makefile | 8 +--- drivers/staging/media/Kconfig | 37 +++++++++++++++++++ drivers/staging/media/Makefile | 7 ++++ drivers/staging/{ => media}/cxd2099/Kconfig | 0 drivers/staging/{ => media}/cxd2099/Makefile | 0 drivers/staging/{ => media}/cxd2099/TODO | 0 drivers/staging/{ => media}/cxd2099/cxd2099.c | 0 drivers/staging/{ => media}/cxd2099/cxd2099.h | 0 drivers/staging/{ => media}/dt3155v4l/Kconfig | 0 .../staging/{ => media}/dt3155v4l/Makefile | 0 .../staging/{ => media}/dt3155v4l/dt3155v4l.c | 0 .../staging/{ => media}/dt3155v4l/dt3155v4l.h | 0 drivers/staging/{ => media}/easycap/Kconfig | 0 drivers/staging/{ => media}/easycap/Makefile | 0 drivers/staging/{ => media}/easycap/README | 0 drivers/staging/{ => media}/easycap/easycap.h | 0 .../{ => media}/easycap/easycap_ioctl.c | 0 .../staging/{ => media}/easycap/easycap_low.c | 0 .../{ => media}/easycap/easycap_main.c | 0 .../{ => media}/easycap/easycap_settings.c | 0 .../{ => media}/easycap/easycap_sound.c | 0 .../{ => media}/easycap/easycap_testcard.c | 0 drivers/staging/{ => media}/go7007/Kconfig | 0 drivers/staging/{ => media}/go7007/Makefile | 0 drivers/staging/{ => media}/go7007/README | 0 .../{ => media}/go7007/go7007-driver.c | 0 .../staging/{ => media}/go7007/go7007-fw.c | 0 .../staging/{ => media}/go7007/go7007-i2c.c | 0 .../staging/{ => media}/go7007/go7007-priv.h | 0 .../staging/{ => media}/go7007/go7007-usb.c | 0 .../staging/{ => media}/go7007/go7007-v4l2.c | 0 drivers/staging/{ => media}/go7007/go7007.h | 0 drivers/staging/{ => media}/go7007/go7007.txt | 0 .../staging/{ => media}/go7007/s2250-board.c | 0 .../staging/{ => media}/go7007/s2250-loader.c | 0 .../staging/{ => media}/go7007/s2250-loader.h | 0 .../{ => media}/go7007/saa7134-go7007.c | 0 .../staging/{ => media}/go7007/snd-go7007.c | 0 drivers/staging/{ => media}/go7007/wis-i2c.h | 0 .../staging/{ => media}/go7007/wis-ov7640.c | 0 .../staging/{ => media}/go7007/wis-saa7113.c | 0 .../staging/{ => media}/go7007/wis-saa7115.c | 0 .../{ => media}/go7007/wis-sony-tuner.c | 0 .../staging/{ => media}/go7007/wis-tw2804.c | 0 .../staging/{ => media}/go7007/wis-tw9903.c | 0 .../staging/{ => media}/go7007/wis-uda1342.c | 0 drivers/staging/{ => media}/lirc/Kconfig | 0 drivers/staging/{ => media}/lirc/Makefile | 0 drivers/staging/{ => media}/lirc/TODO | 0 .../staging/{ => media}/lirc/TODO.lirc_zilog | 0 drivers/staging/{ => media}/lirc/lirc_bt829.c | 0 .../staging/{ => media}/lirc/lirc_ene0100.h | 0 .../{ => media}/lirc/lirc_igorplugusb.c | 0 drivers/staging/{ => media}/lirc/lirc_imon.c | 0 .../staging/{ => media}/lirc/lirc_parallel.c | 0 .../staging/{ => media}/lirc/lirc_parallel.h | 0 drivers/staging/{ => media}/lirc/lirc_sasem.c | 0 .../staging/{ => media}/lirc/lirc_serial.c | 0 drivers/staging/{ => media}/lirc/lirc_sir.c | 0 .../staging/{ => media}/lirc/lirc_ttusbir.c | 0 drivers/staging/{ => media}/lirc/lirc_zilog.c | 0 drivers/staging/{ => media}/solo6x10/Kconfig | 0 drivers/staging/{ => media}/solo6x10/Makefile | 0 drivers/staging/{ => media}/solo6x10/TODO | 0 drivers/staging/{ => media}/solo6x10/core.c | 0 drivers/staging/{ => media}/solo6x10/disp.c | 0 drivers/staging/{ => media}/solo6x10/enc.c | 0 drivers/staging/{ => media}/solo6x10/g723.c | 0 drivers/staging/{ => media}/solo6x10/gpio.c | 0 drivers/staging/{ => media}/solo6x10/i2c.c | 0 drivers/staging/{ => media}/solo6x10/jpeg.h | 0 .../staging/{ => media}/solo6x10/offsets.h | 0 .../staging/{ => media}/solo6x10/osd-font.h | 0 drivers/staging/{ => media}/solo6x10/p2m.c | 0 .../staging/{ => media}/solo6x10/registers.h | 0 .../staging/{ => media}/solo6x10/solo6x10.h | 0 drivers/staging/{ => media}/solo6x10/tw28.c | 0 drivers/staging/{ => media}/solo6x10/tw28.h | 0 .../staging/{ => media}/solo6x10/v4l2-enc.c | 0 drivers/staging/{ => media}/solo6x10/v4l2.c | 0 83 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 drivers/staging/media/Kconfig create mode 100644 drivers/staging/media/Makefile rename drivers/staging/{ => media}/cxd2099/Kconfig (100%) rename drivers/staging/{ => media}/cxd2099/Makefile (100%) rename drivers/staging/{ => media}/cxd2099/TODO (100%) rename drivers/staging/{ => media}/cxd2099/cxd2099.c (100%) rename drivers/staging/{ => media}/cxd2099/cxd2099.h (100%) rename drivers/staging/{ => media}/dt3155v4l/Kconfig (100%) rename drivers/staging/{ => media}/dt3155v4l/Makefile (100%) rename drivers/staging/{ => media}/dt3155v4l/dt3155v4l.c (100%) rename drivers/staging/{ => media}/dt3155v4l/dt3155v4l.h (100%) rename drivers/staging/{ => media}/easycap/Kconfig (100%) rename drivers/staging/{ => media}/easycap/Makefile (100%) rename drivers/staging/{ => media}/easycap/README (100%) rename drivers/staging/{ => media}/easycap/easycap.h (100%) rename drivers/staging/{ => media}/easycap/easycap_ioctl.c (100%) rename drivers/staging/{ => media}/easycap/easycap_low.c (100%) rename drivers/staging/{ => media}/easycap/easycap_main.c (100%) rename drivers/staging/{ => media}/easycap/easycap_settings.c (100%) rename drivers/staging/{ => media}/easycap/easycap_sound.c (100%) rename drivers/staging/{ => media}/easycap/easycap_testcard.c (100%) rename drivers/staging/{ => media}/go7007/Kconfig (100%) rename drivers/staging/{ => media}/go7007/Makefile (100%) rename drivers/staging/{ => media}/go7007/README (100%) rename drivers/staging/{ => media}/go7007/go7007-driver.c (100%) rename drivers/staging/{ => media}/go7007/go7007-fw.c (100%) rename drivers/staging/{ => media}/go7007/go7007-i2c.c (100%) rename drivers/staging/{ => media}/go7007/go7007-priv.h (100%) rename drivers/staging/{ => media}/go7007/go7007-usb.c (100%) rename drivers/staging/{ => media}/go7007/go7007-v4l2.c (100%) rename drivers/staging/{ => media}/go7007/go7007.h (100%) rename drivers/staging/{ => media}/go7007/go7007.txt (100%) rename drivers/staging/{ => media}/go7007/s2250-board.c (100%) rename drivers/staging/{ => media}/go7007/s2250-loader.c (100%) rename drivers/staging/{ => media}/go7007/s2250-loader.h (100%) rename drivers/staging/{ => media}/go7007/saa7134-go7007.c (100%) rename drivers/staging/{ => media}/go7007/snd-go7007.c (100%) rename drivers/staging/{ => media}/go7007/wis-i2c.h (100%) rename drivers/staging/{ => media}/go7007/wis-ov7640.c (100%) rename drivers/staging/{ => media}/go7007/wis-saa7113.c (100%) rename drivers/staging/{ => media}/go7007/wis-saa7115.c (100%) rename drivers/staging/{ => media}/go7007/wis-sony-tuner.c (100%) rename drivers/staging/{ => media}/go7007/wis-tw2804.c (100%) rename drivers/staging/{ => media}/go7007/wis-tw9903.c (100%) rename drivers/staging/{ => media}/go7007/wis-uda1342.c (100%) rename drivers/staging/{ => media}/lirc/Kconfig (100%) rename drivers/staging/{ => media}/lirc/Makefile (100%) rename drivers/staging/{ => media}/lirc/TODO (100%) rename drivers/staging/{ => media}/lirc/TODO.lirc_zilog (100%) rename drivers/staging/{ => media}/lirc/lirc_bt829.c (100%) rename drivers/staging/{ => media}/lirc/lirc_ene0100.h (100%) rename drivers/staging/{ => media}/lirc/lirc_igorplugusb.c (100%) rename drivers/staging/{ => media}/lirc/lirc_imon.c (100%) rename drivers/staging/{ => media}/lirc/lirc_parallel.c (100%) rename drivers/staging/{ => media}/lirc/lirc_parallel.h (100%) rename drivers/staging/{ => media}/lirc/lirc_sasem.c (100%) rename drivers/staging/{ => media}/lirc/lirc_serial.c (100%) rename drivers/staging/{ => media}/lirc/lirc_sir.c (100%) rename drivers/staging/{ => media}/lirc/lirc_ttusbir.c (100%) rename drivers/staging/{ => media}/lirc/lirc_zilog.c (100%) rename drivers/staging/{ => media}/solo6x10/Kconfig (100%) rename drivers/staging/{ => media}/solo6x10/Makefile (100%) rename drivers/staging/{ => media}/solo6x10/TODO (100%) rename drivers/staging/{ => media}/solo6x10/core.c (100%) rename drivers/staging/{ => media}/solo6x10/disp.c (100%) rename drivers/staging/{ => media}/solo6x10/enc.c (100%) rename drivers/staging/{ => media}/solo6x10/g723.c (100%) rename drivers/staging/{ => media}/solo6x10/gpio.c (100%) rename drivers/staging/{ => media}/solo6x10/i2c.c (100%) rename drivers/staging/{ => media}/solo6x10/jpeg.h (100%) rename drivers/staging/{ => media}/solo6x10/offsets.h (100%) rename drivers/staging/{ => media}/solo6x10/osd-font.h (100%) rename drivers/staging/{ => media}/solo6x10/p2m.c (100%) rename drivers/staging/{ => media}/solo6x10/registers.h (100%) rename drivers/staging/{ => media}/solo6x10/solo6x10.h (100%) rename drivers/staging/{ => media}/solo6x10/tw28.c (100%) rename drivers/staging/{ => media}/solo6x10/tw28.h (100%) rename drivers/staging/{ => media}/solo6x10/v4l2-enc.c (100%) rename drivers/staging/{ => media}/solo6x10/v4l2.c (100%) diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile index cf7214edf65f..38019bafb862 100644 --- a/drivers/media/dvb/ddbridge/Makefile +++ b/drivers/media/dvb/ddbridge/Makefile @@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/ ccflags-y += -Idrivers/media/common/tuners/ # For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/cxd2099/ +ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile index 89873615e683..13ebeffb705f 100644 --- a/drivers/media/dvb/ngene/Makefile +++ b/drivers/media/dvb/ngene/Makefile @@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/ ccflags-y += -Idrivers/media/common/tuners/ # For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/cxd2099/ +ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 39df8597d310..25cdff36a78a 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -30,10 +30,6 @@ source "drivers/staging/et131x/Kconfig" source "drivers/staging/slicoss/Kconfig" -source "drivers/staging/go7007/Kconfig" - -source "drivers/staging/cxd2099/Kconfig" - source "drivers/staging/usbip/Kconfig" source "drivers/staging/winbond/Kconfig" @@ -102,20 +98,12 @@ source "drivers/staging/wlags49_h25/Kconfig" source "drivers/staging/sm7xx/Kconfig" -source "drivers/staging/dt3155v4l/Kconfig" - source "drivers/staging/crystalhd/Kconfig" source "drivers/staging/cxt1e1/Kconfig" source "drivers/staging/xgifb/Kconfig" -source "drivers/staging/lirc/Kconfig" - -source "drivers/staging/easycap/Kconfig" - -source "drivers/staging/solo6x10/Kconfig" - source "drivers/staging/tidspbridge/Kconfig" source "drivers/staging/quickstart/Kconfig" @@ -142,6 +130,6 @@ source "drivers/staging/mei/Kconfig" source "drivers/staging/nvec/Kconfig" -source "drivers/staging/media/as102/Kconfig" +source "drivers/staging/media/Kconfig" endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index cd1bcc1f0e66..a25f3f26c7ff 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -4,11 +4,9 @@ obj-$(CONFIG_STAGING) += staging.o obj-y += serial/ +obj-y += media/ obj-$(CONFIG_ET131X) += et131x/ obj-$(CONFIG_SLICOSS) += slicoss/ -obj-$(CONFIG_VIDEO_GO7007) += go7007/ -obj-$(CONFIG_DVB_CXD2099) += cxd2099/ -obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_USBIP_CORE) += usbip/ obj-$(CONFIG_W35UND) += winbond/ obj-$(CONFIG_PRISM2_USB) += wlan-ng/ @@ -43,12 +41,9 @@ obj-$(CONFIG_ZCACHE) += zcache/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ obj-$(CONFIG_FB_SM7XX) += sm7xx/ -obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ obj-$(CONFIG_CRYSTALHD) += crystalhd/ obj-$(CONFIG_CXT1E1) += cxt1e1/ obj-$(CONFIG_FB_XGI) += xgifb/ -obj-$(CONFIG_EASYCAP) += easycap/ -obj-$(CONFIG_SOLO6X10) += solo6x10/ obj-$(CONFIG_TIDSPBRIDGE) += tidspbridge/ obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/ obj-$(CONFIG_SBE_2T3E3) += sbe-2t3e3/ @@ -62,4 +57,3 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ obj-$(CONFIG_DRM_PSB) += gma500/ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_MFD_NVEC) += nvec/ -obj-$(CONFIG_DVB_AS102) += media/as102/ diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig new file mode 100644 index 000000000000..7e5caa39ed3f --- /dev/null +++ b/drivers/staging/media/Kconfig @@ -0,0 +1,37 @@ +menuconfig STAGING_MEDIA + bool "Media staging drivers" + default n + ---help--- + This option allows you to select a number of media drivers that + don't have the "normal" Linux kernel quality level. + Most of them don't follow properly the V4L, DVB and/or RC API's, + so, they won't likely work fine with the existing applications. + That also means that, one fixed, their API's will change to match + the existing ones. + + If you wish to work on these drivers, to help improve them, or + to report problems you have with them, please use the + linux-media@vger.kernel.org mailing list. + + If in doubt, say N here. + + +if STAGING_MEDIA + +# Please keep them in alphabetic order +source "drivers/staging/media/as102/Kconfig" + +source "drivers/staging/media/cxd2099/Kconfig" + +source "drivers/staging/media/dt3155v4l/Kconfig" + +source "drivers/staging/media/easycap/Kconfig" + +source "drivers/staging/media/go7007/Kconfig" + +source "drivers/staging/media/solo6x10/Kconfig" + +# Keep LIRC at the end, as it has sub-menus +source "drivers/staging/media/lirc/Kconfig" + +endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile new file mode 100644 index 000000000000..c69124cdb0d3 --- /dev/null +++ b/drivers/staging/media/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_DVB_AS102) += as102/ +obj-$(CONFIG_DVB_CXD2099) += cxd2099/ +obj-$(CONFIG_EASYCAP) += easycap/ +obj-$(CONFIG_LIRC_STAGING) += lirc/ +obj-$(CONFIG_SOLO6X10) += solo6x10/ +obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ +obj-$(CONFIG_VIDEO_GO7007) += go7007/ diff --git a/drivers/staging/cxd2099/Kconfig b/drivers/staging/media/cxd2099/Kconfig similarity index 100% rename from drivers/staging/cxd2099/Kconfig rename to drivers/staging/media/cxd2099/Kconfig diff --git a/drivers/staging/cxd2099/Makefile b/drivers/staging/media/cxd2099/Makefile similarity index 100% rename from drivers/staging/cxd2099/Makefile rename to drivers/staging/media/cxd2099/Makefile diff --git a/drivers/staging/cxd2099/TODO b/drivers/staging/media/cxd2099/TODO similarity index 100% rename from drivers/staging/cxd2099/TODO rename to drivers/staging/media/cxd2099/TODO diff --git a/drivers/staging/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c similarity index 100% rename from drivers/staging/cxd2099/cxd2099.c rename to drivers/staging/media/cxd2099/cxd2099.c diff --git a/drivers/staging/cxd2099/cxd2099.h b/drivers/staging/media/cxd2099/cxd2099.h similarity index 100% rename from drivers/staging/cxd2099/cxd2099.h rename to drivers/staging/media/cxd2099/cxd2099.h diff --git a/drivers/staging/dt3155v4l/Kconfig b/drivers/staging/media/dt3155v4l/Kconfig similarity index 100% rename from drivers/staging/dt3155v4l/Kconfig rename to drivers/staging/media/dt3155v4l/Kconfig diff --git a/drivers/staging/dt3155v4l/Makefile b/drivers/staging/media/dt3155v4l/Makefile similarity index 100% rename from drivers/staging/dt3155v4l/Makefile rename to drivers/staging/media/dt3155v4l/Makefile diff --git a/drivers/staging/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c similarity index 100% rename from drivers/staging/dt3155v4l/dt3155v4l.c rename to drivers/staging/media/dt3155v4l/dt3155v4l.c diff --git a/drivers/staging/dt3155v4l/dt3155v4l.h b/drivers/staging/media/dt3155v4l/dt3155v4l.h similarity index 100% rename from drivers/staging/dt3155v4l/dt3155v4l.h rename to drivers/staging/media/dt3155v4l/dt3155v4l.h diff --git a/drivers/staging/easycap/Kconfig b/drivers/staging/media/easycap/Kconfig similarity index 100% rename from drivers/staging/easycap/Kconfig rename to drivers/staging/media/easycap/Kconfig diff --git a/drivers/staging/easycap/Makefile b/drivers/staging/media/easycap/Makefile similarity index 100% rename from drivers/staging/easycap/Makefile rename to drivers/staging/media/easycap/Makefile diff --git a/drivers/staging/easycap/README b/drivers/staging/media/easycap/README similarity index 100% rename from drivers/staging/easycap/README rename to drivers/staging/media/easycap/README diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/media/easycap/easycap.h similarity index 100% rename from drivers/staging/easycap/easycap.h rename to drivers/staging/media/easycap/easycap.h diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c similarity index 100% rename from drivers/staging/easycap/easycap_ioctl.c rename to drivers/staging/media/easycap/easycap_ioctl.c diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/media/easycap/easycap_low.c similarity index 100% rename from drivers/staging/easycap/easycap_low.c rename to drivers/staging/media/easycap/easycap_low.c diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c similarity index 100% rename from drivers/staging/easycap/easycap_main.c rename to drivers/staging/media/easycap/easycap_main.c diff --git a/drivers/staging/easycap/easycap_settings.c b/drivers/staging/media/easycap/easycap_settings.c similarity index 100% rename from drivers/staging/easycap/easycap_settings.c rename to drivers/staging/media/easycap/easycap_settings.c diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/media/easycap/easycap_sound.c similarity index 100% rename from drivers/staging/easycap/easycap_sound.c rename to drivers/staging/media/easycap/easycap_sound.c diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/media/easycap/easycap_testcard.c similarity index 100% rename from drivers/staging/easycap/easycap_testcard.c rename to drivers/staging/media/easycap/easycap_testcard.c diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig similarity index 100% rename from drivers/staging/go7007/Kconfig rename to drivers/staging/media/go7007/Kconfig diff --git a/drivers/staging/go7007/Makefile b/drivers/staging/media/go7007/Makefile similarity index 100% rename from drivers/staging/go7007/Makefile rename to drivers/staging/media/go7007/Makefile diff --git a/drivers/staging/go7007/README b/drivers/staging/media/go7007/README similarity index 100% rename from drivers/staging/go7007/README rename to drivers/staging/media/go7007/README diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c similarity index 100% rename from drivers/staging/go7007/go7007-driver.c rename to drivers/staging/media/go7007/go7007-driver.c diff --git a/drivers/staging/go7007/go7007-fw.c b/drivers/staging/media/go7007/go7007-fw.c similarity index 100% rename from drivers/staging/go7007/go7007-fw.c rename to drivers/staging/media/go7007/go7007-fw.c diff --git a/drivers/staging/go7007/go7007-i2c.c b/drivers/staging/media/go7007/go7007-i2c.c similarity index 100% rename from drivers/staging/go7007/go7007-i2c.c rename to drivers/staging/media/go7007/go7007-i2c.c diff --git a/drivers/staging/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h similarity index 100% rename from drivers/staging/go7007/go7007-priv.h rename to drivers/staging/media/go7007/go7007-priv.h diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c similarity index 100% rename from drivers/staging/go7007/go7007-usb.c rename to drivers/staging/media/go7007/go7007-usb.c diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c similarity index 100% rename from drivers/staging/go7007/go7007-v4l2.c rename to drivers/staging/media/go7007/go7007-v4l2.c diff --git a/drivers/staging/go7007/go7007.h b/drivers/staging/media/go7007/go7007.h similarity index 100% rename from drivers/staging/go7007/go7007.h rename to drivers/staging/media/go7007/go7007.h diff --git a/drivers/staging/go7007/go7007.txt b/drivers/staging/media/go7007/go7007.txt similarity index 100% rename from drivers/staging/go7007/go7007.txt rename to drivers/staging/media/go7007/go7007.txt diff --git a/drivers/staging/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c similarity index 100% rename from drivers/staging/go7007/s2250-board.c rename to drivers/staging/media/go7007/s2250-board.c diff --git a/drivers/staging/go7007/s2250-loader.c b/drivers/staging/media/go7007/s2250-loader.c similarity index 100% rename from drivers/staging/go7007/s2250-loader.c rename to drivers/staging/media/go7007/s2250-loader.c diff --git a/drivers/staging/go7007/s2250-loader.h b/drivers/staging/media/go7007/s2250-loader.h similarity index 100% rename from drivers/staging/go7007/s2250-loader.h rename to drivers/staging/media/go7007/s2250-loader.h diff --git a/drivers/staging/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c similarity index 100% rename from drivers/staging/go7007/saa7134-go7007.c rename to drivers/staging/media/go7007/saa7134-go7007.c diff --git a/drivers/staging/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c similarity index 100% rename from drivers/staging/go7007/snd-go7007.c rename to drivers/staging/media/go7007/snd-go7007.c diff --git a/drivers/staging/go7007/wis-i2c.h b/drivers/staging/media/go7007/wis-i2c.h similarity index 100% rename from drivers/staging/go7007/wis-i2c.h rename to drivers/staging/media/go7007/wis-i2c.h diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/media/go7007/wis-ov7640.c similarity index 100% rename from drivers/staging/go7007/wis-ov7640.c rename to drivers/staging/media/go7007/wis-ov7640.c diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/media/go7007/wis-saa7113.c similarity index 100% rename from drivers/staging/go7007/wis-saa7113.c rename to drivers/staging/media/go7007/wis-saa7113.c diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/media/go7007/wis-saa7115.c similarity index 100% rename from drivers/staging/go7007/wis-saa7115.c rename to drivers/staging/media/go7007/wis-saa7115.c diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/media/go7007/wis-sony-tuner.c similarity index 100% rename from drivers/staging/go7007/wis-sony-tuner.c rename to drivers/staging/media/go7007/wis-sony-tuner.c diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/media/go7007/wis-tw2804.c similarity index 100% rename from drivers/staging/go7007/wis-tw2804.c rename to drivers/staging/media/go7007/wis-tw2804.c diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/media/go7007/wis-tw9903.c similarity index 100% rename from drivers/staging/go7007/wis-tw9903.c rename to drivers/staging/media/go7007/wis-tw9903.c diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/media/go7007/wis-uda1342.c similarity index 100% rename from drivers/staging/go7007/wis-uda1342.c rename to drivers/staging/media/go7007/wis-uda1342.c diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig similarity index 100% rename from drivers/staging/lirc/Kconfig rename to drivers/staging/media/lirc/Kconfig diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/media/lirc/Makefile similarity index 100% rename from drivers/staging/lirc/Makefile rename to drivers/staging/media/lirc/Makefile diff --git a/drivers/staging/lirc/TODO b/drivers/staging/media/lirc/TODO similarity index 100% rename from drivers/staging/lirc/TODO rename to drivers/staging/media/lirc/TODO diff --git a/drivers/staging/lirc/TODO.lirc_zilog b/drivers/staging/media/lirc/TODO.lirc_zilog similarity index 100% rename from drivers/staging/lirc/TODO.lirc_zilog rename to drivers/staging/media/lirc/TODO.lirc_zilog diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/media/lirc/lirc_bt829.c similarity index 100% rename from drivers/staging/lirc/lirc_bt829.c rename to drivers/staging/media/lirc/lirc_bt829.c diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/media/lirc/lirc_ene0100.h similarity index 100% rename from drivers/staging/lirc/lirc_ene0100.h rename to drivers/staging/media/lirc/lirc_ene0100.h diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/media/lirc/lirc_igorplugusb.c similarity index 100% rename from drivers/staging/lirc/lirc_igorplugusb.c rename to drivers/staging/media/lirc/lirc_igorplugusb.c diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c similarity index 100% rename from drivers/staging/lirc/lirc_imon.c rename to drivers/staging/media/lirc/lirc_imon.c diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/media/lirc/lirc_parallel.c similarity index 100% rename from drivers/staging/lirc/lirc_parallel.c rename to drivers/staging/media/lirc/lirc_parallel.c diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/media/lirc/lirc_parallel.h similarity index 100% rename from drivers/staging/lirc/lirc_parallel.h rename to drivers/staging/media/lirc/lirc_parallel.h diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c similarity index 100% rename from drivers/staging/lirc/lirc_sasem.c rename to drivers/staging/media/lirc/lirc_sasem.c diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c similarity index 100% rename from drivers/staging/lirc/lirc_serial.c rename to drivers/staging/media/lirc/lirc_serial.c diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c similarity index 100% rename from drivers/staging/lirc/lirc_sir.c rename to drivers/staging/media/lirc/lirc_sir.c diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/media/lirc/lirc_ttusbir.c similarity index 100% rename from drivers/staging/lirc/lirc_ttusbir.c rename to drivers/staging/media/lirc/lirc_ttusbir.c diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c similarity index 100% rename from drivers/staging/lirc/lirc_zilog.c rename to drivers/staging/media/lirc/lirc_zilog.c diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig similarity index 100% rename from drivers/staging/solo6x10/Kconfig rename to drivers/staging/media/solo6x10/Kconfig diff --git a/drivers/staging/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile similarity index 100% rename from drivers/staging/solo6x10/Makefile rename to drivers/staging/media/solo6x10/Makefile diff --git a/drivers/staging/solo6x10/TODO b/drivers/staging/media/solo6x10/TODO similarity index 100% rename from drivers/staging/solo6x10/TODO rename to drivers/staging/media/solo6x10/TODO diff --git a/drivers/staging/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c similarity index 100% rename from drivers/staging/solo6x10/core.c rename to drivers/staging/media/solo6x10/core.c diff --git a/drivers/staging/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c similarity index 100% rename from drivers/staging/solo6x10/disp.c rename to drivers/staging/media/solo6x10/disp.c diff --git a/drivers/staging/solo6x10/enc.c b/drivers/staging/media/solo6x10/enc.c similarity index 100% rename from drivers/staging/solo6x10/enc.c rename to drivers/staging/media/solo6x10/enc.c diff --git a/drivers/staging/solo6x10/g723.c b/drivers/staging/media/solo6x10/g723.c similarity index 100% rename from drivers/staging/solo6x10/g723.c rename to drivers/staging/media/solo6x10/g723.c diff --git a/drivers/staging/solo6x10/gpio.c b/drivers/staging/media/solo6x10/gpio.c similarity index 100% rename from drivers/staging/solo6x10/gpio.c rename to drivers/staging/media/solo6x10/gpio.c diff --git a/drivers/staging/solo6x10/i2c.c b/drivers/staging/media/solo6x10/i2c.c similarity index 100% rename from drivers/staging/solo6x10/i2c.c rename to drivers/staging/media/solo6x10/i2c.c diff --git a/drivers/staging/solo6x10/jpeg.h b/drivers/staging/media/solo6x10/jpeg.h similarity index 100% rename from drivers/staging/solo6x10/jpeg.h rename to drivers/staging/media/solo6x10/jpeg.h diff --git a/drivers/staging/solo6x10/offsets.h b/drivers/staging/media/solo6x10/offsets.h similarity index 100% rename from drivers/staging/solo6x10/offsets.h rename to drivers/staging/media/solo6x10/offsets.h diff --git a/drivers/staging/solo6x10/osd-font.h b/drivers/staging/media/solo6x10/osd-font.h similarity index 100% rename from drivers/staging/solo6x10/osd-font.h rename to drivers/staging/media/solo6x10/osd-font.h diff --git a/drivers/staging/solo6x10/p2m.c b/drivers/staging/media/solo6x10/p2m.c similarity index 100% rename from drivers/staging/solo6x10/p2m.c rename to drivers/staging/media/solo6x10/p2m.c diff --git a/drivers/staging/solo6x10/registers.h b/drivers/staging/media/solo6x10/registers.h similarity index 100% rename from drivers/staging/solo6x10/registers.h rename to drivers/staging/media/solo6x10/registers.h diff --git a/drivers/staging/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h similarity index 100% rename from drivers/staging/solo6x10/solo6x10.h rename to drivers/staging/media/solo6x10/solo6x10.h diff --git a/drivers/staging/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c similarity index 100% rename from drivers/staging/solo6x10/tw28.c rename to drivers/staging/media/solo6x10/tw28.c diff --git a/drivers/staging/solo6x10/tw28.h b/drivers/staging/media/solo6x10/tw28.h similarity index 100% rename from drivers/staging/solo6x10/tw28.h rename to drivers/staging/media/solo6x10/tw28.h diff --git a/drivers/staging/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c similarity index 100% rename from drivers/staging/solo6x10/v4l2-enc.c rename to drivers/staging/media/solo6x10/v4l2-enc.c diff --git a/drivers/staging/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c similarity index 100% rename from drivers/staging/solo6x10/v4l2.c rename to drivers/staging/media/solo6x10/v4l2.c From eec5ce013aa029cf6c91fba4838de13410f65024 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Jul 2011 07:43:15 -0300 Subject: [PATCH 026/144] [media] V4L: sh_mobile_ceu_camera: output image sizes must be a multiple of 4 CEU can only produce images with 4 pixel aligned width and height. Enforce this alignment, adjust comments and simplify some calculations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 49 ++++++++++++++-------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 8615fb81775f..f753df14aa3f 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -121,7 +121,7 @@ struct sh_mobile_ceu_dev { }; struct sh_mobile_ceu_cam { - /* CEU offsets within scaled by the CEU camera output */ + /* CEU offsets within the camera output, before the CEU scaler */ unsigned int ceu_left; unsigned int ceu_top; /* Client output, as seen by the CEU */ @@ -628,22 +628,22 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) left_offset = cam->ceu_left; top_offset = cam->ceu_top; - /* CEU cropping (CFSZR) is applied _after_ the scaling filter (CFLCR) */ + WARN_ON(icd->user_width & 3 || icd->user_height & 3); + + width = icd->user_width; + if (pcdev->image_mode) { in_width = cam->width; if (!pcdev->is_16bit) { in_width *= 2; left_offset *= 2; } - width = icd->user_width; - cdwdr_width = icd->user_width; + cdwdr_width = width; } else { - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + int bytes_per_line = soc_mbus_bytes_per_line(width, icd->current_fmt->host_fmt); unsigned int w_factor; - width = icd->user_width; - switch (icd->current_fmt->host_fmt->packing) { case SOC_MBUS_PACKING_2X8_PADHI: w_factor = 2; @@ -653,10 +653,10 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) } in_width = cam->width * w_factor; - left_offset = left_offset * w_factor; + left_offset *= w_factor; if (bytes_per_line < 0) - cdwdr_width = icd->user_width; + cdwdr_width = width; else cdwdr_width = bytes_per_line; } @@ -664,7 +664,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) height = icd->user_height; in_height = cam->height; if (V4L2_FIELD_NONE != pcdev->field) { - height /= 2; + height = (height / 2) & ~3; in_height /= 2; top_offset /= 2; cdwdr_width *= 2; @@ -686,6 +686,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) ceu_write(pcdev, CAMOR, camor); ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); + /* CFSZR clipping is applied _after_ the scaling filter (CFLCR) */ ceu_write(pcdev, CFSZR, (height << 16) | width); ceu_write(pcdev, CDWDR, cdwdr_width); } @@ -1414,7 +1415,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, capsr = capture_save_reset(pcdev); dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); - /* 1. - 2. Apply iterative camera S_CROP for new input window. */ + /* + * 1. - 2. Apply iterative camera S_CROP for new input window, read back + * actual camera rectangle. + */ ret = client_s_crop(icd, a, &cam_crop); if (ret < 0) return ret; @@ -1498,8 +1502,9 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, ceu_write(pcdev, CFLCR, cflcr); } - icd->user_width = out_width; - icd->user_height = out_height; + icd->user_width = out_width & ~3; + icd->user_height = out_height & ~3; + /* Offsets are applied at the CEU scaling filter input */ cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; @@ -1538,7 +1543,7 @@ static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd, * CEU crop, mapped backed onto the client input (subrect). */ static void calculate_client_output(struct soc_camera_device *icd, - struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) + const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) { struct sh_mobile_ceu_cam *cam = icd->host_priv; struct device *dev = icd->parent; @@ -1623,7 +1628,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, } /* 1.-4. Calculate client output geometry */ - calculate_client_output(icd, &f->fmt.pix, &mf); + calculate_client_output(icd, pix, &mf); mf.field = pix->field; mf.colorspace = pix->colorspace; mf.code = xlate->code; @@ -1700,6 +1705,10 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, pcdev->field = field; pcdev->image_mode = image_mode; + /* CFSZR requirement */ + pix->width &= ~3; + pix->height &= ~3; + return 0; } @@ -1725,7 +1734,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, /* FIXME: calculate using depth and bus width */ - v4l_bound_align_image(&pix->width, 2, 2560, 1, + /* CFSZR requires height and width to be 4-pixel aligned */ + v4l_bound_align_image(&pix->width, 2, 2560, 2, &pix->height, 4, 1920, 2, 0); width = pix->width; @@ -1778,6 +1788,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, pix->height = height; } + pix->width &= ~3; + pix->height &= ~3; + dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n", __func__, ret, pix->pixelformat, pix->width, pix->height); @@ -1824,8 +1837,8 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, out_height != f.fmt.pix.height)) ret = -EINVAL; if (!ret) { - icd->user_width = out_width; - icd->user_height = out_height; + icd->user_width = out_width & ~3; + icd->user_height = out_height & ~3; ret = sh_mobile_ceu_set_bus_param(icd, icd->current_fmt->host_fmt->fourcc); } From 369887411fb0f35585035aa7c253dc7fbe15cbc8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Jul 2011 09:44:40 -0300 Subject: [PATCH 027/144] [media] V4L: sh_mobile_ceu_camera: don't try to improve client scaling, if perfect If the client has managed to configure the precise output format, we don't have to try to further improve it. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index f753df14aa3f..b44f318aa011 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -1279,6 +1279,7 @@ static int client_s_fmt(struct soc_camera_device *icd, unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; unsigned int max_width, max_height; struct v4l2_cropcap cap; + bool ceu_1to1; int ret; ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, @@ -1288,7 +1289,14 @@ static int client_s_fmt(struct soc_camera_device *icd, dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); - if ((width == mf->width && height == mf->height) || !ceu_can_scale) + if (width == mf->width && height == mf->height) { + /* Perfect! The client has done it all. */ + ceu_1to1 = true; + goto update_cache; + } + + ceu_1to1 = false; + if (!ceu_can_scale) goto update_cache; cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -1328,7 +1336,10 @@ update_cache: if (ret < 0) return ret; - update_subrect(cam); + if (ceu_1to1) + cam->subrect = cam->rect; + else + update_subrect(cam); return 0; } @@ -1579,8 +1590,8 @@ static void calculate_client_output(struct soc_camera_device *icd, dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); /* - * 4. Calculate client output window by applying combined scales to real - * input window. + * 4. Calculate desired client output window by applying combined scales + * to client (real) input window. */ mf->width = scale_down(cam->rect.width, scale_h); mf->height = scale_down(cam->rect.height, scale_v); @@ -1627,7 +1638,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, return -EINVAL; } - /* 1.-4. Calculate client output geometry */ + /* 1.-4. Calculate desired client output geometry */ calculate_client_output(icd, pix, &mf); mf.field = pix->field; mf.colorspace = pix->colorspace; From 15f517e2726cae7d9ed2a0bccb6e36dbf3fff456 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 11:03:37 -0300 Subject: [PATCH 028/144] [media] V4L: sh_mobile_ceu_camera: fix field addresses in interleaved mode In interlaced interleaved mode field offset for deinterlacing depends on the pixel format. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 25 ++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index b44f318aa011..7841fde1cc4e 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -267,6 +267,7 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) unsigned long top1, top2; unsigned long bottom1, bottom2; u32 status; + bool planar; int ret = 0; /* @@ -314,17 +315,29 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) phys_addr_top = vb2_dma_contig_plane_dma_addr(pcdev->active, 0); - ceu_write(pcdev, top1, phys_addr_top); - if (V4L2_FIELD_NONE != pcdev->field) { - phys_addr_bottom = phys_addr_top + icd->user_width; - ceu_write(pcdev, bottom1, phys_addr_bottom); - } - switch (icd->current_fmt->host_fmt->fourcc) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: + planar = true; + break; + default: + planar = false; + } + + ceu_write(pcdev, top1, phys_addr_top); + if (V4L2_FIELD_NONE != pcdev->field) { + if (planar) + phys_addr_bottom = phys_addr_top + icd->user_width; + else + phys_addr_bottom = phys_addr_top + + soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + ceu_write(pcdev, bottom1, phys_addr_bottom); + } + + if (planar) { phys_addr_top += icd->user_width * icd->user_height; ceu_write(pcdev, top2, phys_addr_top); From fd861a072ca66b32db923f5cf8199b192317dda7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 11:12:14 -0300 Subject: [PATCH 029/144] [media] V4L: sh_mobile_ceu_camera: remove duplicated code Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 7841fde1cc4e..d1359f441a04 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -1018,9 +1018,6 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int cam->width = mf.width; cam->height = mf.height; - cam->width = mf.width; - cam->height = mf.height; - icd->host_priv = cam; } else { cam = icd->host_priv; From 7cd74ffb04e05c115ebe53a59f83a73e677a2c63 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 11:26:56 -0300 Subject: [PATCH 030/144] [media] V4L: imx074: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/imx074.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 0382ea752e6f..63f17aa57271 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -267,6 +267,17 @@ static int imx074_g_chip_ident(struct v4l2_subdev *sd, return 0; } +static int imx074_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + cfg->type = V4L2_MBUS_CSI2; + cfg->flags = V4L2_MBUS_CSI2_2_LANE | + V4L2_MBUS_CSI2_CHANNEL_0 | + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + + return 0; +} + static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { .s_stream = imx074_s_stream, .s_mbus_fmt = imx074_s_fmt, @@ -275,6 +286,7 @@ static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { .enum_mbus_fmt = imx074_enum_fmt, .g_crop = imx074_g_crop, .cropcap = imx074_cropcap, + .g_mbus_config = imx074_g_mbus_config, }; static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { From 32c69fcc785a2f8122c73d44ad160d9cfc4c9615 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 11:38:01 -0300 Subject: [PATCH 031/144] [media] V4L: soc-camera: add helper functions for new bus configuration type Add helper functions to process the new media bus configuration type similar to soc_camera_apply_sensor_flags() and soc_camera_bus_param_compatible(). Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 34 ++++++++++++++++++++++++++++++ drivers/media/video/soc_mediabus.c | 33 +++++++++++++++++++++++++++++ include/media/soc_camera.h | 6 ++++-- include/media/soc_mediabus.h | 2 ++ 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 5bdfe7e16bc1..8b16152f52fe 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -107,6 +107,40 @@ const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( } EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); +/** + * soc_camera_apply_board_flags() - apply platform SOCAM_SENSOR_INVERT_* flags + * @icl: camera platform parameters + * @cfg: media bus configuration + * @return: resulting flags + */ +unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, + const struct v4l2_mbus_config *cfg) +{ + unsigned long f, flags = cfg->flags; + + /* If only one of the two polarities is supported, switch to the opposite */ + if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { + f = flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW); + if (f == V4L2_MBUS_HSYNC_ACTIVE_HIGH || f == V4L2_MBUS_HSYNC_ACTIVE_LOW) + flags ^= V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW; + } + + if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { + f = flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW); + if (f == V4L2_MBUS_VSYNC_ACTIVE_HIGH || f == V4L2_MBUS_VSYNC_ACTIVE_LOW) + flags ^= V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW; + } + + if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { + f = flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING); + if (f == V4L2_MBUS_PCLK_SAMPLE_RISING || f == V4L2_MBUS_PCLK_SAMPLE_FALLING) + flags ^= V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; + } + + return flags; +} +EXPORT_SYMBOL(soc_camera_apply_board_flags); + /** * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags * @icl: camera platform parameters diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c index bea7c9cf4f88..cf7f2194ded4 100644 --- a/drivers/media/video/soc_mediabus.c +++ b/drivers/media/video/soc_mediabus.c @@ -383,6 +383,39 @@ const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( } EXPORT_SYMBOL(soc_mbus_get_fmtdesc); +unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg, + unsigned int flags) +{ + unsigned long common_flags; + bool hsync = true, vsync = true, pclk, data, mode; + bool mipi_lanes, mipi_clock; + + common_flags = cfg->flags & flags; + + switch (cfg->type) { + case V4L2_MBUS_PARALLEL: + hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_HSYNC_ACTIVE_LOW); + vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_VSYNC_ACTIVE_LOW); + case V4L2_MBUS_BT656: + pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_PCLK_SAMPLE_FALLING); + data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_LOW); + mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); + return (!hsync || !vsync || !pclk || !data || !mode) ? + 0 : common_flags; + case V4L2_MBUS_CSI2: + mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; + mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); + return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; + } + return 0; +} +EXPORT_SYMBOL(soc_mbus_config_compatible); + static int __init soc_mbus_init(void) { return 0; diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 7582952dceae..936a504f0bac 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -300,8 +300,10 @@ static inline void soc_camera_limit_side(int *start, int *length, *start = start_min + length_max - *length; } -extern unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, - unsigned long flags); +unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, + unsigned long flags); +unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, + const struct v4l2_mbus_config *cfg); /* This is only temporary here - until v4l2-subdev begins to link to video_device */ #include diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h index fae432544b41..73f1e7eb60f3 100644 --- a/include/media/soc_mediabus.h +++ b/include/media/soc_mediabus.h @@ -82,5 +82,7 @@ const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf); int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf, unsigned int *numerator, unsigned int *denominator); +unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg, + unsigned int flags); #endif From 32ca2085925b483251d94ecb3e12bb6dfc5c8133 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 11:46:02 -0300 Subject: [PATCH 032/144] [media] V4L: mt9m001: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 40 ++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 4da9cca939c1..7618b3c2fce0 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -13,9 +13,10 @@ #include #include +#include +#include #include #include -#include /* * mt9m001 i2c address 0x5d @@ -710,6 +711,41 @@ static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, return 0; } +static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + /* MT9M001 has all capture_format parameters fixed */ + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + +static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned int bps = soc_mbus_get_fmtdesc(icd->current_fmt->code)->bits_per_sample; + + if (icl->set_bus_param) + return icl->set_bus_param(icl, 1 << (bps - 1)); + + /* + * Without board specific bus width settings we only support the + * sensors native bus width + */ + return bps == 10 ? 0 : -EINVAL; +} + static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .s_stream = mt9m001_s_stream, .s_mbus_fmt = mt9m001_s_fmt, @@ -719,6 +755,8 @@ static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .g_crop = mt9m001_g_crop, .cropcap = mt9m001_cropcap, .enum_mbus_fmt = mt9m001_enum_fmt, + .g_mbus_config = mt9m001_g_mbus_config, + .s_mbus_config = mt9m001_s_mbus_config, }; static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { From 0c0b446d0d77dfdce0127073ea743c2e18ccd338 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 11:48:29 -0300 Subject: [PATCH 033/144] [media] V4L: mt9m111: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m111.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 07af26e6bebd..c9c4655c1fe4 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -14,9 +14,10 @@ #include #include +#include +#include #include #include -#include /* * MT9M111, MT9M112 and MT9M131: @@ -1019,6 +1020,22 @@ static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, return 0; } +static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { .s_mbus_fmt = mt9m111_s_fmt, .g_mbus_fmt = mt9m111_g_fmt, @@ -1027,6 +1044,7 @@ static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { .g_crop = mt9m111_g_crop, .cropcap = mt9m111_cropcap, .enum_mbus_fmt = mt9m111_enum_fmt, + .g_mbus_config = mt9m111_g_mbus_config, }; static struct v4l2_subdev_ops mt9m111_subdev_ops = { From a35057557271ed09a38b9d22483863f5415f2e54 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 11:50:24 -0300 Subject: [PATCH 034/144] [media] V4L: mt9t031: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9t031.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 30547cc3f89b..c5adb2301480 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -807,6 +808,36 @@ static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index, return 0; } +static int mt9t031_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + +static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + if (soc_camera_apply_board_flags(icl, cfg) & + V4L2_MBUS_PCLK_SAMPLE_FALLING) + return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); + else + return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); +} + static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { .s_stream = mt9t031_s_stream, .s_mbus_fmt = mt9t031_s_fmt, @@ -816,6 +847,8 @@ static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { .g_crop = mt9t031_g_crop, .cropcap = mt9t031_cropcap, .enum_mbus_fmt = mt9t031_enum_fmt, + .g_mbus_config = mt9t031_g_mbus_config, + .s_mbus_config = mt9t031_s_mbus_config, }; static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { From d46ebd463c15ec81bcba83686134035893a95564 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 11:52:42 -0300 Subject: [PATCH 035/144] [media] V4L: mt9t112: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9t112.c | 81 ++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index d2e0a50063a2..a3368d8e3193 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -34,11 +34,7 @@ /* #define EXT_CLOCK 24000000 */ /************************************************************************ - - macro - - ************************************************************************/ /* * frame size @@ -80,11 +76,7 @@ #define VAR8(id, offset) _VAR(id, offset, 0x8000) /************************************************************************ - - struct - - ************************************************************************/ struct mt9t112_frame_size { u16 width; @@ -108,15 +100,12 @@ struct mt9t112_priv { int model; u32 flags; /* for flags */ -#define INIT_DONE (1<<0) +#define INIT_DONE (1 << 0) +#define PCLK_RISING (1 << 1) }; /************************************************************************ - - supported format - - ************************************************************************/ static const struct mt9t112_format mt9t112_cfmts[] = { @@ -154,11 +143,7 @@ static const struct mt9t112_format mt9t112_cfmts[] = { }; /************************************************************************ - - general function - - ************************************************************************/ static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) { @@ -758,15 +743,18 @@ static int mt9t112_init_camera(const struct i2c_client *client) } /************************************************************************ - - soc_camera_ops - - ************************************************************************/ static int mt9t112_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { + struct soc_camera_link *icl = to_soc_camera_link(icd); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (soc_camera_apply_sensor_flags(icl, flags) & SOCAM_PCLK_SAMPLE_RISING) + priv->flags |= PCLK_RISING; + return 0; } @@ -795,11 +783,7 @@ static struct soc_camera_ops mt9t112_ops = { }; /************************************************************************ - - v4l2_subdev_core_ops - - ************************************************************************/ static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) @@ -850,11 +834,7 @@ static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { /************************************************************************ - - v4l2_subdev_video_ops - - ************************************************************************/ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) { @@ -877,8 +857,7 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) } if (!(priv->flags & INIT_DONE)) { - u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE & - priv->info->flags) ? 0x0001 : 0x0000; + u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000; ECHECKER(ret, mt9t112_init_camera(client)); @@ -1027,6 +1006,36 @@ static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, return 0; } +static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | + V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + +static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) + priv->flags |= PCLK_RISING; + + return 0; +} + static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { .s_stream = mt9t112_s_stream, .g_mbus_fmt = mt9t112_g_fmt, @@ -1036,14 +1045,12 @@ static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { .g_crop = mt9t112_g_crop, .s_crop = mt9t112_s_crop, .enum_mbus_fmt = mt9t112_enum_fmt, + .g_mbus_config = mt9t112_g_mbus_config, + .s_mbus_config = mt9t112_s_mbus_config, }; /************************************************************************ - - i2c driver - - ************************************************************************/ static struct v4l2_subdev_ops mt9t112_subdev_ops = { .core = &mt9t112_subdev_core_ops, @@ -1147,11 +1154,7 @@ static struct i2c_driver mt9t112_i2c_driver = { }; /************************************************************************ - - module function - - ************************************************************************/ static int __init mt9t112_module_init(void) { From e8e2c70ce61b42b1d9d8953c8a87feb8ba6c6e74 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 05:53:33 -0300 Subject: [PATCH 036/144] [media] V4L: mt9v022: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9v022.c | 76 ++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 51b0fccbfe70..2fc6ca22f31c 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -14,9 +14,10 @@ #include #include +#include +#include #include #include -#include /* * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c @@ -848,6 +849,77 @@ static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, return 0; } +static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | + V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + +static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + unsigned long flags = soc_camera_apply_board_flags(icl, cfg); + unsigned int bps = soc_mbus_get_fmtdesc(icd->current_fmt->code)->bits_per_sample; + int ret; + u16 pixclk = 0; + + dev_info(icd->pdev, "set %d: %s, %dbps\n", icd->current_fmt->code, + icd->current_fmt->host_fmt->name, bps); + + if (icl->set_bus_param) { + ret = icl->set_bus_param(icl, 1 << (bps - 1)); + if (ret) + return ret; + } else if (bps != 10) { + /* + * Without board specific bus width settings we only support the + * sensors native bus width + */ + return -EINVAL; + } + + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + pixclk |= 0x10; + + if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)) + pixclk |= 0x1; + + if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)) + pixclk |= 0x2; + + ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); + if (ret < 0) + return ret; + + if (!(flags & V4L2_MBUS_MASTER)) + mt9v022->chip_control &= ~0x8; + + ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", + pixclk, mt9v022->chip_control); + + return 0; +} + static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { .s_stream = mt9v022_s_stream, .s_mbus_fmt = mt9v022_s_fmt, @@ -857,6 +929,8 @@ static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { .g_crop = mt9v022_g_crop, .cropcap = mt9v022_cropcap, .enum_mbus_fmt = mt9v022_enum_fmt, + .g_mbus_config = mt9v022_g_mbus_config, + .s_mbus_config = mt9v022_s_mbus_config, }; static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { From d463003b56776576b071c4fcfdf391f4bb32d21c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 11:59:53 -0300 Subject: [PATCH 037/144] [media] V4L: ov2640: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov2640.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 9ce2fa037b94..78bf602296f7 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -19,10 +19,11 @@ #include #include #include -#include -#include + #include #include +#include +#include #define VAL_SET(x, mask, rshift, lshift) \ ((((x) >> rshift) & mask) << lshift) @@ -1083,6 +1084,22 @@ static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { #endif }; +static int ov2640_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { .s_stream = ov2640_s_stream, .g_mbus_fmt = ov2640_g_fmt, @@ -1091,6 +1108,7 @@ static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { .cropcap = ov2640_cropcap, .g_crop = ov2640_g_crop, .enum_mbus_fmt = ov2640_enum_fmt, + .g_mbus_config = ov2640_g_mbus_config, }; static struct v4l2_subdev_ops ov2640_subdev_ops = { From 93ac81dcbec35455b9a8181bf3ddd2a225588434 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 12:01:01 -0300 Subject: [PATCH 038/144] [media] V4L: ov5642: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov5642.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 349a4ad3ccc1..7eaeb25d5627 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -855,6 +855,17 @@ static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } +static int ov5642_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + cfg->type = V4L2_MBUS_CSI2; + cfg->flags = V4L2_MBUS_CSI2_2_LANE | + V4L2_MBUS_CSI2_CHANNEL_0 | + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + + return 0; +} + static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { .s_mbus_fmt = ov5642_s_fmt, .g_mbus_fmt = ov5642_g_fmt, @@ -862,6 +873,7 @@ static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { .enum_mbus_fmt = ov5642_enum_fmt, .g_crop = ov5642_g_crop, .cropcap = ov5642_cropcap, + .g_mbus_config = ov5642_g_mbus_config, }; static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { From 59ca25b7eb8f6675be94ec18beb8eb66293f550d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 12:02:00 -0300 Subject: [PATCH 039/144] [media] V4L: ov6650: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov6650.c | 53 +++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 456d9ad9ae5a..a26734d4cf30 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -30,9 +30,9 @@ #include #include +#include #include - /* Register definitions */ #define REG_GAIN 0x00 /* range 00 - 3F */ #define REG_BLUE 0x01 @@ -1111,6 +1111,55 @@ static struct v4l2_subdev_core_ops ov6650_core_ops = { #endif }; +static int ov6650_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_MASTER | + V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + +static int ov6650_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = soc_camera_apply_board_flags(icl, cfg); + int ret; + + if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); + else + ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); + if (ret) + return ret; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); + else + ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); + if (ret) + return ret; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); + else + ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); + + return ret; +} + static struct v4l2_subdev_video_ops ov6650_video_ops = { .s_stream = ov6650_s_stream, .g_mbus_fmt = ov6650_g_fmt, @@ -1122,6 +1171,8 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = { .s_crop = ov6650_s_crop, .g_parm = ov6650_g_parm, .s_parm = ov6650_s_parm, + .g_mbus_config = ov6650_g_mbus_config, + .s_mbus_config = ov6650_s_mbus_config, }; static struct v4l2_subdev_ops ov6650_subdev_ops = { From 2891f37c261306ae3c3d84775500da3cb9428e33 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 12:20:42 -0300 Subject: [PATCH 040/144] [media] V4L: ov772x: rename macros to not pollute the global namespace Macros, defined in a header under include/ should be kept in a local namespace and not pollute the global one. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov772x.c | 8 ++++---- include/media/ov772x.h | 25 ++++++++++++------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 397870f076c1..458265b51e3c 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -822,13 +822,13 @@ static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height, goto ov772x_set_fmt_error; ret = ov772x_mask_set(client, - EDGE_TRSHLD, EDGE_THRESHOLD_MASK, + EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK, priv->info->edgectrl.threshold); if (ret < 0) goto ov772x_set_fmt_error; ret = ov772x_mask_set(client, - EDGE_STRNGT, EDGE_STRENGTH_MASK, + EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK, priv->info->edgectrl.strength); if (ret < 0) goto ov772x_set_fmt_error; @@ -840,13 +840,13 @@ static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height, * set upper and lower limit */ ret = ov772x_mask_set(client, - EDGE_UPPER, EDGE_UPPER_MASK, + EDGE_UPPER, OV772X_EDGE_UPPER_MASK, priv->info->edgectrl.upper); if (ret < 0) goto ov772x_set_fmt_error; ret = ov772x_mask_set(client, - EDGE_LOWER, EDGE_LOWER_MASK, + EDGE_LOWER, OV772X_EDGE_LOWER_MASK, priv->info->edgectrl.lower); if (ret < 0) goto ov772x_set_fmt_error; diff --git a/include/media/ov772x.h b/include/media/ov772x.h index 548bf1155c83..f9e27c0ce901 100644 --- a/include/media/ov772x.h +++ b/include/media/ov772x.h @@ -12,8 +12,6 @@ #ifndef __OV772X_H__ #define __OV772X_H__ -#include - /* for flags */ #define OV772X_FLAG_VFLIP (1 << 0) /* Vertical flip image */ #define OV772X_FLAG_HFLIP (1 << 1) /* Horizontal flip image */ @@ -32,22 +30,23 @@ struct ov772x_edge_ctrl { unsigned char lower; }; -#define OV772X_MANUAL_EDGE_CTRL 0x80 /* un-used bit of strength */ -#define EDGE_STRENGTH_MASK 0x1F -#define EDGE_THRESHOLD_MASK 0x0F -#define EDGE_UPPER_MASK 0xFF -#define EDGE_LOWER_MASK 0xFF +#define OV772X_MANUAL_EDGE_CTRL 0x80 /* un-used bit of strength */ +#define OV772X_EDGE_STRENGTH_MASK 0x1F +#define OV772X_EDGE_THRESHOLD_MASK 0x0F +#define OV772X_EDGE_UPPER_MASK 0xFF +#define OV772X_EDGE_LOWER_MASK 0xFF #define OV772X_AUTO_EDGECTRL(u, l) \ { \ - .upper = (u & EDGE_UPPER_MASK), \ - .lower = (l & EDGE_LOWER_MASK), \ + .upper = (u & OV772X_EDGE_UPPER_MASK), \ + .lower = (l & OV772X_EDGE_LOWER_MASK), \ } -#define OV772X_MANUAL_EDGECTRL(s, t) \ -{ \ - .strength = (s & EDGE_STRENGTH_MASK) | OV772X_MANUAL_EDGE_CTRL,\ - .threshold = (t & EDGE_THRESHOLD_MASK), \ +#define OV772X_MANUAL_EDGECTRL(s, t) \ +{ \ + .strength = (s & OV772X_EDGE_STRENGTH_MASK) | \ + OV772X_MANUAL_EDGE_CTRL, \ + .threshold = (t & OV772X_EDGE_THRESHOLD_MASK), \ } /* From 00cf08f5dcef58878633746a3b10389cb6ce5e4e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 12:25:07 -0300 Subject: [PATCH 041/144] [media] V4L: ov772x: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov772x.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 458265b51e3c..b70ffba58494 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -21,11 +21,12 @@ #include #include #include -#include -#include + +#include #include #include -#include +#include +#include /* * register offset @@ -1095,6 +1096,22 @@ static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index, return 0; } +static int ov772x_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { .s_stream = ov772x_s_stream, .g_mbus_fmt = ov772x_g_fmt, @@ -1103,6 +1120,7 @@ static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { .cropcap = ov772x_cropcap, .g_crop = ov772x_g_crop, .enum_mbus_fmt = ov772x_enum_fmt, + .g_mbus_config = ov772x_g_mbus_config, }; static struct v4l2_subdev_ops ov772x_subdev_ops = { From de2e388d74c77f45eab65c83749b0a4b9eb843d9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 12:28:10 -0300 Subject: [PATCH 042/144] [media] V4L: ov9640: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov9640.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 3681a6ff0815..4156c9f6375b 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -25,9 +25,11 @@ #include #include #include + +#include +#include #include #include -#include #include "ov9640.h" @@ -722,6 +724,22 @@ static struct v4l2_subdev_core_ops ov9640_core_ops = { }; +static int ov9640_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + static struct v4l2_subdev_video_ops ov9640_video_ops = { .s_stream = ov9640_s_stream, .s_mbus_fmt = ov9640_s_fmt, @@ -729,7 +747,7 @@ static struct v4l2_subdev_video_ops ov9640_video_ops = { .enum_mbus_fmt = ov9640_enum_fmt, .cropcap = ov9640_cropcap, .g_crop = ov9640_g_crop, - + .g_mbus_config = ov9640_g_mbus_config, }; static struct v4l2_subdev_ops ov9640_subdev_ops = { From e534c9eac0951b28b0462ffac0043a698436a922 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 12:30:42 -0300 Subject: [PATCH 043/144] [media] V4L: ov9740: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov9740.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index edd1ffcca30b..67b7020c933e 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c @@ -14,8 +14,10 @@ #include #include #include -#include + #include +#include +#include #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) @@ -949,13 +951,30 @@ static struct soc_camera_ops ov9740_ops = { .num_controls = ARRAY_SIZE(ov9740_controls), }; +static int ov9740_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + static struct v4l2_subdev_video_ops ov9740_video_ops = { - .s_stream = ov9740_s_stream, - .s_mbus_fmt = ov9740_s_fmt, - .try_mbus_fmt = ov9740_try_fmt, - .enum_mbus_fmt = ov9740_enum_fmt, - .cropcap = ov9740_cropcap, - .g_crop = ov9740_g_crop, + .s_stream = ov9740_s_stream, + .s_mbus_fmt = ov9740_s_fmt, + .try_mbus_fmt = ov9740_try_fmt, + .enum_mbus_fmt = ov9740_enum_fmt, + .cropcap = ov9740_cropcap, + .g_crop = ov9740_g_crop, + .g_mbus_config = ov9740_g_mbus_config, }; static struct v4l2_subdev_core_ops ov9740_core_ops = { From bc1a1f3a0317925bf311ce27a797d48acc2cd3b0 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 12:33:40 -0300 Subject: [PATCH 044/144] [media] V4L: rj54n1cb0c: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/rj54n1cb0c.c | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 847ccc067e87..d19c79bc0a7f 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -1337,6 +1337,38 @@ static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { #endif }; +static int rj54n1_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = + V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | + V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + +static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ + if (soc_camera_apply_board_flags(icl, cfg) & + V4L2_MBUS_PCLK_SAMPLE_RISING) + return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); + else + return reg_write(client, RJ54N1_OUT_SIGPO, 0); +} + static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { .s_stream = rj54n1_s_stream, .s_mbus_fmt = rj54n1_s_fmt, @@ -1346,6 +1378,8 @@ static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { .g_crop = rj54n1_g_crop, .s_crop = rj54n1_s_crop, .cropcap = rj54n1_cropcap, + .g_mbus_config = rj54n1_g_mbus_config, + .s_mbus_config = rj54n1_s_mbus_config, }; static struct v4l2_subdev_ops rj54n1_subdev_ops = { From 19a1780b628ecbc943465fa4d53b69e94c279f23 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 12:49:13 -0300 Subject: [PATCH 045/144] [media] ARM: ap4evb: switch imx074 configuration to default number of lanes The sh_mobile_csi2 driver will change meaning of the .lanes platform data field from "bitmask of used lanes" to "number of used lanes." To avoid a regression during this transition switch ap4evb to rely on the 2 lane default. Signed-off-by: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-shmobile/board-ap4evb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 5b7edadf4647..f9f66c20c9f1 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -933,7 +933,7 @@ static struct platform_device ap4evb_camera = { static struct sh_csi2_client_config csi2_clients[] = { { .phy = SH_CSI2_PHY_MAIN, - .lanes = 3, + .lanes = 0, /* default: 2 lanes */ .channel = 0, .pdev = &ap4evb_camera, }, From f836c6289b0cfbfaf2f90202d0edcb45f957f7cd Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 13:13:47 -0300 Subject: [PATCH 046/144] [media] V4L: sh_mobile_csi2: verify client compatibility Switch the meaning of the .lanes platform data parameter to specify the number of used lanes instead of a bitmask. Verify bus configuration compatibility with client's capabilities. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_csi2.c | 58 +++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 2893a0134c7e..09ef63d912e3 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -144,11 +145,21 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) udelay(5); iowrite32(0x00000000, priv->base + SH_CSI2_SRST); - if (priv->client->lanes & 3) - tmp |= priv->client->lanes & 3; - else - /* Default - both lanes */ - tmp |= 3; + switch (pdata->type) { + case SH_CSI2C: + if (priv->client->lanes == 1) + tmp |= 1; + else + /* Default - both lanes */ + tmp |= 3; + break; + case SH_CSI2I: + if (!priv->client->lanes || priv->client->lanes > 4) + /* Default - all 4 lanes */ + tmp |= 0xf; + else + tmp |= (1 << priv->client->lanes) - 1; + } if (priv->client->phy == SH_CSI2_PHY_MAIN) tmp |= 0x8000; @@ -185,7 +196,9 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) struct v4l2_subdev *sd, *csi2_sd = &priv->subdev; struct soc_camera_device *icd = NULL; struct device *dev = v4l2_get_subdevdata(&priv->subdev); - int i; + struct v4l2_mbus_config cfg; + unsigned long common_flags, csi2_flags; + int i, ret; v4l2_device_for_each_subdev(sd, csi2_sd->v4l2_dev) if (sd->grp_id) { @@ -205,6 +218,39 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) if (i == pdata->num_clients) return -ENODEV; + /* Check if we can support this camera */ + csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_1_LANE; + + switch (pdata->type) { + case SH_CSI2C: + if (pdata->clients[i].lanes != 1) + csi2_flags |= V4L2_MBUS_CSI2_2_LANE; + break; + case SH_CSI2I: + switch (pdata->clients[i].lanes) { + default: + csi2_flags |= V4L2_MBUS_CSI2_4_LANE; + case 3: + csi2_flags |= V4L2_MBUS_CSI2_3_LANE; + case 2: + csi2_flags |= V4L2_MBUS_CSI2_2_LANE; + } + } + + cfg.type = V4L2_MBUS_CSI2; + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (ret == -ENOIOCTLCMD) + common_flags = csi2_flags; + else if (!ret) + common_flags = soc_mbus_config_compatible(&cfg, + csi2_flags); + else + common_flags = 0; + + if (!common_flags) + return -EINVAL; + + /* All good: camera MIPI configuration supported */ priv->client = pdata->clients + i; priv->set_bus_param = icd->ops->set_bus_param; From 022e52cfe846469363e168b6a0095e7873279811 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 13:19:01 -0300 Subject: [PATCH 047/144] [media] V4L: sh_mobile_csi2: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_csi2.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 09ef63d912e3..6b4044134113 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -36,6 +36,7 @@ struct sh_csi2 { struct v4l2_subdev subdev; struct list_head list; unsigned int irq; + unsigned long mipi_flags; void __iomem *base; struct platform_device *pdev; struct sh_csi2_client_config *client; @@ -128,9 +129,34 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd, return 0; } +static int sh_csi2_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + + return 0; +} + +static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); + struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; + struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); + struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2, + .flags = priv->mipi_flags}; + + return v4l2_subdev_call(client_sd, video, s_mbus_config, &client_cfg); +} + static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { .s_mbus_fmt = sh_csi2_s_fmt, .try_mbus_fmt = sh_csi2_try_fmt, + .g_mbus_config = sh_csi2_g_mbus_config, + .s_mbus_config = sh_csi2_s_mbus_config, }; static void sh_csi2_hwinit(struct sh_csi2 *priv) @@ -251,6 +277,7 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) return -EINVAL; /* All good: camera MIPI configuration supported */ + priv->mipi_flags = common_flags; priv->client = pdata->clients + i; priv->set_bus_param = icd->ops->set_bus_param; From 2ad90b71231a68e2041680e3ae3b7661ebe825ec Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 09:49:37 -0300 Subject: [PATCH 048/144] [media] V4L: tw9910: remove a not really implemented cropping support Cropping is not really correctly implemented by this driver and only needlessly obfuscates the code. Remove it. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tw9910.c | 129 +++++++++++++---------------------- 1 file changed, 46 insertions(+), 83 deletions(-) diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 742482e30011..686512eefed8 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -203,6 +203,10 @@ #define RTSEL_FIELD 0x06 /* 0110 = FIELD */ #define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */ +/* HSYNC start and end are constant for now */ +#define HSYNC_START 0x0260 +#define HSYNC_END 0x0300 + /* * structure */ @@ -220,18 +224,6 @@ struct tw9910_scale_ctrl { u16 vscale; }; -struct tw9910_cropping_ctrl { - u16 vdelay; - u16 vactive; - u16 hdelay; - u16 hactive; -}; - -struct tw9910_hsync_ctrl { - u16 start; - u16 end; -}; - struct tw9910_priv { struct v4l2_subdev subdev; struct tw9910_video_info *info; @@ -329,11 +321,6 @@ static const struct tw9910_scale_ctrl tw9910_pal_scales[] = { }, }; -static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = { - .start = 0x0260, - .end = 0x0300, -}; - /* * general function */ @@ -378,21 +365,20 @@ static int tw9910_set_scale(struct i2c_client *client, return ret; } -static int tw9910_set_hsync(struct i2c_client *client, - const struct tw9910_hsync_ctrl *hsync) +static int tw9910_set_hsync(struct i2c_client *client) { struct tw9910_priv *priv = to_tw9910(client); int ret; /* bit 10 - 3 */ ret = i2c_smbus_write_byte_data(client, HSBEGIN, - (hsync->start & 0x07F8) >> 3); + (HSYNC_START & 0x07F8) >> 3); if (ret < 0) return ret; /* bit 10 - 3 */ ret = i2c_smbus_write_byte_data(client, HSEND, - (hsync->end & 0x07F8) >> 3); + (HSYNC_END & 0x07F8) >> 3); if (ret < 0) return ret; @@ -400,8 +386,8 @@ static int tw9910_set_hsync(struct i2c_client *client, /* bit 2 - 0 */ if (1 == priv->revision) ret = tw9910_mask_set(client, HSLOWCTL, 0x77, - (hsync->start & 0x0007) << 4 | - (hsync->end & 0x0007)); + (HSYNC_START & 0x0007) << 4 | + (HSYNC_END & 0x0007)); return ret; } @@ -433,8 +419,8 @@ static int tw9910_power(struct i2c_client *client, int enable) return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); } -static const struct tw9910_scale_ctrl* -tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height) +static const struct tw9910_scale_ctrl *tw9910_select_norm(struct soc_camera_device *icd, + u32 width, u32 height) { const struct tw9910_scale_ctrl *scale; const struct tw9910_scale_ctrl *ret = NULL; @@ -510,10 +496,13 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) static int tw9910_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { + struct soc_camera_link *icl = to_soc_camera_link(icd); struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct i2c_client *client = v4l2_get_subdevdata(sd); u8 val = VSSL_VVALID | HSSL_DVALID; + flags = soc_camera_apply_sensor_flags(icl, flags); + /* * set OUTCTR1 * @@ -600,19 +589,18 @@ static int tw9910_s_register(struct v4l2_subdev *sd, } #endif -static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) { - struct v4l2_rect *rect = &a->c; struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); struct soc_camera_device *icd = client->dev.platform_data; - int ret = -EINVAL; - u8 val; + int ret = -EINVAL; + u8 val; /* * select suitable norm */ - priv->scale = tw9910_select_norm(icd, rect->width, rect->height); + priv->scale = tw9910_select_norm(icd, *width, *height); if (!priv->scale) goto tw9910_set_fmt_error; @@ -670,14 +658,12 @@ static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) /* * set hsync */ - ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl); + ret = tw9910_set_hsync(client); if (ret < 0) goto tw9910_set_fmt_error; - rect->width = priv->scale->width; - rect->height = priv->scale->height; - rect->left = 0; - rect->top = 0; + *width = priv->scale->width; + *height = priv->scale->height; return ret; @@ -692,27 +678,17 @@ tw9910_set_fmt_error: static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - - if (!priv->scale) { - int ret; - struct v4l2_crop crop = { - .c = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }; - ret = tw9910_s_crop(sd, &crop); - if (ret < 0) - return ret; - } + struct soc_camera_device *icd = client->dev.platform_data; a->c.left = 0; a->c.top = 0; - a->c.width = priv->scale->width; - a->c.height = priv->scale->height; + if (icd->vdev->current_norm & V4L2_STD_NTSC) { + a->c.width = 640; + a->c.height = 480; + } else { + a->c.width = 768; + a->c.height = 576; + } a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; return 0; @@ -720,14 +696,19 @@ static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + a->bounds.left = 0; a->bounds.top = 0; - a->bounds.width = 768; - a->bounds.height = 576; - a->defrect.left = 0; - a->defrect.top = 0; - a->defrect.width = 640; - a->defrect.height = 480; + if (icd->vdev->current_norm & V4L2_STD_NTSC) { + a->bounds.width = 640; + a->bounds.height = 480; + } else { + a->bounds.width = 768; + a->bounds.height = 576; + } + a->defrect = a->bounds; a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; a->pixelaspect.numerator = 1; a->pixelaspect.denominator = 1; @@ -743,15 +724,8 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, if (!priv->scale) { int ret; - struct v4l2_crop crop = { - .c = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }; - ret = tw9910_s_crop(sd, &crop); + u32 width = 640, height = 480; + ret = tw9910_set_frame(sd, &width, &height); if (ret < 0) return ret; } @@ -768,17 +742,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - /* See tw9910_s_crop() - no proper cropping support */ - struct v4l2_crop a = { - .c = { - .left = 0, - .top = 0, - .width = mf->width, - .height = mf->height, - }, - }; + u32 width = mf->width, height = mf->height; int ret; WARN_ON(mf->field != V4L2_FIELD_ANY && @@ -792,10 +756,10 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; - ret = tw9910_s_crop(sd, &a); + ret = tw9910_set_frame(sd, &width, &height); if (!ret) { - mf->width = priv->scale->width; - mf->height = priv->scale->height; + mf->width = width; + mf->height = height; } return ret; } @@ -905,7 +869,6 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { .try_mbus_fmt = tw9910_try_fmt, .cropcap = tw9910_cropcap, .g_crop = tw9910_g_crop, - .s_crop = tw9910_s_crop, .enum_mbus_fmt = tw9910_enum_fmt, }; From 0d3263f9ad74d60cdcc2beaa365913be85769696 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Jul 2011 13:29:27 -0300 Subject: [PATCH 049/144] [media] V4L: tw9910: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tw9910.c | 49 ++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 686512eefed8..4f9fbf2ba35d 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -23,10 +23,12 @@ #include #include #include + +#include +#include +#include #include #include -#include -#include #define GET_ID(val) ((val & 0xF8) >> 3) #define GET_REV(val) (val & 0x07) @@ -862,6 +864,47 @@ static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index, return 0; } +static int tw9910_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(icl, cfg); + + return 0; +} + +static int tw9910_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + u8 val = VSSL_VVALID | HSSL_DVALID; + unsigned long flags = soc_camera_apply_board_flags(icl, cfg); + + /* + * set OUTCTR1 + * + * We use VVALID and DVALID signals to control VSYNC and HSYNC + * outputs, in this mode their polarity is inverted. + */ + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + val |= HSP_HI; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + val |= VSP_HI; + + return i2c_smbus_write_byte_data(client, OUTCTR1, val); +} + static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { .s_stream = tw9910_s_stream, .g_mbus_fmt = tw9910_g_fmt, @@ -870,6 +913,8 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { .cropcap = tw9910_cropcap, .g_crop = tw9910_g_crop, .enum_mbus_fmt = tw9910_enum_fmt, + .g_mbus_config = tw9910_g_mbus_config, + .s_mbus_config = tw9910_s_mbus_config, }; static struct v4l2_subdev_ops tw9910_subdev_ops = { From 84c760a5dec0edab857cc02c29ef334722520310 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 10:06:09 -0300 Subject: [PATCH 050/144] [media] V4L: soc_camera_platform: support the new mbus-config subdev ops Extend the driver to also support [gs]_mbus_config() subdevice video operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera_platform.c | 12 ++++++++++++ include/media/soc_camera_platform.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index 8069cd6bc5e8..7045e458a66e 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -115,6 +115,17 @@ static int soc_camera_platform_cropcap(struct v4l2_subdev *sd, return 0; } +static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); + + cfg->flags = p->mbus_param; + cfg->type = p->mbus_type; + + return 0; +} + static struct v4l2_subdev_video_ops platform_subdev_video_ops = { .s_stream = soc_camera_platform_s_stream, .enum_mbus_fmt = soc_camera_platform_enum_fmt, @@ -123,6 +134,7 @@ static struct v4l2_subdev_video_ops platform_subdev_video_ops = { .try_mbus_fmt = soc_camera_platform_fill_fmt, .g_mbus_fmt = soc_camera_platform_fill_fmt, .s_mbus_fmt = soc_camera_platform_fill_fmt, + .g_mbus_config = soc_camera_platform_g_mbus_config, }; static struct v4l2_subdev_ops platform_subdev_ops = { diff --git a/include/media/soc_camera_platform.h b/include/media/soc_camera_platform.h index 74f0fa15ca47..a15f92be8aba 100644 --- a/include/media/soc_camera_platform.h +++ b/include/media/soc_camera_platform.h @@ -13,6 +13,7 @@ #include #include +#include struct device; @@ -21,6 +22,8 @@ struct soc_camera_platform_info { unsigned long format_depth; struct v4l2_mbus_framefmt format; unsigned long bus_param; + unsigned long mbus_param; + enum v4l2_mbus_type mbus_type; struct soc_camera_device *icd; int (*set_capture)(struct soc_camera_platform_info *info, int enable); }; From 9d3baeb4628fbd608282559758a75215ac865f4d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 10:10:43 -0300 Subject: [PATCH 051/144] [media] V4L: soc-camera: compatible bus-width flags With the new subdevice media-bus configuration methods bus-width is not configured along with other bus parameters, instead, it is derived from the data format. With those methods it is convenient to specify supported bus-widths in the platform data as (1 << (width - 1)). We redefine SOCAM_DATAWIDTH_* flags to use the same convention to make platform data seemlessly reusable. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- include/media/soc_camera.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 936a504f0bac..73337cff85a3 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -241,19 +241,19 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( #define SOCAM_MASTER (1 << 0) #define SOCAM_SLAVE (1 << 1) #define SOCAM_HSYNC_ACTIVE_HIGH (1 << 2) -#define SOCAM_HSYNC_ACTIVE_LOW (1 << 3) +#define SOCAM_HSYNC_ACTIVE_LOW (1 << 6) #define SOCAM_VSYNC_ACTIVE_HIGH (1 << 4) #define SOCAM_VSYNC_ACTIVE_LOW (1 << 5) -#define SOCAM_DATAWIDTH_4 (1 << 6) +#define SOCAM_DATAWIDTH_4 (1 << 3) #define SOCAM_DATAWIDTH_8 (1 << 7) #define SOCAM_DATAWIDTH_9 (1 << 8) #define SOCAM_DATAWIDTH_10 (1 << 9) -#define SOCAM_DATAWIDTH_15 (1 << 10) -#define SOCAM_DATAWIDTH_16 (1 << 11) +#define SOCAM_DATAWIDTH_15 (1 << 14) +#define SOCAM_DATAWIDTH_16 (1 << 15) #define SOCAM_PCLK_SAMPLE_RISING (1 << 12) #define SOCAM_PCLK_SAMPLE_FALLING (1 << 13) -#define SOCAM_DATA_ACTIVE_HIGH (1 << 14) -#define SOCAM_DATA_ACTIVE_LOW (1 << 15) +#define SOCAM_DATA_ACTIVE_HIGH (1 << 10) +#define SOCAM_DATA_ACTIVE_LOW (1 << 11) #define SOCAM_MIPI_1LANE (1 << 16) #define SOCAM_MIPI_2LANE (1 << 17) #define SOCAM_MIPI_3LANE (1 << 18) From d1e87ed7e13988e455491e055a9aebad74eb3aaa Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 10:48:40 -0300 Subject: [PATCH 052/144] [media] ARM: mach-shmobile: convert mackerel to mediabus flags Prepare the board to switch to the new subdevice media-bus configuration operations. Signed-off-by: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-shmobile/board-mackerel.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 3689ad2e9156..8a9100b1afed 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -1226,6 +1226,10 @@ static struct soc_camera_platform_info camera_info = { .bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH, + .mbus_param = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH, + .mbus_type = V4L2_MBUS_PARALLEL, .set_capture = camera_set_capture, }; From 7e5cf0ae269933dd951a9c1b746fb6bd569f1ac3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 10:52:36 -0300 Subject: [PATCH 053/144] [media] sh: convert ap325rxa to mediabus flags Prepare the board to switch to the new subdevice media-bus configuration operations. Signed-off-by: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Mauro Carvalho Chehab --- arch/sh/boards/mach-ap325rxa/setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index d36265758911..93a9f5dc5918 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -348,6 +348,10 @@ static struct soc_camera_platform_info camera_info = { .bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH, + .mbus_param = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH, + .mbus_type = V4L2_MBUS_PARALLEL, .set_capture = camera_set_capture, }; From fae00288c423330b7fd97df59fc90039b6399d93 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 11:11:41 -0300 Subject: [PATCH 054/144] [media] ARM: PXA: use gpio_set_value_cansleep() on pcm990 Camera-switching GPIOs are provided by a i2c GPIO extender, switching them can send the caller to sleep. Use the GPIO API *_cansleep methods explicitly to avoid runtime warnings. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-pxa/pcm990-baseboard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c index 9a9c539f6c01..6d38c6548b3d 100644 --- a/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/arch/arm/mach-pxa/pcm990-baseboard.c @@ -394,9 +394,9 @@ static int pcm990_camera_set_bus_param(struct soc_camera_link *link, } if (flags & SOCAM_DATAWIDTH_8) - gpio_set_value(gpio_bus_switch, 1); + gpio_set_value_cansleep(gpio_bus_switch, 1); else - gpio_set_value(gpio_bus_switch, 0); + gpio_set_value_cansleep(gpio_bus_switch, 0); return 0; } From a4e9f10ba9b788a2254cf26d3f0a22555d439ea4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 12:18:37 -0300 Subject: [PATCH 055/144] [media] V4L: atmel-isi: convert to the new mbus-config subdev operations Switch from soc-camera specific .{query,set}_bus_param() to V4L2 subdevice .[gs]_mbus_config() operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/atmel-isi.c | 136 +++++++++++++++++--------------- 1 file changed, 73 insertions(+), 63 deletions(-) diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 774715d2f84f..06f6595a1c9a 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c @@ -94,6 +94,7 @@ struct atmel_isi { unsigned int irq; struct isi_platform_data *pdata; + u16 width_flags; /* max 12 bits */ struct list_head video_buffer_list; struct frame_buffer *active; @@ -647,50 +648,42 @@ static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) fmt->packing == SOC_MBUS_PACKING_EXTEND16); } -static unsigned long make_bus_param(struct atmel_isi *isi) -{ - unsigned long flags; - /* - * Platform specified synchronization and pixel clock polarities are - * only a recommendation and are only used during probing. Atmel ISI - * camera interface only works in master mode, i.e., uses HSYNC and - * VSYNC signals from the sensor - */ - flags = SOCAM_MASTER | - SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_PCLK_SAMPLE_RISING | - SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_DATA_ACTIVE_HIGH; - - if (isi->pdata->data_width_flags & ISI_DATAWIDTH_10) - flags |= SOCAM_DATAWIDTH_10; - - if (isi->pdata->data_width_flags & ISI_DATAWIDTH_8) - flags |= SOCAM_DATAWIDTH_8; - - if (flags & SOCAM_DATAWIDTH_MASK) - return flags; - - return 0; -} +#define ISI_BUS_PARAM (V4L2_MBUS_MASTER | \ + V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ + V4L2_MBUS_HSYNC_ACTIVE_LOW | \ + V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ + V4L2_MBUS_VSYNC_ACTIVE_LOW | \ + V4L2_MBUS_PCLK_SAMPLE_RISING | \ + V4L2_MBUS_PCLK_SAMPLE_FALLING | \ + V4L2_MBUS_DATA_ACTIVE_HIGH) static int isi_camera_try_bus_param(struct soc_camera_device *icd, unsigned char buswidth) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct atmel_isi *isi = ici->priv; - unsigned long camera_flags; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long common_flags; int ret; - camera_flags = icd->ops->query_bus_param(icd); - ret = soc_camera_bus_param_compatible(camera_flags, - make_bus_param(isi)); - if (!ret) - return -EINVAL; - return 0; + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, + ISI_BUS_PARAM); + if (!common_flags) { + dev_warn(icd->parent, + "Flags incompatible: camera 0x%x, host 0x%x\n", + cfg.flags, ISI_BUS_PARAM); + return -EINVAL; + } + } else if (ret != -ENOIOCTLCMD) { + return ret; + } + + if ((1 << (buswidth - 1)) & isi->width_flags) + return 0; + return -EINVAL; } @@ -812,59 +805,71 @@ static int isi_camera_querycap(struct soc_camera_host *ici, static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct atmel_isi *isi = ici->priv; - unsigned long bus_flags, camera_flags, common_flags; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long common_flags; int ret; u32 cfg1 = 0; - camera_flags = icd->ops->query_bus_param(icd); - - bus_flags = make_bus_param(isi); - common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); - dev_dbg(icd->parent, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", - camera_flags, bus_flags, common_flags); - if (!common_flags) - return -EINVAL; + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, + ISI_BUS_PARAM); + if (!common_flags) { + dev_warn(icd->parent, + "Flags incompatible: camera 0x%x, host 0x%x\n", + cfg.flags, ISI_BUS_PARAM); + return -EINVAL; + } + } else if (ret != -ENOIOCTLCMD) { + return ret; + } else { + common_flags = ISI_BUS_PARAM; + } + dev_dbg(icd->parent, "Flags cam: 0x%x host: 0x%x common: 0x%lx\n", + cfg.flags, ISI_BUS_PARAM, common_flags); /* Make choises, based on platform preferences */ - if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { if (isi->pdata->hsync_act_low) - common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; else - common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; } - if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { if (isi->pdata->vsync_act_low) - common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; else - common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; } - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && + (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { if (isi->pdata->pclk_act_falling) - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; else - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; } - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) { - dev_dbg(icd->parent, "Camera set_bus_param(%lx) returned %d\n", + cfg.flags = common_flags; + ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", common_flags, ret); return ret; } /* set bus param for ISI */ - if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) + if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; - if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) + if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; - if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) + if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; if (isi->pdata->has_emb_sync) @@ -983,6 +988,11 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) goto err_ioremap; } + if (pdata->data_width_flags & ISI_DATAWIDTH_8) + isi->width_flags = 1 << 7; + if (pdata->data_width_flags & ISI_DATAWIDTH_10) + isi->width_flags |= 1 << 9; + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); irq = platform_get_irq(pdev, 0); From 8acbfd3306195f85c2255ecd9b2337cb2ac4c532 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 12:30:21 -0300 Subject: [PATCH 056/144] [media] V4L: mx1_camera: convert to the new mbus-config subdev operations Switch from soc-camera specific .{query,set}_bus_param() to V4L2 subdevice .[gs]_mbus_config() operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mx1_camera.c | 71 +++++++++++++++++++------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 087db12a3a67..18e94c7d2be8 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -78,11 +78,10 @@ #define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \ CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT) -#define CSI_BUS_FLAGS (SOCAM_MASTER | SOCAM_HSYNC_ACTIVE_HIGH | \ - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | \ - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW | \ - SOCAM_DATAWIDTH_8) +#define CSI_BUS_FLAGS (V4L2_MBUS_MASTER | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ + V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ + V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_LOW) #define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */ @@ -490,59 +489,73 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd, static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx1_camera_dev *pcdev = ici->priv; - unsigned long camera_flags, common_flags; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long common_flags; unsigned int csicr1; int ret; - camera_flags = icd->ops->query_bus_param(icd); - /* MX1 supports only 8bit buswidth */ - common_flags = soc_camera_bus_param_compatible(camera_flags, - CSI_BUS_FLAGS); - if (!common_flags) - return -EINVAL; + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, CSI_BUS_FLAGS); + if (!common_flags) { + dev_warn(icd->parent, + "Flags incompatible: camera 0x%x, host 0x%x\n", + cfg.flags, CSI_BUS_FLAGS); + return -EINVAL; + } + } else if (ret != -ENOIOCTLCMD) { + return ret; + } else { + common_flags = CSI_BUS_FLAGS; + } /* Make choises, based on platform choice */ - if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { if (!pcdev->pdata || pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH) - common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; else - common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; } - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && + (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { if (!pcdev->pdata || pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING) - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; else - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; } - if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && - (common_flags & SOCAM_DATA_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { if (!pcdev->pdata || pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH) - common_flags &= ~SOCAM_DATA_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; else - common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; } - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) + cfg.flags = common_flags; + ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", + common_flags, ret); return ret; + } csicr1 = __raw_readl(pcdev->base + CSICR1); - if (common_flags & SOCAM_PCLK_SAMPLE_RISING) + if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) csicr1 |= CSICR1_REDGE; - if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) + if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) csicr1 |= CSICR1_SOF_POL; - if (common_flags & SOCAM_DATA_ACTIVE_LOW) + if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) csicr1 |= CSICR1_DATA_POL; __raw_writel(csicr1, pcdev->base + CSICR1); From db592a24656ec1028728eb4eccc450b925bea268 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 12:38:11 -0300 Subject: [PATCH 057/144] [media] V4L: mx2_camera: convert to the new mbus-config subdev operations Switch from soc-camera specific .{query,set}_bus_param() to V4L2 subdevice .[gs]_mbus_config() operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mx2_camera.c | 96 ++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index ec2410c0c806..a803d9ea8fd6 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c @@ -686,16 +686,15 @@ static void mx2_camera_init_videobuf(struct videobuf_queue *q, icd, &icd->video_lock); } -#define MX2_BUS_FLAGS (SOCAM_DATAWIDTH_8 | \ - SOCAM_MASTER | \ - SOCAM_VSYNC_ACTIVE_HIGH | \ - SOCAM_VSYNC_ACTIVE_LOW | \ - SOCAM_HSYNC_ACTIVE_HIGH | \ - SOCAM_HSYNC_ACTIVE_LOW | \ - SOCAM_PCLK_SAMPLE_RISING | \ - SOCAM_PCLK_SAMPLE_FALLING | \ - SOCAM_DATA_ACTIVE_HIGH | \ - SOCAM_DATA_ACTIVE_LOW) +#define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ + V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ + V4L2_MBUS_VSYNC_ACTIVE_LOW | \ + V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ + V4L2_MBUS_HSYNC_ACTIVE_LOW | \ + V4L2_MBUS_PCLK_SAMPLE_RISING | \ + V4L2_MBUS_PCLK_SAMPLE_FALLING | \ + V4L2_MBUS_DATA_ACTIVE_HIGH | \ + V4L2_MBUS_DATA_ACTIVE_LOW) static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) { @@ -770,46 +769,59 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, static int mx2_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { - struct soc_camera_host *ici = - to_soc_camera_host(icd->parent); + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; - unsigned long camera_flags, common_flags; - int ret = 0; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long common_flags; + int ret; int bytesperline; u32 csicr1 = pcdev->csicr1; - camera_flags = icd->ops->query_bus_param(icd); - - common_flags = soc_camera_bus_param_compatible(camera_flags, - MX2_BUS_FLAGS); - if (!common_flags) - return -EINVAL; - - if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { - if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) - common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; - else - common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; - } - - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { - if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; - else - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; - } - - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS); + if (!common_flags) { + dev_warn(icd->parent, + "Flags incompatible: camera 0x%x, host 0x%x\n", + cfg.flags, MX2_BUS_FLAGS); + return -EINVAL; + } + } else if (ret != -ENOIOCTLCMD) { return ret; + } else { + common_flags = MX2_BUS_FLAGS; + } - if (common_flags & SOCAM_PCLK_SAMPLE_RISING) + if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { + if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; + else + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; + } + + if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && + (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { + if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; + else + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; + } + + cfg.flags = common_flags; + ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", + common_flags, ret); + return ret; + } + + if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) csicr1 |= CSICR1_REDGE; - if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) + if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) csicr1 |= CSICR1_SOF_POL; - if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH) + if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) csicr1 |= CSICR1_HSYNC_POL; if (pcdev->platform_flags & MX2_CAMERA_SWAP16) csicr1 |= CSICR1_SWAP16_EN; From 97a0a611e8dfa8f8f7c7b1c49239b0ab44cc3710 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 15:57:27 -0300 Subject: [PATCH 058/144] [media] V4L: ov2640: remove undefined struct struct ov2640_camera_info isn't declared anywhere, remove it. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov2640.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 78bf602296f7..31f361ed7cc5 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -300,7 +300,6 @@ struct ov2640_win_size { struct ov2640_priv { struct v4l2_subdev subdev; - struct ov2640_camera_info *info; enum v4l2_mbus_pixelcode cfmt_code; const struct ov2640_win_size *win; int model; @@ -1153,8 +1152,6 @@ static int ov2640_probe(struct i2c_client *client, return -ENOMEM; } - priv->info = icl->priv; - v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); icd->ops = &ov2640_ops; From 579cea034237dcfdcac071faa3e00b4528ddf8ec Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 16:00:29 -0300 Subject: [PATCH 059/144] [media] V4L: mx3_camera: convert to the new mbus-config subdev operations Switch from soc-camera specific .{query,set}_bus_param() to V4L2 subdevice .[gs]_mbus_config() operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mx3_camera.c | 197 ++++++++++++++----------------- 1 file changed, 89 insertions(+), 108 deletions(-) diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index c8e958a07e91..f4ef6b993ff1 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -109,6 +109,7 @@ struct mx3_camera_dev { unsigned long platform_flags; unsigned long mclk; + u16 width_flags; /* max 15 bits */ struct list_head capture; spinlock_t lock; /* Protects video buffer lists */ @@ -547,59 +548,28 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd) static int test_platform_param(struct mx3_camera_dev *mx3_cam, unsigned char buswidth, unsigned long *flags) { + /* + * If requested data width is supported by the platform, use it or any + * possible lower value - i.MX31 is smart enough to shift bits + */ + if (buswidth > fls(mx3_cam->width_flags)) + return -EINVAL; + /* * Platform specified synchronization and pixel clock polarities are * only a recommendation and are only used during probing. MX3x * camera interface only works in master mode, i.e., uses HSYNC and * VSYNC signals from the sensor */ - *flags = SOCAM_MASTER | - SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_PCLK_SAMPLE_RISING | - SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_DATA_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_LOW; - - /* - * If requested data width is supported by the platform, use it or any - * possible lower value - i.MX31 is smart enough to schift bits - */ - if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) - *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | - SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) - *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | - SOCAM_DATAWIDTH_4; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) - *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) - *flags |= SOCAM_DATAWIDTH_4; - - switch (buswidth) { - case 15: - if (!(*flags & SOCAM_DATAWIDTH_15)) - return -EINVAL; - break; - case 10: - if (!(*flags & SOCAM_DATAWIDTH_10)) - return -EINVAL; - break; - case 8: - if (!(*flags & SOCAM_DATAWIDTH_8)) - return -EINVAL; - break; - case 4: - if (!(*flags & SOCAM_DATAWIDTH_4)) - return -EINVAL; - break; - default: - dev_warn(mx3_cam->soc_host.v4l2_dev.dev, - "Unsupported bus width %d\n", buswidth); - return -EINVAL; - } + *flags = V4L2_MBUS_MASTER | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_HSYNC_ACTIVE_LOW | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_VSYNC_ACTIVE_LOW | + V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_PCLK_SAMPLE_FALLING | + V4L2_MBUS_DATA_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_LOW; return 0; } @@ -607,9 +577,11 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, static int mx3_camera_try_bus_param(struct soc_camera_device *icd, const unsigned int depth) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; - unsigned long bus_flags, camera_flags; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long bus_flags, common_flags; int ret = test_platform_param(mx3_cam, depth, &bus_flags); dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); @@ -617,15 +589,21 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd, if (ret < 0) return ret; - camera_flags = icd->ops->query_bus_param(icd); + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, + bus_flags); + if (!common_flags) { + dev_warn(icd->parent, + "Flags incompatible: camera 0x%x, host 0x%lx\n", + cfg.flags, bus_flags); + return -EINVAL; + } + } else if (ret != -ENOIOCTLCMD) { + return ret; + } - ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); - if (ret < 0) - dev_warn(icd->parent, - "Flags incompatible: camera %lx, host %lx\n", - camera_flags, bus_flags); - - return ret; + return 0; } static bool chan_filter(struct dma_chan *chan, void *arg) @@ -994,9 +972,11 @@ static int mx3_camera_querycap(struct soc_camera_host *ici, static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; - unsigned long bus_flags, camera_flags, common_flags; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long bus_flags, common_flags; u32 dw, sens_conf; const struct soc_mbus_pixelfmt *fmt; int buswidth; @@ -1008,83 +988,76 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) if (!fmt) return -EINVAL; - buswidth = fmt->bits_per_sample; - ret = test_platform_param(mx3_cam, buswidth, &bus_flags); - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { dev_warn(dev, "Format %x not found\n", pixfmt); return -EINVAL; } + buswidth = fmt->bits_per_sample; + ret = test_platform_param(mx3_cam, buswidth, &bus_flags); + dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); if (ret < 0) return ret; - camera_flags = icd->ops->query_bus_param(icd); - - common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); - dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", - camera_flags, bus_flags, common_flags); - if (!common_flags) { - dev_dbg(dev, "no common flags"); - return -EINVAL; + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, + bus_flags); + if (!common_flags) { + dev_warn(icd->parent, + "Flags incompatible: camera 0x%x, host 0x%lx\n", + cfg.flags, bus_flags); + return -EINVAL; + } + } else if (ret != -ENOIOCTLCMD) { + return ret; + } else { + common_flags = bus_flags; } + dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n", + cfg.flags, bus_flags, common_flags); + /* Make choices, based on platform preferences */ - if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { if (mx3_cam->platform_flags & MX3_CAMERA_HSP) - common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; else - common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; } - if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { if (mx3_cam->platform_flags & MX3_CAMERA_VSP) - common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; else - common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; } - if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && - (common_flags & SOCAM_DATA_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { if (mx3_cam->platform_flags & MX3_CAMERA_DP) - common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; else - common_flags &= ~SOCAM_DATA_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; } - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && + (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { if (mx3_cam->platform_flags & MX3_CAMERA_PCP) - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; else - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; } - /* - * Make the camera work in widest common mode, we'll take care of - * the rest - */ - if (common_flags & SOCAM_DATAWIDTH_15) - common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | - SOCAM_DATAWIDTH_15; - else if (common_flags & SOCAM_DATAWIDTH_10) - common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | - SOCAM_DATAWIDTH_10; - else if (common_flags & SOCAM_DATAWIDTH_8) - common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | - SOCAM_DATAWIDTH_8; - else - common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | - SOCAM_DATAWIDTH_4; - - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) { - dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n", + cfg.flags = common_flags; + ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", common_flags, ret); return ret; } @@ -1108,13 +1081,13 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) /* This has been set in mx3_camera_activate(), but we clear it above */ sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; - if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) + if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; - if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) + if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; - if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) + if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; - if (common_flags & SOCAM_DATA_ACTIVE_LOW) + if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; /* Just do what we're asked to do */ @@ -1199,6 +1172,14 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) "data widths, using default 8 bit\n"); mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; } + if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) + mx3_cam->width_flags = 1 << 3; + if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) + mx3_cam->width_flags |= 1 << 7; + if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) + mx3_cam->width_flags |= 1 << 9; + if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) + mx3_cam->width_flags |= 1 << 14; mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; if (!mx3_cam->mclk) { From 610eb5a456586f7c63704160649ac6454f7d262d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 16:03:33 -0300 Subject: [PATCH 060/144] [media] V4L: mt9m001, mt9v022: add a clarifying comment Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 6 ++++++ drivers/media/video/mt9v022.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 7618b3c2fce0..750ce60abac8 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -734,6 +734,12 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); struct soc_camera_device *icd = client->dev.platform_data; struct soc_camera_link *icl = to_soc_camera_link(icd); + /* + * Cannot use icd->current_fmt->host_fmt->bits_per_sample, because that + * is the number of bits, that the host has to sample, not the number of + * bits, that we have to send. See mx3_camera.c for an example of 10-bit + * formats being truncated to 8 bits by the host. + */ unsigned int bps = soc_mbus_get_fmtdesc(icd->current_fmt->code)->bits_per_sample; if (icl->set_bus_param) diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 2fc6ca22f31c..ddc11d0a6254 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -875,6 +875,12 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, struct soc_camera_link *icl = to_soc_camera_link(icd); struct mt9v022 *mt9v022 = to_mt9v022(client); unsigned long flags = soc_camera_apply_board_flags(icl, cfg); + /* + * Cannot use icd->current_fmt->host_fmt->bits_per_sample, because that + * is the number of bits, that the host has to sample, not the number of + * bits, that we have to send. See mx3_camera.c for an example of 10-bit + * formats being truncated to 8 bits by the host. + */ unsigned int bps = soc_mbus_get_fmtdesc(icd->current_fmt->code)->bits_per_sample; int ret; u16 pixclk = 0; From 92d2c339d2076942baa5f658a8160c8b6d28d78d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 16:29:20 -0300 Subject: [PATCH 061/144] [media] V4L: omap1_camera: convert to the new mbus-config subdev operations Switch from soc-camera specific .{query,set}_bus_param() to V4L2 subdevice .[gs]_mbus_config() operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap1_camera.c | 62 ++++++++++++++++++------------ 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index 8a947e603aca..f24bcaf1d88c 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c @@ -102,10 +102,10 @@ /* end of OMAP1 Camera Interface registers */ -#define SOCAM_BUS_FLAGS (SOCAM_MASTER | \ - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | \ - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8) +#define SOCAM_BUS_FLAGS (V4L2_MBUS_MASTER | \ + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ + V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ + V4L2_MBUS_DATA_ACTIVE_HIGH) #define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1) @@ -1438,41 +1438,55 @@ static int omap1_cam_querycap(struct soc_camera_host *ici, static int omap1_cam_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; struct soc_camera_host *ici = to_soc_camera_host(dev); struct omap1_cam_dev *pcdev = ici->priv; const struct soc_camera_format_xlate *xlate; const struct soc_mbus_pixelfmt *fmt; - unsigned long camera_flags, common_flags; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long common_flags; u32 ctrlclock, mode; int ret; - camera_flags = icd->ops->query_bus_param(icd); - - common_flags = soc_camera_bus_param_compatible(camera_flags, - SOCAM_BUS_FLAGS); - if (!common_flags) - return -EINVAL; - - /* Make choices, possibly based on platform configuration */ - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { - if (!pcdev->pdata || - pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; - else - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS); + if (!common_flags) { + dev_warn(dev, + "Flags incompatible: camera 0x%x, host 0x%x\n", + cfg.flags, SOCAM_BUS_FLAGS); + return -EINVAL; + } + } else if (ret != -ENOIOCTLCMD) { + return ret; + } else { + common_flags = SOCAM_BUS_FLAGS; } - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) + /* Make choices, possibly based on platform configuration */ + if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && + (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { + if (!pcdev->pdata || + pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; + else + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; + } + + cfg.flags = common_flags; + ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", + common_flags, ret); return ret; + } ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); if (ctrlclock & LCLK_EN) CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); - if (common_flags & SOCAM_PCLK_SAMPLE_RISING) { + if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) { dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n"); ctrlclock |= POLCLK; } else { @@ -1716,5 +1730,5 @@ MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg"); MODULE_DESCRIPTION("OMAP1 Camera Interface driver"); MODULE_AUTHOR("Janusz Krzysztofik "); MODULE_LICENSE("GPL v2"); -MODULE_LICENSE(DRIVER_VERSION); +MODULE_VERSION(DRIVER_VERSION); MODULE_ALIAS("platform:" DRIVER_NAME); From 679419aa6e2590d561a8c1df3858d6b284c5cc58 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 16:37:45 -0300 Subject: [PATCH 062/144] [media] V4L: pxa_camera: convert to the new mbus-config subdev operations Switch from soc-camera specific .{query,set}_bus_param() to V4L2 subdevice .[gs]_mbus_config() operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 140 ++++++++++++++++++------------- 1 file changed, 80 insertions(+), 60 deletions(-) diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index d07df22a5ec6..79fb22c89ae9 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -214,6 +214,7 @@ struct pxa_camera_dev { unsigned long ciclk; unsigned long mclk; u32 mclk_divisor; + u16 width_flags; /* max 10 bits */ struct list_head capture; @@ -1020,37 +1021,20 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, * quick capture interface supports both. */ *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? - SOCAM_MASTER : SOCAM_SLAVE) | - SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH | - SOCAM_PCLK_SAMPLE_RISING | - SOCAM_PCLK_SAMPLE_FALLING; + V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_HSYNC_ACTIVE_LOW | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_VSYNC_ACTIVE_LOW | + V4L2_MBUS_DATA_ACTIVE_HIGH | + V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_PCLK_SAMPLE_FALLING; /* If requested data width is supported by the platform, use it */ - switch (buswidth) { - case 10: - if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)) - return -EINVAL; - *flags |= SOCAM_DATAWIDTH_10; - break; - case 9: - if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9)) - return -EINVAL; - *flags |= SOCAM_DATAWIDTH_9; - break; - case 8: - if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) - return -EINVAL; - *flags |= SOCAM_DATAWIDTH_8; - break; - default: - return -EINVAL; - } + if ((1 << (buswidth - 1)) & pcdev->width_flags) + return 0; - return 0; + return -EINVAL; } static void pxa_camera_setup_cicr(struct soc_camera_device *icd, @@ -1070,12 +1054,12 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, * Datawidth is now guaranteed to be equal to one of the three values. * We fix bit-per-pixel equal to data-width... */ - switch (flags & SOCAM_DATAWIDTH_MASK) { - case SOCAM_DATAWIDTH_10: + switch (icd->current_fmt->host_fmt->bits_per_sample) { + case 10: dw = 4; bpp = 0x40; break; - case SOCAM_DATAWIDTH_9: + case 9: dw = 3; bpp = 0x20; break; @@ -1084,7 +1068,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, * Actually it can only be 8 now, * default is just to silence compiler warnings */ - case SOCAM_DATAWIDTH_8: + case 8: dw = 2; bpp = 0; } @@ -1093,11 +1077,11 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, cicr4 |= CICR4_PCLK_EN; if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) cicr4 |= CICR4_MCLK_EN; - if (flags & SOCAM_PCLK_SAMPLE_FALLING) + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) cicr4 |= CICR4_PCP; - if (flags & SOCAM_HSYNC_ACTIVE_LOW) + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) cicr4 |= CICR4_HSP; - if (flags & SOCAM_VSYNC_ACTIVE_LOW) + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) cicr4 |= CICR4_VSP; cicr0 = __raw_readl(pcdev->base + CICR0); @@ -1151,9 +1135,11 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct pxa_camera_dev *pcdev = ici->priv; - unsigned long bus_flags, camera_flags, common_flags; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long bus_flags, common_flags; int ret; struct pxa_cam *cam = icd->host_priv; @@ -1162,45 +1148,59 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) if (ret < 0) return ret; - camera_flags = icd->ops->query_bus_param(icd); - - common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); - if (!common_flags) - return -EINVAL; + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, + bus_flags); + if (!common_flags) { + dev_warn(icd->parent, + "Flags incompatible: camera 0x%x, host 0x%lx\n", + cfg.flags, bus_flags); + return -EINVAL; + } + } else if (ret != -ENOIOCTLCMD) { + return ret; + } else { + common_flags = bus_flags; + } pcdev->channels = 1; /* Make choises, based on platform preferences */ - if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { if (pcdev->platform_flags & PXA_CAMERA_HSP) - common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; else - common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; } - if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { if (pcdev->platform_flags & PXA_CAMERA_VSP) - common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; else - common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; } - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && + (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { if (pcdev->platform_flags & PXA_CAMERA_PCP) - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; else - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; + } + + cfg.flags = common_flags; + ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", + common_flags, ret); + return ret; } cam->flags = common_flags; - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) - return ret; - pxa_camera_setup_cicr(icd, common_flags, pixfmt); return 0; @@ -1209,17 +1209,31 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) static int pxa_camera_try_bus_param(struct soc_camera_device *icd, unsigned char buswidth) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct pxa_camera_dev *pcdev = ici->priv; - unsigned long bus_flags, camera_flags; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long bus_flags, common_flags; int ret = test_platform_param(pcdev, buswidth, &bus_flags); if (ret < 0) return ret; - camera_flags = icd->ops->query_bus_param(icd); + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, + bus_flags); + if (!common_flags) { + dev_warn(icd->parent, + "Flags incompatible: camera 0x%x, host 0x%lx\n", + cfg.flags, bus_flags); + return -EINVAL; + } + } else if (ret == -ENOIOCTLCMD) { + ret = 0; + } - return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; + return ret; } static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { @@ -1687,6 +1701,12 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) "data widths, using default 10 bit\n"); pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; } + if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8) + pcdev->width_flags = 1 << 7; + if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9) + pcdev->width_flags |= 1 << 8; + if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10) + pcdev->width_flags |= 1 << 9; pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; if (!pcdev->mclk) { dev_warn(&pdev->dev, From e1db704326c9a5164da4e24b01e487c0be687fa2 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Jul 2011 18:17:56 -0300 Subject: [PATCH 063/144] [media] V4L: sh_mobile_ceu_camera: convert to the new mbus-config subdev operations Switch from soc-camera specific .{query,set}_bus_param() to V4L2 subdevice .[gs]_mbus_config() operations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 156 +++++++++++---------- 1 file changed, 82 insertions(+), 74 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index d1359f441a04..59101c0be869 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -144,30 +144,6 @@ static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb) return container_of(vb, struct sh_mobile_ceu_buffer, vb); } -static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) -{ - unsigned long flags; - - flags = SOCAM_MASTER | - SOCAM_PCLK_SAMPLE_RISING | - SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH; - - if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS) - flags |= SOCAM_DATAWIDTH_8; - - if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS) - flags |= SOCAM_DATAWIDTH_16; - - if (flags & SOCAM_DATAWIDTH_MASK) - return flags; - - return 0; -} - static void ceu_write(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs, u32 data) { @@ -737,66 +713,90 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) ceu_write(pcdev, CAPSR, capsr); } +/* Find the bus subdevice driver, e.g., CSI2 */ +static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, + struct soc_camera_device *icd) +{ + if (!pcdev->csi2_pdev) + return soc_camera_to_subdev(icd); + + return find_csi2(pcdev); +} + +#define CEU_BUS_FLAGS (V4L2_MBUS_MASTER | \ + V4L2_MBUS_PCLK_SAMPLE_RISING | \ + V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ + V4L2_MBUS_HSYNC_ACTIVE_LOW | \ + V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ + V4L2_MBUS_VSYNC_ACTIVE_LOW | \ + V4L2_MBUS_DATA_ACTIVE_HIGH) + /* Capture is not running, no interrupts, no locking needed */ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; - int ret; - unsigned long camera_flags, common_flags, value; - int yuv_lineskip; + struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); struct sh_mobile_ceu_cam *cam = icd->host_priv; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + unsigned long value, common_flags = CEU_BUS_FLAGS; u32 capsr = capture_save_reset(pcdev); + unsigned int yuv_lineskip; + int ret; - camera_flags = icd->ops->query_bus_param(icd); - common_flags = soc_camera_bus_param_compatible(camera_flags, - make_bus_param(pcdev)); - if (!common_flags) - return -EINVAL; + /* + * If the client doesn't implement g_mbus_config, we just use our + * platform data + */ + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) { + common_flags = soc_mbus_config_compatible(&cfg, + common_flags); + if (!common_flags) + return -EINVAL; + } else if (ret != -ENOIOCTLCMD) { + return ret; + } /* Make choises, based on platform preferences */ - if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) - common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; else - common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; } - if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && + (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) - common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; else - common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; } - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) + cfg.flags = common_flags; + ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) return ret; - switch (common_flags & SOCAM_DATAWIDTH_MASK) { - case SOCAM_DATAWIDTH_8: - pcdev->is_16bit = 0; - break; - case SOCAM_DATAWIDTH_16: + if (icd->current_fmt->host_fmt->bits_per_sample > 8) pcdev->is_16bit = 1; - break; - default: - return -EINVAL; - } + else + pcdev->is_16bit = 0; ceu_write(pcdev, CRCNTR, 0); ceu_write(pcdev, CRCMPR, 0); value = 0x00000010; /* data fetch by default */ - yuv_lineskip = 0; + yuv_lineskip = 0x10; switch (icd->current_fmt->host_fmt->fourcc) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: - yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */ + /* convert 4:2:2 -> 4:2:0 */ + yuv_lineskip = 0; /* skip for NV12/21, no skip for NV16/61 */ /* fall-through */ case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: @@ -822,8 +822,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ - value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; - value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; + value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; + value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; value |= pcdev->is_16bit ? 1 << 12 : 0; /* CSI2 mode */ @@ -866,9 +866,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, * using 7 we swap the data bytes to match the incoming order: * D0, D1, D2, D3, D4, D5, D6, D7 */ - value = 0x00000017; - if (yuv_lineskip) - value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */ + value = 0x00000007 | yuv_lineskip; ceu_write(pcdev, CDOCR, value); ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ @@ -889,13 +887,19 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, { struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; - unsigned long camera_flags, common_flags; + struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); + unsigned long common_flags = CEU_BUS_FLAGS; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + int ret; - camera_flags = icd->ops->query_bus_param(icd); - common_flags = soc_camera_bus_param_compatible(camera_flags, - make_bus_param(pcdev)); - if (!common_flags || buswidth > 16 || - (buswidth > 8 && !(common_flags & SOCAM_DATAWIDTH_16))) + ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + if (!ret) + common_flags = soc_mbus_config_compatible(&cfg, + common_flags); + else if (ret != -ENOIOCTLCMD) + return ret; + + if (!common_flags || buswidth > 16) return -EINVAL; return 0; @@ -905,26 +909,26 @@ static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { { .fourcc = V4L2_PIX_FMT_NV12, .name = "NV12", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_NONE, + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_1_5X8, .order = SOC_MBUS_ORDER_LE, }, { .fourcc = V4L2_PIX_FMT_NV21, .name = "NV21", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_NONE, + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_1_5X8, .order = SOC_MBUS_ORDER_LE, }, { .fourcc = V4L2_PIX_FMT_NV16, .name = "NV16", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_NONE, + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, .order = SOC_MBUS_ORDER_LE, }, { .fourcc = V4L2_PIX_FMT_NV61, .name = "NV61", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_NONE, + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, .order = SOC_MBUS_ORDER_LE, }, }; @@ -933,6 +937,8 @@ static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) { return fmt->packing == SOC_MBUS_PACKING_NONE || + (fmt->bits_per_sample == 8 && + fmt->packing == SOC_MBUS_PACKING_1_5X8) || (fmt->bits_per_sample == 8 && fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || (fmt->bits_per_sample > 8 && @@ -966,6 +972,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int } if (!pcdev->pdata->csi2) { + /* Are there any restrictions in the CSI-2 case? */ ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); if (ret < 0) return 0; @@ -1626,8 +1633,6 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, bool image_mode; enum v4l2_field field; - dev_geo(dev, "S_FMT(pix=0x%x, %ux%u)\n", pixfmt, pix->width, pix->height); - switch (pix->field) { default: pix->field = V4L2_FIELD_NONE; @@ -1665,6 +1670,9 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, image_mode = false; } + dev_info(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, + pix->width, pix->height); + dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); /* 5. - 9. */ From b0050e41bad1789ab5aeec15c3687a73e075b955 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 13:57:53 -0300 Subject: [PATCH 064/144] [media] V4L: soc-camera: camera client operations no longer compulsory With the transition of all soc-camera host drivers to use V4L2 subdevice .[gs]_mbus_config() operations, soc-camera client operations no longer have to be compulsory. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 8b16152f52fe..e05d1c7fee8d 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -482,7 +482,7 @@ static int soc_camera_open(struct file *file) struct soc_camera_host *ici; int ret; - if (!icd->ops) + if (!to_soc_camera_control(icd)) /* No device driver attached */ return -ENODEV; @@ -835,6 +835,9 @@ static int soc_camera_queryctrl(struct file *file, void *priv, return 0; } + if (!icd->ops) + return -EINVAL; + /* Then device controls */ for (i = 0; i < icd->ops->num_controls; i++) if (qc->id == icd->ops->controls[i].id) { @@ -1461,11 +1464,6 @@ static int soc_camera_video_start(struct soc_camera_device *icd) if (!icd->parent) return -ENODEV; - if (!icd->ops || - !icd->ops->query_bus_param || - !icd->ops->set_bus_param) - return -EINVAL; - ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) { dev_err(icd->pdev, "video_register_device failed: %d\n", ret); From 6a34874f9e86e727a9132a52d09b9a62f03bc449 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:33:07 -0300 Subject: [PATCH 065/144] [media] V4L: mt9m001: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 41 ----------------------------------- 1 file changed, 41 deletions(-) diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 750ce60abac8..3555e853e5c9 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -166,45 +166,6 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int mt9m001_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; - - /* Only one width bit may be set */ - if (!is_power_of_2(width_flag)) - return -EINVAL; - - if (icl->set_bus_param) - return icl->set_bus_param(icl, width_flag); - - /* - * Without board specific bus width settings we only support the - * sensors native bus width - */ - if (width_flag == SOCAM_DATAWIDTH_10) - return 0; - - return -EINVAL; -} - -static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - /* MT9M001 has all capture_format parameters fixed */ - unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER; - - if (icl->query_bus_param) - flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -461,8 +422,6 @@ static const struct v4l2_queryctrl mt9m001_controls[] = { }; static struct soc_camera_ops mt9m001_ops = { - .set_bus_param = mt9m001_set_bus_param, - .query_bus_param = mt9m001_query_bus_param, .controls = mt9m001_controls, .num_controls = ARRAY_SIZE(mt9m001_controls), }; From 5e891294f6dd7af617275477946e75d20c5e8136 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:38:46 -0300 Subject: [PATCH 066/144] [media] V4L: mt9m111: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m111.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index c9c4655c1fe4..28d447c6d40e 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -364,21 +364,6 @@ static int mt9m111_reset(struct mt9m111 *mt9m111) return ret; } -static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) -{ - return 0; -} - static int mt9m111_make_rect(struct mt9m111 *mt9m111, struct v4l2_rect *rect) { @@ -699,8 +684,6 @@ static const struct v4l2_queryctrl mt9m111_controls[] = { }; static struct soc_camera_ops mt9m111_ops = { - .query_bus_param = mt9m111_query_bus_param, - .set_bus_param = mt9m111_set_bus_param, .controls = mt9m111_controls, .num_controls = ARRAY_SIZE(mt9m111_controls), }; From 716eba3ec1d8d89acd19617eb0bd85fc9b58497f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:21 -0300 Subject: [PATCH 067/144] [media] V4L: imx074: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/imx074.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 63f17aa57271..20756e03dbb1 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -298,26 +298,6 @@ static struct v4l2_subdev_ops imx074_subdev_ops = { .video = &imx074_subdev_video_ops, }; -/* - * We have to provide soc-camera operations, but we don't have anything to say - * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param - */ -static unsigned long imx074_query_bus_param(struct soc_camera_device *icd) -{ - return 0; -} - -static int imx074_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return -EINVAL; -} - -static struct soc_camera_ops imx074_ops = { - .query_bus_param = imx074_query_bus_param, - .set_bus_param = imx074_set_bus_param, -}; - static int imx074_video_probe(struct soc_camera_device *icd, struct i2c_client *client) { @@ -457,12 +437,11 @@ static int imx074_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); - icd->ops = &imx074_ops; + icd->ops = NULL; priv->fmt = &imx074_colour_fmts[0]; ret = imx074_video_probe(icd, client); if (ret < 0) { - icd->ops = NULL; kfree(priv); return ret; } @@ -476,7 +455,6 @@ static int imx074_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; struct soc_camera_link *icl = to_soc_camera_link(icd); - icd->ops = NULL; if (icl->free_bus) icl->free_bus(icl); kfree(priv); From 0b01e03e5af825303b609f65b7f1a14c07153f18 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:22 -0300 Subject: [PATCH 068/144] [media] V4L: mt9t031: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9t031.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index c5adb2301480..25fb833f6f2c 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -58,11 +58,6 @@ #define MT9T031_COLUMN_SKIP 32 #define MT9T031_ROW_SKIP 20 -#define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \ - SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \ - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \ - SOCAM_MASTER | SOCAM_DATAWIDTH_10) - struct mt9t031 { struct v4l2_subdev subdev; struct v4l2_rect rect; /* Sensor window */ @@ -180,30 +175,6 @@ static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int mt9t031_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - - /* The caller should have queried our parameters, check anyway */ - if (flags & ~MT9T031_BUS_PARAM) - return -EINVAL; - - if (flags & SOCAM_PCLK_SAMPLE_FALLING) - reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); - else - reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); - - return 0; -} - -static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); -} - enum { MT9T031_CTRL_VFLIP, MT9T031_CTRL_HFLIP, @@ -263,8 +234,6 @@ static const struct v4l2_queryctrl mt9t031_controls[] = { }; static struct soc_camera_ops mt9t031_ops = { - .set_bus_param = mt9t031_set_bus_param, - .query_bus_param = mt9t031_query_bus_param, .controls = mt9t031_controls, .num_controls = ARRAY_SIZE(mt9t031_controls), }; From ff51345832628eb641805a01213aeae0bb4a23c1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:22 -0300 Subject: [PATCH 069/144] [media] V4L: mt9t112: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9t112.c | 48 ++--------------------------------- 1 file changed, 2 insertions(+), 46 deletions(-) diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index a3368d8e3193..608a3b6a8e99 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -742,46 +742,6 @@ static int mt9t112_init_camera(const struct i2c_client *client) return ret; } -/************************************************************************ - soc_camera_ops -************************************************************************/ -static int mt9t112_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (soc_camera_apply_sensor_flags(icl, flags) & SOCAM_PCLK_SAMPLE_RISING) - priv->flags |= PCLK_RISING; - - return 0; -} - -static unsigned long mt9t112_query_bus_param(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9t112_priv *priv = to_mt9t112(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH; - - flags |= (priv->info->flags & MT9T112_FLAG_PCLK_RISING_EDGE) ? - SOCAM_PCLK_SAMPLE_RISING : SOCAM_PCLK_SAMPLE_FALLING; - - if (priv->info->flags & MT9T112_FLAG_DATAWIDTH_8) - flags |= SOCAM_DATAWIDTH_8; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static struct soc_camera_ops mt9t112_ops = { - .set_bus_param = mt9t112_set_bus_param, - .query_bus_param = mt9t112_query_bus_param, -}; - /************************************************************************ v4l2_subdev_core_ops ************************************************************************/ @@ -1117,13 +1077,11 @@ static int mt9t112_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - icd->ops = &mt9t112_ops; + icd->ops = NULL; ret = mt9t112_camera_probe(icd, client); - if (ret) { - icd->ops = NULL; + if (ret) kfree(priv); - } return ret; } @@ -1131,9 +1089,7 @@ static int mt9t112_probe(struct i2c_client *client, static int mt9t112_remove(struct i2c_client *client) { struct mt9t112_priv *priv = to_mt9t112(client); - struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; kfree(priv); return 0; } From 0125b7c2fcc324bccd9c5e56b4afeecaac14c56d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:23 -0300 Subject: [PATCH 070/144] [media] V4L: mt9v022: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9v022.c | 74 ----------------------------------- 1 file changed, 74 deletions(-) diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index ddc11d0a6254..53149a73874b 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -200,78 +200,6 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int mt9v022_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; - int ret; - u16 pixclk = 0; - - /* Only one width bit may be set */ - if (!is_power_of_2(width_flag)) - return -EINVAL; - - if (icl->set_bus_param) { - ret = icl->set_bus_param(icl, width_flag); - if (ret) - return ret; - } else { - /* - * Without board specific bus width settings we only support the - * sensors native bus width - */ - if (width_flag != SOCAM_DATAWIDTH_10) - return -EINVAL; - } - - flags = soc_camera_apply_sensor_flags(icl, flags); - - if (flags & SOCAM_PCLK_SAMPLE_FALLING) - pixclk |= 0x10; - - if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH)) - pixclk |= 0x1; - - if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH)) - pixclk |= 0x2; - - ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); - if (ret < 0) - return ret; - - if (!(flags & SOCAM_MASTER)) - mt9v022->chip_control &= ~0x8; - - ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); - if (ret < 0) - return ret; - - dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", - pixclk, mt9v022->chip_control); - - return 0; -} - -static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned int flags = SOCAM_MASTER | SOCAM_SLAVE | - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH; - - if (icl->query_bus_param) - flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -558,8 +486,6 @@ static const struct v4l2_queryctrl mt9v022_controls[] = { }; static struct soc_camera_ops mt9v022_ops = { - .set_bus_param = mt9v022_set_bus_param, - .query_bus_param = mt9v022_query_bus_param, .controls = mt9v022_controls, .num_controls = ARRAY_SIZE(mt9v022_controls), }; From 6c67056a77b3087c40cd97a12930688014ef29c9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:24 -0300 Subject: [PATCH 071/144] [media] V4L: ov2640: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov2640.c | 40 ------------------------------------ 1 file changed, 40 deletions(-) diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 31f361ed7cc5..2826aff5ea27 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -701,44 +701,6 @@ static int ov2640_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int ov2640_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; - - /* Only one width bit may be set */ - if (!is_power_of_2(width_flag)) - return -EINVAL; - - if (icl->set_bus_param) - return icl->set_bus_param(icl, width_flag); - - /* - * Without board specific bus width settings we support only the - * sensors native bus width witch are tested working - */ - if (width_flag & (SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8)) - return 0; - - return 0; -} - -static unsigned long ov2640_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH; - - if (icl->query_bus_param) - flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - static int ov2640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1067,8 +1029,6 @@ err: } static struct soc_camera_ops ov2640_ops = { - .set_bus_param = ov2640_set_bus_param, - .query_bus_param = ov2640_query_bus_param, .controls = ov2640_controls, .num_controls = ARRAY_SIZE(ov2640_controls), }; From ea04ddce4fe5c11eaccc95a23579f0ae513907ba Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:24 -0300 Subject: [PATCH 072/144] [media] V4L: ov5642: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov5642.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 7eaeb25d5627..b36d42bfeab2 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -889,26 +889,6 @@ static struct v4l2_subdev_ops ov5642_subdev_ops = { .video = &ov5642_subdev_video_ops, }; -/* - * We have to provide soc-camera operations, but we don't have anything to say - * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param - */ -static unsigned long soc_ov5642_query_bus_param(struct soc_camera_device *icd) -{ - return 0; -} - -static int soc_ov5642_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return -EINVAL; -} - -static struct soc_camera_ops soc_ov5642_ops = { - .query_bus_param = soc_ov5642_query_bus_param, - .set_bus_param = soc_ov5642_set_bus_param, -}; - static int ov5642_video_probe(struct soc_camera_device *icd, struct i2c_client *client) { @@ -962,7 +942,7 @@ static int ov5642_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); - icd->ops = &soc_ov5642_ops; + icd->ops = NULL; priv->fmt = &ov5642_colour_fmts[0]; ret = ov5642_video_probe(icd, client); @@ -972,7 +952,6 @@ static int ov5642_probe(struct i2c_client *client, return 0; error: - icd->ops = NULL; kfree(priv); return ret; } @@ -983,7 +962,6 @@ static int ov5642_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; struct soc_camera_link *icl = to_soc_camera_link(icd); - icd->ops = NULL; if (icl->free_bus) icl->free_bus(icl); kfree(priv); From db669e79ed27b7842d1d3495836238fb46e29769 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:25 -0300 Subject: [PATCH 073/144] [media] V4L: ov6650: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov6650.c | 50 ++---------------------------------- 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index a26734d4cf30..654b2f591ae2 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -419,52 +419,6 @@ static int ov6650_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -/* Alter bus settings on camera side */ -static int ov6650_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - int ret; - - flags = soc_camera_apply_sensor_flags(icl, flags); - - if (flags & SOCAM_PCLK_SAMPLE_RISING) - ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); - else - ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); - if (ret) - return ret; - - if (flags & SOCAM_HSYNC_ACTIVE_LOW) - ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); - else - ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); - if (ret) - return ret; - - if (flags & SOCAM_VSYNC_ACTIVE_HIGH) - ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); - else - ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); - - return ret; -} - -/* Request bus settings on camera side */ -static unsigned long ov6650_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - unsigned long flags = SOCAM_MASTER | - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; - - return soc_camera_apply_sensor_flags(icl, flags); -} - /* Get status of additional camera capabilities */ static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { @@ -1095,8 +1049,6 @@ static int ov6650_video_probe(struct soc_camera_device *icd, } static struct soc_camera_ops ov6650_ops = { - .set_bus_param = ov6650_set_bus_param, - .query_bus_param = ov6650_query_bus_param, .controls = ov6650_controls, .num_controls = ARRAY_SIZE(ov6650_controls), }; @@ -1111,6 +1063,7 @@ static struct v4l2_subdev_core_ops ov6650_core_ops = { #endif }; +/* Request bus settings on camera side */ static int ov6650_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { @@ -1129,6 +1082,7 @@ static int ov6650_g_mbus_config(struct v4l2_subdev *sd, return 0; } +/* Alter bus settings on camera side */ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { From 284f28eec2a44e3ce81abbb451bca72a5d5833f3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 18:24:25 -0300 Subject: [PATCH 074/144] [media] sh: ap3rxa: remove redundant soc-camera platform data fields The sh_mobile_ceu_camera driver has been converted to use the V4L2 subdevice .[gs]_mbus_config() operations, therefore we don't need SOCAM_* flags for the soc_camera_platform driver anymore. The ov772x driver only supports 8 bits per sample pixel codes, hence the OV772X_FLAG_8BIT flag has no effect. Remove both of them. Signed-off-by: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Mauro Carvalho Chehab --- arch/sh/boards/mach-ap325rxa/setup.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 93a9f5dc5918..7030f4c8cf11 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -345,9 +345,6 @@ static struct soc_camera_platform_info camera_info = { .width = 640, .height = 480, }, - .bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | - SOCAM_DATA_ACTIVE_HIGH, .mbus_param = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH, @@ -505,8 +502,7 @@ static struct i2c_board_info ap325rxa_i2c_camera[] = { }; static struct ov772x_camera_info ov7725_info = { - .flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP | \ - OV772X_FLAG_8BIT, + .flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP, .edgectrl = OV772X_AUTO_EDGECTRL(0xf, 0), }; From cb626371f872070e7fb4ee9caa7bc873c3ceec55 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 18:29:01 -0300 Subject: [PATCH 075/144] [media] sh: migor: remove unused ov772x buswidth flag The ov772x driver only supports 8 bits per sample pixel codes, hence the OV772X_FLAG_8BIT flag has no effect. Remove it. Signed-off-by: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Mauro Carvalho Chehab --- arch/sh/boards/mach-migor/setup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 2d4c9c8c6664..e4c81195929c 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -448,9 +448,7 @@ static struct i2c_board_info migor_i2c_camera[] = { }, }; -static struct ov772x_camera_info ov7725_info = { - .flags = OV772X_FLAG_8BIT, -}; +static struct ov772x_camera_info ov7725_info; static struct soc_camera_link ov7725_link = { .power = ov7725_power, From 3e1b6b72b9a33a12efbe29f046335098c53dbb58 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 19:02:34 -0300 Subject: [PATCH 076/144] [media] V4L: ov772x: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov772x.c | 25 ------------------------- include/media/ov772x.h | 1 - 2 files changed, 26 deletions(-) diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index b70ffba58494..f77e8995fe40 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -621,29 +621,6 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int ov772x_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct ov772x_priv *priv = i2c_get_clientdata(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH; - - if (priv->info->flags & OV772X_FLAG_8BIT) - flags |= SOCAM_DATAWIDTH_8; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); @@ -1070,8 +1047,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd, } static struct soc_camera_ops ov772x_ops = { - .set_bus_param = ov772x_set_bus_param, - .query_bus_param = ov772x_query_bus_param, .controls = ov772x_controls, .num_controls = ARRAY_SIZE(ov772x_controls), }; diff --git a/include/media/ov772x.h b/include/media/ov772x.h index f9e27c0ce901..00dbb7c4feae 100644 --- a/include/media/ov772x.h +++ b/include/media/ov772x.h @@ -15,7 +15,6 @@ /* for flags */ #define OV772X_FLAG_VFLIP (1 << 0) /* Vertical flip image */ #define OV772X_FLAG_HFLIP (1 << 1) /* Horizontal flip image */ -#define OV772X_FLAG_8BIT (1 << 2) /* default 10 bit */ /* * for Edge ctrl From 88e816a2d5d53b791d0ecc314bf2369d826be1d2 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:26 -0300 Subject: [PATCH 077/144] [media] V4L: ov9640: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov9640.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 4156c9f6375b..352a8fb68b84 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -286,29 +286,6 @@ static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -/* Alter bus settings on camera side */ -static int ov9640_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -/* Request bus settings on camera side */ -static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - /* - * REVISIT: the camera probably can do 10 bit transfers, but I don't - * have those pins connected on my hardware. - */ - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; - - return soc_camera_apply_sensor_flags(icl, flags); -} - /* Get status of additional camera capabilities */ static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { @@ -648,8 +625,6 @@ static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } - - static int ov9640_video_probe(struct soc_camera_device *icd, struct i2c_client *client) { @@ -707,8 +682,6 @@ err: } static struct soc_camera_ops ov9640_ops = { - .set_bus_param = ov9640_set_bus_param, - .query_bus_param = ov9640_query_bus_param, .controls = ov9640_controls, .num_controls = ARRAY_SIZE(ov9640_controls), }; @@ -724,6 +697,7 @@ static struct v4l2_subdev_core_ops ov9640_core_ops = { }; +/* Request bus settings on camera side */ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { From 3d780ad712d3de61da5ba0ce206a261646dc68dc Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:27 -0300 Subject: [PATCH 078/144] [media] V4L: ov9740: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov9740.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index 67b7020c933e..5920f600990f 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c @@ -562,25 +562,6 @@ static int ov9740_s_stream(struct v4l2_subdev *sd, int enable) return ret; } -/* Alter bus settings on camera side */ -static int ov9740_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -/* Request bus settings on camera side */ -static unsigned long ov9740_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; - - return soc_camera_apply_sensor_flags(icl, flags); -} - /* select nearest higher resolution for capture */ static void ov9740_res_roundup(u32 *width, u32 *height) { @@ -945,12 +926,11 @@ err: } static struct soc_camera_ops ov9740_ops = { - .set_bus_param = ov9740_set_bus_param, - .query_bus_param = ov9740_query_bus_param, .controls = ov9740_controls, .num_controls = ARRAY_SIZE(ov9740_controls), }; +/* Request bus settings on camera side */ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { From 4a54fab70c97c5a4fabc486946ee8b3c9986f8eb Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:27 -0300 Subject: [PATCH 079/144] [media] V4L: rj54n1cb0c: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/rj54n1cb0c.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index d19c79bc0a7f..c30221104c6f 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -499,31 +499,6 @@ static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80); } -static int rj54n1_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ - - if (flags & SOCAM_PCLK_SAMPLE_RISING) - return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); - else - return reg_write(client, RJ54N1_OUT_SIGPO, 0); -} - -static unsigned long rj54n1_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - const unsigned long flags = - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_MASTER | SOCAM_DATAWIDTH_8 | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH; - - return soc_camera_apply_sensor_flags(icl, flags); -} - static int rj54n1_set_rect(struct i2c_client *client, u16 reg_x, u16 reg_y, u16 reg_xy, u32 width, u32 height) @@ -1240,8 +1215,6 @@ static const struct v4l2_queryctrl rj54n1_controls[] = { }; static struct soc_camera_ops rj54n1_ops = { - .set_bus_param = rj54n1_set_bus_param, - .query_bus_param = rj54n1_query_bus_param, .controls = rj54n1_controls, .num_controls = ARRAY_SIZE(rj54n1_controls), }; From 78a07f018c9d1eb1ee5798c5d3456260cc63c014 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 14:42:28 -0300 Subject: [PATCH 080/144] [media] V4L: sh_mobile_csi2: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_csi2.c | 31 ---------------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 6b4044134113..6f9f2b7ee453 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -40,8 +40,6 @@ struct sh_csi2 { void __iomem *base; struct platform_device *pdev; struct sh_csi2_client_config *client; - unsigned long (*query_bus_param)(struct soc_camera_device *); - int (*set_bus_param)(struct soc_camera_device *, unsigned long); }; static int sh_csi2_try_fmt(struct v4l2_subdev *sd, @@ -200,22 +198,6 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) iowrite32(tmp, priv->base + SH_CSI2_CHKSUM); } -static int sh_csi2_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - const unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH; - - return soc_camera_apply_sensor_flags(icl, flags); -} - static int sh_csi2_client_connect(struct sh_csi2 *priv) { struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; @@ -280,11 +262,6 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) priv->mipi_flags = common_flags; priv->client = pdata->clients + i; - priv->set_bus_param = icd->ops->set_bus_param; - priv->query_bus_param = icd->ops->query_bus_param; - icd->ops->set_bus_param = sh_csi2_set_bus_param; - icd->ops->query_bus_param = sh_csi2_query_bus_param; - csi2_sd->grp_id = (long)icd; pm_runtime_get_sync(dev); @@ -296,17 +273,9 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) static void sh_csi2_client_disconnect(struct sh_csi2 *priv) { - struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; - priv->client = NULL; priv->subdev.grp_id = 0; - /* Driver is about to be unbound */ - icd->ops->set_bus_param = priv->set_bus_param; - icd->ops->query_bus_param = priv->query_bus_param; - priv->set_bus_param = NULL; - priv->query_bus_param = NULL; - pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); } From 71f5ec8406e0d2f7c85bc1207df88207cf784377 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 18:19:36 -0300 Subject: [PATCH 081/144] [media] ARM: mach-shmobile: mackerel doesn't need legacy SOCAM_* flags anymore The sh_mobile_ceu_camera driver has been converted to use the V4L2 subdevice .[gs]_mbus_config() operations, therefore we don't need SOCAM_* flags for the soc_camera_platform driver anymore. Remove them. Signed-off-by: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-shmobile/board-mackerel.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 8a9100b1afed..682042306ea2 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -1223,9 +1223,6 @@ static struct soc_camera_platform_info camera_info = { .width = 640, .height = 480, }, - .bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | - SOCAM_DATA_ACTIVE_HIGH, .mbus_param = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH, From 1067247f56c5a9325332148c0dea42a2aa7e718f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 18:36:01 -0300 Subject: [PATCH 082/144] [media] V4L: soc_camera_platform: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera_platform.c | 31 +---------------------- include/media/soc_camera_platform.h | 1 - 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index 7045e458a66e..f5ebe59a5555 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -30,32 +30,12 @@ static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) return container_of(subdev, struct soc_camera_platform_priv, subdev); } -static struct soc_camera_platform_info *get_info(struct soc_camera_device *icd) -{ - struct platform_device *pdev = - to_platform_device(to_soc_camera_control(icd)); - return pdev->dev.platform_data; -} - static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) { struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); return p->set_capture(p, enable); } -static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -static unsigned long -soc_camera_platform_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_platform_info *p = get_info(icd); - return p->bus_param; -} - static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { @@ -142,11 +122,6 @@ static struct v4l2_subdev_ops platform_subdev_ops = { .video = &platform_subdev_video_ops, }; -static struct soc_camera_ops soc_camera_platform_ops = { - .set_bus_param = soc_camera_platform_set_bus_param, - .query_bus_param = soc_camera_platform_query_bus_param, -}; - static int soc_camera_platform_probe(struct platform_device *pdev) { struct soc_camera_host *ici; @@ -175,7 +150,7 @@ static int soc_camera_platform_probe(struct platform_device *pdev) /* Set the control device reference */ icd->control = &pdev->dev; - icd->ops = &soc_camera_platform_ops; + icd->ops = NULL; ici = to_soc_camera_host(icd->parent); @@ -190,7 +165,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev) return ret; evdrs: - icd->ops = NULL; platform_set_drvdata(pdev, NULL); kfree(priv); return ret; @@ -199,11 +173,8 @@ evdrs: static int soc_camera_platform_remove(struct platform_device *pdev) { struct soc_camera_platform_priv *priv = get_priv(pdev); - struct soc_camera_platform_info *p = pdev->dev.platform_data; - struct soc_camera_device *icd = p->icd; v4l2_device_unregister_subdev(&priv->subdev); - icd->ops = NULL; platform_set_drvdata(pdev, NULL); kfree(priv); return 0; diff --git a/include/media/soc_camera_platform.h b/include/media/soc_camera_platform.h index a15f92be8aba..8aa4200a0b1d 100644 --- a/include/media/soc_camera_platform.h +++ b/include/media/soc_camera_platform.h @@ -21,7 +21,6 @@ struct soc_camera_platform_info { const char *format_name; unsigned long format_depth; struct v4l2_mbus_framefmt format; - unsigned long bus_param; unsigned long mbus_param; enum v4l2_mbus_type mbus_type; struct soc_camera_device *icd; From 5476ea8d67b9e2b258c1c9ce6620e69bf13ecf0f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 18:37:36 -0300 Subject: [PATCH 083/144] [media] V4L: tw9910: remove superfluous soc-camera client operations Now that all soc-camera hosts have been ported to use V4L2 subdevice mediabus-config operations and soc-camera client bus-parameter operations have been made optional, they can be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tw9910.c | 53 ++---------------------------------- 1 file changed, 3 insertions(+), 50 deletions(-) diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 4f9fbf2ba35d..40cc1494b377 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -453,7 +453,7 @@ static const struct tw9910_scale_ctrl *tw9910_select_norm(struct soc_camera_devi } /* - * soc_camera_ops function + * subdevice operations */ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) { @@ -495,44 +495,6 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) return tw9910_power(client, enable); } -static int tw9910_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 val = VSSL_VVALID | HSSL_DVALID; - - flags = soc_camera_apply_sensor_flags(icl, flags); - - /* - * set OUTCTR1 - * - * We use VVALID and DVALID signals to control VSYNC and HSYNC - * outputs, in this mode their polarity is inverted. - */ - if (flags & SOCAM_HSYNC_ACTIVE_LOW) - val |= HSP_HI; - - if (flags & SOCAM_VSYNC_ACTIVE_LOW) - val |= VSP_HI; - - return i2c_smbus_write_byte_data(client, OUTCTR1, val); -} - -static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct tw9910_priv *priv = to_tw9910(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_LOW | SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; - - return soc_camera_apply_sensor_flags(icl, flags); -} - static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) { int ret = -EINVAL; @@ -840,11 +802,6 @@ static int tw9910_video_probe(struct soc_camera_device *icd, return 0; } -static struct soc_camera_ops tw9910_ops = { - .set_bus_param = tw9910_set_bus_param, - .query_bus_param = tw9910_query_bus_param, -}; - static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { .g_chip_ident = tw9910_g_chip_ident, .s_std = tw9910_s_std, @@ -964,14 +921,12 @@ static int tw9910_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - icd->ops = &tw9910_ops; + icd->ops = NULL; icd->iface = icl->bus_id; ret = tw9910_video_probe(icd, client); - if (ret) { - icd->ops = NULL; + if (ret) kfree(priv); - } return ret; } @@ -979,9 +934,7 @@ static int tw9910_probe(struct i2c_client *client, static int tw9910_remove(struct i2c_client *client) { struct tw9910_priv *priv = to_tw9910(client); - struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; kfree(priv); return 0; } From d839fe17a13562897e52e29c13d09ac0435dee85 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Jul 2011 18:42:57 -0300 Subject: [PATCH 084/144] [media] V4L: soc-camera: remove soc-camera client bus-param operations and supporting code soc-camera has been completely ported over to V4L2 subdevice mbus-config operations, soc-camera client bus-param operations and supporting code can now be removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 34 --------------------- include/media/soc_camera.h | 52 +++++--------------------------- 2 files changed, 8 insertions(+), 78 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index e05d1c7fee8d..ac23916552db 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -141,40 +141,6 @@ unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, } EXPORT_SYMBOL(soc_camera_apply_board_flags); -/** - * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags - * @icl: camera platform parameters - * @flags: flags to be inverted according to platform configuration - * @return: resulting flags - */ -unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, - unsigned long flags) -{ - unsigned long f; - - /* If only one of the two polarities is supported, switch to the opposite */ - if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { - f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW); - if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW) - flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW; - } - - if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { - f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW); - if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW) - flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW; - } - - if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { - f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING); - if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING) - flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING; - } - - return flags; -} -EXPORT_SYMBOL(soc_camera_apply_sensor_flags); - #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ ((x) >> 24) & 0xff diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 73337cff85a3..1864e2242d45 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -12,6 +12,7 @@ #ifndef SOC_CAMERA_H #define SOC_CAMERA_H +#include #include #include #include @@ -194,8 +195,6 @@ struct soc_camera_format_xlate { }; struct soc_camera_ops { - unsigned long (*query_bus_param)(struct soc_camera_device *); - int (*set_bus_param)(struct soc_camera_device *, unsigned long); const struct v4l2_queryctrl *controls; int num_controls; }; @@ -238,53 +237,18 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( return NULL; } -#define SOCAM_MASTER (1 << 0) -#define SOCAM_SLAVE (1 << 1) -#define SOCAM_HSYNC_ACTIVE_HIGH (1 << 2) -#define SOCAM_HSYNC_ACTIVE_LOW (1 << 6) -#define SOCAM_VSYNC_ACTIVE_HIGH (1 << 4) -#define SOCAM_VSYNC_ACTIVE_LOW (1 << 5) -#define SOCAM_DATAWIDTH_4 (1 << 3) -#define SOCAM_DATAWIDTH_8 (1 << 7) -#define SOCAM_DATAWIDTH_9 (1 << 8) -#define SOCAM_DATAWIDTH_10 (1 << 9) -#define SOCAM_DATAWIDTH_15 (1 << 14) -#define SOCAM_DATAWIDTH_16 (1 << 15) -#define SOCAM_PCLK_SAMPLE_RISING (1 << 12) -#define SOCAM_PCLK_SAMPLE_FALLING (1 << 13) -#define SOCAM_DATA_ACTIVE_HIGH (1 << 10) -#define SOCAM_DATA_ACTIVE_LOW (1 << 11) -#define SOCAM_MIPI_1LANE (1 << 16) -#define SOCAM_MIPI_2LANE (1 << 17) -#define SOCAM_MIPI_3LANE (1 << 18) -#define SOCAM_MIPI_4LANE (1 << 19) -#define SOCAM_MIPI (SOCAM_MIPI_1LANE | SOCAM_MIPI_2LANE | \ - SOCAM_MIPI_3LANE | SOCAM_MIPI_4LANE) +#define SOCAM_DATAWIDTH(x) BIT((x) - 1) +#define SOCAM_DATAWIDTH_4 SOCAM_DATAWIDTH(4) +#define SOCAM_DATAWIDTH_8 SOCAM_DATAWIDTH(8) +#define SOCAM_DATAWIDTH_9 SOCAM_DATAWIDTH(9) +#define SOCAM_DATAWIDTH_10 SOCAM_DATAWIDTH(10) +#define SOCAM_DATAWIDTH_15 SOCAM_DATAWIDTH(15) +#define SOCAM_DATAWIDTH_16 SOCAM_DATAWIDTH(16) #define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \ SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \ SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_16) -static inline unsigned long soc_camera_bus_param_compatible( - unsigned long camera_flags, unsigned long bus_flags) -{ - unsigned long common_flags, hsync, vsync, pclk, data, buswidth, mode; - unsigned long mipi; - - common_flags = camera_flags & bus_flags; - - hsync = common_flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW); - vsync = common_flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW); - pclk = common_flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING); - data = common_flags & (SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW); - mode = common_flags & (SOCAM_MASTER | SOCAM_SLAVE); - buswidth = common_flags & SOCAM_DATAWIDTH_MASK; - mipi = common_flags & SOCAM_MIPI; - - return ((!hsync || !vsync || !pclk || !data || !mode || !buswidth) && !mipi) ? 0 : - common_flags; -} - static inline void soc_camera_limit_side(int *start, int *length, unsigned int start_min, unsigned int length_min, unsigned int length_max) From 377c9ba772b0c3f848c12810231eb103aad473eb Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 3 Aug 2011 13:42:31 -0300 Subject: [PATCH 085/144] [media] V4L: mt9t112: fix broken cropping and scaling G_CROP, S_CROP, CROPCAP, G_FMT, and S_FMT functionality in the mt9t112 driver was broken on many occasions. This patch allows consistent cropping for rectangles also larger than VGA and cleans up multiple other issues in this area. It still doesn't add support for proper scaling, using the sensor own scaler, so input window is still always equal to the output frame. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9t112.c | 119 ++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 49 deletions(-) diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 608a3b6a8e99..25cdcb90768a 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -78,11 +78,6 @@ /************************************************************************ struct ************************************************************************/ -struct mt9t112_frame_size { - u16 width; - u16 height; -}; - struct mt9t112_format { enum v4l2_mbus_pixelcode code; enum v4l2_colorspace colorspace; @@ -95,7 +90,7 @@ struct mt9t112_priv { struct mt9t112_camera_info *info; struct i2c_client *client; struct soc_camera_device icd; - struct mt9t112_frame_size frame; + struct v4l2_rect frame; const struct mt9t112_format *format; int model; u32 flags; @@ -348,13 +343,10 @@ static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) } #endif -static void mt9t112_frame_check(u32 *width, u32 *height) +static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top) { - if (*width > MAX_WIDTH) - *width = MAX_WIDTH; - - if (*height > MAX_HEIGHT) - *height = MAX_HEIGHT; + soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH); + soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT); } static int mt9t112_set_a_frame_size(const struct i2c_client *client, @@ -849,19 +841,12 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, +static int mt9t112_set_params(struct mt9t112_priv *priv, + const struct v4l2_rect *rect, enum v4l2_mbus_pixelcode code) { - struct mt9t112_priv *priv = to_mt9t112(client); int i; - priv->format = NULL; - - /* - * frame size check - */ - mt9t112_frame_check(&width, &height); - /* * get color format */ @@ -872,8 +857,13 @@ static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, if (i == ARRAY_SIZE(mt9t112_cfmts)) return -EINVAL; - priv->frame.width = (u16)width; - priv->frame.height = (u16)height; + priv->frame = *rect; + + /* + * frame size check + */ + mt9t112_frame_check(&priv->frame.width, &priv->frame.height, + &priv->frame.left, &priv->frame.top); priv->format = mt9t112_cfmts + i; @@ -884,9 +874,12 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) { a->bounds.left = 0; a->bounds.top = 0; - a->bounds.width = VGA_WIDTH; - a->bounds.height = VGA_HEIGHT; - a->defrect = a->bounds; + a->bounds.width = MAX_WIDTH; + a->bounds.height = MAX_HEIGHT; + a->defrect.left = 0; + a->defrect.top = 0; + a->defrect.width = VGA_WIDTH; + a->defrect.height = VGA_HEIGHT; a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; a->pixelaspect.numerator = 1; a->pixelaspect.denominator = 1; @@ -896,11 +889,11 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { - a->c.left = 0; - a->c.top = 0; - a->c.width = VGA_WIDTH; - a->c.height = VGA_HEIGHT; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + a->c = priv->frame; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; return 0; } @@ -908,10 +901,10 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); struct v4l2_rect *rect = &a->c; - return mt9t112_set_params(client, rect->width, rect->height, - V4L2_MBUS_FMT_UYVY8_2X8); + return mt9t112_set_params(priv, rect, priv->format->code); } static int mt9t112_g_fmt(struct v4l2_subdev *sd, @@ -920,16 +913,9 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); - if (!priv->format) { - int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT, - V4L2_MBUS_FMT_UYVY8_2X8); - if (ret < 0) - return ret; - } - mf->width = priv->frame.width; mf->height = priv->frame.height; - /* TODO: set colorspace */ + mf->colorspace = priv->format->colorspace; mf->code = priv->format->code; mf->field = V4L2_FIELD_NONE; @@ -940,17 +926,42 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + struct v4l2_rect rect = { + .width = mf->width, + .height = mf->height, + .left = priv->frame.left, + .top = priv->frame.top, + }; + int ret; - /* TODO: set colorspace */ - return mt9t112_set_params(client, mf->width, mf->height, mf->code); + ret = mt9t112_set_params(priv, &rect, mf->code); + + if (!ret) + mf->colorspace = priv->format->colorspace; + + return ret; } static int mt9t112_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - mt9t112_frame_check(&mf->width, &mf->height); + unsigned int top, left; + int i; + + for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++) + if (mt9t112_cfmts[i].code == mf->code) + break; + + if (i == ARRAY_SIZE(mt9t112_cfmts)) { + mf->code = V4L2_MBUS_FMT_UYVY8_2X8; + mf->colorspace = V4L2_COLORSPACE_JPEG; + } else { + mf->colorspace = mt9t112_cfmts[i].colorspace; + } + + mt9t112_frame_check(&mf->width, &mf->height, &left, &top); - /* TODO: set colorspace */ mf->field = V4L2_FIELD_NONE; return 0; @@ -963,6 +974,7 @@ static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, return -EINVAL; *code = mt9t112_cfmts[index].code; + return 0; } @@ -1055,10 +1067,16 @@ static int mt9t112_camera_probe(struct soc_camera_device *icd, static int mt9t112_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct mt9t112_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; - int ret; + struct mt9t112_priv *priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl; + struct v4l2_rect rect = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .left = (MAX_WIDTH - VGA_WIDTH) / 2, + .top = (MAX_HEIGHT - VGA_HEIGHT) / 2, + }; + int ret; if (!icd) { dev_err(&client->dev, "mt9t112: missing soc-camera data!\n"); @@ -1083,6 +1101,9 @@ static int mt9t112_probe(struct i2c_client *client, if (ret) kfree(priv); + /* Cannot fail: using the default supported pixel code */ + mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8); + return ret; } From 6ac939c06f34eaba2bc4b3be1d7f6bf26f629a23 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 22 Aug 2011 12:35:09 -0300 Subject: [PATCH 086/144] [media] V4L: sh-mobile-ceu-camera: fix mixed CSI2 & parallel camera case The current sh_mobile_ceu_camera driver can cause an Oops, if a CSI2 and a parallel camera are registered on the same CEU. Fix it by making CSI2 association with a camera more targeted. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 59101c0be869..5c8ddd821df6 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -717,10 +717,13 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, struct soc_camera_device *icd) { - if (!pcdev->csi2_pdev) - return soc_camera_to_subdev(icd); + if (pcdev->csi2_pdev) { + struct v4l2_subdev *csi2_sd = find_csi2(pcdev); + if (csi2_sd && csi2_sd->grp_id == (u32)icd) + return csi2_sd; + } - return find_csi2(pcdev); + return soc_camera_to_subdev(icd); } #define CEU_BUS_FLAGS (V4L2_MBUS_MASTER | \ From 2b3d0457b8b2562bb25e3244ea591f0f6373701b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 22 Aug 2011 12:57:45 -0300 Subject: [PATCH 087/144] [media] V4L: omap1-camera: fix Oops with NULL platform data Consistently check for platform data != NULL before dereferencing. Signed-off-by: Guennadi Liakhovetski Acked-by: Janusz Krzysztofik Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap1_camera.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index f24bcaf1d88c..e87ae2f634b2 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c @@ -1579,10 +1579,10 @@ static int __init omap1_cam_probe(struct platform_device *pdev) pcdev->clk = clk; pcdev->pdata = pdev->dev.platform_data; - pcdev->pflags = pcdev->pdata->flags; - - if (pcdev->pdata) + if (pcdev->pdata) { + pcdev->pflags = pcdev->pdata->flags; pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000; + } switch (pcdev->camexclk) { case 6000000: @@ -1592,6 +1592,7 @@ static int __init omap1_cam_probe(struct platform_device *pdev) case 24000000: break; default: + /* pcdev->camexclk != 0 => pcdev->pdata != NULL */ dev_warn(&pdev->dev, "Incorrect sensor clock frequency %ld kHz, " "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, " @@ -1599,8 +1600,7 @@ static int __init omap1_cam_probe(struct platform_device *pdev) pcdev->pdata->camexclk_khz); pcdev->camexclk = 0; case 0: - dev_info(&pdev->dev, - "Not providing sensor clock\n"); + dev_info(&pdev->dev, "Not providing sensor clock\n"); } INIT_LIST_HEAD(&pcdev->capture); From ebc087d0905c41d7fe450866eb1afd1f661cba76 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 31 Aug 2011 06:51:10 -0300 Subject: [PATCH 088/144] [media] V4L: add a new videobuf2 buffer state VB2_BUF_STATE_PREPARED This patch prepares for a better separation of the buffer preparation stage. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 61 ++++++++++++++++++---------- include/media/videobuf2-core.h | 2 + 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 3f5c7a38e6e8..b88b5b08792b 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -366,6 +366,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b->flags |= V4L2_BUF_FLAG_DONE; break; case VB2_BUF_STATE_DEQUEUED: + case VB2_BUF_STATE_PREPARED: /* nothing */ break; } @@ -832,6 +833,33 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) q->ops->buf_queue(vb); } +static int __buf_prepare(struct vb2_buffer *vb, struct v4l2_buffer *b) +{ + struct vb2_queue *q = vb->vb2_queue; + int ret; + + switch (q->memory) { + case V4L2_MEMORY_MMAP: + ret = __qbuf_mmap(vb, b); + break; + case V4L2_MEMORY_USERPTR: + ret = __qbuf_userptr(vb, b); + break; + default: + WARN(1, "Invalid queue type\n"); + ret = -EINVAL; + } + + if (!ret) + ret = call_qop(q, buf_prepare, vb); + if (ret) + dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); + else + vb->state = VB2_BUF_STATE_PREPARED; + + return ret; +} + /** * vb2_qbuf() - Queue a buffer from userspace * @q: videobuf2 queue @@ -841,8 +869,8 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) * Should be called from vidioc_qbuf ioctl handler of a driver. * This function: * 1) verifies the passed buffer, - * 2) calls buf_prepare callback in the driver (if provided), in which - * driver-specific buffer initialization can be performed, + * 2) if necessary, calls buf_prepare callback in the driver (if provided), in + * which driver-specific buffer initialization can be performed, * 3) if streaming is on, queues the buffer in driver by the means of buf_queue * callback for processing. * @@ -852,7 +880,7 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) { struct vb2_buffer *vb; - int ret = 0; + int ret; if (q->fileio) { dprintk(1, "qbuf: file io in progress\n"); @@ -881,29 +909,18 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) return -EINVAL; } - if (vb->state != VB2_BUF_STATE_DEQUEUED) { + switch (vb->state) { + case VB2_BUF_STATE_DEQUEUED: + ret = __buf_prepare(vb, b); + if (ret) + return ret; + case VB2_BUF_STATE_PREPARED: + break; + default: dprintk(1, "qbuf: buffer already in use\n"); return -EINVAL; } - if (q->memory == V4L2_MEMORY_MMAP) - ret = __qbuf_mmap(vb, b); - else if (q->memory == V4L2_MEMORY_USERPTR) - ret = __qbuf_userptr(vb, b); - else { - WARN(1, "Invalid queue type\n"); - return -EINVAL; - } - - if (ret) - return ret; - - ret = call_qop(q, buf_prepare, vb); - if (ret) { - dprintk(1, "qbuf: buffer preparation failed\n"); - return ret; - } - /* * Add to the queued buffers list, a buffer will stay on it until * dequeued in dqbuf. diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index ea55c08eddfb..dbd10acc8e80 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -105,6 +105,7 @@ enum vb2_fileio_flags { /** * enum vb2_buffer_state - current video buffer state * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control + * @VB2_BUF_STATE_PREPARED: buffer prepared in videobuf and by the driver * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver * @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used * in a hardware operation @@ -116,6 +117,7 @@ enum vb2_fileio_flags { */ enum vb2_buffer_state { VB2_BUF_STATE_DEQUEUED, + VB2_BUF_STATE_PREPARED, VB2_BUF_STATE_QUEUED, VB2_BUF_STATE_ACTIVE, VB2_BUF_STATE_DONE, From 2150158b31a3290cc883cf6dea4f5d6803b6b811 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 28 Sep 2011 11:34:06 -0300 Subject: [PATCH 089/144] [media] V4L: add two new ioctl()s for multi-size videobuffer management A possibility to preallocate and initialise buffers of different sizes in V4L2 is required for an efficient implementation of a snapshot mode. This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF and defines respective data structures. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-compat-ioctl32.c | 67 ++++++++++++++++++++--- drivers/media/video/v4l2-ioctl.c | 36 ++++++++++++ include/linux/videodev2.h | 18 ++++++ include/media/v4l2-ioctl.h | 2 + 4 files changed, 115 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 61979b70f388..e77e0cfc9312 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -159,11 +159,16 @@ struct v4l2_format32 { } fmt; }; -static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +struct v4l2_create_buffers32 { + __u32 index; /* output: buffers index...index + count - 1 have been created */ + __u32 count; + enum v4l2_memory memory; + struct v4l2_format32 format; /* filled in by the user, plane sizes calculated by the driver */ + __u32 reserved[8]; +}; + +static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) || - get_user(kp->type, &up->type)) - return -EFAULT; switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: @@ -192,11 +197,24 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user } } -static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +{ + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) || + get_user(kp->type, &up->type)) + return -EFAULT; + return __get_v4l2_format32(kp, up); +} + +static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +{ + if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || + copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format.fmt))) + return -EFAULT; + return __get_v4l2_format32(&kp->format, &up->format); +} + +static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || - put_user(kp->type, &up->type)) - return -EFAULT; switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: @@ -225,6 +243,22 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user } } +static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +{ + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || + put_user(kp->type, &up->type)) + return -EFAULT; + return __put_v4l2_format32(kp, up); +} + +static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +{ + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || + copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) + return -EFAULT; + return __put_v4l2_format32(&kp->format, &up->format); +} + struct v4l2_standard32 { __u32 index; __u32 id[2]; /* __u64 would get the alignment wrong */ @@ -702,6 +736,8 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32) +#define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32) +#define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32) #define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) #define VIDIOC_STREAMON32 _IOW ('V', 18, s32) @@ -721,6 +757,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar struct v4l2_standard v2s; struct v4l2_ext_controls v2ecs; struct v4l2_event v2ev; + struct v4l2_create_buffers v2crt; unsigned long vx; int vi; } karg; @@ -751,6 +788,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break; case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break; + case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break; + case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break; } switch (cmd) { @@ -775,6 +814,12 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar compatible_arg = 0; break; + case VIDIOC_CREATE_BUFS: + err = get_v4l2_create32(&karg.v2crt, up); + compatible_arg = 0; + break; + + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: @@ -860,6 +905,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_format32(&karg.v2f, up); break; + case VIDIOC_CREATE_BUFS: + err = put_v4l2_create32(&karg.v2crt, up); + break; + case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: @@ -959,6 +1008,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_DQEVENT32: case VIDIOC_SUBSCRIBE_EVENT: case VIDIOC_UNSUBSCRIBE_EVENT: + case VIDIOC_CREATE_BUFS32: + case VIDIOC_PREPARE_BUF32: ret = do_video_ioctl(file, cmd, arg); break; diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 24fd43322150..e1da8fc9dd2f 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -273,6 +273,8 @@ static const char *v4l2_ioctls[] = { [_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT", [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT", [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT", + [_IOC_NR(VIDIOC_CREATE_BUFS)] = "VIDIOC_CREATE_BUFS", + [_IOC_NR(VIDIOC_PREPARE_BUF)] = "VIDIOC_PREPARE_BUF", }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) @@ -2104,6 +2106,40 @@ static long __video_do_ioctl(struct file *file, dbgarg(cmd, "type=0x%8.8x", sub->type); break; } + case VIDIOC_CREATE_BUFS: + { + struct v4l2_create_buffers *create = arg; + + if (!ops->vidioc_create_bufs) + break; + if (ret_prio) { + ret = ret_prio; + break; + } + ret = check_fmt(ops, create->format.type); + if (ret) + break; + + ret = ops->vidioc_create_bufs(file, fh, create); + + dbgarg(cmd, "count=%d @ %d\n", create->count, create->index); + break; + } + case VIDIOC_PREPARE_BUF: + { + struct v4l2_buffer *b = arg; + + if (!ops->vidioc_prepare_buf) + break; + ret = check_fmt(ops, b->type); + if (ret) + break; + + ret = ops->vidioc_prepare_buf(file, fh, b); + + dbgarg(cmd, "index=%d", b->index); + break; + } default: if (!ops->vidioc_default) break; diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 225560c1a10f..cd512f07beed 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -653,6 +653,10 @@ struct v4l2_buffer { #define V4L2_BUF_FLAG_ERROR 0x0040 #define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ #define V4L2_BUF_FLAG_INPUT 0x0200 /* input field is valid */ +#define V4L2_BUF_FLAG_PREPARED 0x0400 /* Buffer is prepared for queuing */ +/* Cache handling flags */ +#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800 +#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000 /* * O V E R L A Y P R E V I E W @@ -2138,6 +2142,15 @@ struct v4l2_dbg_chip_ident { __u32 revision; /* chip revision, chip specific */ } __attribute__ ((packed)); +/* VIDIOC_CREATE_BUFS */ +struct v4l2_create_buffers { + __u32 index; /* output: buffers index...index + count - 1 have been created */ + __u32 count; + enum v4l2_memory memory; + struct v4l2_format format; /* "type" is used always, the rest if sizeimage == 0 */ + __u32 reserved[8]; +}; + /* * I O C T L C O D E S F O R V I D E O D E V I C E S * @@ -2228,6 +2241,11 @@ struct v4l2_dbg_chip_ident { #define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) #define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) +/* Experimental, the below two ioctls may change over the next couple of kernel + versions */ +#define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers) +#define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer) + /* Reminder: when adding new ioctls please add support for them to drivers/media/video/v4l2-compat-ioctl32.c as well! */ diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index dd9f1e7b8ff7..4d1c74ad4c84 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -122,6 +122,8 @@ struct v4l2_ioctl_ops { int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b); int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b); + int (*vidioc_create_bufs)(struct file *file, void *fh, struct v4l2_create_buffers *b); + int (*vidioc_prepare_buf)(struct file *file, void *fh, struct v4l2_buffer *b); int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i); int (*vidioc_g_fbuf) (struct file *file, void *fh, From 21db3e07e1c6302556ae3215ddf0539f5d763b62 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 28 Sep 2011 07:23:27 -0300 Subject: [PATCH 090/144] [media] V4L: videobuf2: update buffer state on VIDIOC_QBUF V4L2 specification states, that the videobuffer state flags have to be updated on VIDIOC_QBUF ioctl(). Videobuf2 currently doesn't do that, which is fixed by this patch. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index b88b5b08792b..82b51be3ca72 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -935,6 +935,9 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) if (q->streaming) __enqueue_in_driver(vb); + /* Fill buffer information for the userspace */ + __fill_v4l2_buffer(vb, b); + dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); return 0; } From 55093284fb6f9009a339e522773417bdd54ec144 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 28 Sep 2011 08:10:58 -0300 Subject: [PATCH 091/144] [media] V4L: document the new VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF ioctl()s [mchehab@redhat.com: remove emacs format crap at the end of the new files] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/compat.xml | 3 + Documentation/DocBook/media/v4l/io.xml | 27 ++++ Documentation/DocBook/media/v4l/v4l2.xml | 2 + .../DocBook/media/v4l/vidioc-create-bufs.xml | 139 ++++++++++++++++++ .../DocBook/media/v4l/vidioc-prepare-buf.xml | 88 +++++++++++ 5 files changed, 259 insertions(+) create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 91410b6e7e08..b68698f96e7f 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2486,6 +2486,9 @@ ioctls. Flash API. + + &VIDIOC-CREATE-BUFS; and &VIDIOC-PREPARE-BUF; ioctls. + diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index c57d1ec6291c..3f47df1aa54a 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -927,6 +927,33 @@ ioctl is called. Applications set or clear this flag before calling the VIDIOC_QBUF ioctl. + + V4L2_BUF_FLAG_PREPARED + 0x0400 + The buffer has been prepared for I/O and can be queued by the +application. Drivers set or clear this flag when the +VIDIOC_QUERYBUF, VIDIOC_PREPARE_BUF, VIDIOC_QBUF or VIDIOC_DQBUF ioctl is called. + + + V4L2_BUF_FLAG_NO_CACHE_INVALIDATE + 0x0400 + Caches do not have to be invalidated for this buffer. +Typically applications shall use this flag if the data captured in the buffer +is not going to be touched by the CPU, instead the buffer will, probably, be +passed on to a DMA-capable hardware unit for further processing or output. + + + + V4L2_BUF_FLAG_NO_CACHE_CLEAN + 0x0800 + Caches do not have to be cleaned for this buffer. +Typically applications shall use this flag for output buffers if the data +in this buffer has not been created by the CPU but by some DMA-capable unit, +in which case caches have not been used. + diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 40132c277647..2ab365c10fb9 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -469,6 +469,7 @@ and discussions on the V4L mailing list. &sub-close; &sub-ioctl; + &sub-create-bufs; &sub-cropcap; &sub-dbg-g-chip-ident; &sub-dbg-g-register; @@ -511,6 +512,7 @@ and discussions on the V4L mailing list. &sub-queryctrl; &sub-query-dv-preset; &sub-querystd; + &sub-prepare-buf; &sub-reqbufs; &sub-s-hw-freq-seek; &sub-streamon; diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml new file mode 100644 index 000000000000..73ae8a6cd004 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml @@ -0,0 +1,139 @@ + + + ioctl VIDIOC_CREATE_BUFS + &manvol; + + + + VIDIOC_CREATE_BUFS + Create buffers for Memory Mapped or User Pointer I/O + + + + + + int ioctl + int fd + int request + struct v4l2_create_buffers *argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_CREATE_BUFS + + + + argp + + + + + + + + + Description + + This ioctl is used to create buffers for memory +mapped or user pointer +I/O. It can be used as an alternative or in addition to the +VIDIOC_REQBUFS ioctl, when a tighter control over buffers +is required. This ioctl can be called multiple times to create buffers of +different sizes. + + To allocate device buffers applications initialize relevant fields of +the v4l2_create_buffers structure. They set the +type field in the +v4l2_format structure, embedded in this +structure, to the respective stream or buffer type. +count must be set to the number of required buffers. +memory specifies the required I/O method. The +format field shall typically be filled in using +either the VIDIOC_TRY_FMT or +VIDIOC_G_FMT ioctl(). Additionally, applications can adjust +sizeimage fields to fit their specific needs. The +reserved array must be zeroed. + + When the ioctl is called with a pointer to this structure the driver +will attempt to allocate up to the requested number of buffers and store the +actual number allocated and the starting index in the +count and the index fields +respectively. On return count can be smaller than +the number requested. The driver may also increase buffer sizes if required, +however, it will not update sizeimage field values. +The user has to use VIDIOC_QUERYBUF to retrieve that +information. + + + struct <structname>v4l2_create_buffers</structname> + + &cs-str; + + + __u32 + index + The starting buffer index, returned by the driver. + + + __u32 + count + The number of buffers requested or granted. + + + &v4l2-memory; + memory + Applications set this field to +V4L2_MEMORY_MMAP or +V4L2_MEMORY_USERPTR. + + + &v4l2-format; + format + Filled in by the application, preserved by the driver. + + + __u32 + reserved[8] + A place holder for future extensions. + + + +
+
+ + + &return-value; + + + + ENOMEM + + No memory to allocate buffers for memory +mapped I/O. + + + + EINVAL + + The buffer type (type field) or the +requested I/O method (memory) is not +supported. + + + + +
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml new file mode 100644 index 000000000000..7bde698760e4 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml @@ -0,0 +1,88 @@ + + + ioctl VIDIOC_PREPARE_BUF + &manvol; + + + + VIDIOC_PREPARE_BUF + Prepare a buffer for I/O + + + + + + int ioctl + int fd + int request + struct v4l2_buffer *argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_PREPARE_BUF + + + + argp + + + + + + + + + Description + + Applications can optionally call the +VIDIOC_PREPARE_BUF ioctl to pass ownership of the buffer +to the driver before actually enqueuing it, using the +VIDIOC_QBUF ioctl, and to prepare it for future I/O. +Such preparations may include cache invalidation or cleaning. Performing them +in advance saves time during the actual I/O. In case such cache operations are +not required, the application can use one of +V4L2_BUF_FLAG_NO_CACHE_INVALIDATE and +V4L2_BUF_FLAG_NO_CACHE_CLEAN flags to skip the respective +step. + + The v4l2_buffer structure is +specified in . + + + + &return-value; + + + + EBUSY + + File I/O is in progress. + + + + EINVAL + + The buffer type is not +supported, or the index is out of bounds, +or no buffers have been allocated yet, or the +userptr or +length are invalid. + + + + + From fc714e70dd063e6887d09872ac6158b0c20cc817 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Aug 2011 10:30:21 -0300 Subject: [PATCH 092/144] [media] V4L: vb2: prepare to support multi-size buffers In preparation for the forthcoming VIDIOC_CREATE_BUFS ioctl add a "const struct v4l2_format *" argument to the .queue_setup() vb2 operation. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/atmel-isi.c | 6 +++--- drivers/media/video/marvell-ccic/mcam-core.c | 3 ++- drivers/media/video/mem2mem_testdev.c | 7 ++++--- drivers/media/video/mx3_camera.c | 1 + drivers/media/video/pwc/pwc-if.c | 6 +++--- drivers/media/video/s5p-fimc/fimc-capture.c | 6 +++--- drivers/media/video/s5p-fimc/fimc-core.c | 6 +++--- drivers/media/video/s5p-mfc/s5p_mfc_dec.c | 7 ++++--- drivers/media/video/s5p-mfc/s5p_mfc_enc.c | 5 +++-- drivers/media/video/s5p-tv/mixer_video.c | 4 ++-- drivers/media/video/sh_mobile_ceu_camera.c | 1 + drivers/media/video/videobuf2-core.c | 6 +++--- drivers/media/video/vivi.c | 6 +++--- include/media/videobuf2-core.h | 6 +++--- 14 files changed, 38 insertions(+), 32 deletions(-) diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 06f6595a1c9a..8c775c59e120 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c @@ -249,9 +249,9 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 1141b976dff4..80ec64d2d6d8 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c @@ -883,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam) * Videobuf2 interface code. */ -static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, +static int mcam_vb_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *nbufs, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index 9594b52f8605..12897e8a3314 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -738,9 +738,10 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { * Queue operations */ -static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) +static int m2mtest_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); struct m2mtest_q_data *q_data; diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index f4ef6b993ff1..24c2fe0714c5 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -191,6 +191,7 @@ static void mx3_cam_dma_done(void *arg) * Calculate the __buffer__ (not data) size and number of buffers. */ static int mx3_videobuf_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 360be226718d..01ff643e682d 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -744,9 +744,9 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) /***************************************************************************/ /* Videobuf2 operations */ -static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { struct pwc_device *pdev = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 931f469604b0..c8d91b0cd9bd 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -246,9 +246,9 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; } -static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned int sizes[], - void *allocators[]) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *allocators[]) { struct fimc_ctx *ctx = vq->drv_priv; struct fimc_fmt *fmt = ctx->d_frame.fmt; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6c1c9cb55378..19ca6db38b2f 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -670,9 +670,9 @@ static void fimc_job_abort(void *priv) fimc_m2m_shutdown(priv); } -static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned int sizes[], - void *allocators[]) +static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *allocators[]) { struct fimc_ctx *ctx = vb2_get_drv_priv(vq); struct fimc_frame *f; diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index bfbe08432050..725634d9736d 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c @@ -744,9 +744,10 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { .vidioc_g_crop = vidioc_g_crop, }; -static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, - unsigned int *plane_count, unsigned int psize[], - void *allocators[]) +static int s5p_mfc_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *buf_count, + unsigned int *plane_count, unsigned int psize[], + void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index 4c90e53bd964..ecef127dbc66 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c @@ -1513,8 +1513,9 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) } static int s5p_mfc_queue_setup(struct vb2_queue *vq, - unsigned int *buf_count, unsigned int *plane_count, - unsigned int psize[], void *allocators[]) + const struct v4l2_format *fmt, + unsigned int *buf_count, unsigned int *plane_count, + unsigned int psize[], void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index 4917e2c2b321..e16d3a4bc1dc 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c @@ -727,8 +727,8 @@ static const struct v4l2_file_operations mxr_fops = { .unlocked_ioctl = video_ioctl2, }; -static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, + unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct mxr_layer *layer = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 5c8ddd821df6..0cb19689cfe8 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -193,6 +193,7 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) * Videobuf operations */ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 82b51be3ca72..f04f27d68cec 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -530,7 +530,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * Ask the driver how many buffers and planes per buffer it requires. * Driver also sets the size and allocator context for each plane. */ - ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, + ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); if (ret) return ret; @@ -549,8 +549,8 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) unsigned int orig_num_buffers; orig_num_buffers = num_buffers = ret; - ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, - q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, NULL, &num_buffers, + &num_planes, q->plane_sizes, q->alloc_ctx); if (ret) goto free_mem; diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 7cf94c09d99a..7d754fbcccbf 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -650,9 +650,9 @@ static void vivi_stop_generating(struct vivi_dev *dev) /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { struct vivi_dev *dev = vb2_get_drv_priv(vq); unsigned long size; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index dbd10acc8e80..692e35c232a9 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -218,9 +218,9 @@ struct vb2_buffer { * pre-queued buffers before calling STREAMON */ struct vb2_ops { - int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers, - unsigned int *num_planes, unsigned int sizes[], - void *alloc_ctxs[]); + int (*queue_setup)(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]); void (*wait_prepare)(struct vb2_queue *q); void (*wait_finish)(struct vb2_queue *q); From 2d86401c2cbfce9f99b08ba168bdb60b2eb7796e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 28 Sep 2011 09:23:02 -0300 Subject: [PATCH 093/144] [media] V4L: vb2: add support for buffers of different sizes on a single queue The two recently added ioctl()s VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF allow user-space applications to allocate video buffers of different sizes and hand them over to the driver for fast switching between different frame formats. This patch adds support for buffers of different sizes on the same buffer-queue to vb2. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 294 ++++++++++++++++++++++----- include/media/videobuf2-core.h | 35 ++-- 2 files changed, 270 insertions(+), 59 deletions(-) diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index f04f27d68cec..9005dc9991ab 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -38,7 +38,8 @@ module_param(debug, int, 0644); (((q)->ops->op) ? ((q)->ops->op(args)) : 0) #define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ - V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR) + V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \ + V4L2_BUF_FLAG_PREPARED) /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer @@ -109,13 +110,22 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) * __setup_offsets() - setup unique offsets ("cookies") for every plane in * every buffer on the queue */ -static void __setup_offsets(struct vb2_queue *q) +static void __setup_offsets(struct vb2_queue *q, unsigned int n) { unsigned int buffer, plane; struct vb2_buffer *vb; - unsigned long off = 0; + unsigned long off; - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + if (q->num_buffers) { + struct v4l2_plane *p; + vb = q->bufs[q->num_buffers - 1]; + p = &vb->v4l2_planes[vb->num_planes - 1]; + off = PAGE_ALIGN(p->m.mem_offset + p->length); + } else { + off = 0; + } + + for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) { vb = q->bufs[buffer]; if (!vb) continue; @@ -161,7 +171,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, vb->state = VB2_BUF_STATE_DEQUEUED; vb->vb2_queue = q; vb->num_planes = num_planes; - vb->v4l2_buf.index = buffer; + vb->v4l2_buf.index = q->num_buffers + buffer; vb->v4l2_buf.type = q->type; vb->v4l2_buf.memory = memory; @@ -189,15 +199,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, } } - q->bufs[buffer] = vb; + q->bufs[q->num_buffers + buffer] = vb; } - q->num_buffers = buffer; - - __setup_offsets(q); + __setup_offsets(q, buffer); dprintk(1, "Allocated %d buffers, %d plane(s) each\n", - q->num_buffers, num_planes); + buffer, num_planes); return buffer; } @@ -205,12 +213,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, /** * __vb2_free_mem() - release all video buffer memory for a given queue */ -static void __vb2_free_mem(struct vb2_queue *q) +static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) { unsigned int buffer; struct vb2_buffer *vb; - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + ++buffer) { vb = q->bufs[buffer]; if (!vb) continue; @@ -224,17 +233,18 @@ static void __vb2_free_mem(struct vb2_queue *q) } /** - * __vb2_queue_free() - free the queue - video memory and related information - * and return the queue to an uninitialized state. Might be called even if the - * queue has already been freed. + * __vb2_queue_free() - free buffers at the end of the queue - video memory and + * related information, if no buffers are left return the queue to an + * uninitialized state. Might be called even if the queue has already been freed. */ -static void __vb2_queue_free(struct vb2_queue *q) +static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) { unsigned int buffer; /* Call driver-provided cleanup function for each buffer, if provided */ if (q->ops->buf_cleanup) { - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + ++buffer) { if (NULL == q->bufs[buffer]) continue; q->ops->buf_cleanup(q->bufs[buffer]); @@ -242,23 +252,25 @@ static void __vb2_queue_free(struct vb2_queue *q) } /* Release video buffer memory */ - __vb2_free_mem(q); + __vb2_free_mem(q, buffers); /* Free videobuf buffers */ - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + ++buffer) { kfree(q->bufs[buffer]); q->bufs[buffer] = NULL; } - q->num_buffers = 0; - q->memory = 0; + q->num_buffers -= buffers; + if (!q->num_buffers) + q->memory = 0; } /** * __verify_planes_array() - verify that the planes array passed in struct * v4l2_buffer from userspace can be safely used */ -static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b) +static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) { /* Is memory for copying plane information present? */ if (NULL == b->m.planes) { @@ -318,7 +330,7 @@ static bool __buffers_in_use(struct vb2_queue *q) static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; - int ret = 0; + int ret; /* Copy back data such as timestamp, flags, input, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); @@ -365,8 +377,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) case VB2_BUF_STATE_DONE: b->flags |= V4L2_BUF_FLAG_DONE; break; - case VB2_BUF_STATE_DEQUEUED: case VB2_BUF_STATE_PREPARED: + b->flags |= V4L2_BUF_FLAG_PREPARED; + break; + case VB2_BUF_STATE_DEQUEUED: /* nothing */ break; } @@ -374,7 +388,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) if (__buffer_in_use(q, vb)) b->flags |= V4L2_BUF_FLAG_MAPPED; - return ret; + return 0; } /** @@ -460,7 +474,7 @@ static int __verify_mmap_ops(struct vb2_queue *q) */ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) { - unsigned int num_buffers, num_planes; + unsigned int num_buffers, allocated_buffers, num_planes = 0; int ret = 0; if (q->fileio) { @@ -508,7 +522,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -EBUSY; } - __vb2_queue_free(q); + __vb2_queue_free(q, q->num_buffers); /* * In case of REQBUFS(0) return immediately without calling @@ -542,43 +556,167 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -ENOMEM; } + allocated_buffers = ret; + /* * Check if driver can handle the allocated number of buffers. */ - if (ret < num_buffers) { - unsigned int orig_num_buffers; + if (allocated_buffers < num_buffers) { + num_buffers = allocated_buffers; - orig_num_buffers = num_buffers = ret; ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); - if (ret) - goto free_mem; - if (orig_num_buffers < num_buffers) { + if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; - goto free_mem; - } /* - * Ok, driver accepted smaller number of buffers. + * Either the driver has accepted a smaller number of buffers, + * or .queue_setup() returned an error */ - ret = num_buffers; + } + + q->num_buffers = allocated_buffers; + + if (ret < 0) { + __vb2_queue_free(q, allocated_buffers); + return ret; } /* * Return the number of successfully allocated buffers * to the userspace. */ - req->count = ret; + req->count = allocated_buffers; return 0; - -free_mem: - __vb2_queue_free(q); - return ret; } EXPORT_SYMBOL_GPL(vb2_reqbufs); +/** + * vb2_create_bufs() - Allocate buffers and any required auxiliary structs + * @q: videobuf2 queue + * @create: creation parameters, passed from userspace to vidioc_create_bufs + * handler in driver + * + * Should be called from vidioc_create_bufs ioctl handler of a driver. + * This function: + * 1) verifies parameter sanity + * 2) calls the .queue_setup() queue operation + * 3) performs any necessary memory allocations + * + * The return values from this function are intended to be directly returned + * from vidioc_create_bufs handler in driver. + */ +int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) +{ + unsigned int num_planes = 0, num_buffers, allocated_buffers; + int ret = 0; + + if (q->fileio) { + dprintk(1, "%s(): file io in progress\n", __func__); + return -EBUSY; + } + + if (create->memory != V4L2_MEMORY_MMAP + && create->memory != V4L2_MEMORY_USERPTR) { + dprintk(1, "%s(): unsupported memory type\n", __func__); + return -EINVAL; + } + + if (create->format.type != q->type) { + dprintk(1, "%s(): requested type is incorrect\n", __func__); + return -EINVAL; + } + + /* + * Make sure all the required memory ops for given memory type + * are available. + */ + if (create->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { + dprintk(1, "%s(): MMAP for current setup unsupported\n", __func__); + return -EINVAL; + } + + if (create->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { + dprintk(1, "%s(): USERPTR for current setup unsupported\n", __func__); + return -EINVAL; + } + + if (q->num_buffers == VIDEO_MAX_FRAME) { + dprintk(1, "%s(): maximum number of buffers already allocated\n", + __func__); + return -ENOBUFS; + } + + create->index = q->num_buffers; + + if (!q->num_buffers) { + memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); + memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); + q->memory = create->memory; + } + + num_buffers = min(create->count, VIDEO_MAX_FRAME - q->num_buffers); + + /* + * Ask the driver, whether the requested number of buffers, planes per + * buffer and their sizes are acceptable + */ + ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, + &num_planes, q->plane_sizes, q->alloc_ctx); + if (ret) + return ret; + + /* Finally, allocate buffers and video memory */ + ret = __vb2_queue_alloc(q, create->memory, num_buffers, + num_planes); + if (ret < 0) { + dprintk(1, "Memory allocation failed with error: %d\n", ret); + return ret; + } + + allocated_buffers = ret; + + /* + * Check if driver can handle the so far allocated number of buffers. + */ + if (ret < num_buffers) { + num_buffers = ret; + + /* + * q->num_buffers contains the total number of buffers, that the + * queue driver has set up + */ + ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, + &num_planes, q->plane_sizes, q->alloc_ctx); + + if (!ret && allocated_buffers < num_buffers) + ret = -ENOMEM; + + /* + * Either the driver has accepted a smaller number of buffers, + * or .queue_setup() returned an error + */ + } + + q->num_buffers += allocated_buffers; + + if (ret < 0) { + __vb2_queue_free(q, allocated_buffers); + return ret; + } + + /* + * Return the number of successfully allocated buffers + * to the userspace. + */ + create->count = allocated_buffers; + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_create_bufs); + /** * vb2_plane_vaddr() - Return a kernel virtual address of a given plane * @vb: vb2_buffer to which the plane in question belongs to @@ -663,7 +801,7 @@ EXPORT_SYMBOL_GPL(vb2_buffer_done); * __fill_vb2_buffer() - fill a vb2_buffer with information provided in * a v4l2_buffer by the userspace */ -static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, +static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, struct v4l2_plane *v4l2_planes) { unsigned int plane; @@ -727,7 +865,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, /** * __qbuf_userptr() - handle qbuf of a USERPTR buffer */ -static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) +static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) { struct v4l2_plane planes[VIDEO_MAX_PLANES]; struct vb2_queue *q = vb->vb2_queue; @@ -816,7 +954,7 @@ err: /** * __qbuf_mmap() - handle qbuf of an MMAP buffer */ -static int __qbuf_mmap(struct vb2_buffer *vb, struct v4l2_buffer *b) +static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) { return __fill_vb2_buffer(vb, b, vb->v4l2_planes); } @@ -833,7 +971,7 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) q->ops->buf_queue(vb); } -static int __buf_prepare(struct vb2_buffer *vb, struct v4l2_buffer *b) +static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; int ret; @@ -860,6 +998,68 @@ static int __buf_prepare(struct vb2_buffer *vb, struct v4l2_buffer *b) return ret; } +/** + * vb2_prepare_buf() - Pass ownership of a buffer from userspace to the kernel + * @q: videobuf2 queue + * @b: buffer structure passed from userspace to vidioc_prepare_buf + * handler in driver + * + * Should be called from vidioc_prepare_buf ioctl handler of a driver. + * This function: + * 1) verifies the passed buffer, + * 2) calls buf_prepare callback in the driver (if provided), in which + * driver-specific buffer initialization can be performed, + * + * The return values from this function are intended to be directly returned + * from vidioc_prepare_buf handler in driver. + */ +int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) +{ + struct vb2_buffer *vb; + int ret; + + if (q->fileio) { + dprintk(1, "%s(): file io in progress\n", __func__); + return -EBUSY; + } + + if (b->type != q->type) { + dprintk(1, "%s(): invalid buffer type\n", __func__); + return -EINVAL; + } + + if (b->index >= q->num_buffers) { + dprintk(1, "%s(): buffer index out of range\n", __func__); + return -EINVAL; + } + + vb = q->bufs[b->index]; + if (NULL == vb) { + /* Should never happen */ + dprintk(1, "%s(): buffer is NULL\n", __func__); + return -EINVAL; + } + + if (b->memory != q->memory) { + dprintk(1, "%s(): invalid memory type\n", __func__); + return -EINVAL; + } + + if (vb->state != VB2_BUF_STATE_DEQUEUED) { + dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); + return -EINVAL; + } + + ret = __buf_prepare(vb, b); + if (ret < 0) + return ret; + + __fill_v4l2_buffer(vb, b); + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_prepare_buf); + /** * vb2_qbuf() - Queue a buffer from userspace * @q: videobuf2 queue @@ -1484,7 +1684,7 @@ void vb2_queue_release(struct vb2_queue *q) { __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); - __vb2_queue_free(q); + __vb2_queue_free(q, q->num_buffers); } EXPORT_SYMBOL_GPL(vb2_queue_release); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 692e35c232a9..55c57d3d3e63 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -169,13 +169,21 @@ struct vb2_buffer { /** * struct vb2_ops - driver-specific callbacks * - * @queue_setup: called from a VIDIOC_REQBUFS handler, before - * memory allocation; driver should return the required - * number of buffers in num_buffers, the required number - * of planes per buffer in num_planes; the size of each - * plane should be set in the sizes[] array and optional - * per-plane allocator specific context in alloc_ctxs[] - * array + * @queue_setup: called from VIDIOC_REQBUFS and VIDIOC_CREATE_BUFS + * handlers before memory allocation, or, if + * *num_planes != 0, after the allocation to verify a + * smaller number of buffers. Driver should return + * the required number of buffers in *num_buffers, the + * required number of planes per buffer in *num_planes; the + * size of each plane should be set in the sizes[] array + * and optional per-plane allocator specific context in the + * alloc_ctxs[] array. When called from VIDIOC_REQBUFS, + * fmt == NULL, the driver has to use the currently + * configured format and *num_buffers is the total number + * of buffers, that are being allocated. When called from + * VIDIOC_CREATE_BUFS, fmt != NULL and it describes the + * target frame format. In this case *num_buffers are being + * allocated additionally to q->num_buffers. * @wait_prepare: release any locks taken while calling vb2 functions; * it is called before an ioctl needs to wait for a new * buffer to arrive; required to avoid a deadlock in @@ -188,11 +196,11 @@ struct vb2_buffer { * perform additional buffer-related initialization; * initialization failure (return != 0) will prevent * queue setup from completing successfully; optional - * @buf_prepare: called every time the buffer is queued from userspace; - * drivers may perform any initialization required before - * each hardware operation in this callback; - * if an error is returned, the buffer will not be queued - * in driver; optional + * @buf_prepare: called every time the buffer is queued from userspace + * and from the VIDIOC_PREPARE_BUF ioctl; drivers may + * perform any initialization required before each hardware + * operation in this callback; if an error is returned, the + * buffer will not be queued in driver; optional * @buf_finish: called before every dequeue of the buffer back to * userspace; drivers may perform any operations required * before userspace accesses the buffer; optional @@ -300,6 +308,9 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q); int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b); int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req); +int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create); +int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b); + int vb2_queue_init(struct vb2_queue *q); void vb2_queue_release(struct vb2_queue *q); From 1d3564d91f94d0b598304eb6ebe3b83a83176f7a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 25 Aug 2011 13:26:53 -0300 Subject: [PATCH 094/144] [media] dmaengine: ipu-idmac: add support for the DMA_PAUSE control To support multi-size buffers in the mx3_camera V4L2 driver we have to be able to stop DMA on a channel without releasing descriptors and completely halting the hardware. Use the DMA_PAUSE control to implement this mode. Signed-off-by: Guennadi Liakhovetski Acked-by: Vinod Koul Signed-off-by: Mauro Carvalho Chehab --- drivers/dma/ipu/ipu_idmac.c | 65 ++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index 6815905a772f..ddc2a1331822 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -1307,6 +1307,7 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id) ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) { callback = descnew->txd.callback; callback_param = descnew->txd.callback_param; + list_del_init(&descnew->list); spin_unlock(&ichan->lock); if (callback) callback(callback_param); @@ -1428,39 +1429,58 @@ static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, { struct idmac_channel *ichan = to_idmac_chan(chan); struct idmac *idmac = to_idmac(chan->device); + struct ipu *ipu = to_ipu(idmac); + struct list_head *list, *tmp; unsigned long flags; int i; - /* Only supports DMA_TERMINATE_ALL */ - if (cmd != DMA_TERMINATE_ALL) - return -ENXIO; + switch (cmd) { + case DMA_PAUSE: + spin_lock_irqsave(&ipu->lock, flags); + ipu_ic_disable_task(ipu, chan->chan_id); - ipu_disable_channel(idmac, ichan, - ichan->status >= IPU_CHANNEL_ENABLED); + /* Return all descriptors into "prepared" state */ + list_for_each_safe(list, tmp, &ichan->queue) + list_del_init(list); - tasklet_disable(&to_ipu(idmac)->tasklet); + ichan->sg[0] = NULL; + ichan->sg[1] = NULL; - /* ichan->queue is modified in ISR, have to spinlock */ - spin_lock_irqsave(&ichan->lock, flags); - list_splice_init(&ichan->queue, &ichan->free_list); + spin_unlock_irqrestore(&ipu->lock, flags); - if (ichan->desc) - for (i = 0; i < ichan->n_tx_desc; i++) { - struct idmac_tx_desc *desc = ichan->desc + i; - if (list_empty(&desc->list)) - /* Descriptor was prepared, but not submitted */ - list_add(&desc->list, &ichan->free_list); + ichan->status = IPU_CHANNEL_INITIALIZED; + break; + case DMA_TERMINATE_ALL: + ipu_disable_channel(idmac, ichan, + ichan->status >= IPU_CHANNEL_ENABLED); - async_tx_clear_ack(&desc->txd); - } + tasklet_disable(&ipu->tasklet); - ichan->sg[0] = NULL; - ichan->sg[1] = NULL; - spin_unlock_irqrestore(&ichan->lock, flags); + /* ichan->queue is modified in ISR, have to spinlock */ + spin_lock_irqsave(&ichan->lock, flags); + list_splice_init(&ichan->queue, &ichan->free_list); - tasklet_enable(&to_ipu(idmac)->tasklet); + if (ichan->desc) + for (i = 0; i < ichan->n_tx_desc; i++) { + struct idmac_tx_desc *desc = ichan->desc + i; + if (list_empty(&desc->list)) + /* Descriptor was prepared, but not submitted */ + list_add(&desc->list, &ichan->free_list); - ichan->status = IPU_CHANNEL_INITIALIZED; + async_tx_clear_ack(&desc->txd); + } + + ichan->sg[0] = NULL; + ichan->sg[1] = NULL; + spin_unlock_irqrestore(&ichan->lock, flags); + + tasklet_enable(&ipu->tasklet); + + ichan->status = IPU_CHANNEL_INITIALIZED; + break; + default: + return -ENOSYS; + } return 0; } @@ -1663,7 +1683,6 @@ static void __exit ipu_idmac_exit(struct ipu *ipu) struct idmac_channel *ichan = ipu->channel + i; idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0); - idmac_prep_slave_sg(&ichan->dma_chan, NULL, 0, DMA_NONE, 0); } dma_async_device_unregister(&idmac->dma); From ee02da64558f04fb30c2462fdeabdfafc87a9799 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 6 Sep 2011 12:36:39 -0300 Subject: [PATCH 095/144] [media] soc_camera: add control handler support The soc_camera framework is switched over to use the control framework. After this patch none of the controls in subdevs or host drivers are available, until those drivers are also converted to the control framework. Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: moved code around, fixed problems] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 94 +++++++------------------------- include/media/soc_camera.h | 2 + 2 files changed, 21 insertions(+), 75 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index ac23916552db..b56f4b78273d 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -512,6 +512,7 @@ static int soc_camera_open(struct file *file) if (ret < 0) goto einitvb; } + v4l2_ctrl_handler_setup(&icd->ctrl_handler); } file->private_data = icd; @@ -781,78 +782,6 @@ static int soc_camera_streamoff(struct file *file, void *priv, return 0; } -static int soc_camera_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - int i; - - WARN_ON(priv != file->private_data); - - if (!qc->id) - return -EINVAL; - - /* First check host controls */ - for (i = 0; i < ici->ops->num_controls; i++) - if (qc->id == ici->ops->controls[i].id) { - memcpy(qc, &(ici->ops->controls[i]), - sizeof(*qc)); - return 0; - } - - if (!icd->ops) - return -EINVAL; - - /* Then device controls */ - for (i = 0; i < icd->ops->num_controls; i++) - if (qc->id == icd->ops->controls[i].id) { - memcpy(qc, &(icd->ops->controls[i]), - sizeof(*qc)); - return 0; - } - - return -EINVAL; -} - -static int soc_camera_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - WARN_ON(priv != file->private_data); - - if (ici->ops->get_ctrl) { - ret = ici->ops->get_ctrl(icd, ctrl); - if (ret != -ENOIOCTLCMD) - return ret; - } - - return v4l2_subdev_call(sd, core, g_ctrl, ctrl); -} - -static int soc_camera_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - WARN_ON(priv != file->private_data); - - if (ici->ops->set_ctrl) { - ret = ici->ops->set_ctrl(icd, ctrl); - if (ret != -ENOIOCTLCMD) - return ret; - } - - return v4l2_subdev_call(sd, core, s_ctrl, ctrl); -} - static int soc_camera_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a) { @@ -1055,6 +984,17 @@ static int soc_camera_probe(struct soc_camera_device *icd) dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); + /* + * Currently the subdev with the largest number of controls (13) is + * ov6550. So let's pick 16 as a hint for the control handler. Note + * that this is a hint only: too large and you waste some memory, too + * small and there is a (very) small performance hit when looking up + * controls in the internal hash. + */ + ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16); + if (ret < 0) + return ret; + ret = regulator_bulk_get(icd->pdev, icl->num_regulators, icl->regulators); if (ret < 0) @@ -1108,6 +1048,9 @@ static int soc_camera_probe(struct soc_camera_device *icd) sd = soc_camera_to_subdev(icd); sd->grp_id = (long)icd; + if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler)) + goto ectrl; + /* At this point client .probe() should have run already */ ret = soc_camera_init_user_formats(icd); if (ret < 0) @@ -1146,6 +1089,7 @@ evidstart: mutex_unlock(&icd->video_lock); soc_camera_free_user_formats(icd); eiufmt: +ectrl: if (icl->board_info) { soc_camera_free_i2c(icd); } else { @@ -1162,6 +1106,7 @@ eadd: epower: regulator_bulk_free(icl->num_regulators, icl->regulators); ereg: + v4l2_ctrl_handler_free(&icd->ctrl_handler); return ret; } @@ -1176,6 +1121,7 @@ static int soc_camera_remove(struct soc_camera_device *icd) BUG_ON(!icd->parent); + v4l2_ctrl_handler_free(&icd->ctrl_handler); if (vdev) { video_unregister_device(vdev); icd->vdev = NULL; @@ -1381,9 +1327,6 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_dqbuf = soc_camera_dqbuf, .vidioc_streamon = soc_camera_streamon, .vidioc_streamoff = soc_camera_streamoff, - .vidioc_queryctrl = soc_camera_queryctrl, - .vidioc_g_ctrl = soc_camera_g_ctrl, - .vidioc_s_ctrl = soc_camera_s_ctrl, .vidioc_cropcap = soc_camera_cropcap, .vidioc_g_crop = soc_camera_g_crop, .vidioc_s_crop = soc_camera_s_crop, @@ -1412,6 +1355,7 @@ static int video_dev_create(struct soc_camera_device *icd) vdev->ioctl_ops = &soc_camera_ioctl_ops; vdev->release = video_device_release; vdev->tvnorms = V4L2_STD_UNKNOWN; + vdev->ctrl_handler = &icd->ctrl_handler; vdev->lock = &icd->video_lock; icd->vdev = vdev; diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 1864e2242d45..2e15e17130da 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -19,6 +19,7 @@ #include #include #include +#include #include struct file; @@ -40,6 +41,7 @@ struct soc_camera_device { struct soc_camera_sense *sense; /* See comment in struct definition */ struct soc_camera_ops *ops; struct video_device *vdev; + struct v4l2_ctrl_handler ctrl_handler; const struct soc_camera_format_xlate *current_fmt; struct soc_camera_format_xlate *user_formats; int num_user_formats; From d34bfcd2a1e5f6be5ae81030b7a6193094632955 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 5 Sep 2011 17:07:47 -0300 Subject: [PATCH 096/144] [media] sh_mobile_ceu_camera: implement the control handler And since this is the last and only host driver that uses controls, also remove the now obsolete control fields from soc_camera.h. Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: moved code around, fixed problems] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 91 +++++++++------------- include/media/soc_camera.h | 4 - 2 files changed, 38 insertions(+), 57 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 0cb19689cfe8..5d5781bd1447 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -951,6 +951,38 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); +static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct soc_camera_device, + ctrl_handler); +} + +static int sh_mobile_ceu_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct soc_camera_device *icd = ctrl_to_icd(ctrl); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + + switch (ctrl->id) { + case V4L2_CID_SHARPNESS: + switch (icd->current_fmt->host_fmt->fourcc) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + ceu_write(pcdev, CLFCR, !ctrl->val); + return 0; + } + break; + } + + return -EINVAL; +} + +static const struct v4l2_ctrl_ops sh_mobile_ceu_ctrl_ops = { + .s_ctrl = sh_mobile_ceu_s_ctrl, +}; + static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { @@ -987,6 +1019,12 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int struct v4l2_rect rect; int shift = 0; + /* Add our control */ + v4l2_ctrl_new_std(&icd->ctrl_handler, &sh_mobile_ceu_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 1, 1, 0); + if (icd->ctrl_handler.error) + return icd->ctrl_handler.error; + /* FIXME: subwindow is lost between close / open */ /* Cache current client geometry */ @@ -1915,55 +1953,6 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, return vb2_queue_init(q); } -static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd, - struct v4l2_control *ctrl) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - u32 val; - - switch (ctrl->id) { - case V4L2_CID_SHARPNESS: - val = ceu_read(pcdev, CLFCR); - ctrl->value = val ^ 1; - return 0; - } - return -ENOIOCTLCMD; -} - -static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd, - struct v4l2_control *ctrl) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - switch (ctrl->id) { - case V4L2_CID_SHARPNESS: - switch (icd->current_fmt->host_fmt->fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - ceu_write(pcdev, CLFCR, !ctrl->value); - return 0; - } - return -EINVAL; - } - return -ENOIOCTLCMD; -} - -static const struct v4l2_queryctrl sh_mobile_ceu_controls[] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Low-pass filter", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { .owner = THIS_MODULE, .add = sh_mobile_ceu_add_device, @@ -1975,14 +1964,10 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { .set_livecrop = sh_mobile_ceu_set_livecrop, .set_fmt = sh_mobile_ceu_set_fmt, .try_fmt = sh_mobile_ceu_try_fmt, - .set_ctrl = sh_mobile_ceu_set_ctrl, - .get_ctrl = sh_mobile_ceu_get_ctrl, .poll = sh_mobile_ceu_poll, .querycap = sh_mobile_ceu_querycap, .set_bus_param = sh_mobile_ceu_set_bus_param, .init_videobuf2 = sh_mobile_ceu_init_videobuf, - .controls = sh_mobile_ceu_controls, - .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls), }; struct bus_wait { diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 2e15e17130da..d41b8bd74445 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -96,14 +96,10 @@ struct soc_camera_host_ops { int (*reqbufs)(struct soc_camera_device *, struct v4l2_requestbuffers *); int (*querycap)(struct soc_camera_host *, struct v4l2_capability *); int (*set_bus_param)(struct soc_camera_device *, __u32); - int (*get_ctrl)(struct soc_camera_device *, struct v4l2_control *); - int (*set_ctrl)(struct soc_camera_device *, struct v4l2_control *); int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *); int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *); int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *); unsigned int (*poll)(struct file *, poll_table *); - const struct v4l2_queryctrl *controls; - int num_controls; }; #define SOCAM_SENSOR_INVERT_PCLK (1 << 0) From 839b48dff10990c03f7d41afdaf5853cb3c0ab83 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 09:49:30 -0300 Subject: [PATCH 097/144] [media] ov9640: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov9640.c | 119 +++++++++++------------------------ drivers/media/video/ov9640.h | 4 +- 2 files changed, 38 insertions(+), 85 deletions(-) diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 352a8fb68b84..12d33a9c07b0 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "ov9640.h" @@ -164,27 +165,6 @@ static enum v4l2_mbus_pixelcode ov9640_codes[] = { V4L2_MBUS_FMT_RGB565_2X8_LE, }; -static const struct v4l2_queryctrl ov9640_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - /* read a register */ static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) { @@ -286,52 +266,25 @@ static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -/* Get status of additional camera capabilities */ -static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - } - return 0; -} - /* Set status of additional camera capabilities */ -static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - int ret = 0; + struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); switch (ctrl->id) { case V4L2_CID_VFLIP: - priv->flag_vflip = ctrl->value; - if (ctrl->value) - ret = ov9640_reg_rmw(client, OV9640_MVFP, + if (ctrl->val) + return ov9640_reg_rmw(client, OV9640_MVFP, OV9640_MVFP_V, 0); - else - ret = ov9640_reg_rmw(client, OV9640_MVFP, - 0, OV9640_MVFP_V); - break; + return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); case V4L2_CID_HFLIP: - priv->flag_hflip = ctrl->value; - if (ctrl->value) - ret = ov9640_reg_rmw(client, OV9640_MVFP, + if (ctrl->val) + return ov9640_reg_rmw(client, OV9640_MVFP, OV9640_MVFP_H, 0); - else - ret = ov9640_reg_rmw(client, OV9640_MVFP, - 0, OV9640_MVFP_H); - break; + return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); } - - return ret; + return -EINVAL; } /* Get chip identification */ @@ -643,20 +596,14 @@ static int ov9640_video_probe(struct soc_camera_device *icd, */ ret = ov9640_reg_read(client, OV9640_PID, &pid); + if (!ret) + ret = ov9640_reg_read(client, OV9640_VER, &ver); + if (!ret) + ret = ov9640_reg_read(client, OV9640_MIDH, &midh); + if (!ret) + ret = ov9640_reg_read(client, OV9640_MIDL, &midl); if (ret) - goto err; - - ret = ov9640_reg_read(client, OV9640_VER, &ver); - if (ret) - goto err; - - ret = ov9640_reg_read(client, OV9640_MIDH, &midh); - if (ret) - goto err; - - ret = ov9640_reg_read(client, OV9640_MIDL, &midl); - if (ret) - goto err; + return ret; switch (VERSION(pid, ver)) { case OV9640_V2: @@ -670,25 +617,20 @@ static int ov9640_video_probe(struct soc_camera_device *icd, break; default: dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); - ret = -ENODEV; - goto err; + return -ENODEV; } dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", devname, pid, ver, midh, midl); -err: - return ret; + return v4l2_ctrl_handler_setup(&priv->hdl); } -static struct soc_camera_ops ov9640_ops = { - .controls = ov9640_controls, - .num_controls = ARRAY_SIZE(ov9640_controls), +static const struct v4l2_ctrl_ops ov9640_ctrl_ops = { + .s_ctrl = ov9640_s_ctrl, }; static struct v4l2_subdev_core_ops ov9640_core_ops = { - .g_ctrl = ov9640_g_ctrl, - .s_ctrl = ov9640_s_ctrl, .g_chip_ident = ov9640_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov9640_get_register, @@ -760,12 +702,23 @@ static int ov9640_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); - icd->ops = &ov9640_ops; + v4l2_ctrl_handler_init(&priv->hdl, 2); + v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; + + kfree(priv); + return err; + } ret = ov9640_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } @@ -777,6 +730,8 @@ static int ov9640_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov9640_priv *priv = to_ov9640_sensor(sd); + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); return 0; } diff --git a/drivers/media/video/ov9640.h b/drivers/media/video/ov9640.h index f8a51b70792e..6b33a972c83c 100644 --- a/drivers/media/video/ov9640.h +++ b/drivers/media/video/ov9640.h @@ -198,12 +198,10 @@ struct ov9640_reg { struct ov9640_priv { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; int model; int revision; - - bool flag_vflip; - bool flag_hflip; }; #endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ From 91b6286ff3190fece7314b61ef330da96c4d644f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 05:12:03 -0300 Subject: [PATCH 098/144] [media] ov772x: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov772x.c | 114 +++++++++++------------------------ 1 file changed, 36 insertions(+), 78 deletions(-) diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index f77e8995fe40..9b540421e2cb 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -401,6 +402,7 @@ struct ov772x_win_size { struct ov772x_priv { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; struct ov772x_camera_info *info; const struct ov772x_color_format *cfmt; const struct ov772x_win_size *win; @@ -518,36 +520,6 @@ static const struct ov772x_win_size ov772x_win_qvga = { .regs = ov772x_qvga_regs, }; -static const struct v4l2_queryctrl ov772x_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_BAND_STOP_FILTER, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Band-stop filter", - .minimum = 0, - .maximum = 256, - .step = 1, - .default_value = 0, - }, -}; - /* * general function */ @@ -621,52 +593,30 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - case V4L2_CID_BAND_STOP_FILTER: - ctrl->value = priv->band_filter; - break; - } - return 0; -} - -static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) { + struct ov772x_priv *priv = container_of(ctrl->handler, + struct ov772x_priv, hdl); + struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); int ret = 0; u8 val; switch (ctrl->id) { case V4L2_CID_VFLIP: - val = ctrl->value ? VFLIP_IMG : 0x00; - priv->flag_vflip = ctrl->value; + val = ctrl->val ? VFLIP_IMG : 0x00; + priv->flag_vflip = ctrl->val; if (priv->info->flags & OV772X_FLAG_VFLIP) val ^= VFLIP_IMG; - ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val); - break; + return ov772x_mask_set(client, COM3, VFLIP_IMG, val); case V4L2_CID_HFLIP: - val = ctrl->value ? HFLIP_IMG : 0x00; - priv->flag_hflip = ctrl->value; + val = ctrl->val ? HFLIP_IMG : 0x00; + priv->flag_hflip = ctrl->val; if (priv->info->flags & OV772X_FLAG_HFLIP) val ^= HFLIP_IMG; - ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val); - break; + return ov772x_mask_set(client, COM3, HFLIP_IMG, val); case V4L2_CID_BAND_STOP_FILTER: - if ((unsigned)ctrl->value > 256) - ctrl->value = 256; - if (ctrl->value == priv->band_filter) - break; - if (!ctrl->value) { + if (!ctrl->val) { /* Switch the filter off, it is on now */ ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); if (!ret) @@ -674,7 +624,7 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) BNDF_ON_OFF, 0); } else { /* Switch the filter on, set AEC low limit */ - val = 256 - ctrl->value; + val = 256 - ctrl->val; ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF); if (!ret) @@ -682,11 +632,11 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 0xff, val); } if (!ret) - priv->band_filter = ctrl->value; - break; + priv->band_filter = ctrl->val; + return ret; } - return ret; + return -EINVAL; } static int ov772x_g_chip_ident(struct v4l2_subdev *sd, @@ -1042,18 +992,14 @@ static int ov772x_video_probe(struct soc_camera_device *icd, ver, i2c_smbus_read_byte_data(client, MIDH), i2c_smbus_read_byte_data(client, MIDL)); - - return 0; + return v4l2_ctrl_handler_setup(&priv->hdl); } -static struct soc_camera_ops ov772x_ops = { - .controls = ov772x_controls, - .num_controls = ARRAY_SIZE(ov772x_controls), +static const struct v4l2_ctrl_ops ov772x_ctrl_ops = { + .s_ctrl = ov772x_s_ctrl, }; static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { - .g_ctrl = ov772x_g_ctrl, - .s_ctrl = ov772x_s_ctrl, .g_chip_ident = ov772x_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov772x_g_register, @@ -1139,12 +1085,24 @@ static int ov772x_probe(struct i2c_client *client, priv->info = icl->priv; v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 3); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; - icd->ops = &ov772x_ops; + kfree(priv); + return err; + } ret = ov772x_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } @@ -1154,9 +1112,9 @@ static int ov772x_probe(struct i2c_client *client, static int ov772x_remove(struct i2c_client *client) { struct ov772x_priv *priv = to_ov772x(client); - struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); return 0; } From b5518a415158320d41bc31d6887d5c2aa1c9a164 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 3 Nov 2011 10:11:11 -0300 Subject: [PATCH 099/144] [media] V4L: sh-mobile-ceu-camera: prepare to support multi-size buffers Prepare the sh_mobile_ceu_camera friver to support the new VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF ioctl()s. The .queue_setup() vb2 operation must be able to handle buffer sizes, provided by the caller, and the .buf_prepare() operation must not use the currently configured frame format for its operation. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 128 +++++++++++++-------- 1 file changed, 83 insertions(+), 45 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 5d5781bd1447..a3153ca14089 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -90,7 +90,6 @@ struct sh_mobile_ceu_buffer { struct vb2_buffer vb; /* v4l buffer must be first */ struct list_head queue; - enum v4l2_mbus_pixelcode code; }; struct sh_mobile_ceu_dev { @@ -100,7 +99,8 @@ struct sh_mobile_ceu_dev { unsigned int irq; void __iomem *base; - unsigned long video_limit; + size_t video_limit; + size_t buf_total; spinlock_t lock; /* Protects video buffer lists */ struct list_head capture; @@ -192,6 +192,12 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) /* * Videobuf operations */ + +/* + * .queue_setup() is called to check, whether the driver can accept the + * requested number of buffers and to fill in plane sizes + * for the current frame format if required + */ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int *count, unsigned int *num_planes, @@ -200,26 +206,47 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); + int bytes_per_line; + unsigned int height; + if (fmt) { + const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, + fmt->fmt.pix.pixelformat); + if (!xlate) + return -EINVAL; + bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, + xlate->host_fmt); + height = fmt->fmt.pix.height; + } else { + /* Called from VIDIOC_REQBUFS or in compatibility mode */ + bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + height = icd->user_height; + } if (bytes_per_line < 0) return bytes_per_line; - *num_planes = 1; + sizes[0] = bytes_per_line * height; - pcdev->sequence = 0; - sizes[0] = bytes_per_line * icd->user_height; alloc_ctxs[0] = pcdev->alloc_ctx; + if (!vq->num_buffers) + pcdev->sequence = 0; + if (!*count) *count = 2; - if (pcdev->video_limit) { - if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit) - *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]); + /* If *num_planes != 0, we have already verified *count. */ + if (pcdev->video_limit && !*num_planes) { + size_t size = PAGE_ALIGN(sizes[0]) * *count; + + if (size + pcdev->buf_total > pcdev->video_limit) + *count = (pcdev->video_limit - pcdev->buf_total) / + PAGE_ALIGN(sizes[0]); } + *num_planes = 1; + dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); return 0; @@ -331,44 +358,11 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) { - struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); - struct sh_mobile_ceu_buffer *buf; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - unsigned long size; - - if (bytes_per_line < 0) - return bytes_per_line; - - buf = to_ceu_vb(vb); - - dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, - vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); + struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); /* Added list head initialization on alloc */ WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); -#ifdef DEBUG - /* - * This can be useful if you want to see if we actually fill - * the buffer with something - */ - if (vb2_plane_vaddr(vb, 0)) - memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); -#endif - - BUG_ON(NULL == icd->current_fmt); - - size = icd->user_height * bytes_per_line; - - if (vb2_plane_size(vb, 0) < size) { - dev_err(icd->parent, "Buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); - return -ENOBUFS; - } - - vb2_set_plane_payload(vb, 0, size); - return 0; } @@ -378,10 +372,35 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); + unsigned long size; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + goto error; + + size = icd->user_height * bytes_per_line; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n", + vb->v4l2_buf.index, vb2_plane_size(vb, 0), size); + goto error; + } + + vb2_set_plane_payload(vb, 0, size); dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); +#ifdef DEBUG + /* + * This can be useful if you want to see if we actually fill + * the buffer with something + */ + if (vb2_plane_vaddr(vb, 0)) + memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); +#endif + spin_lock_irq(&pcdev->lock); list_add_tail(&buf->queue, &pcdev->capture); @@ -395,6 +414,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) sh_mobile_ceu_capture(pcdev); } spin_unlock_irq(&pcdev->lock); + + return; + +error: + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); } static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) @@ -419,11 +443,23 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) if (buf->queue.next) list_del_init(&buf->queue); + pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0)); + dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, + pcdev->buf_total); + spin_unlock_irq(&pcdev->lock); } static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) { + struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + + pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0)); + dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, + pcdev->buf_total); + /* This is for locking debugging only */ INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); return 0; @@ -525,6 +561,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) pm_runtime_get_sync(ici->v4l2_dev.dev); + pcdev->buf_total = 0; + ret = sh_mobile_ceu_soft_reset(pcdev); csi2_sd = find_csi2(pcdev); @@ -1712,7 +1750,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, image_mode = false; } - dev_info(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, + dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, pix->width, pix->height); dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); From 07f92448045a23d27dbc3ece3abcb6bafc618d43 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 3 Nov 2011 10:14:00 -0300 Subject: [PATCH 100/144] [media] V4L: mx3-camera: prepare to support multi-size buffers Prepare the mx3_camera friver to support the new VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF ioctl()s. The .queue_setup() vb2 operation must be able to handle buffer sizes, provided by the caller, and the .buf_prepare() operation must not use the currently configured frame format for its operation, which makes it superfluous for this driver. Its functionality is moved into .buf_queue(). Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mx3_camera.c | 161 ++++++++++++++++--------------- 1 file changed, 85 insertions(+), 76 deletions(-) diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 24c2fe0714c5..f96f92f00f92 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -114,6 +114,7 @@ struct mx3_camera_dev { struct list_head capture; spinlock_t lock; /* Protects video buffer lists */ struct mx3_camera_buffer *active; + size_t buf_total; struct vb2_alloc_ctx *alloc_ctx; enum v4l2_field field; int sequence; @@ -198,73 +199,46 @@ static int mx3_videobuf_setup(struct vb2_queue *vq, struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - if (bytes_per_line < 0) - return bytes_per_line; + int bytes_per_line; + unsigned int height; if (!mx3_cam->idmac_channel[0]) return -EINVAL; - *num_planes = 1; - - mx3_cam->sequence = 0; - sizes[0] = bytes_per_line * icd->user_height; - alloc_ctxs[0] = mx3_cam->alloc_ctx; - - if (!*count) - *count = 32; - - if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) - *count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0]; - - return 0; -} - -static int mx3_videobuf_prepare(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; - struct scatterlist *sg; - struct mx3_camera_buffer *buf; - size_t new_size; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + if (fmt) { + const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, + fmt->fmt.pix.pixelformat); + if (!xlate) + return -EINVAL; + bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, + xlate->host_fmt); + height = fmt->fmt.pix.height; + } else { + /* Called from VIDIOC_REQBUFS or in compatibility mode */ + bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - + height = icd->user_height; + } if (bytes_per_line < 0) return bytes_per_line; - buf = to_mx3_vb(vb); - sg = &buf->sg; + sizes[0] = bytes_per_line * height; - new_size = bytes_per_line * icd->user_height; + alloc_ctxs[0] = mx3_cam->alloc_ctx; - if (vb2_plane_size(vb, 0) < new_size) { - dev_err(icd->parent, "Buffer too small (%lu < %zu)\n", - vb2_plane_size(vb, 0), new_size); - return -ENOBUFS; - } + if (!vq->num_buffers) + mx3_cam->sequence = 0; - if (buf->state == CSI_BUF_NEEDS_INIT) { - sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); - sg_dma_len(sg) = new_size; + if (!*count) + *count = 2; - buf->txd = ichan->dma_chan.device->device_prep_slave_sg( - &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT); - if (!buf->txd) - return -EIO; + /* If *num_planes != 0, we have already verified *count. */ + if (!*num_planes && + sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024) + *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) / + sizes[0]; - buf->txd->callback_param = buf->txd; - buf->txd->callback = mx3_cam_dma_done; - - buf->state = CSI_BUF_PREPARED; - } - - vb2_set_plane_payload(vb, 0, new_size); + *num_planes = 1; return 0; } @@ -288,28 +262,58 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct mx3_camera_buffer *buf = to_mx3_vb(vb); - struct dma_async_tx_descriptor *txd = buf->txd; - struct idmac_channel *ichan = to_idmac_chan(txd->chan); + struct scatterlist *sg = &buf->sg; + struct dma_async_tx_descriptor *txd; + struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; struct idmac_video_param *video = &ichan->params.video; - dma_cookie_t cookie; - u32 fourcc = icd->current_fmt->host_fmt->fourcc; + const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, host_fmt); unsigned long flags; + dma_cookie_t cookie; + size_t new_size; + + BUG_ON(bytes_per_line <= 0); + + new_size = bytes_per_line * icd->user_height; + + if (vb2_plane_size(vb, 0) < new_size) { + dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n", + vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size); + goto error; + } + + if (buf->state == CSI_BUF_NEEDS_INIT) { + sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); + sg_dma_len(sg) = new_size; + + txd = ichan->dma_chan.device->device_prep_slave_sg( + &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT); + if (!txd) + goto error; + + txd->callback_param = txd; + txd->callback = mx3_cam_dma_done; + + buf->state = CSI_BUF_PREPARED; + buf->txd = txd; + } else { + txd = buf->txd; + } + + vb2_set_plane_payload(vb, 0, new_size); /* This is the configuration of one sg-element */ - video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); + video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc); if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { /* - * If the IPU DMA channel is configured to transport - * generic 8-bit data, we have to set up correctly the - * geometry parameters upon the current pixel format. - * So, since the DMA horizontal parameters are expressed - * in bytes not pixels, convert these in the right unit. + * If the IPU DMA channel is configured to transfer generic + * 8-bit data, we have to set up the geometry parameters + * correctly, according to the current pixel format. The DMA + * horizontal parameters in this case are expressed in bytes, + * not in pixels. */ - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - BUG_ON(bytes_per_line <= 0); - video->out_width = bytes_per_line; video->out_height = icd->user_height; video->out_stride = bytes_per_line; @@ -353,6 +357,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) mx3_cam->active = NULL; spin_unlock_irqrestore(&mx3_cam->lock, flags); +error: vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); } @@ -386,17 +391,24 @@ static void mx3_videobuf_release(struct vb2_buffer *vb) } spin_unlock_irqrestore(&mx3_cam->lock, flags); + + mx3_cam->buf_total -= vb2_plane_size(vb, 0); } static int mx3_videobuf_init(struct vb2_buffer *vb) { + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct mx3_camera_dev *mx3_cam = ici->priv; struct mx3_camera_buffer *buf = to_mx3_vb(vb); + /* This is for locking debugging only */ INIT_LIST_HEAD(&buf->queue); sg_init_table(&buf->sg, 1); buf->state = CSI_BUF_NEEDS_INIT; - buf->txd = NULL; + + mx3_cam->buf_total += vb2_plane_size(vb, 0); return 0; } @@ -407,13 +419,12 @@ static int mx3_stop_streaming(struct vb2_queue *q) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; - struct dma_chan *chan; struct mx3_camera_buffer *buf, *tmp; unsigned long flags; if (ichan) { - chan = &ichan->dma_chan; - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + struct dma_chan *chan = &ichan->dma_chan; + chan->device->device_control(chan, DMA_PAUSE, 0); } spin_lock_irqsave(&mx3_cam->lock, flags); @@ -421,8 +432,8 @@ static int mx3_stop_streaming(struct vb2_queue *q) mx3_cam->active = NULL; list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { - buf->state = CSI_BUF_NEEDS_INIT; list_del_init(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } spin_unlock_irqrestore(&mx3_cam->lock, flags); @@ -432,7 +443,6 @@ static int mx3_stop_streaming(struct vb2_queue *q) static struct vb2_ops mx3_videobuf_ops = { .queue_setup = mx3_videobuf_setup, - .buf_prepare = mx3_videobuf_prepare, .buf_queue = mx3_videobuf_queue, .buf_cleanup = mx3_videobuf_release, .buf_init = mx3_videobuf_init, @@ -516,6 +526,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd) mx3_camera_activate(mx3_cam, icd); + mx3_cam->buf_total = 0; mx3_cam->icd = icd; dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", @@ -1263,8 +1274,6 @@ static int __devexit mx3_camera_remove(struct platform_device *pdev) dmaengine_put(); - dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n"); - return 0; } From 7ae77ee92fea7c115324096372a2a125d8bc26d7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 28 Sep 2011 09:25:28 -0300 Subject: [PATCH 101/144] [media] V4L: soc-camera: add 2 new ioctl() handlers This patch adds two new ioctl() handlers: .vidioc_create_bufs() and .vidioc_prepare_buf() for compliant vb2 soc-camera hosts. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 33 ++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index b56f4b78273d..8d5c421a803c 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -318,6 +318,32 @@ static int soc_camera_dqbuf(struct file *file, void *priv, return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); } +static int soc_camera_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *create) +{ + struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + + /* videobuf2 only */ + if (ici->ops->init_videobuf) + return -EINVAL; + else + return vb2_create_bufs(&icd->vb2_vidq, create); +} + +static int soc_camera_prepare_buf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + + /* videobuf2 only */ + if (ici->ops->init_videobuf) + return -EINVAL; + else + return vb2_prepare_buf(&icd->vb2_vidq, b); +} + /* Always entered with .video_lock held */ static int soc_camera_init_user_formats(struct soc_camera_device *icd) { @@ -1041,6 +1067,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (!control || !control->driver || !dev_get_drvdata(control) || !try_module_get(control->driver->owner)) { icl->del_device(icd); + ret = -ENODEV; goto enodrv; } } @@ -1312,19 +1339,21 @@ static int soc_camera_device_register(struct soc_camera_device *icd) static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_querycap = soc_camera_querycap, + .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, .vidioc_enum_input = soc_camera_enum_input, .vidioc_g_input = soc_camera_g_input, .vidioc_s_input = soc_camera_s_input, .vidioc_s_std = soc_camera_s_std, .vidioc_enum_framesizes = soc_camera_enum_fsizes, .vidioc_reqbufs = soc_camera_reqbufs, - .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, .vidioc_querybuf = soc_camera_querybuf, .vidioc_qbuf = soc_camera_qbuf, .vidioc_dqbuf = soc_camera_dqbuf, + .vidioc_create_bufs = soc_camera_create_bufs, + .vidioc_prepare_buf = soc_camera_prepare_buf, .vidioc_streamon = soc_camera_streamon, .vidioc_streamoff = soc_camera_streamoff, .vidioc_cropcap = soc_camera_cropcap, From 489759c0ca26bcd405c82966bdce7ff7fec5a110 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 7 Sep 2011 11:59:47 -0300 Subject: [PATCH 102/144] [media] V4L: sh_mobile_ceu_camera: the host shall configure the pipeline It is a task of the host / bridge driver to bind single subdevices into a pipeline, not of respective subdevices. Eventually this might be handled by the Media Controller API. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index a3153ca14089..f390682629cf 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -566,16 +566,24 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) ret = sh_mobile_ceu_soft_reset(pcdev); csi2_sd = find_csi2(pcdev); + if (csi2_sd) + csi2_sd->grp_id = (long)icd; ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); - if (ret != -ENODEV && ret != -ENOIOCTLCMD && ret < 0) { + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { pm_runtime_put_sync(ici->v4l2_dev.dev); - } else { - pcdev->icd = icd; - ret = 0; + return ret; } - return ret; + /* + * -ENODEV is special: either csi2_sd == NULL or the CSI-2 driver + * has not found this soc-camera device among its clients + */ + if (ret == -ENODEV && csi2_sd) + csi2_sd->grp_id = 0; + pcdev->icd = icd; + + return 0; } /* Called with .video_lock held */ @@ -588,6 +596,8 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) BUG_ON(icd != pcdev->icd); v4l2_subdev_call(csi2_sd, core, s_power, 0); + if (csi2_sd) + csi2_sd->grp_id = 0; /* disable capture, disable interrupts */ ceu_write(pcdev, CEIER, 0); sh_mobile_ceu_soft_reset(pcdev); From da83d9dc0ac18ffb07b5b344e237005a0ba08089 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 5 Sep 2011 08:26:20 -0300 Subject: [PATCH 103/144] [media] V4L: sh_mobile_csi2: do not guess the client, the host tells us We do not have to scan the list of subdevices to find our client - the sensor, the host has already set our grp_id value. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_csi2.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 6f9f2b7ee453..91c680a72849 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -201,22 +201,13 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) static int sh_csi2_client_connect(struct sh_csi2 *priv) { struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; - struct v4l2_subdev *sd, *csi2_sd = &priv->subdev; - struct soc_camera_device *icd = NULL; + struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; + struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); struct device *dev = v4l2_get_subdevdata(&priv->subdev); struct v4l2_mbus_config cfg; unsigned long common_flags, csi2_flags; int i, ret; - v4l2_device_for_each_subdev(sd, csi2_sd->v4l2_dev) - if (sd->grp_id) { - icd = (struct soc_camera_device *)sd->grp_id; - break; - } - - if (!icd) - return -EINVAL; - for (i = 0; i < pdata->num_clients; i++) if (&pdata->clients[i].pdev->dev == icd->pdev) break; @@ -246,7 +237,7 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) } cfg.type = V4L2_MBUS_CSI2; - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &cfg); if (ret == -ENOIOCTLCMD) common_flags = csi2_flags; else if (!ret) @@ -262,8 +253,6 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) priv->mipi_flags = common_flags; priv->client = pdata->clients + i; - csi2_sd->grp_id = (long)icd; - pm_runtime_get_sync(dev); sh_csi2_hwinit(priv); @@ -274,7 +263,6 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) static void sh_csi2_client_disconnect(struct sh_csi2 *priv) { priv->client = NULL; - priv->subdev.grp_id = 0; pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); } From 3dcc731a93679d75a1f90a969b34aa9d7acd1cbf Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 5 Sep 2011 12:33:21 -0300 Subject: [PATCH 104/144] [media] V4L: soc-camera: split a function into two The soc_camera_power_set() function processes two cases: power on anf off. These two cases don't share and common code, and the function is always called with a constant power on / off argument. Splitting this function into two removes a condition check, reduces indentation levels and makes the code look cleaner. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 65 +++++++++++++++++--------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 8d5c421a803c..d3eeb08be321 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -50,49 +50,52 @@ static LIST_HEAD(hosts); static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ -static int soc_camera_power_set(struct soc_camera_device *icd, - struct soc_camera_link *icl, - int power_on) +static int soc_camera_power_on(struct soc_camera_device *icd, + struct soc_camera_link *icl) { int ret; - if (power_on) { - ret = regulator_bulk_enable(icl->num_regulators, - icl->regulators); - if (ret < 0) { - dev_err(icd->pdev, "Cannot enable regulators\n"); - return ret; - } + ret = regulator_bulk_enable(icl->num_regulators, + icl->regulators); + if (ret < 0) { + dev_err(icd->pdev, "Cannot enable regulators\n"); + return ret; + } - if (icl->power) - ret = icl->power(icd->pdev, power_on); + if (icl->power) { + ret = icl->power(icd->pdev, 1); if (ret < 0) { dev_err(icd->pdev, "Platform failed to power-on the camera.\n"); regulator_bulk_disable(icl->num_regulators, icl->regulators); - return ret; } - } else { - ret = 0; - if (icl->power) - ret = icl->power(icd->pdev, 0); + } + + return ret; +} + +static int soc_camera_power_off(struct soc_camera_device *icd, + struct soc_camera_link *icl) +{ + int ret; + + if (icl->power) { + ret = icl->power(icd->pdev, 0); if (ret < 0) { dev_err(icd->pdev, "Platform failed to power-off the camera.\n"); return ret; } - - ret = regulator_bulk_disable(icl->num_regulators, - icl->regulators); - if (ret < 0) { - dev_err(icd->pdev, "Cannot disable regulators\n"); - return ret; - } } - return 0; + ret = regulator_bulk_disable(icl->num_regulators, + icl->regulators); + if (ret < 0) + dev_err(icd->pdev, "Cannot disable regulators\n"); + + return ret; } const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( @@ -502,7 +505,7 @@ static int soc_camera_open(struct file *file) }, }; - ret = soc_camera_power_set(icd, icl, 1); + ret = soc_camera_power_on(icd, icl); if (ret < 0) goto epower; @@ -556,7 +559,7 @@ esfmt: eresume: ici->ops->remove(icd); eiciadd: - soc_camera_power_set(icd, icl, 0); + soc_camera_power_off(icd, icl); epower: icd->use_count--; module_put(ici->ops->owner); @@ -580,7 +583,7 @@ static int soc_camera_close(struct file *file) if (ici->ops->init_videobuf2) vb2_queue_release(&icd->vb2_vidq); - soc_camera_power_set(icd, icl, 0); + soc_camera_power_off(icd, icl); } if (icd->streamer == file) @@ -1026,7 +1029,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (ret < 0) goto ereg; - ret = soc_camera_power_set(icd, icl, 1); + ret = soc_camera_power_on(icd, icl); if (ret < 0) goto epower; @@ -1106,7 +1109,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) ici->ops->remove(icd); - soc_camera_power_set(icd, icl, 0); + soc_camera_power_off(icd, icl); mutex_unlock(&icd->video_lock); @@ -1129,7 +1132,7 @@ eadddev: evdc: ici->ops->remove(icd); eadd: - soc_camera_power_set(icd, icl, 0); + soc_camera_power_off(icd, icl); epower: regulator_bulk_free(icl->num_regulators, icl->regulators); ereg: From fff96b6685d6fec14deaacbce9e27fbb8feed53d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 5 Sep 2011 13:50:27 -0300 Subject: [PATCH 105/144] [media] V4L: soc_camera_platform: do not leave dangling invalid pointers The life-time of soc-camera device objects can be longer, than the time, it is attached to a client driver, therefore all references to the driver own data have to be cleared, when the driver is detached. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera_platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index f5ebe59a5555..c8f6b188496d 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -173,7 +173,9 @@ evdrs: static int soc_camera_platform_remove(struct platform_device *pdev) { struct soc_camera_platform_priv *priv = get_priv(pdev); + struct soc_camera_platform_info *p = v4l2_get_subdevdata(&priv->subdev); + p->icd->control = NULL; v4l2_device_unregister_subdev(&priv->subdev); platform_set_drvdata(pdev, NULL); kfree(priv); From 7b9d8c3c4cfa0dc21f630c17c5f20e524dab487c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 8 Sep 2011 04:36:06 -0300 Subject: [PATCH 106/144] [media] V4L: soc-camera: call subdevice .s_power() method, when powering up or down Currently soc-camera can use power regulators and platform specific methods to power clients up and down. Additionally, client drivers can provide their own subdevice .s_power() methods, acting directly on the device. This patch adds calls to this method, when external power supplies are on. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 42 ++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index d3eeb08be321..9a62ed08d86a 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -53,10 +53,9 @@ static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ static int soc_camera_power_on(struct soc_camera_device *icd, struct soc_camera_link *icl) { - int ret; - - ret = regulator_bulk_enable(icl->num_regulators, - icl->regulators); + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + int ret = regulator_bulk_enable(icl->num_regulators, + icl->regulators); if (ret < 0) { dev_err(icd->pdev, "Cannot enable regulators\n"); return ret; @@ -67,19 +66,33 @@ static int soc_camera_power_on(struct soc_camera_device *icd, if (ret < 0) { dev_err(icd->pdev, "Platform failed to power-on the camera.\n"); - - regulator_bulk_disable(icl->num_regulators, - icl->regulators); + goto elinkpwr; } } + ret = v4l2_subdev_call(sd, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + goto esdpwr; + + return 0; + +esdpwr: + if (icl->power) + icl->power(icd->pdev, 0); +elinkpwr: + regulator_bulk_disable(icl->num_regulators, + icl->regulators); return ret; } static int soc_camera_power_off(struct soc_camera_device *icd, struct soc_camera_link *icl) { - int ret; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + int ret = v4l2_subdev_call(sd, core, s_power, 0); + + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; if (icl->power) { ret = icl->power(icd->pdev, 0); @@ -1029,6 +1042,12 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (ret < 0) goto ereg; + /* + * This will not yet call v4l2_subdev_core_ops::s_power(1), because the + * subdevice has not been initialised yet. We'll have to call it once + * again after initialisation, even though it shouldn't be needed, we + * don't do any IO here. + */ ret = soc_camera_power_on(icd, icl); if (ret < 0) goto epower; @@ -1099,6 +1118,10 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (ret < 0) goto evidstart; + ret = v4l2_subdev_call(sd, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) + goto esdpwr; + /* Try to improve our guess of a reasonable window format */ if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { icd->user_width = mf.width; @@ -1115,6 +1138,8 @@ static int soc_camera_probe(struct soc_camera_device *icd) return 0; +esdpwr: + video_unregister_device(icd->vdev); evidstart: mutex_unlock(&icd->video_lock); soc_camera_free_user_formats(icd); @@ -1129,6 +1154,7 @@ ectrl: enodrv: eadddev: video_device_release(icd->vdev); + icd->vdev = NULL; evdc: ici->ops->remove(icd); eadd: From 25e965ad2727527216724142d1fbeeb0e9dcf7a8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 05:20:33 -0300 Subject: [PATCH 107/144] [media] rj54n1cb0c: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/rj54n1cb0c.c | 141 +++++++++---------------------- 1 file changed, 38 insertions(+), 103 deletions(-) diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index c30221104c6f..9a871537d233 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -18,6 +18,7 @@ #include #include #include +#include #define RJ54N1_DEV_CODE 0x0400 #define RJ54N1_DEV_CODE2 0x0401 @@ -148,6 +149,7 @@ struct rj54n1_clock_div { struct rj54n1 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; struct rj54n1_clock_div clk_div; const struct rj54n1_datafmt *fmt; struct v4l2_rect rect; /* Sensor window */ @@ -1177,132 +1179,51 @@ static int rj54n1_s_register(struct v4l2_subdev *sd, } #endif -static const struct v4l2_queryctrl rj54n1_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 66, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, -}; - -static struct soc_camera_ops rj54n1_ops = { - .controls = rj54n1_controls, - .num_controls = ARRAY_SIZE(rj54n1_controls), -}; - -static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl) { + struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl); + struct v4l2_subdev *sd = &rj54n1->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); - if (data < 0) - return -EIO; - ctrl->value = !(data & 1); - break; - case V4L2_CID_HFLIP: - data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); - if (data < 0) - return -EIO; - ctrl->value = !(data & 2); - break; - case V4L2_CID_GAIN: - data = reg_read(client, RJ54N1_Y_GAIN); - if (data < 0) - return -EIO; - - ctrl->value = data / 2; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = rj54n1->auto_wb; - break; - } - - return 0; -} - -static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - int data; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - const struct v4l2_queryctrl *qctrl; - - qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id); - if (!qctrl) - return -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1); else data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_HFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2); else data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_GAIN: - if (ctrl->value > qctrl->maximum || - ctrl->value < qctrl->minimum) - return -EINVAL; - else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0) + if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0) return -EIO; - break; + return 0; case V4L2_CID_AUTO_WHITE_BALANCE: /* Auto WB area - whole image */ - if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->value << 7, + if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7, 0x80) < 0) return -EIO; - rj54n1->auto_wb = ctrl->value; - break; + rj54n1->auto_wb = ctrl->val; + return 0; } - return 0; + return -EINVAL; } +static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = { + .s_ctrl = rj54n1_s_ctrl, +}; + static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { - .g_ctrl = rj54n1_g_ctrl, - .s_ctrl = rj54n1_s_ctrl, .g_chip_ident = rj54n1_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = rj54n1_g_register, @@ -1432,8 +1353,22 @@ static int rj54n1_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops); + v4l2_ctrl_handler_init(&rj54n1->hdl, 4); + v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 66); + v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + rj54n1->subdev.ctrl_handler = &rj54n1->hdl; + if (rj54n1->hdl.error) { + int err = rj54n1->hdl.error; - icd->ops = &rj54n1_ops; + kfree(rj54n1); + return err; + } rj54n1->clk_div = clk_div; rj54n1->rect.left = RJ54N1_COLUMN_SKIP; @@ -1449,12 +1384,11 @@ static int rj54n1_probe(struct i2c_client *client, ret = rj54n1_video_probe(icd, client, rj54n1_priv); if (ret < 0) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&rj54n1->hdl); kfree(rj54n1); return ret; } - - return ret; + return v4l2_ctrl_handler_setup(&rj54n1->hdl); } static int rj54n1_remove(struct i2c_client *client) @@ -1463,9 +1397,10 @@ static int rj54n1_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; struct soc_camera_link *icl = to_soc_camera_link(icd); - icd->ops = NULL; + v4l2_device_unregister_subdev(&rj54n1->subdev); if (icl->free_bus) icl->free_bus(icl); + v4l2_ctrl_handler_free(&rj54n1->hdl); kfree(rj54n1); return 0; From ab7b50ae406ee918ba68a13133a9cdf89c70fe4f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 05:22:39 -0300 Subject: [PATCH 108/144] [media] mt9v022: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9v022.c | 265 ++++++++++++++-------------------- 1 file changed, 107 insertions(+), 158 deletions(-) diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 53149a73874b..7e2aeda21752 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -18,6 +18,7 @@ #include #include #include +#include /* * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c @@ -101,6 +102,17 @@ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { struct mt9v022 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct { + /* exposure/auto-exposure cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; + struct { + /* gain/auto-gain cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; struct v4l2_rect rect; /* Sensor window */ const struct mt9v022_datafmt *fmt; const struct mt9v022_datafmt *fmts; @@ -179,6 +191,8 @@ static int mt9v022_init(struct i2c_client *client) ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); if (!ret) ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); + if (!ret) + return v4l2_ctrl_handler_setup(&mt9v022->hdl); return ret; } @@ -431,215 +445,117 @@ static int mt9v022_s_register(struct v4l2_subdev *sd, } #endif -static const struct v4l2_queryctrl mt9v022_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Analog Gain", - .minimum = 64, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9v022_ops = { - .controls = mt9v022_controls, - .num_controls = ARRAY_SIZE(mt9v022_controls), -}; - -static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { + struct mt9v022 *mt9v022 = container_of(ctrl->handler, + struct mt9v022, hdl); + struct v4l2_subdev *sd = &mt9v022->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct v4l2_queryctrl *qctrl; + struct v4l2_ctrl *gain = mt9v022->gain; + struct v4l2_ctrl *exp = mt9v022->exposure; unsigned long range; int data; - qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); - switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, MT9V022_READ_MODE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x10); - break; - case V4L2_CID_HFLIP: - data = reg_read(client, MT9V022_READ_MODE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x20); - break; - case V4L2_CID_EXPOSURE_AUTO: - data = reg_read(client, MT9V022_AEC_AGC_ENABLE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x1); - break; case V4L2_CID_AUTOGAIN: - data = reg_read(client, MT9V022_AEC_AGC_ENABLE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x2); - break; - case V4L2_CID_GAIN: data = reg_read(client, MT9V022_ANALOG_GAIN); if (data < 0) return -EIO; - range = qctrl->maximum - qctrl->minimum; - ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; - - break; - case V4L2_CID_EXPOSURE: + range = gain->maximum - gain->minimum; + gain->val = ((data - 16) * range + 24) / 48 + gain->minimum; + return 0; + case V4L2_CID_EXPOSURE_AUTO: data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); if (data < 0) return -EIO; - range = qctrl->maximum - qctrl->minimum; - ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; - - break; + range = exp->maximum - exp->minimum; + exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; + return 0; } - return 0; + return -EINVAL; } -static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) { - int data; + struct mt9v022 *mt9v022 = container_of(ctrl->handler, + struct mt9v022, hdl); + struct v4l2_subdev *sd = &mt9v022->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct v4l2_queryctrl *qctrl; - - qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); - if (!qctrl) - return -EINVAL; + int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9V022_READ_MODE, 0x10); else data = reg_clear(client, MT9V022_READ_MODE, 0x10); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_HFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9V022_READ_MODE, 0x20); else data = reg_clear(client, MT9V022_READ_MODE, 0x20); if (data < 0) return -EIO; - break; - case V4L2_CID_GAIN: - /* mt9v022 has minimum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - unsigned long range = qctrl->maximum - qctrl->minimum; + return 0; + case V4L2_CID_AUTOGAIN: + if (ctrl->val) { + if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) + return -EIO; + } else { + struct v4l2_ctrl *gain = mt9v022->gain; + /* mt9v022 has minimum == default */ + unsigned long range = gain->maximum - gain->minimum; /* Valid values 16 to 64, 32 to 64 must be even. */ - unsigned long gain = ((ctrl->value - qctrl->minimum) * + unsigned long gain_val = ((gain->val - gain->minimum) * 48 + range / 2) / range + 16; - if (gain >= 32) - gain &= ~1; + + if (gain_val >= 32) + gain_val &= ~1; + /* * The user wants to set gain manually, hope, she * knows, what she's doing... Switch AGC off. */ - if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) return -EIO; dev_dbg(&client->dev, "Setting gain from %d to %lu\n", - reg_read(client, MT9V022_ANALOG_GAIN), gain); - if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) + reg_read(client, MT9V022_ANALOG_GAIN), gain_val); + if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0) return -EIO; } - break; - case V4L2_CID_EXPOSURE: - /* mt9v022 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - unsigned long range = qctrl->maximum - qctrl->minimum; - unsigned long shutter = ((ctrl->value - qctrl->minimum) * - 479 + range / 2) / range + 1; + return 0; + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_AUTO) { + data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); + } else { + struct v4l2_ctrl *exp = mt9v022->exposure; + unsigned long range = exp->maximum - exp->minimum; + unsigned long shutter = ((exp->val - exp->minimum) * + 479 + range / 2) / range + 1; + /* * The user wants to set shutter width manually, hope, * she knows, what she's doing... Switch AEC off. */ - - if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) + data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); + if (data < 0) return -EIO; - dev_dbg(&client->dev, "Shutter width from %d to %lu\n", - reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), - shutter); + reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), + shutter); if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, - shutter) < 0) + shutter) < 0) return -EIO; } - break; - case V4L2_CID_AUTOGAIN: - if (ctrl->value) - data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); - else - data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); - if (data < 0) - return -EIO; - break; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->value) - data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); - else - data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); - if (data < 0) - return -EIO; - break; + return 0; } - return 0; + return -EINVAL; } /* @@ -752,9 +668,12 @@ static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) return 0; } +static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = { + .g_volatile_ctrl = mt9v022_g_volatile_ctrl, + .s_ctrl = mt9v022_s_ctrl, +}; + static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { - .g_ctrl = mt9v022_g_ctrl, - .s_ctrl = mt9v022_s_ctrl, .g_chip_ident = mt9v022_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9v022_g_register, @@ -906,10 +825,39 @@ static int mt9v022_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); + v4l2_ctrl_handler_init(&mt9v022->hdl, 6); + v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 64); + + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ + mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl, + &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 255, 1, 255); + + mt9v022->subdev.ctrl_handler = &mt9v022->hdl; + if (mt9v022->hdl.error) { + int err = mt9v022->hdl.error; + + kfree(mt9v022); + return err; + } + v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure, + V4L2_EXPOSURE_MANUAL, true); + v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true); mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; - icd->ops = &mt9v022_ops; /* * MT9V022 _really_ corrupts the first read out line. * TODO: verify on i.MX31 @@ -922,7 +870,7 @@ static int mt9v022_probe(struct i2c_client *client, ret = mt9v022_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&mt9v022->hdl); kfree(mt9v022); } @@ -934,8 +882,9 @@ static int mt9v022_remove(struct i2c_client *client) struct mt9v022 *mt9v022 = to_mt9v022(client); struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&mt9v022->subdev); mt9v022_video_remove(icd); + v4l2_ctrl_handler_free(&mt9v022->hdl); kfree(mt9v022); return 0; From f026671d2bbbe8b25906bd266a1164a73fdeaa7f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 05:43:05 -0300 Subject: [PATCH 109/144] [media] ov2640: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov2640.c | 90 +++++++++++------------------------- 1 file changed, 27 insertions(+), 63 deletions(-) diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 2826aff5ea27..981767f2d8ea 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -24,6 +24,7 @@ #include #include #include +#include #define VAL_SET(x, mask, rshift, lshift) \ ((((x) >> rshift) & mask) << lshift) @@ -300,11 +301,10 @@ struct ov2640_win_size { struct ov2640_priv { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; enum v4l2_mbus_pixelcode cfmt_code; const struct ov2640_win_size *win; int model; - u16 flag_vflip:1; - u16 flag_hflip:1; }; /* @@ -609,29 +609,6 @@ static enum v4l2_mbus_pixelcode ov2640_codes[] = { V4L2_MBUS_FMT_RGB565_2X8_LE, }; -/* - * Supported controls - */ -static const struct v4l2_queryctrl ov2640_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - /* * General functions */ @@ -701,43 +678,23 @@ static int ov2640_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int ov2640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) { + struct v4l2_subdev *sd = + &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2640_priv *priv = to_ov2640(client); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - } - return 0; -} - -static int ov2640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2640_priv *priv = to_ov2640(client); - int ret = 0; u8 val; switch (ctrl->id) { case V4L2_CID_VFLIP: - val = ctrl->value ? REG04_VFLIP_IMG : 0x00; - priv->flag_vflip = ctrl->value ? 1 : 0; - ret = ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); - break; + val = ctrl->val ? REG04_VFLIP_IMG : 0x00; + return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); case V4L2_CID_HFLIP: - val = ctrl->value ? REG04_HFLIP_IMG : 0x00; - priv->flag_hflip = ctrl->value ? 1 : 0; - ret = ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); - break; + val = ctrl->val ? REG04_HFLIP_IMG : 0x00; + return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); } - return ret; + return -EINVAL; } static int ov2640_g_chip_ident(struct v4l2_subdev *sd, @@ -1022,20 +979,17 @@ static int ov2640_video_probe(struct soc_camera_device *icd, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", devname, pid, ver, midh, midl); - return 0; + return v4l2_ctrl_handler_setup(&priv->hdl); err: return ret; } -static struct soc_camera_ops ov2640_ops = { - .controls = ov2640_controls, - .num_controls = ARRAY_SIZE(ov2640_controls), +static const struct v4l2_ctrl_ops ov2640_ctrl_ops = { + .s_ctrl = ov2640_s_ctrl, }; static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { - .g_ctrl = ov2640_g_ctrl, - .s_ctrl = ov2640_s_ctrl, .g_chip_ident = ov2640_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov2640_g_register, @@ -1113,12 +1067,22 @@ static int ov2640_probe(struct i2c_client *client, } v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 2); + v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; - icd->ops = &ov2640_ops; + kfree(priv); + return err; + } ret = ov2640_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } else { dev_info(&adapter->dev, "OV2640 Probed\n"); @@ -1130,9 +1094,9 @@ static int ov2640_probe(struct i2c_client *client, static int ov2640_remove(struct i2c_client *client) { struct ov2640_priv *priv = to_ov2640(client); - struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); return 0; } From afd9690c72c3acf77b7f8731b2fcafafd3b7e29e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 12 Sep 2011 09:52:01 -0300 Subject: [PATCH 110/144] [media] ov6650: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] [jkrzyszt@tis.icnet.pl: fix a typo in the register name] Acked-by: Janusz Krzysztofik Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov6650.c | 395 +++++++++++------------------------ 1 file changed, 122 insertions(+), 273 deletions(-) diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 654b2f591ae2..efa45132c992 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -32,6 +32,7 @@ #include #include #include +#include /* Register definitions */ #define REG_GAIN 0x00 /* range 00 - 3F */ @@ -177,20 +178,23 @@ struct ov6650_reg { struct ov6650 { struct v4l2_subdev subdev; - - int gain; - int blue; - int red; - int saturation; - int hue; - int brightness; - int exposure; - int gamma; - int aec; - bool vflip; - bool hflip; - bool awb; - bool agc; + struct v4l2_ctrl_handler hdl; + struct { + /* exposure/autoexposure cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; + struct { + /* gain/autogain cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; + struct { + /* blue/red/autowhitebalance cluster */ + struct v4l2_ctrl *autowb; + struct v4l2_ctrl *blue; + struct v4l2_ctrl *red; + }; bool half_scale; /* scale down output by 2 */ struct v4l2_rect rect; /* sensor cropping window */ unsigned long pclk_limit; /* from host */ @@ -210,126 +214,6 @@ static enum v4l2_mbus_pixelcode ov6650_codes[] = { V4L2_MBUS_FMT_Y8_1X8, }; -static const struct v4l2_queryctrl ov6650_controls[] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "AGC", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = DEF_GAIN, - }, - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "AWB", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = DEF_BLUE, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = DEF_RED, - }, - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 0xf, - .step = 1, - .default_value = 0x8, - }, - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = HUE_MASK, - .step = 1, - .default_value = DEF_HUE, - }, - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x80, - }, - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "AEC", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = DEF_AECH, - }, - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x12, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - /* read a register */ static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) { @@ -420,166 +304,91 @@ static int ov6650_s_stream(struct v4l2_subdev *sd, int enable) } /* Get status of additional camera capabilities */ -static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { + struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); + struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - uint8_t reg; + uint8_t reg, reg2; int ret = 0; switch (ctrl->id) { case V4L2_CID_AUTOGAIN: - ctrl->value = priv->agc; - break; - case V4L2_CID_GAIN: - if (priv->agc) { - ret = ov6650_reg_read(client, REG_GAIN, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->gain; - } - break; + ret = ov6650_reg_read(client, REG_GAIN, ®); + if (!ret) + priv->gain->val = reg; + return ret; case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = priv->awb; - break; - case V4L2_CID_BLUE_BALANCE: - if (priv->awb) { - ret = ov6650_reg_read(client, REG_BLUE, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->blue; + ret = ov6650_reg_read(client, REG_BLUE, ®); + if (!ret) + ret = ov6650_reg_read(client, REG_RED, ®2); + if (!ret) { + priv->blue->val = reg; + priv->red->val = reg2; } - break; - case V4L2_CID_RED_BALANCE: - if (priv->awb) { - ret = ov6650_reg_read(client, REG_RED, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->red; - } - break; - case V4L2_CID_SATURATION: - ctrl->value = priv->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = priv->hue; - break; - case V4L2_CID_BRIGHTNESS: - ctrl->value = priv->brightness; - break; + return ret; case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = priv->aec; - break; - case V4L2_CID_EXPOSURE: - if (priv->aec) { - ret = ov6650_reg_read(client, REG_AECH, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->exposure; - } - break; - case V4L2_CID_GAMMA: - ctrl->value = priv->gamma; - break; - case V4L2_CID_VFLIP: - ctrl->value = priv->vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->hflip; - break; + ret = ov6650_reg_read(client, REG_AECH, ®); + if (!ret) + priv->exposure->val = reg; + return ret; } - return ret; + return -EINVAL; } /* Set status of additional camera capabilities */ -static int ov6650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) { + struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); + struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); int ret = 0; switch (ctrl->id) { case V4L2_CID_AUTOGAIN: ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_AGC : 0, COMB_AGC); - if (!ret) - priv->agc = ctrl->value; - break; - case V4L2_CID_GAIN: - ret = ov6650_reg_write(client, REG_GAIN, ctrl->value); - if (!ret) - priv->gain = ctrl->value; - break; + ctrl->val ? COMB_AGC : 0, COMB_AGC); + if (!ret && !ctrl->val) + ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val); + return ret; case V4L2_CID_AUTO_WHITE_BALANCE: ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_AWB : 0, COMB_AWB); - if (!ret) - priv->awb = ctrl->value; - break; - case V4L2_CID_BLUE_BALANCE: - ret = ov6650_reg_write(client, REG_BLUE, ctrl->value); - if (!ret) - priv->blue = ctrl->value; - break; - case V4L2_CID_RED_BALANCE: - ret = ov6650_reg_write(client, REG_RED, ctrl->value); - if (!ret) - priv->red = ctrl->value; - break; - case V4L2_CID_SATURATION: - ret = ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->value), - SAT_MASK); - if (!ret) - priv->saturation = ctrl->value; - break; - case V4L2_CID_HUE: - ret = ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->value), - HUE_MASK); - if (!ret) - priv->hue = ctrl->value; - break; - case V4L2_CID_BRIGHTNESS: - ret = ov6650_reg_write(client, REG_BRT, ctrl->value); - if (!ret) - priv->brightness = ctrl->value; - break; - case V4L2_CID_EXPOSURE_AUTO: - switch (ctrl->value) { - case V4L2_EXPOSURE_AUTO: - ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); - break; - default: - ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); - break; + ctrl->val ? COMB_AWB : 0, COMB_AWB); + if (!ret && !ctrl->val) { + ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val); + if (!ret) + ret = ov6650_reg_write(client, REG_RED, + priv->red->val); } - if (!ret) - priv->aec = ctrl->value; - break; - case V4L2_CID_EXPOSURE: - ret = ov6650_reg_write(client, REG_AECH, ctrl->value); - if (!ret) - priv->exposure = ctrl->value; - break; + return ret; + case V4L2_CID_SATURATION: + return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val), + SAT_MASK); + case V4L2_CID_HUE: + return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val), + HUE_MASK); + case V4L2_CID_BRIGHTNESS: + return ov6650_reg_write(client, REG_BRT, ctrl->val); + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_AUTO) + ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); + else + ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); + if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) + ret = ov6650_reg_write(client, REG_AECH, + priv->exposure->val); + return ret; case V4L2_CID_GAMMA: - ret = ov6650_reg_write(client, REG_GAM1, ctrl->value); - if (!ret) - priv->gamma = ctrl->value; - break; + return ov6650_reg_write(client, REG_GAM1, ctrl->val); case V4L2_CID_VFLIP: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_FLIP_V : 0, COMB_FLIP_V); - if (!ret) - priv->vflip = ctrl->value; - break; + return ov6650_reg_rmw(client, REG_COMB, + ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V); case V4L2_CID_HFLIP: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_FLIP_H : 0, COMB_FLIP_H); - if (!ret) - priv->hflip = ctrl->value; - break; + return ov6650_reg_rmw(client, REG_COMB, + ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H); } - return ret; + return -EINVAL; } /* Get chip identification */ @@ -1048,14 +857,12 @@ static int ov6650_video_probe(struct soc_camera_device *icd, return ret; } -static struct soc_camera_ops ov6650_ops = { - .controls = ov6650_controls, - .num_controls = ARRAY_SIZE(ov6650_controls), +static const struct v4l2_ctrl_ops ov6550_ctrl_ops = { + .g_volatile_ctrl = ov6550_g_volatile_ctrl, + .s_ctrl = ov6550_s_ctrl, }; static struct v4l2_subdev_core_ops ov6650_core_ops = { - .g_ctrl = ov6650_g_ctrl, - .s_ctrl = ov6650_s_ctrl, .g_chip_ident = ov6650_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov6650_get_register, @@ -1164,8 +971,46 @@ static int ov6650_probe(struct i2c_client *client, } v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 13); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN); + priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE); + priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_SATURATION, 0, 0xf, 1, 0x8); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); + priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, + &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); - icd->ops = &ov6650_ops; + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; + + kfree(priv); + return err; + } + v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); + v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); + v4l2_ctrl_auto_cluster(2, &priv->autoexposure, + V4L2_EXPOSURE_MANUAL, true); priv->rect.left = DEF_HSTRT << 1; priv->rect.top = DEF_VSTRT << 1; @@ -1176,9 +1021,11 @@ static int ov6650_probe(struct i2c_client *client, priv->colorspace = V4L2_COLORSPACE_JPEG; ret = ov6650_video_probe(icd, client); + if (!ret) + ret = v4l2_ctrl_handler_setup(&priv->hdl); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } @@ -1189,6 +1036,8 @@ static int ov6650_remove(struct i2c_client *client) { struct ov6650 *priv = to_ov6650(client); + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); return 0; } From 34e181c5211f106f1d464e9bcb50bb88398126e2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 06:03:11 -0300 Subject: [PATCH 111/144] [media] ov9740: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov9740.c | 83 ++++++++++++------------------------ 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index 5920f600990f..3dd910dcc5b8 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c @@ -18,6 +18,7 @@ #include #include #include +#include #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) @@ -194,6 +195,7 @@ struct ov9740_reg { struct ov9740_priv { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; int ident; u16 model; @@ -394,27 +396,6 @@ static enum v4l2_mbus_pixelcode ov9740_codes[] = { V4L2_MBUS_FMT_YUYV8_2X8, }; -static const struct v4l2_queryctrl ov9740_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - /* read a register */ static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) { @@ -771,36 +752,18 @@ static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) return 0; } -/* Get status of additional camera capabilities */ -static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov9740_priv *priv = to_ov9740(sd); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - default: - return -EINVAL; - } - - return 0; -} - /* Set status of additional camera capabilities */ -static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl) { - struct ov9740_priv *priv = to_ov9740(sd); + struct ov9740_priv *priv = + container_of(ctrl->handler, struct ov9740_priv, hdl); switch (ctrl->id) { case V4L2_CID_VFLIP: - priv->flag_vflip = ctrl->value; + priv->flag_vflip = ctrl->val; break; case V4L2_CID_HFLIP: - priv->flag_hflip = ctrl->value; + priv->flag_hflip = ctrl->val; break; default: return -EINVAL; @@ -925,11 +888,6 @@ err: return ret; } -static struct soc_camera_ops ov9740_ops = { - .controls = ov9740_controls, - .num_controls = ARRAY_SIZE(ov9740_controls), -}; - /* Request bus settings on camera side */ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) @@ -958,8 +916,6 @@ static struct v4l2_subdev_video_ops ov9740_video_ops = { }; static struct v4l2_subdev_core_ops ov9740_core_ops = { - .g_ctrl = ov9740_g_ctrl, - .s_ctrl = ov9740_s_ctrl, .g_chip_ident = ov9740_g_chip_ident, .s_power = ov9740_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -973,6 +929,10 @@ static struct v4l2_subdev_ops ov9740_subdev_ops = { .video = &ov9740_video_ops, }; +static const struct v4l2_ctrl_ops ov9740_ctrl_ops = { + .s_ctrl = ov9740_s_ctrl, +}; + /* * i2c_driver function */ @@ -980,7 +940,7 @@ static int ov9740_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov9740_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_device *icd = client->dev.platform_data; struct soc_camera_link *icl; int ret; @@ -1002,12 +962,24 @@ static int ov9740_probe(struct i2c_client *client, } v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 13); + v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; - icd->ops = &ov9740_ops; + kfree(priv); + return err; + } ret = ov9740_video_probe(icd, client); + if (!ret) + ret = v4l2_ctrl_handler_setup(&priv->hdl); if (ret < 0) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } @@ -1018,8 +990,9 @@ static int ov9740_remove(struct i2c_client *client) { struct ov9740_priv *priv = i2c_get_clientdata(client); + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); - return 0; } From 2dd7d29c783db1efa875e585770feb2cd7aaaf32 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 06:04:30 -0300 Subject: [PATCH 112/144] [media] mt9m001: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 218 ++++++++++++---------------------- 1 file changed, 77 insertions(+), 141 deletions(-) diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 3555e853e5c9..42bb3c89cfe6 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -17,6 +17,7 @@ #include #include #include +#include /* * mt9m001 i2c address 0x5d @@ -85,15 +86,19 @@ static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { struct mt9m001 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct { + /* exposure/auto-exposure cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; struct v4l2_rect rect; /* Sensor window */ const struct mt9m001_datafmt *fmt; const struct mt9m001_datafmt *fmts; int num_fmts; int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ - unsigned int gain; - unsigned int exposure; + unsigned int total_h; unsigned short y_skip_top; /* Lines to skip at the top */ - unsigned char autoexposure; }; static struct mt9m001 *to_mt9m001(const struct i2c_client *client) @@ -171,10 +176,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); struct v4l2_rect rect = a->c; - struct soc_camera_device *icd = client->dev.platform_data; int ret; const u16 hblank = 9, vblank = 25; - unsigned int total_h; if (mt9m001->fmts == mt9m001_colour_fmts) /* @@ -193,7 +196,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) soc_camera_limit_side(&rect.top, &rect.height, MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); - total_h = rect.height + mt9m001->y_skip_top + vblank; + mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank; /* Blanking and start values - default... */ ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); @@ -213,17 +216,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) if (!ret) ret = reg_write(client, MT9M001_WINDOW_HEIGHT, rect.height + mt9m001->y_skip_top - 1); - if (!ret && mt9m001->autoexposure) { - ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); - if (!ret) { - const struct v4l2_queryctrl *qctrl = - soc_camera_find_qctrl(icd->ops, - V4L2_CID_EXPOSURE); - mt9m001->exposure = (524 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - 1048 + qctrl->minimum; - } - } + if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO) + ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h); if (!ret) mt9m001->rect = rect; @@ -383,105 +377,48 @@ static int mt9m001_s_register(struct v4l2_subdev *sd, } #endif -static const struct v4l2_queryctrl mt9m001_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9m001_ops = { - .controls = mt9m001_controls, - .num_controls = ARRAY_SIZE(mt9m001_controls), -}; - -static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - int data; + struct mt9m001 *mt9m001 = container_of(ctrl->handler, + struct mt9m001, hdl); + s32 min, max; switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, MT9M001_READ_OPTIONS2); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x8000); - break; case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = mt9m001->autoexposure; - break; - case V4L2_CID_GAIN: - ctrl->value = mt9m001->gain; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = mt9m001->exposure; + min = mt9m001->exposure->minimum; + max = mt9m001->exposure->maximum; + mt9m001->exposure->val = + (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min; break; } return 0; } -static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) { + struct mt9m001 *mt9m001 = container_of(ctrl->handler, + struct mt9m001, hdl); + struct v4l2_subdev *sd = &mt9m001->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_device *icd = client->dev.platform_data; - const struct v4l2_queryctrl *qctrl; + struct v4l2_ctrl *exp = mt9m001->exposure; int data; - qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id); - - if (!qctrl) - return -EINVAL; - switch (ctrl->id) { case V4L2_CID_VFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); else data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); if (data < 0) return -EIO; - break; + return 0; + case V4L2_CID_GAIN: - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; /* See Datasheet Table 7, Gain settings. */ - if (ctrl->value <= qctrl->default_value) { + if (ctrl->val <= ctrl->default_value) { /* Pack it into 0..1 step 0.125, register values 0..8 */ - unsigned long range = qctrl->default_value - qctrl->minimum; - data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; + unsigned long range = ctrl->default_value - ctrl->minimum; + data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range; dev_dbg(&client->dev, "Setting gain %d\n", data); data = reg_write(client, MT9M001_GLOBAL_GAIN, data); @@ -490,8 +427,8 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) } else { /* Pack it into 1.125..15 variable step, register values 9..67 */ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ - unsigned long range = qctrl->maximum - qctrl->default_value - 1; - unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * + unsigned long range = ctrl->maximum - ctrl->default_value - 1; + unsigned long gain = ((ctrl->val - ctrl->default_value - 1) * 111 + range / 2) / range + 9; if (gain <= 32) @@ -507,47 +444,30 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (data < 0) return -EIO; } + return 0; - /* Success */ - mt9m001->gain = ctrl->value; - break; - case V4L2_CID_EXPOSURE: - /* mt9m001 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - unsigned long range = qctrl->maximum - qctrl->minimum; - unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 + + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_MANUAL) { + unsigned long range = exp->maximum - exp->minimum; + unsigned long shutter = ((exp->val - exp->minimum) * 1048 + range / 2) / range + 1; dev_dbg(&client->dev, "Setting shutter width from %d to %lu\n", - reg_read(client, MT9M001_SHUTTER_WIDTH), - shutter); + reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) return -EIO; - mt9m001->exposure = ctrl->value; - mt9m001->autoexposure = 0; - } - break; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->value) { + } else { const u16 vblank = 25; - unsigned int total_h = mt9m001->rect.height + + + mt9m001->total_h = mt9m001->rect.height + mt9m001->y_skip_top + vblank; - if (reg_write(client, MT9M001_SHUTTER_WIDTH, - total_h) < 0) + if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0) return -EIO; - qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); - mt9m001->exposure = (524 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - 1048 + qctrl->minimum; - mt9m001->autoexposure = 1; - } else - mt9m001->autoexposure = 0; - break; + } + return 0; } - return 0; + return -EINVAL; } /* @@ -621,10 +541,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, dev_err(&client->dev, "Failed to initialise the camera\n"); /* mt9m001_init() has reset the chip, returning registers to defaults */ - mt9m001->gain = 64; - mt9m001->exposure = 255; - - return ret; + return v4l2_ctrl_handler_setup(&mt9m001->hdl); } static void mt9m001_video_remove(struct soc_camera_device *icd) @@ -647,9 +564,12 @@ static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) return 0; } +static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = { + .g_volatile_ctrl = mt9m001_g_volatile_ctrl, + .s_ctrl = mt9m001_s_ctrl, +}; + static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { - .g_ctrl = mt9m001_g_ctrl, - .s_ctrl = mt9m001_s_ctrl, .g_chip_ident = mt9m001_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9m001_g_register, @@ -765,25 +685,40 @@ static int mt9m001_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); + v4l2_ctrl_handler_init(&mt9m001->hdl, 4); + v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 64); + mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 255, 1, 255); + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ + mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl, + &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + mt9m001->subdev.ctrl_handler = &mt9m001->hdl; + if (mt9m001->hdl.error) { + int err = mt9m001->hdl.error; + + kfree(mt9m001); + return err; + } + v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure, + V4L2_EXPOSURE_MANUAL, true); /* Second stage probe - when a capture adapter is there */ - icd->ops = &mt9m001_ops; - mt9m001->y_skip_top = 0; mt9m001->rect.left = MT9M001_COLUMN_SKIP; mt9m001->rect.top = MT9M001_ROW_SKIP; mt9m001->rect.width = MT9M001_MAX_WIDTH; mt9m001->rect.height = MT9M001_MAX_HEIGHT; - /* - * Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width - */ - mt9m001->autoexposure = 1; - ret = mt9m001_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&mt9m001->hdl); kfree(mt9m001); } @@ -795,7 +730,8 @@ static int mt9m001_remove(struct i2c_client *client) struct mt9m001 *mt9m001 = to_mt9m001(client); struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&mt9m001->subdev); + v4l2_ctrl_handler_free(&mt9m001->hdl); mt9m001_video_remove(icd); kfree(mt9m001); From af8425c54beb3c32cbb503a379132b3975535289 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 06:56:57 -0300 Subject: [PATCH 113/144] [media] mt9m111: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m111.c | 203 ++++++++-------------------------- 1 file changed, 48 insertions(+), 155 deletions(-) diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 28d447c6d40e..8cacbf016848 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* @@ -178,6 +179,8 @@ enum mt9m111_context { struct mt9m111 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *gain; int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code * from v4l2-chip-ident.h */ enum mt9m111_context context; @@ -186,13 +189,8 @@ struct mt9m111 { int power_count; const struct mt9m111_datafmt *fmt; int lastpage; /* PageMap cache value */ - unsigned int gain; - unsigned char autoexposure; unsigned char datawidth; unsigned int powered:1; - unsigned int hflip:1; - unsigned int vflip:1; - unsigned int autowhitebalance:1; }; static struct mt9m111 *to_mt9m111(const struct i2c_client *client) @@ -646,48 +644,6 @@ static int mt9m111_s_register(struct v4l2_subdev *sd, } #endif -static const struct v4l2_queryctrl mt9m111_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Verticaly", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontaly", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { /* gain = 1/32*val (=>gain=1 if val==32) */ - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 63 * 2 * 2, - .step = 1, - .default_value = 32, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9m111_ops = { - .controls = mt9m111_controls, - .num_controls = ARRAY_SIZE(mt9m111_controls), -}; - static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); @@ -728,7 +684,6 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) if (gain > 63 * 2 * 2) return -EINVAL; - mt9m111->gain = gain; if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) val = (1 << 10) | (1 << 9) | (gain / 4); else if ((gain >= 64) && (gain < 64 * 2)) @@ -742,118 +697,47 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int ret; if (on) - ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); - else - ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); - - if (!ret) - mt9m111->autoexposure = on; - - return ret; + return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); + return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); } static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int ret; if (on) - ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); - else - ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); - - if (!ret) - mt9m111->autowhitebalance = on; - - return ret; + return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); + return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); } -static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - int data; + struct mt9m111 *mt9m111 = container_of(ctrl->handler, + struct mt9m111, hdl); switch (ctrl->id) { case V4L2_CID_VFLIP: - if (mt9m111->context == HIGHPOWER) - data = reg_read(READ_MODE_B); - else - data = reg_read(READ_MODE_A); - - if (data < 0) - return -EIO; - ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS); - break; - case V4L2_CID_HFLIP: - if (mt9m111->context == HIGHPOWER) - data = reg_read(READ_MODE_B); - else - data = reg_read(READ_MODE_A); - - if (data < 0) - return -EIO; - ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); - break; - case V4L2_CID_GAIN: - data = mt9m111_get_global_gain(mt9m111); - if (data < 0) - return data; - ctrl->value = data; - break; - case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = mt9m111->autoexposure; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = mt9m111->autowhitebalance; - break; - } - return 0; -} - -static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - const struct v4l2_queryctrl *qctrl; - int ret; - - qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); - if (!qctrl) - return -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - mt9m111->vflip = ctrl->value; - ret = mt9m111_set_flip(mt9m111, ctrl->value, + return mt9m111_set_flip(mt9m111, ctrl->val, MT9M111_RMB_MIRROR_ROWS); - break; case V4L2_CID_HFLIP: - mt9m111->hflip = ctrl->value; - ret = mt9m111_set_flip(mt9m111, ctrl->value, + return mt9m111_set_flip(mt9m111, ctrl->val, MT9M111_RMB_MIRROR_COLS); - break; case V4L2_CID_GAIN: - ret = mt9m111_set_global_gain(mt9m111, ctrl->value); - break; + return mt9m111_set_global_gain(mt9m111, ctrl->val); case V4L2_CID_EXPOSURE_AUTO: - ret = mt9m111_set_autoexposure(mt9m111, ctrl->value); - break; + return mt9m111_set_autoexposure(mt9m111, ctrl->val); case V4L2_CID_AUTO_WHITE_BALANCE: - ret = mt9m111_set_autowhitebalance(mt9m111, ctrl->value); - break; - default: - ret = -EINVAL; + return mt9m111_set_autowhitebalance(mt9m111, ctrl->val); } - return ret; + return -EINVAL; } static int mt9m111_suspend(struct mt9m111 *mt9m111) { - mt9m111->gain = mt9m111_get_global_gain(mt9m111); + v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111)); return 0; } @@ -863,11 +747,7 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111) mt9m111_set_context(mt9m111, mt9m111->context); mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); mt9m111_setup_rect(mt9m111, &mt9m111->rect); - mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); - mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); - mt9m111_set_global_gain(mt9m111, mt9m111->gain); - mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); - mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance); + v4l2_ctrl_handler_setup(&mt9m111->hdl); } static int mt9m111_resume(struct mt9m111 *mt9m111) @@ -895,8 +775,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111) ret = mt9m111_reset(mt9m111); if (!ret) ret = mt9m111_set_context(mt9m111, mt9m111->context); - if (!ret) - ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); if (ret) dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); return ret; @@ -919,9 +797,6 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, mt9m111->lastpage = -1; - mt9m111->autoexposure = 1; - mt9m111->autowhitebalance = 1; - data = reg_read(CHIP_VERSION); switch (data) { @@ -935,17 +810,16 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); break; default: - ret = -ENODEV; dev_err(&client->dev, "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", data); - goto ei2c; + return -ENODEV; } ret = mt9m111_init(mt9m111); - -ei2c: - return ret; + if (ret) + return ret; + return v4l2_ctrl_handler_setup(&mt9m111->hdl); } static int mt9m111_s_power(struct v4l2_subdev *sd, int on) @@ -982,9 +856,11 @@ out: return ret; } +static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = { + .s_ctrl = mt9m111_s_ctrl, +}; + static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { - .g_ctrl = mt9m111_g_ctrl, - .s_ctrl = mt9m111_s_ctrl, .g_chip_ident = mt9m111_g_chip_ident, .s_power = mt9m111_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -1066,10 +942,27 @@ static int mt9m111_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); + v4l2_ctrl_handler_init(&mt9m111->hdl, 5); + v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, + V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32); + v4l2_ctrl_new_std_menu(&mt9m111->hdl, + &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + mt9m111->subdev.ctrl_handler = &mt9m111->hdl; + if (mt9m111->hdl.error) { + int err = mt9m111->hdl.error; + + kfree(mt9m111); + return err; + } /* Second stage probe - when a capture adapter is there */ - icd->ops = &mt9m111_ops; - mt9m111->rect.left = MT9M111_MIN_DARK_COLS; mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; mt9m111->rect.width = MT9M111_MAX_WIDTH; @@ -1078,7 +971,7 @@ static int mt9m111_probe(struct i2c_client *client, ret = mt9m111_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&mt9m111->hdl); kfree(mt9m111); } @@ -1088,9 +981,9 @@ static int mt9m111_probe(struct i2c_client *client, static int mt9m111_remove(struct i2c_client *client) { struct mt9m111 *mt9m111 = to_mt9m111(client); - struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&mt9m111->subdev); + v4l2_ctrl_handler_free(&mt9m111->hdl); kfree(mt9m111); return 0; From 41efcd7a6862951fd13c0e950ef05b865d7488a8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 06:08:51 -0300 Subject: [PATCH 114/144] [media] mt9t031: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9t031.c | 252 ++++++++++++---------------------- 1 file changed, 86 insertions(+), 166 deletions(-) diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 25fb833f6f2c..7ce37990a446 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -19,6 +19,7 @@ #include #include #include +#include /* * mt9t031 i2c address 0x5d @@ -60,14 +61,18 @@ struct mt9t031 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct { + /* exposure/auto-exposure cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; struct v4l2_rect rect; /* Sensor window */ int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ u16 xskip; u16 yskip; - unsigned int gain; + unsigned int total_h; unsigned short y_skip_top; /* Lines to skip at the top */ - unsigned int exposure; - unsigned char autoexposure; }; static struct mt9t031 *to_mt9t031(const struct i2c_client *client) @@ -175,69 +180,6 @@ static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -enum { - MT9T031_CTRL_VFLIP, - MT9T031_CTRL_HFLIP, - MT9T031_CTRL_GAIN, - MT9T031_CTRL_EXPOSURE, - MT9T031_CTRL_EXPOSURE_AUTO, -}; - -static const struct v4l2_queryctrl mt9t031_controls[] = { - [MT9T031_CTRL_VFLIP] = { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - [MT9T031_CTRL_HFLIP] = { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - [MT9T031_CTRL_GAIN] = { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, - [MT9T031_CTRL_EXPOSURE] = { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, - [MT9T031_CTRL_EXPOSURE_AUTO] = { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9t031_ops = { - .controls = mt9t031_controls, - .num_controls = ARRAY_SIZE(mt9t031_controls), -}; - /* target must be _even_ */ static u16 mt9t031_skip(s32 *source, s32 target, s32 max) { @@ -334,17 +276,10 @@ static int mt9t031_set_params(struct i2c_client *client, if (ret >= 0) ret = reg_write(client, MT9T031_WINDOW_HEIGHT, rect->height + mt9t031->y_skip_top - 1); - if (ret >= 0 && mt9t031->autoexposure) { - unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank; - ret = set_shutter(client, total_h); - if (ret >= 0) { - const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; - const struct v4l2_queryctrl *qctrl = - &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; - mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - shutter_max + qctrl->minimum; - } + if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) { + mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank; + + ret = set_shutter(client, mt9t031->total_h); } /* Re-enable register update, commit all changes */ @@ -513,71 +448,57 @@ static int mt9t031_s_register(struct v4l2_subdev *sd, } #endif -static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - int data; + struct mt9t031 *mt9t031 = container_of(ctrl->handler, + struct mt9t031, hdl); + const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK; + s32 min, max; switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, MT9T031_READ_MODE_2); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x8000); - break; - case V4L2_CID_HFLIP: - data = reg_read(client, MT9T031_READ_MODE_2); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x4000); - break; case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = mt9t031->autoexposure; - break; - case V4L2_CID_GAIN: - ctrl->value = mt9t031->gain; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = mt9t031->exposure; + min = mt9t031->exposure->minimum; + max = mt9t031->exposure->maximum; + mt9t031->exposure->val = + (shutter_max / 2 + (mt9t031->total_h - 1) * (max - min)) + / shutter_max + min; break; } return 0; } -static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl) { + struct mt9t031 *mt9t031 = container_of(ctrl->handler, + struct mt9t031, hdl); + struct v4l2_subdev *sd = &mt9t031->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - const struct v4l2_queryctrl *qctrl; + struct v4l2_ctrl *exp = mt9t031->exposure; int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); else data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_HFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); else data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_GAIN: - qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN]; - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; /* See Datasheet Table 7, Gain settings. */ - if (ctrl->value <= qctrl->default_value) { + if (ctrl->val <= ctrl->default_value) { /* Pack it into 0..1 step 0.125, register values 0..8 */ - unsigned long range = qctrl->default_value - qctrl->minimum; - data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; + unsigned long range = ctrl->default_value - ctrl->minimum; + data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range; dev_dbg(&client->dev, "Setting gain %d\n", data); data = reg_write(client, MT9T031_GLOBAL_GAIN, data); @@ -586,9 +507,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) } else { /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ - unsigned long range = qctrl->maximum - qctrl->default_value - 1; + unsigned long range = ctrl->maximum - ctrl->default_value - 1; /* calculated gain: map 65..127 to 9..1024 step 0.125 */ - unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * + unsigned long gain = ((ctrl->val - ctrl->default_value - 1) * 1015 + range / 2) / range + 9; if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ @@ -605,19 +526,13 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (data < 0) return -EIO; } + return 0; - /* Success */ - mt9t031->gain = ctrl->value; - break; - case V4L2_CID_EXPOSURE: - qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; - /* mt9t031 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - const unsigned long range = qctrl->maximum - qctrl->minimum; - const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 + - range / 2) / range + 1; + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_MANUAL) { + unsigned int range = exp->maximum - exp->minimum; + unsigned int shutter = ((exp->val - exp->minimum) * 1048 + + range / 2) / range + 1; u32 old; get_shutter(client, &old); @@ -625,27 +540,15 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) old, shutter); if (set_shutter(client, shutter) < 0) return -EIO; - mt9t031->exposure = ctrl->value; - mt9t031->autoexposure = 0; - } - break; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->value) { + } else { const u16 vblank = MT9T031_VERTICAL_BLANK; - const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; - unsigned int total_h = mt9t031->rect.height + + mt9t031->total_h = mt9t031->rect.height + mt9t031->y_skip_top + vblank; - if (set_shutter(client, total_h) < 0) + if (set_shutter(client, mt9t031->total_h) < 0) return -EIO; - qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; - mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - shutter_max + qctrl->minimum; - mt9t031->autoexposure = 1; - } else - mt9t031->autoexposure = 0; - break; + } + return 0; default: return -EINVAL; } @@ -735,15 +638,12 @@ static int mt9t031_video_probe(struct i2c_client *client) dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); ret = mt9t031_idle(client); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "Failed to initialise the camera\n"); - else + } else { vdev->dev.type = &mt9t031_dev_type; - - /* mt9t031_idle() has reset the chip to default. */ - mt9t031->exposure = 255; - mt9t031->gain = 64; - + v4l2_ctrl_handler_setup(&mt9t031->hdl); + } return ret; } @@ -757,9 +657,12 @@ static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) return 0; } +static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { + .g_volatile_ctrl = mt9t031_g_volatile_ctrl, + .s_ctrl = mt9t031_s_ctrl, +}; + static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { - .g_ctrl = mt9t031_g_ctrl, - .s_ctrl = mt9t031_s_ctrl, .g_chip_ident = mt9t031_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9t031_g_register, @@ -844,8 +747,6 @@ static int mt9t031_probe(struct i2c_client *client, dev_err(&client->dev, "MT9T031 driver needs platform data\n"); return -EINVAL; } - - icd->ops = &mt9t031_ops; } if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { @@ -859,6 +760,33 @@ static int mt9t031_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); + v4l2_ctrl_handler_init(&mt9t031->hdl, 5); + v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 64); + + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ + mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl, + &mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 255, 1, 255); + + mt9t031->subdev.ctrl_handler = &mt9t031->hdl; + if (mt9t031->hdl.error) { + int err = mt9t031->hdl.error; + + kfree(mt9t031); + return err; + } + v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure, + V4L2_EXPOSURE_MANUAL, true); mt9t031->y_skip_top = 0; mt9t031->rect.left = MT9T031_COLUMN_SKIP; @@ -866,12 +794,6 @@ static int mt9t031_probe(struct i2c_client *client, mt9t031->rect.width = MT9T031_MAX_WIDTH; mt9t031->rect.height = MT9T031_MAX_HEIGHT; - /* - * Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width - */ - mt9t031->autoexposure = 1; - mt9t031->xskip = 1; mt9t031->yskip = 1; @@ -882,8 +804,7 @@ static int mt9t031_probe(struct i2c_client *client, mt9t031_disable(client); if (ret) { - if (icd) - icd->ops = NULL; + v4l2_ctrl_handler_free(&mt9t031->hdl); kfree(mt9t031); } @@ -893,10 +814,9 @@ static int mt9t031_probe(struct i2c_client *client, static int mt9t031_remove(struct i2c_client *client) { struct mt9t031 *mt9t031 = to_mt9t031(client); - struct soc_camera_device *icd = client->dev.platform_data; - if (icd) - icd->ops = NULL; + v4l2_device_unregister_subdev(&mt9t031->subdev); + v4l2_ctrl_handler_free(&mt9t031->hdl); kfree(mt9t031); return 0; From 0934d94a52423fac35922c2e29d72a43db7ddd48 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 8 Sep 2011 13:16:56 -0300 Subject: [PATCH 115/144] [media] soc_camera: remove the now obsolete struct soc_camera_ops Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: mt9m001 hunk moved to an earlier patch] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/imx074.c | 1 - drivers/media/video/mt9t112.c | 2 -- drivers/media/video/ov5642.c | 1 - drivers/media/video/soc_camera_platform.c | 2 -- drivers/media/video/tw9910.c | 1 - include/media/soc_camera.h | 18 ------------------ 6 files changed, 25 deletions(-) diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 20756e03dbb1..3f5d4de8b91b 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -437,7 +437,6 @@ static int imx074_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); - icd->ops = NULL; priv->fmt = &imx074_colour_fmts[0]; ret = imx074_video_probe(icd, client); diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 25cdcb90768a..b8da7fe9a6bd 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -1095,8 +1095,6 @@ static int mt9t112_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - icd->ops = NULL; - ret = mt9t112_camera_probe(icd, client); if (ret) kfree(priv); diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index b36d42bfeab2..163a6f7ff8ef 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -942,7 +942,6 @@ static int ov5642_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); - icd->ops = NULL; priv->fmt = &ov5642_colour_fmts[0]; ret = ov5642_video_probe(icd, client); diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index c8f6b188496d..4402a8a74f7a 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -150,8 +150,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev) /* Set the control device reference */ icd->control = &pdev->dev; - icd->ops = NULL; - ici = to_soc_camera_host(icd->parent); v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 40cc1494b377..2fddd1fbe529 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -921,7 +921,6 @@ static int tw9910_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - icd->ops = NULL; icd->iface = icl->bus_id; ret = tw9910_video_probe(icd, client); diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index d41b8bd74445..6398ff0f08ab 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -39,7 +39,6 @@ struct soc_camera_device { unsigned char iface; /* Host number */ unsigned char devnum; /* Device number per host */ struct soc_camera_sense *sense; /* See comment in struct definition */ - struct soc_camera_ops *ops; struct video_device *vdev; struct v4l2_ctrl_handler ctrl_handler; const struct soc_camera_format_xlate *current_fmt; @@ -192,11 +191,6 @@ struct soc_camera_format_xlate { const struct soc_mbus_pixelfmt *host_fmt; }; -struct soc_camera_ops { - const struct v4l2_queryctrl *controls; - int num_controls; -}; - #define SOCAM_SENSE_PCLK_CHANGED (1 << 0) /** @@ -223,18 +217,6 @@ struct soc_camera_sense { unsigned long pixel_clock; }; -static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( - struct soc_camera_ops *ops, int id) -{ - int i; - - for (i = 0; i < ops->num_controls; i++) - if (ops->controls[i].id == id) - return &ops->controls[i]; - - return NULL; -} - #define SOCAM_DATAWIDTH(x) BIT((x) - 1) #define SOCAM_DATAWIDTH_4 SOCAM_DATAWIDTH(4) #define SOCAM_DATAWIDTH_8 SOCAM_DATAWIDTH(8) From 09362ec25c3f42d00a4008d0622bfbca68e540f5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 7 Sep 2011 18:07:23 -0300 Subject: [PATCH 116/144] [media] V4L: docbook documentation for struct v4l2_create_buffers Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-compat-ioctl32.c | 13 +++++++++++-- include/linux/videodev2.h | 14 +++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index e77e0cfc9312..c68531b88279 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -159,11 +159,20 @@ struct v4l2_format32 { } fmt; }; +/** + * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument + * @index: on return, index of the first created buffer + * @count: entry: number of requested buffers, + * return: number of created buffers + * @memory: buffer memory type + * @format: frame format, for which buffers are requested + * @reserved: future extensions + */ struct v4l2_create_buffers32 { - __u32 index; /* output: buffers index...index + count - 1 have been created */ + __u32 index; __u32 count; enum v4l2_memory memory; - struct v4l2_format32 format; /* filled in by the user, plane sizes calculated by the driver */ + struct v4l2_format32 format; __u32 reserved[8]; }; diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index cd512f07beed..66945a6f628d 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -2142,12 +2142,20 @@ struct v4l2_dbg_chip_ident { __u32 revision; /* chip revision, chip specific */ } __attribute__ ((packed)); -/* VIDIOC_CREATE_BUFS */ +/** + * struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument + * @index: on return, index of the first created buffer + * @count: entry: number of requested buffers, + * return: number of created buffers + * @memory: buffer memory type + * @format: frame format, for which buffers are requested + * @reserved: future extensions + */ struct v4l2_create_buffers { - __u32 index; /* output: buffers index...index + count - 1 have been created */ + __u32 index; __u32 count; enum v4l2_memory memory; - struct v4l2_format format; /* "type" is used always, the rest if sizeimage == 0 */ + struct v4l2_format format; __u32 reserved[8]; }; From 14178aa57ce6ac4f05b4df8ea9e010486ce83a76 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 21 Sep 2011 15:16:30 -0300 Subject: [PATCH 117/144] [media] V4L: soc-camera: start removing struct soc_camera_device from client drivers Remove most trivial uses of struct soc_camera_device from most client drivers, abstracting some of them inside inline functions. Next steps will eliminate remaining uses and modify inline functions to not use struct soc_camera_device. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/imx074.c | 17 +++--------- drivers/media/video/mt9m001.c | 39 ++++++++------------------- drivers/media/video/mt9m111.c | 24 ++++------------- drivers/media/video/mt9t031.c | 22 ++++++---------- drivers/media/video/mt9t112.c | 45 ++++++++++++-------------------- drivers/media/video/mt9v022.c | 44 ++++++++----------------------- drivers/media/video/ov2640.c | 27 +++++-------------- drivers/media/video/ov5642.c | 17 +++--------- drivers/media/video/ov6650.c | 20 ++++---------- drivers/media/video/ov772x.c | 29 +++++++------------- drivers/media/video/ov9640.c | 21 +++------------ drivers/media/video/ov9740.c | 21 +++------------ drivers/media/video/rj54n1cb0c.c | 27 +++++-------------- drivers/media/video/tw9910.c | 32 +++++++---------------- include/media/soc_camera.h | 25 +++++++++++++++--- 15 files changed, 125 insertions(+), 285 deletions(-) diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 3f5d4de8b91b..4f3ce7fa87df 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -298,8 +298,7 @@ static struct v4l2_subdev_ops imx074_subdev_ops = { .video = &imx074_subdev_video_ops, }; -static int imx074_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int imx074_video_probe(struct i2c_client *client) { int ret; u16 id; @@ -409,17 +408,10 @@ static int imx074_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct imx074 *priv; - struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "IMX074: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "IMX074: missing platform data!\n"); return -EINVAL; @@ -439,7 +431,7 @@ static int imx074_probe(struct i2c_client *client, priv->fmt = &imx074_colour_fmts[0]; - ret = imx074_video_probe(icd, client); + ret = imx074_video_probe(client); if (ret < 0) { kfree(priv); return ret; @@ -451,8 +443,7 @@ static int imx074_probe(struct i2c_client *client, static int imx074_remove(struct i2c_client *client) { struct imx074 *priv = to_imx074(client); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); if (icl->free_bus) icl->free_bus(icl); diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 42bb3c89cfe6..58cdcedf53de 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -205,7 +205,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) /* * The caller provides a supported format, as verified per - * call to icd->try_fmt() + * call to .try_mbus_fmt() */ if (!ret) ret = reg_write(client, MT9M001_COLUMN_START, rect.left); @@ -474,19 +474,14 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ -static int mt9m001_video_probe(struct soc_camera_device *icd, +static int mt9m001_video_probe(struct soc_camera_link *icl, struct i2c_client *client) { struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); s32 data; unsigned long flags; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* Enable the chip */ data = reg_write(client, MT9M001_CHIP_ENABLE, 1); dev_dbg(&client->dev, "write: %d\n", data); @@ -544,12 +539,8 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, return v4l2_ctrl_handler_setup(&mt9m001->hdl); } -static void mt9m001_video_remove(struct soc_camera_device *icd) +static void mt9m001_video_remove(struct soc_camera_link *icl) { - struct soc_camera_link *icl = to_soc_camera_link(icd); - - dev_dbg(icd->pdev, "Video removed: %p, %p\n", - icd->parent, icd->vdev); if (icl->free_bus) icl->free_bus(icl); } @@ -594,8 +585,7 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); /* MT9M001 has all capture_format parameters fixed */ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | @@ -610,9 +600,9 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + const struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = soc_camera_from_i2c(client); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); /* * Cannot use icd->current_fmt->host_fmt->bits_per_sample, because that * is the number of bits, that the host has to sample, not the number of @@ -658,17 +648,10 @@ static int mt9m001_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9m001 *mt9m001; - struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "MT9M001: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "MT9M001 driver needs platform data\n"); return -EINVAL; @@ -716,7 +699,7 @@ static int mt9m001_probe(struct i2c_client *client, mt9m001->rect.width = MT9M001_MAX_WIDTH; mt9m001->rect.height = MT9M001_MAX_HEIGHT; - ret = mt9m001_video_probe(icd, client); + ret = mt9m001_video_probe(icl, client); if (ret) { v4l2_ctrl_handler_free(&mt9m001->hdl); kfree(mt9m001); @@ -728,11 +711,11 @@ static int mt9m001_probe(struct i2c_client *client, static int mt9m001_remove(struct i2c_client *client) { struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); v4l2_device_unregister_subdev(&mt9m001->subdev); v4l2_ctrl_handler_free(&mt9m001->hdl); - mt9m001_video_remove(icd); + mt9m001_video_remove(icl); kfree(mt9m001); return 0; diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 8cacbf016848..9feeb0cb6722 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -784,19 +784,12 @@ static int mt9m111_init(struct mt9m111 *mt9m111) * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ -static int mt9m111_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int mt9m111_video_probe(struct i2c_client *client) { struct mt9m111 *mt9m111 = to_mt9m111(client); s32 data; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - - mt9m111->lastpage = -1; - data = reg_read(CHIP_VERSION); switch (data) { @@ -883,8 +876,7 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | @@ -915,17 +907,10 @@ static int mt9m111_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9m111 *mt9m111; - struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "mt9m111: soc-camera data missing!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "mt9m111: driver needs platform data\n"); return -EINVAL; @@ -968,8 +953,9 @@ static int mt9m111_probe(struct i2c_client *client, mt9m111->rect.width = MT9M111_MAX_WIDTH; mt9m111->rect.height = MT9M111_MAX_HEIGHT; mt9m111->fmt = &mt9m111_colour_fmts[0]; + mt9m111->lastpage = -1; - ret = mt9m111_video_probe(icd, client); + ret = mt9m111_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&mt9m111->hdl); kfree(mt9m111); diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 7ce37990a446..95cd602ae4ec 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -265,7 +265,7 @@ static int mt9t031_set_params(struct i2c_client *client, /* * The caller provides a supported format, as guaranteed by - * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() + * .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap() */ if (ret >= 0) ret = reg_write(client, MT9T031_COLUMN_START, rect->left); @@ -573,8 +573,7 @@ static int mt9t031_runtime_suspend(struct device *dev) static int mt9t031_runtime_resume(struct device *dev) { struct video_device *vdev = to_video_device(dev); - struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct v4l2_subdev *sd = soc_camera_vdev_to_subdev(vdev); struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t031 *mt9t031 = to_mt9t031(client); @@ -684,8 +683,7 @@ static int mt9t031_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -700,8 +698,7 @@ static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_FALLING) @@ -737,16 +734,13 @@ static int mt9t031_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9t031 *mt9t031; - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int ret; - if (icd) { - struct soc_camera_link *icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "MT9T031 driver needs platform data\n"); - return -EINVAL; - } + if (!icl) { + dev_err(&client->dev, "MT9T031 driver needs platform data\n"); + return -EINVAL; } if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index b8da7fe9a6bd..5b045a1097c6 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -89,7 +89,6 @@ struct mt9t112_priv { struct v4l2_subdev subdev; struct mt9t112_camera_info *info; struct i2c_client *client; - struct soc_camera_device icd; struct v4l2_rect frame; const struct mt9t112_format *format; int model; @@ -306,38 +305,38 @@ static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) n = (n >> 8) & 0x003f; enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; - dev_info(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); + dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); vco = 2 * m * ext / (n+1); enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; - dev_info(&client->dev, "VCO : %10u K %s\n", vco, enable); + dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); clk = vco / (p1+1) / (p2+1); enable = (96000 < clk) ? "X" : ""; - dev_info(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); clk = vco / (p3+1); enable = (768000 < clk) ? "X" : ""; - dev_info(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); clk = vco / (p6+1); enable = (96000 < clk) ? "X" : ""; - dev_info(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); clk = vco / (p5+1); enable = (54000 < clk) ? "X" : ""; - dev_info(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); clk = vco / (p4+1); enable = (70000 < clk) ? "X" : ""; - dev_info(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); clk = vco / (p7+1); - dev_info(&client->dev, "External sensor : %10u K\n", clk); + dev_dbg(&client->dev, "External sensor : %10u K\n", clk); clk = ext / (n+1); enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; - dev_info(&client->dev, "PFD : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); return 0; } @@ -982,8 +981,7 @@ static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | @@ -998,8 +996,7 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct mt9t112_priv *priv = to_mt9t112(client); if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) @@ -1029,17 +1026,12 @@ static struct v4l2_subdev_ops mt9t112_subdev_ops = { .video = &mt9t112_subdev_video_ops, }; -static int mt9t112_camera_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int mt9t112_camera_probe(struct i2c_client *client) { struct mt9t112_priv *priv = to_mt9t112(client); const char *devname; int chipid; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show chip ID */ @@ -1068,8 +1060,7 @@ static int mt9t112_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9t112_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct v4l2_rect rect = { .width = VGA_WIDTH, .height = VGA_HEIGHT, @@ -1078,15 +1069,11 @@ static int mt9t112_probe(struct i2c_client *client, }; int ret; - if (!icd) { - dev_err(&client->dev, "mt9t112: missing soc-camera data!\n"); + if (!icl || !icl->priv) { + dev_err(&client->dev, "mt9t112: missing platform data!\n"); return -EINVAL; } - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) - return -EINVAL; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -1095,7 +1082,7 @@ static int mt9t112_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - ret = mt9t112_camera_probe(icd, client); + ret = mt9t112_camera_probe(client); if (ret) kfree(priv); diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 7e2aeda21752..72b179b2ad6c 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -332,7 +332,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, /* * The caller provides a supported format, as verified per call to - * icd->try_fmt(), datawidth is from our supported format list + * .try_mbus_fmt(), datawidth is from our supported format list */ switch (mf->code) { case V4L2_MBUS_FMT_Y8_1X8: @@ -562,19 +562,14 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ -static int mt9v022_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int mt9v022_video_probe(struct i2c_client *client) { struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); s32 data; int ret; unsigned long flags; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* Read out the chip version register */ data = reg_read(client, MT9V022_CHIP_VERSION); @@ -648,16 +643,6 @@ ei2c: return ret; } -static void mt9v022_video_remove(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - dev_dbg(icd->pdev, "Video removed: %p, %p\n", - icd->parent, icd->vdev); - if (icl->free_bus) - icl->free_bus(icl); -} - static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -698,8 +683,7 @@ static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | @@ -730,8 +714,8 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, int ret; u16 pixclk = 0; - dev_info(icd->pdev, "set %d: %s, %dbps\n", icd->current_fmt->code, - icd->current_fmt->host_fmt->name, bps); + dev_dbg(icd->pdev, "set %d: %s, %dbps\n", icd->current_fmt->code, + icd->current_fmt->host_fmt->name, bps); if (icl->set_bus_param) { ret = icl->set_bus_param(icl, 1 << (bps - 1)); @@ -798,17 +782,10 @@ static int mt9v022_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9v022 *mt9v022; - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; int ret; - if (!icd) { - dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "MT9V022 driver needs platform data\n"); return -EINVAL; @@ -868,7 +845,7 @@ static int mt9v022_probe(struct i2c_client *client, mt9v022->rect.width = MT9V022_MAX_WIDTH; mt9v022->rect.height = MT9V022_MAX_HEIGHT; - ret = mt9v022_video_probe(icd, client); + ret = mt9v022_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&mt9v022->hdl); kfree(mt9v022); @@ -880,10 +857,11 @@ static int mt9v022_probe(struct i2c_client *client, static int mt9v022_remove(struct i2c_client *client) { struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); v4l2_device_unregister_subdev(&mt9v022->subdev); - mt9v022_video_remove(icd); + if (icl->free_bus) + icl->free_bus(icl); v4l2_ctrl_handler_free(&mt9v022->hdl); kfree(mt9v022); diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 981767f2d8ea..d37a5cceebb6 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -942,18 +942,13 @@ static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int ov2640_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov2640_video_probe(struct i2c_client *client) { struct ov2640_priv *priv = to_ov2640(client); u8 pid, ver, midh, midl; const char *devname; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show product ID and manufacturer ID */ @@ -1001,8 +996,7 @@ static int ov2640_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -1035,18 +1029,11 @@ static struct v4l2_subdev_ops ov2640_subdev_ops = { static int ov2640_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct ov2640_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; + struct ov2640_priv *priv; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; - if (!icd) { - dev_err(&adapter->dev, "OV2640: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&adapter->dev, "OV2640: Missing platform_data for driver\n"); @@ -1080,7 +1067,7 @@ static int ov2640_probe(struct i2c_client *client, return err; } - ret = ov2640_video_probe(icd, client); + ret = ov2640_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 163a6f7ff8ef..2a26602fc86d 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -889,8 +889,7 @@ static struct v4l2_subdev_ops ov5642_subdev_ops = { .video = &ov5642_subdev_video_ops, }; -static int ov5642_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov5642_video_probe(struct i2c_client *client) { int ret; u8 id_high, id_low; @@ -921,16 +920,9 @@ static int ov5642_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov5642 *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "OV5642: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "OV5642: missing platform data!\n"); return -EINVAL; @@ -944,7 +936,7 @@ static int ov5642_probe(struct i2c_client *client, priv->fmt = &ov5642_colour_fmts[0]; - ret = ov5642_video_probe(icd, client); + ret = ov5642_video_probe(client); if (ret < 0) goto error; @@ -958,8 +950,7 @@ error: static int ov5642_remove(struct i2c_client *client) { struct ov5642 *priv = to_ov5642(client); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); if (icl->free_bus) icl->free_bus(icl); diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index efa45132c992..f060eaaf916f 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -820,8 +820,7 @@ static int ov6650_prog_dflt(struct i2c_client *client) return ret; } -static int ov6650_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov6650_video_probe(struct i2c_client *client) { u8 pidh, pidl, midh, midl; int ret = 0; @@ -875,8 +874,7 @@ static int ov6650_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | @@ -894,8 +892,7 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); unsigned long flags = soc_camera_apply_board_flags(icl, cfg); int ret; @@ -948,16 +945,9 @@ static int ov6650_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov6650 *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "Missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "Missing platform_data for driver\n"); return -EINVAL; @@ -1020,7 +1010,7 @@ static int ov6650_probe(struct i2c_client *client, priv->code = V4L2_MBUS_FMT_YUYV8_2X8; priv->colorspace = V4L2_COLORSPACE_JPEG; - ret = ov6650_video_probe(icd, client); + ret = ov6650_video_probe(client); if (!ret) ret = v4l2_ctrl_handler_setup(&priv->hdl); diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 9b540421e2cb..a2146c30771e 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -953,17 +953,12 @@ static int ov772x_try_fmt(struct v4l2_subdev *sd, return 0; } -static int ov772x_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov772x_video_probe(struct i2c_client *client) { struct ov772x_priv *priv = to_ov772x(client); u8 pid, ver; const char *devname; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show product ID and manufacturer ID */ @@ -1021,8 +1016,7 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -1056,21 +1050,16 @@ static struct v4l2_subdev_ops ov772x_subdev_ops = { static int ov772x_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct ov772x_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; + struct ov772x_priv *priv; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; - if (!icd) { - dev_err(&client->dev, "OV772X: missing soc-camera data!\n"); + if (!icl || !icl->priv) { + dev_err(&client->dev, "OV772X: missing platform data!\n"); return -EINVAL; } - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) - return -EINVAL; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&adapter->dev, "I2C-Adapter doesn't support " @@ -1100,7 +1089,7 @@ static int ov772x_probe(struct i2c_client *client, return err; } - ret = ov772x_video_probe(icd, client); + ret = ov772x_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 12d33a9c07b0..f9babf39d802 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -578,8 +578,7 @@ static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int ov9640_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov9640_video_probe(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov9640_priv *priv = to_ov9640_sensor(sd); @@ -587,10 +586,6 @@ static int ov9640_video_probe(struct soc_camera_device *icd, const char *devname; int ret = 0; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show product ID and manufacturer ID */ @@ -644,8 +639,7 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -678,16 +672,9 @@ static int ov9640_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov9640_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "Missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "Missing platform_data for driver\n"); return -EINVAL; @@ -715,7 +702,7 @@ static int ov9640_probe(struct i2c_client *client, return err; } - ret = ov9640_video_probe(icd, client); + ret = ov9640_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&priv->hdl); diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index 3dd910dcc5b8..9558aca86818 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c @@ -836,18 +836,13 @@ static int ov9740_set_register(struct v4l2_subdev *sd, } #endif -static int ov9740_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov9740_video_probe(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov9740_priv *priv = to_ov9740(sd); u8 modelhi, modello; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show product ID and manufacturer ID */ @@ -893,8 +888,7 @@ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -940,16 +934,9 @@ static int ov9740_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov9740_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "Missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "Missing platform_data for driver\n"); return -EINVAL; @@ -975,7 +962,7 @@ static int ov9740_probe(struct i2c_client *client, return err; } - ret = ov9740_video_probe(icd, client); + ret = ov9740_video_probe(client); if (!ret) ret = v4l2_ctrl_handler_setup(&priv->hdl); if (ret < 0) { diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 9a871537d233..fcb14d93a24c 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -1235,8 +1235,7 @@ static int rj54n1_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | @@ -1252,8 +1251,7 @@ static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ if (soc_camera_apply_board_flags(icl, cfg) & @@ -1285,17 +1283,12 @@ static struct v4l2_subdev_ops rj54n1_subdev_ops = { * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ -static int rj54n1_video_probe(struct soc_camera_device *icd, - struct i2c_client *client, +static int rj54n1_video_probe(struct i2c_client *client, struct rj54n1_pdata *priv) { int data1, data2; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* Read out the chip version register */ data1 = reg_read(client, RJ54N1_DEV_CODE); data2 = reg_read(client, RJ54N1_DEV_CODE2); @@ -1323,18 +1316,11 @@ static int rj54n1_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct rj54n1 *rj54n1; - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; struct rj54n1_pdata *rj54n1_priv; int ret; - if (!icd) { - dev_err(&client->dev, "RJ54N1CB0C: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl || !icl->priv) { dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); return -EINVAL; @@ -1382,7 +1368,7 @@ static int rj54n1_probe(struct i2c_client *client, rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); - ret = rj54n1_video_probe(icd, client, rj54n1_priv); + ret = rj54n1_video_probe(client, rj54n1_priv); if (ret < 0) { v4l2_ctrl_handler_free(&rj54n1->hdl); kfree(rj54n1); @@ -1394,8 +1380,7 @@ static int rj54n1_probe(struct i2c_client *client, static int rj54n1_remove(struct i2c_client *client) { struct rj54n1 *rj54n1 = to_rj54n1(client); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); v4l2_device_unregister_subdev(&rj54n1->subdev); if (icl->free_bus) diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 2fddd1fbe529..5a3722b756c7 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -764,10 +764,6 @@ static int tw9910_video_probe(struct soc_camera_device *icd, struct tw9910_priv *priv = to_tw9910(client); s32 id; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * tw9910 only use 8 or 16 bit bus width */ @@ -825,8 +821,7 @@ static int tw9910_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | @@ -842,8 +837,7 @@ static int tw9910_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); u8 val = VSSL_VVALID | HSSL_DVALID; unsigned long flags = soc_camera_apply_board_flags(icl, cfg); @@ -887,23 +881,19 @@ static int tw9910_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct tw9910_priv *priv; - struct tw9910_video_info *info; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = + struct tw9910_priv *priv; + struct tw9910_video_info *info; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + int ret; - if (!icd) { - dev_err(&client->dev, "TW9910: missing soc-camera data!\n"); + if (!icl || !icl->priv) { + dev_err(&client->dev, "TW9910: missing platform data!\n"); return -EINVAL; } - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) - return -EINVAL; - info = icl->priv; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -921,8 +911,6 @@ static int tw9910_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - icd->iface = icl->bus_id; - ret = tw9910_video_probe(icd, client); if (ret) kfree(priv); diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 6398ff0f08ab..67a52c729eff 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -251,18 +251,35 @@ unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, /* This is only temporary here - until v4l2-subdev begins to link to video_device */ #include -static inline struct video_device *soc_camera_i2c_to_vdev(struct i2c_client *client) +static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client) { struct soc_camera_device *icd = client->dev.platform_data; - return icd->vdev; + return icd ? icd->vdev : NULL; } -static inline struct soc_camera_device *soc_camera_from_vb2q(struct vb2_queue *vq) +static inline struct soc_camera_link *soc_camera_i2c_to_link(const struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + return icd ? to_soc_camera_link(icd) : NULL; +} + +static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_device *vdev) +{ + struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); + return soc_camera_to_subdev(icd); +} + +static inline struct soc_camera_device *soc_camera_from_i2c(const struct i2c_client *client) +{ + return client->dev.platform_data; +} + +static inline struct soc_camera_device *soc_camera_from_vb2q(const struct vb2_queue *vq) { return container_of(vq, struct soc_camera_device, vb2_vidq); } -static inline struct soc_camera_device *soc_camera_from_vbq(struct videobuf_queue *vq) +static inline struct soc_camera_device *soc_camera_from_vbq(const struct videobuf_queue *vq) { return container_of(vq, struct soc_camera_device, vb_vidq); } From 443f483aa2494b93d73ba122cafdf2ef89989ed7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 07:06:50 -0300 Subject: [PATCH 118/144] [media] V4L: mt9m001, mt9v022: use internally cached pixel code Using the internally cached pixel code, instead of the one, provided by the soc-camera, removes one more use of struct soc_camera_device in these drivers. Also remove the no longer needed soc_camera_from_i2c() inline function. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 10 ++-------- drivers/media/video/mt9v022.c | 14 ++------------ include/media/soc_camera.h | 5 ----- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 58cdcedf53de..63ae5c61c9bf 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -601,15 +601,9 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { const struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = soc_camera_from_i2c(client); struct soc_camera_link *icl = soc_camera_i2c_to_link(client); - /* - * Cannot use icd->current_fmt->host_fmt->bits_per_sample, because that - * is the number of bits, that the host has to sample, not the number of - * bits, that we have to send. See mx3_camera.c for an example of 10-bit - * formats being truncated to 8 bits by the host. - */ - unsigned int bps = soc_mbus_get_fmtdesc(icd->current_fmt->code)->bits_per_sample; + struct mt9m001 *mt9m001 = to_mt9m001(client); + unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample; if (icl->set_bus_param) return icl->set_bus_param(icl, 1 << (bps - 1)); diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 72b179b2ad6c..b6a29f7de82c 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -700,23 +700,13 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct mt9v022 *mt9v022 = to_mt9v022(client); unsigned long flags = soc_camera_apply_board_flags(icl, cfg); - /* - * Cannot use icd->current_fmt->host_fmt->bits_per_sample, because that - * is the number of bits, that the host has to sample, not the number of - * bits, that we have to send. See mx3_camera.c for an example of 10-bit - * formats being truncated to 8 bits by the host. - */ - unsigned int bps = soc_mbus_get_fmtdesc(icd->current_fmt->code)->bits_per_sample; + unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample; int ret; u16 pixclk = 0; - dev_dbg(icd->pdev, "set %d: %s, %dbps\n", icd->current_fmt->code, - icd->current_fmt->host_fmt->name, bps); - if (icl->set_bus_param) { ret = icl->set_bus_param(icl, 1 << (bps - 1)); if (ret) diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 67a52c729eff..dac57598ee57 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -269,11 +269,6 @@ static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_d return soc_camera_to_subdev(icd); } -static inline struct soc_camera_device *soc_camera_from_i2c(const struct i2c_client *client) -{ - return client->dev.platform_data; -} - static inline struct soc_camera_device *soc_camera_from_vb2q(const struct vb2_queue *vq) { return container_of(vq, struct soc_camera_device, vb2_vidq); From 2fbdc9bd42c993a6b179a4ddb972b551644aad6e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 06:40:56 -0300 Subject: [PATCH 119/144] [media] V4L: sh_mobile_csi2: fix unbalanced pm_runtime_put() If the sh_mobile_csi2 driver didn't attach to a client, normally, because the respective device connects to the SoC over the parallel CEU interface and doesn't use the CSI-2 controller, it also shouldn't call pm_runtime_put() on attempted disconnect. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_csi2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 91c680a72849..37706eb81f25 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -208,6 +208,9 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) unsigned long common_flags, csi2_flags; int i, ret; + if (priv->client) + return -EBUSY; + for (i = 0; i < pdata->num_clients; i++) if (&pdata->clients[i].pdev->dev == icd->pdev) break; @@ -262,6 +265,9 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) static void sh_csi2_client_disconnect(struct sh_csi2 *priv) { + if (!priv->client) + return; + priv->client = NULL; pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); From 3e0ec41c5c5ee14e27f65e28d4a616de34f59a97 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 13 Sep 2011 08:07:55 -0300 Subject: [PATCH 120/144] [media] V4L: dynamically allocate video_device nodes in subdevices Currently only very few drivers actually use video_device nodes, embedded in struct v4l2_subdev. Allocate these nodes dynamically for those drivers to save memory for the rest. Signed-off-by: Guennadi Liakhovetski Tested-by: Sylwester Nawrocki Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-device.c | 36 ++++++++++++++++++++++++++----- include/media/v4l2-subdev.h | 4 ++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index e6a2c3b302d4..9fc0ae8a526a 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -21,6 +21,7 @@ #include #include #include +#include #if defined(CONFIG_SPI) #include #endif @@ -193,6 +194,13 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); +static void v4l2_device_release_subdev_node(struct video_device *vdev) +{ + struct v4l2_subdev *sd = video_get_drvdata(vdev); + sd->devnode = NULL; + kfree(vdev); +} + int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) { struct video_device *vdev; @@ -206,22 +214,40 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) continue; - vdev = &sd->devnode; + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); + if (!vdev) { + err = -ENOMEM; + goto clean_up; + } + + video_set_drvdata(vdev, sd); strlcpy(vdev->name, sd->name, sizeof(vdev->name)); vdev->v4l2_dev = v4l2_dev; vdev->fops = &v4l2_subdev_fops; - vdev->release = video_device_release_empty; + vdev->release = v4l2_device_release_subdev_node; vdev->ctrl_handler = sd->ctrl_handler; err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, sd->owner); - if (err < 0) - return err; + if (err < 0) { + kfree(vdev); + goto clean_up; + } #if defined(CONFIG_MEDIA_CONTROLLER) sd->entity.v4l.major = VIDEO_MAJOR; sd->entity.v4l.minor = vdev->minor; #endif + sd->devnode = vdev; } return 0; + +clean_up: + list_for_each_entry(sd, &v4l2_dev->subdevs, list) { + if (!sd->devnode) + break; + video_unregister_device(sd->devnode); + } + + return err; } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); @@ -247,7 +273,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) if (v4l2_dev->mdev) media_device_unregister_entity(&sd->entity); #endif - video_unregister_device(&sd->devnode); + video_unregister_device(sd->devnode); module_put(sd->owner); } EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 257da1a30f66..5dd049a7437d 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -534,13 +534,13 @@ struct v4l2_subdev { void *dev_priv; void *host_priv; /* subdev device node */ - struct video_device devnode; + struct video_device *devnode; }; #define media_entity_to_v4l2_subdev(ent) \ container_of(ent, struct v4l2_subdev, entity) #define vdev_to_v4l2_subdev(vdev) \ - container_of(vdev, struct v4l2_subdev, devnode) + video_get_drvdata(vdev) /* * Used for storing subdev information per file handle From 1a99b972a86ba9c3984c042f7f641458ad4812d0 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 13:10:02 -0300 Subject: [PATCH 121/144] [media] V4L: add .g_std() core V4L2 subdevice operation VIDIOC_G_STD can return the current TV-norm to the user in one of two ways: if an .vidioc_g_std() ioctl operation is provided by the driver, it is called, otherwise the value ot the .current_norm field of struct video_device is returned. Since subdevice drivers currently have no access to struct video_device objects, the only way to provide this information to the user is by implementing a .g_std() method. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5dd049a7437d..f0f3358d1b1b 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -158,6 +158,7 @@ struct v4l2_subdev_core_ops { int (*s_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); int (*try_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm); + int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm); int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm); long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); #ifdef CONFIG_VIDEO_ADV_DEBUG From 2f0babb7e43278247df512263581c4738afa4cbc Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 13:39:20 -0300 Subject: [PATCH 122/144] [media] V4L: soc-camera: make (almost) all client drivers re-usable outside of the framework The most important change in this patch is direct linking to struct soc_camera_link via the client->dev.platform_data pointer. This makes most of the soc-camera client drivers also usable outside of the soc-camera framework. After this change all what is needed for these drivers to function are inclusions of soc-camera headers for some convenience macros, suitably configured platform data, which is anyway always required, and loaded soc-camera core module for library functions. If desired, these library functions can be made generic in the future and moved to a more neutral location. The only two client drivers, that still depend on soc-camera are: mt9t031: it uses struct video_device for its PM. Since no hardware is available, alternative methods cannot be tested. ov6650: it uses struct soc_camera_device to pass its sense data back to the bridge driver. A generic v4l2-subdevice approach should be developed to perform this. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9t031.c | 29 ++++++++++++++---- drivers/media/video/ov6650.c | 2 +- drivers/media/video/soc_camera.c | 11 ++++++- drivers/media/video/tw9910.c | 50 +++++++++++++++++++------------- include/media/soc_camera.h | 6 ++-- 5 files changed, 68 insertions(+), 30 deletions(-) diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 95cd602ae4ec..0226486d59be 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -21,6 +21,13 @@ #include #include +/* + * ATTENTION: this driver still cannot be used outside of the soc-camera + * framework because of its PM implementation, using the video_device node. + * If hardware becomes available for testing, alternative PM approaches shall + * be considered and tested. + */ + /* * mt9t031 i2c address 0x5d * The platform has to define i2c_board_info and link to it from @@ -606,6 +613,19 @@ static struct device_type mt9t031_dev_type = { .pm = &mt9t031_dev_pm_ops, }; +static int mt9t031_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct video_device *vdev = soc_camera_i2c_to_vdev(client); + + if (on) + vdev->dev.type = &mt9t031_dev_type; + else + vdev->dev.type = NULL; + + return 0; +} + /* * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one @@ -613,7 +633,6 @@ static struct device_type mt9t031_dev_type = { static int mt9t031_video_probe(struct i2c_client *client) { struct mt9t031 *mt9t031 = to_mt9t031(client); - struct video_device *vdev = soc_camera_i2c_to_vdev(client); s32 data; int ret; @@ -637,12 +656,11 @@ static int mt9t031_video_probe(struct i2c_client *client) dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); ret = mt9t031_idle(client); - if (ret < 0) { + if (ret < 0) dev_err(&client->dev, "Failed to initialise the camera\n"); - } else { - vdev->dev.type = &mt9t031_dev_type; + else v4l2_ctrl_handler_setup(&mt9t031->hdl); - } + return ret; } @@ -663,6 +681,7 @@ static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { .g_chip_ident = mt9t031_g_chip_ident, + .s_power = mt9t031_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9t031_g_register, .s_register = mt9t031_s_register, diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index f060eaaf916f..eb296f9e69f4 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -541,7 +541,7 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe, static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; struct soc_camera_sense *sense = icd->sense; struct ov6650 *priv = to_ov6650(client); bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 9a62ed08d86a..b72580c38957 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -249,6 +249,14 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) return v4l2_subdev_call(sd, core, s_std, *a); } +static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) +{ + struct soc_camera_device *icd = file->private_data; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + + return v4l2_subdev_call(sd, core, g_std, a); +} + static int soc_camera_enum_fsizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { @@ -977,7 +985,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, goto ei2cga; } - icl->board_info->platform_data = icd; + icl->board_info->platform_data = icl; subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, icl->board_info, NULL); @@ -1376,6 +1384,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_g_input = soc_camera_g_input, .vidioc_s_input = soc_camera_s_input, .vidioc_s_std = soc_camera_s_std, + .vidioc_g_std = soc_camera_g_std, .vidioc_enum_framesizes = soc_camera_enum_fsizes, .vidioc_reqbufs = soc_camera_reqbufs, .vidioc_querybuf = soc_camera_querybuf, diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 5a3722b756c7..efce5371915e 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -230,6 +230,7 @@ struct tw9910_priv { struct v4l2_subdev subdev; struct tw9910_video_info *info; const struct tw9910_scale_ctrl *scale; + v4l2_std_id norm; u32 revision; }; @@ -421,12 +422,11 @@ static int tw9910_power(struct i2c_client *client, int enable) return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); } -static const struct tw9910_scale_ctrl *tw9910_select_norm(struct soc_camera_device *icd, +static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm, u32 width, u32 height) { const struct tw9910_scale_ctrl *scale; const struct tw9910_scale_ctrl *ret = NULL; - v4l2_std_id norm = icd->vdev->current_norm; __u32 diff = 0xffffffff, tmp; int size, i; @@ -495,14 +495,27 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) return tw9910_power(client, enable); } +static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + + *norm = priv->norm; + + return 0; +} + static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) { - int ret = -EINVAL; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); - if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL)) - ret = 0; + if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL))) + return -EINVAL; - return ret; + priv->norm = norm; + + return 0; } static int tw9910_g_chip_ident(struct v4l2_subdev *sd, @@ -557,14 +570,13 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); - struct soc_camera_device *icd = client->dev.platform_data; int ret = -EINVAL; u8 val; /* * select suitable norm */ - priv->scale = tw9910_select_norm(icd, *width, *height); + priv->scale = tw9910_select_norm(priv->norm, *width, *height); if (!priv->scale) goto tw9910_set_fmt_error; @@ -642,11 +654,11 @@ tw9910_set_fmt_error: static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; + struct tw9910_priv *priv = to_tw9910(client); a->c.left = 0; a->c.top = 0; - if (icd->vdev->current_norm & V4L2_STD_NTSC) { + if (priv->norm & V4L2_STD_NTSC) { a->c.width = 640; a->c.height = 480; } else { @@ -661,11 +673,11 @@ static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; + struct tw9910_priv *priv = to_tw9910(client); a->bounds.left = 0; a->bounds.top = 0; - if (icd->vdev->current_norm & V4L2_STD_NTSC) { + if (priv->norm & V4L2_STD_NTSC) { a->bounds.width = 640; a->bounds.height = 480; } else { @@ -732,7 +744,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; + struct tw9910_priv *priv = to_tw9910(client); const struct tw9910_scale_ctrl *scale; if (V4L2_FIELD_ANY == mf->field) { @@ -748,7 +760,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, /* * select suitable norm */ - scale = tw9910_select_norm(icd, mf->width, mf->height); + scale = tw9910_select_norm(priv->norm, mf->width, mf->height); if (!scale) return -EINVAL; @@ -758,8 +770,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, return 0; } -static int tw9910_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int tw9910_video_probe(struct i2c_client *client) { struct tw9910_priv *priv = to_tw9910(client); s32 id; @@ -792,8 +803,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd, dev_info(&client->dev, "tw9910 Product ID %0x:%0x\n", id, priv->revision); - icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; - icd->vdev->current_norm = V4L2_STD_NTSC; + priv->norm = V4L2_STD_NTSC; return 0; } @@ -801,6 +811,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd, static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { .g_chip_ident = tw9910_g_chip_ident, .s_std = tw9910_s_std, + .g_std = tw9910_g_std, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = tw9910_g_register, .s_register = tw9910_s_register, @@ -883,7 +894,6 @@ static int tw9910_probe(struct i2c_client *client, { struct tw9910_priv *priv; struct tw9910_video_info *info; - struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct soc_camera_link *icl = soc_camera_i2c_to_link(client); @@ -911,7 +921,7 @@ static int tw9910_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - ret = tw9910_video_probe(icd, client); + ret = tw9910_video_probe(client); if (ret) kfree(priv); diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index dac57598ee57..b1377b931eb7 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -253,14 +253,14 @@ unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, #include static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client) { - struct soc_camera_device *icd = client->dev.platform_data; + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; return icd ? icd->vdev : NULL; } static inline struct soc_camera_link *soc_camera_i2c_to_link(const struct i2c_client *client) { - struct soc_camera_device *icd = client->dev.platform_data; - return icd ? to_soc_camera_link(icd) : NULL; + return client->dev.platform_data; } static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_device *vdev) From 95d20109ad6478ecea5e93ba191270fb645d52c7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 13:56:04 -0300 Subject: [PATCH 123/144] [media] V4L: replace soc-camera specific soc_mediabus.h with v4l2-mediabus.h Most users of the header only need pixel code definitions, which are now located in the generic header. Switch over to reduce soc-camera dependencies. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/imx074.c | 2 +- drivers/media/video/mt9m111.c | 2 +- drivers/media/video/mt9t031.c | 2 +- drivers/media/video/mt9t112.c | 2 +- drivers/media/video/ov2640.c | 2 +- drivers/media/video/ov5642.c | 2 +- drivers/media/video/ov6650.c | 2 +- drivers/media/video/ov772x.c | 2 +- drivers/media/video/ov9640.c | 2 +- drivers/media/video/ov9740.c | 2 +- drivers/media/video/rj54n1cb0c.c | 2 +- drivers/media/video/tw9910.c | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 4f3ce7fa87df..8775e262bb6e 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -12,11 +12,11 @@ #include #include +#include #include #include #include -#include #include #include diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 9feeb0cb6722..f023cc092c2b 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -13,9 +13,9 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 0226486d59be..7ee84cc578b9 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -13,10 +13,10 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 5b045a1097c6..32114a3c0ca7 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -22,11 +22,11 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index d37a5cceebb6..b5247cb64fde 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -18,10 +18,10 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 2a26602fc86d..54178cbeabb4 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -19,9 +19,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index eb296f9e69f4..8d17c519a9f7 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -28,9 +28,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index a2146c30771e..9f6ce3d8a29e 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -20,11 +20,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index f9babf39d802..a4f99797eb56 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -24,10 +24,10 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index 9558aca86818..d9a9f7174f7a 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c @@ -14,9 +14,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index fcb14d93a24c..6afc61689549 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -11,11 +11,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index efce5371915e..a514fa61116c 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -22,10 +22,10 @@ #include #include #include +#include #include #include -#include #include #include #include From 171f1a48bb3f95e3ecb37ecd6e8577118d601460 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Thu, 8 Sep 2011 13:15:24 -0300 Subject: [PATCH 124/144] [media] media: ov5642: Add support for arbitrary resolution This patch adds the ability to get arbitrary resolutions with a width up to 2592 and a height up to 720 pixels instead of the standard 1280x720 only. Signed-off-by: Bastian Hecht Acked-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov5642.c | 240 ++++++++++++++++++++++++----------- 1 file changed, 167 insertions(+), 73 deletions(-) diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 54178cbeabb4..bb37ec80f274 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -14,8 +14,10 @@ * published by the Free Software Foundation. */ +#include #include #include +#include #include #include #include @@ -35,7 +37,7 @@ #define REG_WINDOW_START_Y_LOW 0x3803 #define REG_WINDOW_WIDTH_HIGH 0x3804 #define REG_WINDOW_WIDTH_LOW 0x3805 -#define REG_WINDOW_HEIGHT_HIGH 0x3806 +#define REG_WINDOW_HEIGHT_HIGH 0x3806 #define REG_WINDOW_HEIGHT_LOW 0x3807 #define REG_OUT_WIDTH_HIGH 0x3808 #define REG_OUT_WIDTH_LOW 0x3809 @@ -45,20 +47,45 @@ #define REG_OUT_TOTAL_WIDTH_LOW 0x380d #define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e #define REG_OUT_TOTAL_HEIGHT_LOW 0x380f +#define REG_OUTPUT_FORMAT 0x4300 +#define REG_ISP_CTRL_01 0x5001 +#define REG_AVG_WINDOW_END_X_HIGH 0x5682 +#define REG_AVG_WINDOW_END_X_LOW 0x5683 +#define REG_AVG_WINDOW_END_Y_HIGH 0x5686 +#define REG_AVG_WINDOW_END_Y_LOW 0x5687 -/* - * define standard resolution. - * Works currently only for up to 720 lines - * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720 - */ - -#define OV5642_WIDTH 1280 -#define OV5642_HEIGHT 720 -#define OV5642_TOTAL_WIDTH 3200 -#define OV5642_TOTAL_HEIGHT 2000 +/* active pixel array size */ #define OV5642_SENSOR_SIZE_X 2592 #define OV5642_SENSOR_SIZE_Y 1944 +/* + * About OV5642 resolution, cropping and binning: + * This sensor supports it all, at least in the feature description. + * Unfortunately, no combination of appropriate registers settings could make + * the chip work the intended way. As it works with predefined register lists, + * some undocumented registers are presumably changed there to achieve their + * goals. + * This driver currently only works for resolutions up to 720 lines with a + * 1:1 scale. Hopefully these restrictions will be removed in the future. + */ +#define OV5642_MAX_WIDTH OV5642_SENSOR_SIZE_X +#define OV5642_MAX_HEIGHT 720 + +/* default sizes */ +#define OV5642_DEFAULT_WIDTH 1280 +#define OV5642_DEFAULT_HEIGHT OV5642_MAX_HEIGHT + +/* minimum extra blanking */ +#define BLANKING_EXTRA_WIDTH 500 +#define BLANKING_EXTRA_HEIGHT 20 + +/* + * the sensor's autoexposure is buggy when setting total_height low. + * It tries to expose longer than 1 frame period without taking care of it + * and this leads to weird output. So we set 1000 lines as minimum. + */ +#define BLANKING_MIN_HEIGHT 1000 + struct regval_list { u16 reg_num; u8 value; @@ -582,6 +609,11 @@ struct ov5642_datafmt { struct ov5642 { struct v4l2_subdev subdev; const struct ov5642_datafmt *fmt; + struct v4l2_rect crop_rect; + + /* blanking information */ + int total_width; + int total_height; }; static const struct ov5642_datafmt ov5642_colour_fmts[] = { @@ -642,6 +674,21 @@ static int reg_write(struct i2c_client *client, u16 reg, u8 val) return 0; } + +/* + * convenience function to write 16 bit register values that are split up + * into two consecutive high and low parts + */ +static int reg_write16(struct i2c_client *client, u16 reg, u16 val16) +{ + int ret; + + ret = reg_write(client, reg, val16 >> 8); + if (ret) + return ret; + return reg_write(client, reg + 1, val16 & 0x00ff); +} + #ifdef CONFIG_VIDEO_ADV_DEBUG static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { @@ -685,58 +732,55 @@ static int ov5642_write_array(struct i2c_client *client, return 0; } -static int ov5642_set_resolution(struct i2c_client *client) +static int ov5642_set_resolution(struct v4l2_subdev *sd) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5642 *priv = to_ov5642(client); + int width = priv->crop_rect.width; + int height = priv->crop_rect.height; + int total_width = priv->total_width; + int total_height = priv->total_height; + int start_x = (OV5642_SENSOR_SIZE_X - width) / 2; + int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2; int ret; - u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8; - u8 start_x_low = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff; - u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8; - u8 start_y_low = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff; - u8 width_high = OV5642_WIDTH >> 8; - u8 width_low = OV5642_WIDTH & 0xff; - u8 height_high = OV5642_HEIGHT >> 8; - u8 height_low = OV5642_HEIGHT & 0xff; - - u8 total_width_high = OV5642_TOTAL_WIDTH >> 8; - u8 total_width_low = OV5642_TOTAL_WIDTH & 0xff; - u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8; - u8 total_height_low = OV5642_TOTAL_HEIGHT & 0xff; - - ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high); + /* + * This should set the starting point for cropping. + * Doesn't work so far. + */ + ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x); if (!ret) - ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low); - if (!ret) - ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high); - if (!ret) - ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low); + ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y); + if (!ret) { + priv->crop_rect.left = start_x; + priv->crop_rect.top = start_y; + } if (!ret) - ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high); + ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width); if (!ret) - ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low); - if (!ret) - ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high); - if (!ret) - ret = reg_write(client, REG_WINDOW_HEIGHT_LOW, height_low); + ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height); + if (ret) + return ret; + priv->crop_rect.width = width; + priv->crop_rect.height = height; + /* Set the output window size. Only 1:1 scale is supported so far. */ + ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width); if (!ret) - ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high); - if (!ret) - ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low); - if (!ret) - ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high); - if (!ret) - ret = reg_write(client, REG_OUT_HEIGHT_LOW, height_low); + ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height); + /* Total width = output size + blanking */ if (!ret) - ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high); + ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width); if (!ret) - ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low); + ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height); + + /* Sets the window for AWB calculations */ if (!ret) - ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high); + ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width); if (!ret) - ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW, total_height_low); + ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height); return ret; } @@ -744,18 +788,18 @@ static int ov5642_set_resolution(struct i2c_client *client) static int ov5642_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5642 *priv = to_ov5642(client); const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); - dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n", - __func__, mf->code, mf->width, mf->height); + mf->width = priv->crop_rect.width; + mf->height = priv->crop_rect.height; if (!fmt) { mf->code = ov5642_colour_fmts[0].code; mf->colorspace = ov5642_colour_fmts[0].colorspace; } - mf->width = OV5642_WIDTH; - mf->height = OV5642_HEIGHT; mf->field = V4L2_FIELD_NONE; return 0; @@ -767,20 +811,13 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5642 *priv = to_ov5642(client); - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); - /* MIPI CSI could have changed the format, double-check */ if (!ov5642_find_datafmt(mf->code)) return -EINVAL; ov5642_try_fmt(sd, mf); - priv->fmt = ov5642_find_datafmt(mf->code); - ov5642_write_array(client, ov5642_default_regs_init); - ov5642_set_resolution(client); - ov5642_write_array(client, ov5642_default_regs_finalise); - return 0; } @@ -794,8 +831,8 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd, mf->code = fmt->code; mf->colorspace = fmt->colorspace; - mf->width = OV5642_WIDTH; - mf->height = OV5642_HEIGHT; + mf->width = priv->crop_rect.width; + mf->height = priv->crop_rect.height; mf->field = V4L2_FIELD_NONE; return 0; @@ -828,15 +865,44 @@ static int ov5642_g_chip_ident(struct v4l2_subdev *sd, return 0; } +static int ov5642_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5642 *priv = to_ov5642(client); + struct v4l2_rect *rect = &a->c; + int ret; + + v4l_bound_align_image(&rect->width, 48, OV5642_MAX_WIDTH, 1, + &rect->height, 32, OV5642_MAX_HEIGHT, 1, 0); + + priv->crop_rect.width = rect->width; + priv->crop_rect.height = rect->height; + priv->total_width = rect->width + BLANKING_EXTRA_WIDTH; + priv->total_height = max_t(int, rect->height + + BLANKING_EXTRA_HEIGHT, + BLANKING_MIN_HEIGHT); + priv->crop_rect.width = rect->width; + priv->crop_rect.height = rect->height; + + ret = ov5642_write_array(client, ov5642_default_regs_init); + if (!ret) + ret = ov5642_set_resolution(sd); + if (!ret) + ret = ov5642_write_array(client, ov5642_default_regs_finalise); + + return ret; +} + static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5642 *priv = to_ov5642(client); struct v4l2_rect *rect = &a->c; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - rect->top = 0; - rect->left = 0; - rect->width = OV5642_WIDTH; - rect->height = OV5642_HEIGHT; + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + *rect = priv->crop_rect; return 0; } @@ -845,8 +911,8 @@ static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) { a->bounds.left = 0; a->bounds.top = 0; - a->bounds.width = OV5642_WIDTH; - a->bounds.height = OV5642_HEIGHT; + a->bounds.width = OV5642_MAX_WIDTH; + a->bounds.height = OV5642_MAX_HEIGHT; a->defrect = a->bounds; a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; a->pixelaspect.numerator = 1; @@ -859,24 +925,43 @@ static int ov5642_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { cfg->type = V4L2_MBUS_CSI2; - cfg->flags = V4L2_MBUS_CSI2_2_LANE | - V4L2_MBUS_CSI2_CHANNEL_0 | - V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; return 0; } +static int ov5642_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client; + int ret; + + if (!on) + return 0; + + client = v4l2_get_subdevdata(sd); + ret = ov5642_write_array(client, ov5642_default_regs_init); + if (!ret) + ret = ov5642_set_resolution(sd); + if (!ret) + ret = ov5642_write_array(client, ov5642_default_regs_finalise); + + return ret; +} + static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { .s_mbus_fmt = ov5642_s_fmt, .g_mbus_fmt = ov5642_g_fmt, .try_mbus_fmt = ov5642_try_fmt, .enum_mbus_fmt = ov5642_enum_fmt, + .s_crop = ov5642_s_crop, .g_crop = ov5642_g_crop, .cropcap = ov5642_cropcap, .g_mbus_config = ov5642_g_mbus_config, }; static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { + .s_power = ov5642_s_power, .g_chip_ident = ov5642_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov5642_get_register, @@ -934,7 +1019,16 @@ static int ov5642_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); - priv->fmt = &ov5642_colour_fmts[0]; + priv->fmt = &ov5642_colour_fmts[0]; + + priv->crop_rect.width = OV5642_DEFAULT_WIDTH; + priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; + priv->crop_rect.left = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2; + priv->crop_rect.top = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2; + priv->crop_rect.width = OV5642_DEFAULT_WIDTH; + priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; + priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH; + priv->total_height = BLANKING_MIN_HEIGHT; ret = ov5642_video_probe(client); if (ret < 0) From 2e56d933fd967a72d5ee4250e1cb6f9de29d936f Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 12 Sep 2011 08:25:25 -0300 Subject: [PATCH 125/144] [media] media: ov6650: stylistic improvements * with no "retrun ret;" at the end, there is no need to initialize ret any longer, * consequently use conditional expressions, not if...else constructs, throughout ov6650_s_ctrl(), * v4l2_ctrl_new_std_menu() max value of V4L2_EXPOSURE_MANUAL instead of equivalent 1 looks more clear. Created on top of "Converting soc_camera to the control framework" series. Signed-off-by: Janusz Krzysztofik Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov6650.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 8d17c519a9f7..d5b057207a7b 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -310,7 +310,7 @@ static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); uint8_t reg, reg2; - int ret = 0; + int ret; switch (ctrl->id) { case V4L2_CID_AUTOGAIN: @@ -342,7 +342,7 @@ static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; + int ret; switch (ctrl->id) { case V4L2_CID_AUTOGAIN: @@ -370,10 +370,8 @@ static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_BRIGHTNESS: return ov6650_reg_write(client, REG_BRT, ctrl->val); case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->val == V4L2_EXPOSURE_AUTO) - ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); - else - ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); + ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val == + V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC); if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) ret = ov6650_reg_write(client, REG_AECH, priv->exposure->val); @@ -983,8 +981,8 @@ static int ov6650_probe(struct i2c_client *client, v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, - &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, - V4L2_EXPOSURE_AUTO); + &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, + V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, From d26a6635b24210791cf4b71fd861738270c8cc3c Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sun, 4 Sep 2011 19:08:54 -0300 Subject: [PATCH 126/144] [media] v4l: Add AUTO option for the V4L2_CID_POWER_LINE_FREQUENCY control V4L2_CID_POWER_LINE_FREQUENCY control allows applications to instruct a driver what is the power line frequency so an appropriate filter can be used by the device to cancel flicker by compensating the light intensity ripple. Currently in the menu we have entries for 50 Hz and 60 Hz and for entirely disabling the anti-flicker filter. However some devices are capable of automatically detecting the frequency, so add V4L2_CID_POWER_LINE_FREQUENCY_AUTO entry for them. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 5 +++-- drivers/media/video/v4l2-ctrls.c | 1 + include/linux/videodev2.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 23fdf79f8cf3..3bc5ee8b2c74 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -232,8 +232,9 @@ control is deprecated. New drivers and applications should use the Enables a power line frequency filter to avoid flicker. Possible values for enum v4l2_power_line_frequency are: V4L2_CID_POWER_LINE_FREQUENCY_DISABLED (0), -V4L2_CID_POWER_LINE_FREQUENCY_50HZ (1) and -V4L2_CID_POWER_LINE_FREQUENCY_60HZ (2). +V4L2_CID_POWER_LINE_FREQUENCY_50HZ (1), +V4L2_CID_POWER_LINE_FREQUENCY_60HZ (2) and +V4L2_CID_POWER_LINE_FREQUENCY_AUTO (3). V4L2_CID_HUE_AUTO diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index fc8666ae408f..5552f8137571 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -210,6 +210,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Disabled", "50 Hz", "60 Hz", + "Auto", NULL }; static const char * const camera_exposure_auto[] = { diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 66945a6f628d..4b752d5ee80e 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1169,6 +1169,7 @@ enum v4l2_power_line_frequency { V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0, V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1, V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO = 3, }; #define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25) #define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26) From bfa8dd3a05248457fce18712e7bc0499030b3100 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 4 Oct 2011 14:05:58 -0300 Subject: [PATCH 127/144] [media] v4l: Add v4l2 subdev driver for S5K6AAFX sensor This driver exposes preview mode operation of the S5K6AAFX sensor with embedded SoC ISP. The native capture (snapshot) operation mode is not supported. Following controls are available: manual/auto exposure and gain, power line frequency (anti-flicker), saturation, sharpness, brightness, contrast, white balance temperature, color effects, horizontal/vertical image flip, frame interval, auto white balance. RGB component gains are currently exposed through private controls. Reviewed-by: Sakari Ailus Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 7 + drivers/media/video/Makefile | 1 + drivers/media/video/s5k6aa.c | 1680 ++++++++++++++++++++++++++++++++++ include/media/s5k6aa.h | 51 ++ 4 files changed, 1739 insertions(+) create mode 100644 drivers/media/video/s5k6aa.c create mode 100644 include/media/s5k6aa.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d471d1e5a744..b303a3f8a9f8 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -517,6 +517,13 @@ config VIDEO_NOON010PC30 source "drivers/media/video/m5mols/Kconfig" +config VIDEO_S5K6AA + tristate "Samsung S5K6AAFX sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + ---help--- + This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M + camera sensor with an embedded SoC image signal processor. + comment "Flash devices" config VIDEO_ADP1653 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index faba1e333110..117f9c4b4cb9 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ +obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c new file mode 100644 index 000000000000..2446736b7871 --- /dev/null +++ b/drivers/media/video/s5k6aa.c @@ -0,0 +1,1680 @@ +/* + * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor + * with embedded SoC ISP. + * + * Copyright (C) 2011, Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * Based on a driver authored by Dongsoo Nathaniel Kim. + * Copyright (C) 2009, Dongsoo Nathaniel Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, 0644); + +#define DRIVER_NAME "S5K6AA" + +/* The token to indicate array termination */ +#define S5K6AA_TERM 0xffff +#define S5K6AA_OUT_WIDTH_DEF 640 +#define S5K6AA_OUT_HEIGHT_DEF 480 +#define S5K6AA_WIN_WIDTH_MAX 1280 +#define S5K6AA_WIN_HEIGHT_MAX 1024 +#define S5K6AA_WIN_WIDTH_MIN 8 +#define S5K6AA_WIN_HEIGHT_MIN 8 + +/* + * H/W register Interface (0xD0000000 - 0xD0000FFF) + */ +#define AHB_MSB_ADDR_PTR 0xfcfc +#define GEN_REG_OFFSH 0xd000 +#define REG_CMDWR_ADDRH 0x0028 +#define REG_CMDWR_ADDRL 0x002a +#define REG_CMDRD_ADDRH 0x002c +#define REG_CMDRD_ADDRL 0x002e +#define REG_CMDBUF0_ADDR 0x0f12 +#define REG_CMDBUF1_ADDR 0x0f10 + +/* + * Host S/W Register interface (0x70000000 - 0x70002000) + * The value of the two most significant address bytes is 0x7000, + * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs. + */ +#define HOST_SWIF_OFFSH 0x7000 + +/* Initialization parameters */ +/* Master clock frequency in KHz */ +#define REG_I_INCLK_FREQ_L 0x01b8 +#define REG_I_INCLK_FREQ_H 0x01ba +#define MIN_MCLK_FREQ_KHZ 6000U +#define MAX_MCLK_FREQ_KHZ 27000U +#define REG_I_USE_NPVI_CLOCKS 0x01c6 +#define REG_I_USE_NMIPI_CLOCKS 0x01c8 + +/* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */ +#define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc) +#define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce) +#define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0) +#define SYS_PLL_OUT_FREQ (48000000 / 4000) +#define PCLK_FREQ_MIN (24000000 / 4000) +#define PCLK_FREQ_MAX (48000000 / 4000) +#define REG_I_INIT_PARAMS_UPDATED 0x01e0 +#define REG_I_ERROR_INFO 0x01e2 + +/* General purpose parameters */ +#define REG_USER_BRIGHTNESS 0x01e4 +#define REG_USER_CONTRAST 0x01e6 +#define REG_USER_SATURATION 0x01e8 +#define REG_USER_SHARPBLUR 0x01ea + +#define REG_G_SPEC_EFFECTS 0x01ee +#define REG_G_ENABLE_PREV 0x01f0 +#define REG_G_ENABLE_PREV_CHG 0x01f2 +#define REG_G_NEW_CFG_SYNC 0x01f8 +#define REG_G_PREVZOOM_IN_WIDTH 0x020a +#define REG_G_PREVZOOM_IN_HEIGHT 0x020c +#define REG_G_PREVZOOM_IN_XOFFS 0x020e +#define REG_G_PREVZOOM_IN_YOFFS 0x0210 +#define REG_G_INPUTS_CHANGE_REQ 0x021a +#define REG_G_ACTIVE_PREV_CFG 0x021c +#define REG_G_PREV_CFG_CHG 0x021e +#define REG_G_PREV_OPEN_AFTER_CH 0x0220 +#define REG_G_PREV_CFG_ERROR 0x0222 + +/* Preview control section. n = 0...4. */ +#define PREG(n, x) ((n) * 0x26 + x) +#define REG_P_OUT_WIDTH(n) PREG(n, 0x0242) +#define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244) +#define REG_P_FMT(n) PREG(n, 0x0246) +#define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248) +#define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a) +#define REG_P_PVI_MASK(n) PREG(n, 0x024c) +#define REG_P_CLK_INDEX(n) PREG(n, 0x024e) +#define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250) +#define FR_RATE_DYNAMIC 0 +#define FR_RATE_FIXED 1 +#define FR_RATE_FIXED_ACCURATE 2 +#define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252) +#define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */ +#define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */ +/* Frame period in 0.1 ms units */ +#define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254) +#define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256) +/* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */ +#define US_TO_FR_TIME(__t) ((__t) / 100) +#define S5K6AA_MIN_FR_TIME 33300 /* us */ +#define S5K6AA_MAX_FR_TIME 650000 /* us */ +#define S5K6AA_MAX_HIGHRES_FR_TIME 666 /* x100 us */ +/* The below 5 registers are for "device correction" values */ +#define REG_P_COLORTEMP(n) PREG(n, 0x025e) +#define REG_P_PREV_MIRROR(n) PREG(n, 0x0262) + +/* Extended image property controls */ +/* Exposure time in 10 us units */ +#define REG_SF_USR_EXPOSURE_L 0x03c6 +#define REG_SF_USR_EXPOSURE_H 0x03c8 +#define REG_SF_USR_EXPOSURE_CHG 0x03ca +#define REG_SF_USR_TOT_GAIN 0x03cc +#define REG_SF_USR_TOT_GAIN_CHG 0x03ce +#define REG_SF_RGAIN 0x03d0 +#define REG_SF_RGAIN_CHG 0x03d2 +#define REG_SF_GGAIN 0x03d4 +#define REG_SF_GGAIN_CHG 0x03d6 +#define REG_SF_BGAIN 0x03d8 +#define REG_SF_BGAIN_CHG 0x03da +#define REG_SF_FLICKER_QUANT 0x03dc +#define REG_SF_FLICKER_QUANT_CHG 0x03de + +/* Output interface (parallel/MIPI) setup */ +#define REG_OIF_EN_MIPI_LANES 0x03fa +#define REG_OIF_EN_PACKETS 0x03fc +#define REG_OIF_CFG_CHG 0x03fe + +/* Auto-algorithms enable mask */ +#define REG_DBG_AUTOALG_EN 0x0400 +#define AALG_ALL_EN_MASK (1 << 0) +#define AALG_AE_EN_MASK (1 << 1) +#define AALG_DIVLEI_EN_MASK (1 << 2) +#define AALG_WB_EN_MASK (1 << 3) +#define AALG_FLICKER_EN_MASK (1 << 5) +#define AALG_FIT_EN_MASK (1 << 6) +#define AALG_WRHW_EN_MASK (1 << 7) + +/* Firmware revision information */ +#define REG_FW_APIVER 0x012e +#define S5K6AAFX_FW_APIVER 0x0001 +#define REG_FW_REVISION 0x0130 + +/* For now we use only one user configuration register set */ +#define S5K6AA_MAX_PRESETS 1 + +static const char * const s5k6aa_supply_names[] = { + "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */ + "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */ + "vdd_reg", /* Regulator input power 1.8V (1.7V to 1.9V) + or 2.8V (2.6V to 3.0) */ + "vddio", /* I/O supply 1.8V (1.65V to 1.95V) + or 2.8V (2.5V to 3.1V) */ +}; +#define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names) + +enum s5k6aa_gpio_id { + STBY, + RST, + GPIO_NUM, +}; + +struct s5k6aa_regval { + u16 addr; + u16 val; +}; + +struct s5k6aa_pixfmt { + enum v4l2_mbus_pixelcode code; + u32 colorspace; + /* REG_P_FMT(x) register value */ + u16 reg_p_fmt; +}; + +struct s5k6aa_preset { + /* output pixel format and resolution */ + struct v4l2_mbus_framefmt mbus_fmt; + u8 clk_id; + u8 index; +}; + +struct s5k6aa_ctrls { + struct v4l2_ctrl_handler handler; + /* Auto / manual white balance cluster */ + struct v4l2_ctrl *awb; + struct v4l2_ctrl *gain_red; + struct v4l2_ctrl *gain_blue; + struct v4l2_ctrl *gain_green; + /* Mirror cluster */ + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + /* Auto exposure / manual exposure and gain cluster */ + struct v4l2_ctrl *auto_exp; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; +}; + +struct s5k6aa_interval { + u16 reg_fr_time; + struct v4l2_fract interval; + /* Maximum rectangle for the interval */ + struct v4l2_frmsize_discrete size; +}; + +struct s5k6aa { + struct v4l2_subdev sd; + struct media_pad pad; + + enum v4l2_mbus_type bus_type; + u8 mipi_lanes; + + int (*s_power)(int enable); + struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES]; + struct s5k6aa_gpio gpio[GPIO_NUM]; + + /* external master clock frequency */ + unsigned long mclk_frequency; + /* ISP internal master clock frequency */ + u16 clk_fop; + /* output pixel clock frequency range */ + u16 pclk_fmin; + u16 pclk_fmax; + + unsigned int inv_hflip:1; + unsigned int inv_vflip:1; + + /* protects the struct members below */ + struct mutex lock; + + /* sensor matrix scan window */ + struct v4l2_rect ccd_rect; + + struct s5k6aa_ctrls ctrls; + struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS]; + struct s5k6aa_preset *preset; + const struct s5k6aa_interval *fiv; + + unsigned int streaming:1; + unsigned int apply_cfg:1; + unsigned int apply_crop:1; + unsigned int power; +}; + +static struct s5k6aa_regval s5k6aa_analog_config[] = { + /* Analog settings */ + { 0x112a, 0x0000 }, { 0x1132, 0x0000 }, + { 0x113e, 0x0000 }, { 0x115c, 0x0000 }, + { 0x1164, 0x0000 }, { 0x1174, 0x0000 }, + { 0x1178, 0x0000 }, { 0x077a, 0x0000 }, + { 0x077c, 0x0000 }, { 0x077e, 0x0000 }, + { 0x0780, 0x0000 }, { 0x0782, 0x0000 }, + { 0x0784, 0x0000 }, { 0x0786, 0x0000 }, + { 0x0788, 0x0000 }, { 0x07a2, 0x0000 }, + { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 }, + { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 }, + { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 }, + { 0x07bc, 0x0004 }, { 0x07be, 0x0005 }, + { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 }, +}; + +/* TODO: Add RGB888 and Bayer format */ +static const struct s5k6aa_pixfmt s5k6aa_formats[] = { + { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 }, + /* range 16-240 */ + { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 }, + { V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 }, +}; + +static const struct s5k6aa_interval s5k6aa_intervals[] = { + { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */ + { 666, {15000, 1000000}, {1280, 1024} }, /* 15 fps */ + { 500, {20000, 1000000}, {1280, 720} }, /* 20 fps */ + { 400, {25000, 1000000}, {640, 480} }, /* 25 fps */ + { 333, {33300, 1000000}, {640, 480} }, /* 30 fps */ +}; + +#define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */ + +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd; +} + +static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd) +{ + return container_of(sd, struct s5k6aa, sd); +} + +/* Set initial values for all preview presets */ +static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa) +{ + struct s5k6aa_preset *preset = &s5k6aa->presets[0]; + int i; + + for (i = 0; i < S5K6AA_MAX_PRESETS; i++) { + preset->mbus_fmt.width = S5K6AA_OUT_WIDTH_DEF; + preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF; + preset->mbus_fmt.code = s5k6aa_formats[0].code; + preset->index = i; + preset->clk_id = 0; + preset++; + } + + s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX]; + s5k6aa->preset = &s5k6aa->presets[0]; +} + +static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val) +{ + u8 wbuf[2] = {addr >> 8, addr & 0xFF}; + struct i2c_msg msg[2]; + u8 rbuf[2]; + int ret; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = wbuf; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = rbuf; + + ret = i2c_transfer(client->adapter, msg, 2); + *val = be16_to_cpu(*((u16 *)rbuf)); + + v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val); + + return ret == 2 ? 0 : ret; +} + +static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val) +{ + u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF}; + + int ret = i2c_master_send(client, buf, 4); + v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val); + + return ret == 4 ? 0 : ret; +} + +/* The command register write, assumes Command_Wr_addH = 0x7000. */ +static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val) +{ + int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr); + if (ret) + return ret; + return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val); +} + +/* The command register read, assumes Command_Rd_addH = 0x7000. */ +static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val) +{ + int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr); + if (ret) + return ret; + return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val); +} + +static int s5k6aa_write_array(struct v4l2_subdev *sd, + const struct s5k6aa_regval *msg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 addr_incr = 0; + int ret = 0; + + while (msg->addr != S5K6AA_TERM) { + if (addr_incr != 2) + ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL, + msg->addr); + if (ret) + break; + ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val); + if (ret) + break; + /* Assume that msg->addr is always less than 0xfffc */ + addr_incr = (msg + 1)->addr - msg->addr; + msg++; + } + + return ret; +} + +/* Configure the AHB high address bytes for GTG registers access */ +static int s5k6aa_set_ahb_address(struct i2c_client *client) +{ + int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH); + if (ret) + return ret; + ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH); + if (ret) + return ret; + return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH); +} + +/** + * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration + * + * Configure the internal ISP PLL for the required output frequency. + * Locking: called with s5k6aa.lock mutex held. + */ +static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa) +{ + struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); + unsigned long fmclk = s5k6aa->mclk_frequency / 1000; + u16 status; + int ret; + + if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ, + "Invalid clock frequency: %ld\n", fmclk)) + return -EINVAL; + + s5k6aa->pclk_fmin = PCLK_FREQ_MIN; + s5k6aa->pclk_fmax = PCLK_FREQ_MAX; + s5k6aa->clk_fop = SYS_PLL_OUT_FREQ; + + /* External input clock frequency in kHz */ + ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16); + if (!ret) + ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF); + if (!ret) + ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1); + /* Internal PLL frequency */ + if (!ret) + ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop); + if (!ret) + ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0), + s5k6aa->pclk_fmin); + if (!ret) + ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0), + s5k6aa->pclk_fmax); + if (!ret) + ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1); + if (!ret) + ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status); + + return ret ? ret : (status ? -EINVAL : 0); +} + +/* Set horizontal and vertical image flipping */ +static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + int index = s5k6aa->preset->index; + + unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip; + unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1); + + return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip); +} + +/* Configure auto/manual white balance and R/G/B gains */ +static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb) +{ + struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); + struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; + u16 reg; + + int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, ®); + + if (!ret && !awb) { + ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val); + if (!ret) + ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1); + if (ret) + return ret; + + ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val); + if (!ret) + ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1); + if (ret) + return ret; + + ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val); + if (!ret) + ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1); + } + if (!ret) { + reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK; + ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg); + } + + return ret; +} + +/* Program FW with exposure time, 'exposure' in us units */ +static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure) +{ + unsigned int time = exposure / 10; + + int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff); + if (!ret) + ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16); + if (ret) + return ret; + return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1); +} + +static int s5k6aa_set_user_gain(struct i2c_client *client, int gain) +{ + int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain); + if (ret) + return ret; + return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1); +} + +/* Set auto/manual exposure and total gain */ +static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value) +{ + struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); + unsigned int exp_time = s5k6aa->ctrls.exposure->val; + u16 auto_alg; + + int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg); + if (ret) + return ret; + + v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n", + exp_time, value, auto_alg); + + if (value == V4L2_EXPOSURE_AUTO) { + auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK; + } else { + ret = s5k6aa_set_user_exposure(c, exp_time); + if (ret) + return ret; + ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val); + if (ret) + return ret; + auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK); + } + + return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg); +} + +static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + u16 auto_alg; + int ret; + + ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg); + if (ret) + return ret; + + if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) { + auto_alg |= AALG_FLICKER_EN_MASK; + } else { + auto_alg &= ~AALG_FLICKER_EN_MASK; + /* The V4L2_CID_LINE_FREQUENCY control values match + * the register values */ + ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value); + if (ret) + return ret; + ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1); + if (ret) + return ret; + } + + return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg); +} + +static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + static const struct v4l2_control colorfx[] = { + { V4L2_COLORFX_NONE, 0 }, + { V4L2_COLORFX_BW, 1 }, + { V4L2_COLORFX_NEGATIVE, 2 }, + { V4L2_COLORFX_SEPIA, 3 }, + { V4L2_COLORFX_SKY_BLUE, 4 }, + { V4L2_COLORFX_SKETCH, 5 }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(colorfx); i++) { + if (colorfx[i].id == val) + return s5k6aa_write(client, REG_G_SPEC_EFFECTS, + colorfx[i].value); + } + return -EINVAL; +} + +static int s5k6aa_preview_config_status(struct i2c_client *client) +{ + u16 error = 0; + int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error); + + v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret); + return ret ? ret : (error ? -EINVAL : 0); +} + +static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa, + struct v4l2_mbus_framefmt *mf) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++) + if (mf->colorspace == s5k6aa_formats[i].colorspace && + mf->code == s5k6aa_formats[i].code) + return i; + return 0; +} + +static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa, + struct s5k6aa_preset *preset) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt); + int ret; + + ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index), + preset->mbus_fmt.width); + if (!ret) + ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index), + preset->mbus_fmt.height); + if (!ret) + ret = s5k6aa_write(client, REG_P_FMT(preset->index), + s5k6aa_formats[fmt_index].reg_p_fmt); + return ret; +} + +static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa) +{ + struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); + struct v4l2_rect *r = &s5k6aa->ccd_rect; + int ret; + + ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width); + if (!ret) + ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height); + if (!ret) + ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left); + if (!ret) + ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top); + if (!ret) + ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1); + if (!ret) + s5k6aa->apply_crop = 0; + + return ret; +} + +/** + * s5k6aa_configure_video_bus - configure the video output interface + * @bus_type: video bus type: parallel or MIPI-CSI + * @nlanes: number of MIPI lanes to be used (MIPI-CSI only) + * + * Note: Only parallel bus operation has been tested. + */ +static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa, + enum v4l2_mbus_type bus_type, int nlanes) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + u16 cfg = 0; + int ret; + + /* + * TODO: The sensor is supposed to support BT.601 and BT.656 + * but there is nothing indicating how to switch between both + * in the datasheet. For now default BT.601 interface is assumed. + */ + if (bus_type == V4L2_MBUS_CSI2) + cfg = nlanes; + else if (bus_type != V4L2_MBUS_PARALLEL) + return -EINVAL; + + ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg); + if (ret) + return ret; + return s5k6aa_write(client, REG_OIF_CFG_CHG, 1); +} + +/* This function should be called when switching to new user configuration set*/ +static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout, + int cid) +{ + unsigned long end = jiffies + msecs_to_jiffies(timeout); + u16 reg = 1; + int ret; + + ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid); + if (!ret) + ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); + if (!ret) + ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1); + if (timeout == 0) + return ret; + + while (ret >= 0 && time_is_after_jiffies(end)) { + ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, ®); + if (!reg) + return 0; + usleep_range(1000, 5000); + } + return ret ? ret : -ETIMEDOUT; +} + +/** + * s5k6aa_set_prev_config - write user preview register set + * + * Configure output resolution and color fromat, pixel clock + * frequency range, device frame rate type and frame period range. + */ +static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa, + struct s5k6aa_preset *preset) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + int idx = preset->index; + u16 frame_rate_q; + int ret; + + if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME) + frame_rate_q = FR_RATE_Q_BEST_FRRATE; + else + frame_rate_q = FR_RATE_Q_BEST_QUALITY; + + ret = s5k6aa_set_output_framefmt(s5k6aa, preset); + if (!ret) + ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx), + s5k6aa->pclk_fmax); + if (!ret) + ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx), + s5k6aa->pclk_fmin); + if (!ret) + ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx), + preset->clk_id); + if (!ret) + ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx), + FR_RATE_DYNAMIC); + if (!ret) + ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx), + frame_rate_q); + if (!ret) + ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx), + s5k6aa->fiv->reg_fr_time + 33); + if (!ret) + ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx), + s5k6aa->fiv->reg_fr_time - 33); + if (!ret) + ret = s5k6aa_new_config_sync(client, 250, idx); + if (!ret) + ret = s5k6aa_preview_config_status(client); + if (!ret) + s5k6aa->apply_cfg = 0; + + v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n", + s5k6aa->fiv->reg_fr_time, ret); + return ret; +} + +/** + * s5k6aa_initialize_isp - basic ISP MCU initialization + * + * Configure AHB addresses for registers read/write; configure PLLs for + * required output pixel clock. The ISP power supply needs to be already + * enabled, with an optional H/W reset. + * Locking: called with s5k6aa.lock mutex held. + */ +static int s5k6aa_initialize_isp(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret; + + s5k6aa->apply_crop = 1; + s5k6aa->apply_cfg = 1; + msleep(100); + + ret = s5k6aa_set_ahb_address(client); + if (ret) + return ret; + ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type, + s5k6aa->mipi_lanes); + if (ret) + return ret; + ret = s5k6aa_write_array(sd, s5k6aa_analog_config); + if (ret) + return ret; + msleep(20); + + return s5k6aa_configure_pixel_clocks(s5k6aa); +} + +static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val) +{ + if (!gpio_is_valid(priv->gpio[id].gpio)) + return 0; + gpio_set_value(priv->gpio[id].gpio, !!val); + return 1; +} + +static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id) +{ + return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level); +} + +static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id) +{ + return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level); +} + +static int __s5k6aa_power_on(struct s5k6aa *s5k6aa) +{ + int ret; + + ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); + if (ret) + return ret; + if (s5k6aa_gpio_deassert(s5k6aa, STBY)) + usleep_range(150, 200); + + if (s5k6aa->s_power) + ret = s5k6aa->s_power(1); + usleep_range(4000, 4000); + + if (s5k6aa_gpio_deassert(s5k6aa, RST)) + msleep(20); + + return ret; +} + +static int __s5k6aa_power_off(struct s5k6aa *s5k6aa) +{ + int ret; + + if (s5k6aa_gpio_assert(s5k6aa, RST)) + usleep_range(100, 150); + + if (s5k6aa->s_power) { + ret = s5k6aa->s_power(0); + if (ret) + return ret; + } + if (s5k6aa_gpio_assert(s5k6aa, STBY)) + usleep_range(50, 100); + s5k6aa->streaming = 0; + + return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); +} + +/* + * V4L2 subdev core and video operations + */ +static int s5k6aa_set_power(struct v4l2_subdev *sd, int on) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret = 0; + + mutex_lock(&s5k6aa->lock); + + if (!on == s5k6aa->power) { + if (on) { + ret = __s5k6aa_power_on(s5k6aa); + if (!ret) + ret = s5k6aa_initialize_isp(sd); + } else { + ret = __s5k6aa_power_off(s5k6aa); + } + + if (!ret) + s5k6aa->power += on ? 1 : -1; + } + + mutex_unlock(&s5k6aa->lock); + + if (!on || ret || s5k6aa->power != 1) + return ret; + + return v4l2_ctrl_handler_setup(sd->ctrl_handler); +} + +static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + int ret = 0; + + ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable); + if (!ret) + ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1); + if (!ret) + s5k6aa->streaming = enable; + + return ret; +} + +static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret = 0; + + mutex_lock(&s5k6aa->lock); + + if (s5k6aa->streaming == !on) { + if (!ret && s5k6aa->apply_cfg) + ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset); + if (s5k6aa->apply_crop) + ret = s5k6aa_set_input_params(s5k6aa); + if (!ret) + ret = __s5k6aa_stream(s5k6aa, !!on); + } + mutex_unlock(&s5k6aa->lock); + + return ret; +} + +static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + + mutex_lock(&s5k6aa->lock); + fi->interval = s5k6aa->fiv->interval; + mutex_unlock(&s5k6aa->lock); + + return 0; +} + +static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa, + struct v4l2_subdev_frame_interval *fi) +{ + struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt; + const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0]; + unsigned int err, min_err = UINT_MAX; + unsigned int i, fr_time; + + if (fi->interval.denominator == 0) + return -EINVAL; + + fr_time = fi->interval.numerator * 10000 / fi->interval.denominator; + + for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) { + const struct s5k6aa_interval *iv = &s5k6aa_intervals[i]; + + if (mbus_fmt->width > iv->size.width || + mbus_fmt->height > iv->size.height) + continue; + + err = abs(iv->reg_fr_time - fr_time); + if (err < min_err) { + fiv = iv; + min_err = err; + } + } + s5k6aa->fiv = fiv; + + v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n", + fiv->reg_fr_time * 100); + return 0; +} + +static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret; + + v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n", + fi->interval.numerator, fi->interval.denominator); + + mutex_lock(&s5k6aa->lock); + ret = __s5k6aa_set_frame_interval(s5k6aa, fi); + s5k6aa->apply_cfg = 1; + + mutex_unlock(&s5k6aa->lock); + return ret; +} + +/* + * V4L2 subdev pad level and video operations + */ +static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_interval_enum *fie) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + const struct s5k6aa_interval *fi; + int ret = 0; + + if (fie->index > ARRAY_SIZE(s5k6aa_intervals)) + return -EINVAL; + + v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN, + S5K6AA_WIN_WIDTH_MAX, 1, + &fie->height, S5K6AA_WIN_HEIGHT_MIN, + S5K6AA_WIN_HEIGHT_MAX, 1, 0); + + mutex_lock(&s5k6aa->lock); + fi = &s5k6aa_intervals[fie->index]; + if (fie->width > fi->size.width || fie->height > fi->size.height) + ret = -EINVAL; + else + fie->interval = fi->interval; + mutex_unlock(&s5k6aa->lock); + + return ret; +} + +static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(s5k6aa_formats)) + return -EINVAL; + + code->code = s5k6aa_formats[code->index].code; + return 0; +} + +static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + int i = ARRAY_SIZE(s5k6aa_formats); + + if (fse->index > 0) + return -EINVAL; + + while (--i) + if (fse->code == s5k6aa_formats[i].code) + break; + + fse->code = s5k6aa_formats[i].code; + fse->min_width = S5K6AA_WIN_WIDTH_MIN; + fse->max_width = S5K6AA_WIN_WIDTH_MAX; + fse->max_height = S5K6AA_WIN_HEIGHT_MIN; + fse->min_height = S5K6AA_WIN_HEIGHT_MAX; + + return 0; +} + +static struct v4l2_rect * +__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + return &s5k6aa->ccd_rect; + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(fh, 0); + + return NULL; +} + +static void s5k6aa_try_format(struct s5k6aa *s5k6aa, + struct v4l2_mbus_framefmt *mf) +{ + unsigned int index; + + v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN, + S5K6AA_WIN_WIDTH_MAX, 1, + &mf->height, S5K6AA_WIN_HEIGHT_MIN, + S5K6AA_WIN_HEIGHT_MAX, 1, 0); + + if (mf->colorspace != V4L2_COLORSPACE_JPEG && + mf->colorspace != V4L2_COLORSPACE_REC709) + mf->colorspace = V4L2_COLORSPACE_JPEG; + + index = s5k6aa_get_pixfmt_index(s5k6aa, mf); + + mf->colorspace = s5k6aa_formats[index].colorspace; + mf->code = s5k6aa_formats[index].code; + mf->field = V4L2_FIELD_NONE; +} + +static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + struct v4l2_mbus_framefmt *mf; + + memset(fmt->reserved, 0, sizeof(fmt->reserved)); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, 0); + fmt->format = *mf; + return 0; + } + + mutex_lock(&s5k6aa->lock); + fmt->format = s5k6aa->preset->mbus_fmt; + mutex_unlock(&s5k6aa->lock); + + return 0; +} + +static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + struct s5k6aa_preset *preset = s5k6aa->preset; + struct v4l2_mbus_framefmt *mf; + struct v4l2_rect *crop; + int ret = 0; + + mutex_lock(&s5k6aa->lock); + s5k6aa_try_format(s5k6aa, &fmt->format); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + crop = v4l2_subdev_get_try_crop(fh, 0); + } else { + if (s5k6aa->streaming) { + ret = -EBUSY; + } else { + mf = &preset->mbus_fmt; + crop = &s5k6aa->ccd_rect; + s5k6aa->apply_cfg = 1; + } + } + + if (ret == 0) { + struct v4l2_subdev_frame_interval fiv = { + .interval = {0, 1} + }; + + *mf = fmt->format; + /* + * Make sure the crop window is valid, i.e. its size is + * greater than the output window, as the ISP supports + * only down-scaling. + */ + crop->width = clamp_t(unsigned int, crop->width, mf->width, + S5K6AA_WIN_WIDTH_MAX); + crop->height = clamp_t(unsigned int, crop->height, mf->height, + S5K6AA_WIN_HEIGHT_MAX); + crop->left = clamp_t(unsigned int, crop->left, 0, + S5K6AA_WIN_WIDTH_MAX - crop->width); + crop->top = clamp_t(unsigned int, crop->top, 0, + S5K6AA_WIN_HEIGHT_MAX - crop->height); + + /* Reset to minimum possible frame interval */ + ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv); + } + mutex_unlock(&s5k6aa->lock); + + return ret; +} + +static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + struct v4l2_rect *rect; + + memset(crop->reserved, 0, sizeof(crop->reserved)); + mutex_lock(&s5k6aa->lock); + + rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); + if (rect) + crop->rect = *rect; + + mutex_unlock(&s5k6aa->lock); + + v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n", + rect->left, rect->top, rect->width, rect->height); + + return 0; +} + +static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + struct v4l2_mbus_framefmt *mf; + unsigned int max_x, max_y; + struct v4l2_rect *crop_r; + + mutex_lock(&s5k6aa->lock); + crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); + + if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + mf = &s5k6aa->preset->mbus_fmt; + s5k6aa->apply_crop = 1; + } else { + mf = v4l2_subdev_get_try_format(fh, 0); + } + v4l_bound_align_image(&crop->rect.width, mf->width, + S5K6AA_WIN_WIDTH_MAX, 1, + &crop->rect.height, mf->height, + S5K6AA_WIN_HEIGHT_MAX, 1, 0); + + max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1; + max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1; + + crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x); + crop->rect.top = clamp_t(unsigned int, crop->rect.top, 0, max_y); + + *crop_r = crop->rect; + + mutex_unlock(&s5k6aa->lock); + + v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n", + crop_r->left, crop_r->top, crop_r->width, crop_r->height); + + return 0; +} + +static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = { + .enum_mbus_code = s5k6aa_enum_mbus_code, + .enum_frame_size = s5k6aa_enum_frame_size, + .enum_frame_interval = s5k6aa_enum_frame_interval, + .get_fmt = s5k6aa_get_fmt, + .set_fmt = s5k6aa_set_fmt, + .get_crop = s5k6aa_get_crop, + .set_crop = s5k6aa_set_crop, +}; + +static const struct v4l2_subdev_video_ops s5k6aa_video_ops = { + .g_frame_interval = s5k6aa_g_frame_interval, + .s_frame_interval = s5k6aa_s_frame_interval, + .s_stream = s5k6aa_s_stream, +}; + +/* + * V4L2 subdev controls + */ + +static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int idx, err = 0; + + v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val); + + mutex_lock(&s5k6aa->lock); + /* + * If the device is not powered up by the host driver do + * not apply any controls to H/W at this time. Instead + * the controls will be restored right after power-up. + */ + if (s5k6aa->power == 0) + goto unlock; + idx = s5k6aa->preset->index; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + err = s5k6aa_set_awb(s5k6aa, ctrl->val); + break; + + case V4L2_CID_BRIGHTNESS: + err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val); + break; + + case V4L2_CID_COLORFX: + err = s5k6aa_set_colorfx(s5k6aa, ctrl->val); + break; + + case V4L2_CID_CONTRAST: + err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val); + break; + + case V4L2_CID_EXPOSURE_AUTO: + err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val); + break; + + case V4L2_CID_HFLIP: + err = s5k6aa_set_mirror(s5k6aa, ctrl->val); + if (err) + break; + err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); + break; + + case V4L2_CID_POWER_LINE_FREQUENCY: + err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val); + break; + + case V4L2_CID_SATURATION: + err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val); + break; + + case V4L2_CID_SHARPNESS: + err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val); + break; + + case V4L2_CID_WHITE_BALANCE_TEMPERATURE: + err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val); + if (err) + break; + err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); + break; + } +unlock: + mutex_unlock(&s5k6aa->lock); + return err; +} + +static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = { + .s_ctrl = s5k6aa_s_ctrl, +}; + +static int s5k6aa_log_status(struct v4l2_subdev *sd) +{ + v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); + return 0; +} + +#define V4L2_CID_RED_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1001) +#define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002) +#define V4L2_CID_BLUE_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1003) + +static const struct v4l2_ctrl_config s5k6aa_ctrls[] = { + { + .ops = &s5k6aa_ctrl_ops, + .id = V4L2_CID_RED_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Red", + .min = 0, + .max = 256, + .def = 127, + .step = 1, + }, { + .ops = &s5k6aa_ctrl_ops, + .id = V4L2_CID_GREEN_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Green", + .min = 0, + .max = 256, + .def = 127, + .step = 1, + }, { + .ops = &s5k6aa_ctrl_ops, + .id = V4L2_CID_BLUE_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Blue", + .min = 0, + .max = 256, + .def = 127, + .step = 1, + }, +}; + +static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa) +{ + const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops; + struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + + int ret = v4l2_ctrl_handler_init(hdl, 16); + if (ret) + return ret; + /* Auto white balance cluster */ + ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); + ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL); + ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL); + ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL); + v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false); + + ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_cluster(2, &ctrls->hflip); + + ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, + V4L2_CID_EXPOSURE_AUTO, + V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); + /* Exposure time: x 1 us */ + ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, + 0, 6000000U, 1, 100000U); + /* Total gain: 256 <=> 1x */ + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, + 0, 256, 1, 256); + v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false); + + v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO); + + v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX, + V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE); + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE, + 0, 256, 1, 0); + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0); + + if (hdl->error) { + ret = hdl->error; + v4l2_ctrl_handler_free(hdl); + return ret; + } + + s5k6aa->sd.ctrl_handler = hdl; + return 0; +} + +/* + * V4L2 subdev internal operations + */ +static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0); + + format->colorspace = s5k6aa_formats[0].colorspace; + format->code = s5k6aa_formats[0].code; + format->width = S5K6AA_OUT_WIDTH_DEF; + format->height = S5K6AA_OUT_HEIGHT_DEF; + format->field = V4L2_FIELD_NONE; + + crop->width = S5K6AA_WIN_WIDTH_MAX; + crop->height = S5K6AA_WIN_HEIGHT_MAX; + crop->left = 0; + crop->top = 0; + + return 0; +} + +int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + u16 api_ver = 0, fw_rev = 0; + + int ret = s5k6aa_set_ahb_address(client); + + if (!ret) + ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver); + if (!ret) + ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev); + if (ret) { + v4l2_err(&s5k6aa->sd, "FW revision check failed!\n"); + return ret; + } + + v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n", + api_ver, fw_rev); + + return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV; +} + +static int s5k6aa_registered(struct v4l2_subdev *sd) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret; + + mutex_lock(&s5k6aa->lock); + ret = __s5k6aa_power_on(s5k6aa); + if (!ret) { + msleep(100); + ret = s5k6aa_check_fw_revision(s5k6aa); + __s5k6aa_power_off(s5k6aa); + } + mutex_unlock(&s5k6aa->lock); + + return ret; +} + +static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = { + .registered = s5k6aa_registered, + .open = s5k6aa_open, +}; + +static const struct v4l2_subdev_core_ops s5k6aa_core_ops = { + .s_power = s5k6aa_set_power, + .log_status = s5k6aa_log_status, +}; + +static const struct v4l2_subdev_ops s5k6aa_subdev_ops = { + .core = &s5k6aa_core_ops, + .pad = &s5k6aa_pad_ops, + .video = &s5k6aa_video_ops, +}; + +/* + * GPIO setup + */ +static int s5k6aa_configure_gpio(int nr, int val, const char *name) +{ + unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + int ret; + + if (!gpio_is_valid(nr)) + return 0; + ret = gpio_request_one(nr, flags, name); + if (!ret) + gpio_export(nr, 0); + return ret; +} + +static void s5k6aa_free_gpios(struct s5k6aa *s5k6aa) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s5k6aa->gpio); i++) { + if (!gpio_is_valid(s5k6aa->gpio[i].gpio)) + continue; + gpio_free(s5k6aa->gpio[i].gpio); + s5k6aa->gpio[i].gpio = -EINVAL; + } +} + +static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa, + const struct s5k6aa_platform_data *pdata) +{ + const struct s5k6aa_gpio *gpio = &pdata->gpio_stby; + int ret; + + s5k6aa->gpio[STBY].gpio = -EINVAL; + s5k6aa->gpio[RST].gpio = -EINVAL; + + ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_STBY"); + if (ret) { + s5k6aa_free_gpios(s5k6aa); + return ret; + } + s5k6aa->gpio[STBY] = *gpio; + if (gpio_is_valid(gpio->gpio)) + gpio_set_value(gpio->gpio, 0); + + gpio = &pdata->gpio_reset; + ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_RST"); + if (ret) { + s5k6aa_free_gpios(s5k6aa); + return ret; + } + s5k6aa->gpio[RST] = *gpio; + if (gpio_is_valid(gpio->gpio)) + gpio_set_value(gpio->gpio, 0); + + return 0; +} + +static int s5k6aa_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct s5k6aa_platform_data *pdata = client->dev.platform_data; + struct v4l2_subdev *sd; + struct s5k6aa *s5k6aa; + int i, ret; + + if (pdata == NULL) { + dev_err(&client->dev, "Platform data not specified\n"); + return -EINVAL; + } + + if (pdata->mclk_frequency == 0) { + dev_err(&client->dev, "MCLK frequency not specified\n"); + return -EINVAL; + } + + s5k6aa = kzalloc(sizeof(*s5k6aa), GFP_KERNEL); + if (!s5k6aa) + return -ENOMEM; + + mutex_init(&s5k6aa->lock); + + s5k6aa->mclk_frequency = pdata->mclk_frequency; + s5k6aa->bus_type = pdata->bus_type; + s5k6aa->mipi_lanes = pdata->nlanes; + s5k6aa->s_power = pdata->set_power; + s5k6aa->inv_hflip = pdata->horiz_flip; + s5k6aa->inv_vflip = pdata->vert_flip; + + sd = &s5k6aa->sd; + strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); + v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); + + sd->internal_ops = &s5k6aa_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; + ret = media_entity_init(&sd->entity, 1, &s5k6aa->pad, 0); + if (ret) + goto out_err1; + + ret = s5k6aa_configure_gpios(s5k6aa, pdata); + if (ret) + goto out_err2; + + for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++) + s5k6aa->supplies[i].supply = s5k6aa_supply_names[i]; + + ret = regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES, + s5k6aa->supplies); + if (ret) { + dev_err(&client->dev, "Failed to get regulators\n"); + goto out_err3; + } + + ret = s5k6aa_initialize_ctrls(s5k6aa); + if (ret) + goto out_err4; + + s5k6aa_presets_data_init(s5k6aa); + + s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX; + s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX; + s5k6aa->ccd_rect.left = 0; + s5k6aa->ccd_rect.top = 0; + + return 0; + +out_err4: + regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); +out_err3: + s5k6aa_free_gpios(s5k6aa); +out_err2: + media_entity_cleanup(&s5k6aa->sd.entity); +out_err1: + kfree(s5k6aa); + return ret; +} + +static int s5k6aa_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(sd->ctrl_handler); + media_entity_cleanup(&sd->entity); + regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); + s5k6aa_free_gpios(s5k6aa); + kfree(s5k6aa); + + return 0; +} + +static const struct i2c_device_id s5k6aa_id[] = { + { DRIVER_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, s5k6aa_id); + + +static struct i2c_driver s5k6aa_i2c_driver = { + .driver = { + .name = DRIVER_NAME + }, + .probe = s5k6aa_probe, + .remove = s5k6aa_remove, + .id_table = s5k6aa_id, +}; + +static int __init s5k6aa_init(void) +{ + return i2c_add_driver(&s5k6aa_i2c_driver); +} + +static void __exit s5k6aa_exit(void) +{ + i2c_del_driver(&s5k6aa_i2c_driver); +} + +module_init(s5k6aa_init); +module_exit(s5k6aa_exit); + +MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver"); +MODULE_AUTHOR("Sylwester Nawrocki "); +MODULE_LICENSE("GPL"); diff --git a/include/media/s5k6aa.h b/include/media/s5k6aa.h new file mode 100644 index 000000000000..ba34f7055e55 --- /dev/null +++ b/include/media/s5k6aa.h @@ -0,0 +1,51 @@ +/* + * S5K6AAFX camera sensor driver header + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef S5K6AA_H +#define S5K6AA_H + +#include + +/** + * struct s5k6aa_gpio - data structure describing a GPIO + * @gpio: GPIO number + * @level: indicates active state of the @gpio + */ +struct s5k6aa_gpio { + int gpio; + int level; +}; + +/** + * struct s5k6aa_platform_data - s5k6aa driver platform data + * @set_power: an additional callback to the board code, called + * after enabling the regulators and before switching + * the sensor off + * @mclk_frequency: sensor's master clock frequency in Hz + * @gpio_reset: GPIO driving RESET pin + * @gpio_stby: GPIO driving STBY pin + * @nlanes: maximum number of MIPI-CSI lanes used + * @horiz_flip: default horizontal image flip value, non zero to enable + * @vert_flip: default vertical image flip value, non zero to enable + */ + +struct s5k6aa_platform_data { + int (*set_power)(int enable); + unsigned long mclk_frequency; + struct s5k6aa_gpio gpio_reset; + struct s5k6aa_gpio gpio_stby; + enum v4l2_mbus_type bus_type; + u8 nlanes; + u8 horiz_flip; + u8 vert_flip; +}; + +#endif /* S5K6AA_H */ From 6f524ec156ba31a18425fad9dd1287be0701d9d1 Mon Sep 17 00:00:00 2001 From: Scott Jiang <[scott.jiang.linux@gmail.com]> Date: Wed, 21 Sep 2011 09:25:23 -0300 Subject: [PATCH 128/144] [media] vb2: add vb2_get_unmapped_area in vb2 core no mmu system needs get_unmapped_area file operations to do mmap Signed-off-by: Scott Jiang Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 31 ++++++++++++++++++++++++++++ include/media/videobuf2-core.h | 7 +++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 9005dc9991ab..979e544388cb 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -1567,6 +1567,37 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) } EXPORT_SYMBOL_GPL(vb2_mmap); +#ifndef CONFIG_MMU +unsigned long vb2_get_unmapped_area(struct vb2_queue *q, + unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags) +{ + unsigned long off = pgoff << PAGE_SHIFT; + struct vb2_buffer *vb; + unsigned int buffer, plane; + int ret; + + if (q->memory != V4L2_MEMORY_MMAP) { + dprintk(1, "Queue is not currently set up for mmap\n"); + return -EINVAL; + } + + /* + * Find the plane corresponding to the offset passed by userspace. + */ + ret = __find_plane_by_offset(q, off, &buffer, &plane); + if (ret) + return ret; + + vb = q->bufs[buffer]; + + return (unsigned long)vb2_plane_vaddr(vb, plane); +} +EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); +#endif + static int __vb2_init_fileio(struct vb2_queue *q, int read); static int __vb2_cleanup_fileio(struct vb2_queue *q); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 55c57d3d3e63..a15d1f1b319e 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -322,6 +322,13 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type); int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type); int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma); +#ifndef CONFIG_MMU +unsigned long vb2_get_unmapped_area(struct vb2_queue *q, + unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags); +#endif unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait); size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, loff_t *ppos, int nonblock); From 57f6217be1d129e3e38bac3eadc20cbf909666b6 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 30 Sep 2011 07:56:02 -0300 Subject: [PATCH 129/144] [media] MFC: Change MFC firmware binary name This patch renames the MFC firmware binary to avoid SoC name in it. Signed-off-by: Sachin Kamat Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c index 5f4da80051bb..f2481a85e0a2 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c @@ -38,7 +38,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) * into kernel. */ mfc_debug_enter(); err = request_firmware((const struct firmware **)&fw_blob, - "s5pc110-mfc.fw", dev->v4l2_dev.dev); + "s5p-mfc.fw", dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; @@ -116,7 +116,7 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) * into kernel. */ mfc_debug_enter(); err = request_firmware((const struct firmware **)&fw_blob, - "s5pc110-mfc.fw", dev->v4l2_dev.dev); + "s5p-mfc.fw", dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; From 63b4ca23ed2b35742bebf8cb2af49b84b24442c6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 22 Sep 2011 16:54:34 -0300 Subject: [PATCH 130/144] [media] omap3isp: Move media_entity_cleanup() from unregister() to cleanup() The media_entity_cleanup() function belong to the module cleanup handlers, not the entity registration handlers. Move it there. Create a omap3isp_video_cleanup() function to cleanup the video node entity, and call it from the module cleanup handlers. Rename omap3isp_stat_free() to omap3isp_stat_cleanup(). Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 5 +++-- drivers/media/video/omap3isp/ispccp2.c | 5 +++-- drivers/media/video/omap3isp/ispcsi2.c | 6 ++++-- drivers/media/video/omap3isp/isph3a_aewb.c | 2 +- drivers/media/video/omap3isp/isph3a_af.c | 2 +- drivers/media/video/omap3isp/isphist.c | 2 +- drivers/media/video/omap3isp/isppreview.c | 9 ++++++--- drivers/media/video/omap3isp/ispresizer.c | 7 +++++-- drivers/media/video/omap3isp/ispstat.c | 4 ++-- drivers/media/video/omap3isp/ispstat.h | 2 +- drivers/media/video/omap3isp/ispvideo.c | 9 ++++++--- drivers/media/video/omap3isp/ispvideo.h | 1 + 12 files changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 253fdcce2df2..98804d5f89c2 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -2206,8 +2206,6 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) { - media_entity_cleanup(&ccdc->subdev.entity); - v4l2_device_unregister_subdev(&ccdc->subdev); omap3isp_video_unregister(&ccdc->video_out); } @@ -2287,6 +2285,9 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) { struct isp_ccdc_device *ccdc = &isp->isp_ccdc; + omap3isp_video_cleanup(&ccdc->video_out); + media_entity_cleanup(&ccdc->subdev.entity); + /* Free LSC requests. As the CCDC is stopped there's no active request, * so only the pending request and the free queue need to be handled. */ diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index fa1d09b0ad98..b8e0863b194c 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -1100,8 +1100,6 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) */ void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) { - media_entity_cleanup(&ccp2->subdev.entity); - v4l2_device_unregister_subdev(&ccp2->subdev); omap3isp_video_unregister(&ccp2->video_in); } @@ -1146,6 +1144,9 @@ void omap3isp_ccp2_cleanup(struct isp_device *isp) { struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; + omap3isp_video_cleanup(&ccp2->video_in); + media_entity_cleanup(&ccp2->subdev.entity); + regulator_put(ccp2->vdds_csib); } diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 69161a682b3d..5612e95ac0b8 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -1241,8 +1241,6 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) { - media_entity_cleanup(&csi2->subdev.entity); - v4l2_device_unregister_subdev(&csi2->subdev); omap3isp_video_unregister(&csi2->video_out); } @@ -1277,6 +1275,10 @@ error: */ void omap3isp_csi2_cleanup(struct isp_device *isp) { + struct isp_csi2_device *csi2a = &isp->isp_csi2a; + + omap3isp_video_cleanup(&csi2a->video_out); + media_entity_cleanup(&csi2a->subdev.entity); } /* diff --git a/drivers/media/video/omap3isp/isph3a_aewb.c b/drivers/media/video/omap3isp/isph3a_aewb.c index 8068cefd8d89..a3c76bf18175 100644 --- a/drivers/media/video/omap3isp/isph3a_aewb.c +++ b/drivers/media/video/omap3isp/isph3a_aewb.c @@ -370,5 +370,5 @@ void omap3isp_h3a_aewb_cleanup(struct isp_device *isp) { kfree(isp->isp_aewb.priv); kfree(isp->isp_aewb.recover_priv); - omap3isp_stat_free(&isp->isp_aewb); + omap3isp_stat_cleanup(&isp->isp_aewb); } diff --git a/drivers/media/video/omap3isp/isph3a_af.c b/drivers/media/video/omap3isp/isph3a_af.c index ba54d0acdecf..58e0bc414899 100644 --- a/drivers/media/video/omap3isp/isph3a_af.c +++ b/drivers/media/video/omap3isp/isph3a_af.c @@ -425,5 +425,5 @@ void omap3isp_h3a_af_cleanup(struct isp_device *isp) { kfree(isp->isp_af.priv); kfree(isp->isp_af.recover_priv); - omap3isp_stat_free(&isp->isp_af); + omap3isp_stat_cleanup(&isp->isp_af); } diff --git a/drivers/media/video/omap3isp/isphist.c b/drivers/media/video/omap3isp/isphist.c index 1743856b30d1..1163907bcddc 100644 --- a/drivers/media/video/omap3isp/isphist.c +++ b/drivers/media/video/omap3isp/isphist.c @@ -516,5 +516,5 @@ void omap3isp_hist_cleanup(struct isp_device *isp) if (HIST_USING_DMA(&isp->isp_hist)) omap_free_dma(isp->isp_hist.dma_ch); kfree(isp->isp_hist.priv); - omap3isp_stat_free(&isp->isp_hist); + omap3isp_stat_cleanup(&isp->isp_hist); } diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index aba537af87e4..84a18b66b23c 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -2046,10 +2046,7 @@ static int preview_init_entities(struct isp_prev_device *prev) void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) { - media_entity_cleanup(&prev->subdev.entity); - v4l2_device_unregister_subdev(&prev->subdev); - v4l2_ctrl_handler_free(&prev->ctrls); omap3isp_video_unregister(&prev->video_in); omap3isp_video_unregister(&prev->video_out); } @@ -2085,6 +2082,12 @@ error: void omap3isp_preview_cleanup(struct isp_device *isp) { + struct isp_prev_device *prev = &isp->isp_prev; + + v4l2_ctrl_handler_free(&prev->ctrls); + omap3isp_video_cleanup(&prev->video_in); + omap3isp_video_cleanup(&prev->video_out); + media_entity_cleanup(&prev->subdev.entity); } /* diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 0bb0f8cd36f5..78ce0406a232 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1674,8 +1674,6 @@ static int resizer_init_entities(struct isp_res_device *res) void omap3isp_resizer_unregister_entities(struct isp_res_device *res) { - media_entity_cleanup(&res->subdev.entity); - v4l2_device_unregister_subdev(&res->subdev); omap3isp_video_unregister(&res->video_in); omap3isp_video_unregister(&res->video_out); @@ -1712,6 +1710,11 @@ error: void omap3isp_resizer_cleanup(struct isp_device *isp) { + struct isp_res_device *res = &isp->isp_res; + + omap3isp_video_cleanup(&res->video_in); + omap3isp_video_cleanup(&res->video_out); + media_entity_cleanup(&res->subdev.entity); } /* diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index 732905552261..bf0e5a771857 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -1062,7 +1062,6 @@ int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, void omap3isp_stat_unregister_entities(struct ispstat *stat) { - media_entity_cleanup(&stat->subdev.entity); v4l2_device_unregister_subdev(&stat->subdev); } @@ -1085,8 +1084,9 @@ int omap3isp_stat_init(struct ispstat *stat, const char *name, return isp_stat_init_entities(stat, name, sd_ops); } -void omap3isp_stat_free(struct ispstat *stat) +void omap3isp_stat_cleanup(struct ispstat *stat) { + media_entity_cleanup(&stat->subdev.entity); isp_stat_bufs_free(stat); kfree(stat->buf); } diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index d86da94fa50d..9b7c8654dc8a 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h @@ -144,7 +144,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat, struct omap3isp_stat_data *data); int omap3isp_stat_init(struct ispstat *stat, const char *name, const struct v4l2_subdev_ops *sd_ops); -void omap3isp_stat_free(struct ispstat *stat); +void omap3isp_stat_cleanup(struct ispstat *stat); int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, struct v4l2_event_subscription *sub); diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 0cb8a9f9d675..7d74ebbdb63b 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -1325,6 +1325,11 @@ int omap3isp_video_init(struct isp_video *video, const char *name) return 0; } +void omap3isp_video_cleanup(struct isp_video *video) +{ + media_entity_cleanup(&video->video.entity); +} + int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) { int ret; @@ -1341,8 +1346,6 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) void omap3isp_video_unregister(struct isp_video *video) { - if (video_is_registered(&video->video)) { - media_entity_cleanup(&video->video.entity); + if (video_is_registered(&video->video)) video_unregister_device(&video->video); - } } diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 53160aa24e6e..08cbfa144e6e 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -190,6 +190,7 @@ struct isp_video_fh { container_of(q, struct isp_video_fh, queue) int omap3isp_video_init(struct isp_video *video, const char *name); +void omap3isp_video_cleanup(struct isp_video *video); int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev); void omap3isp_video_unregister(struct isp_video *video); From 39099d09ae4605003696919d7c3a6e8a96607c4b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 22 Sep 2011 16:59:26 -0300 Subject: [PATCH 131/144] [media] omap3isp: Move *_init_entities() functions to the init/cleanup section Group all init/cleanup functions together to make the code more readable. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 62 ++++++------ drivers/media/video/omap3isp/ispccp2.c | 112 +++++++++++----------- drivers/media/video/omap3isp/ispcsi2.c | 84 ++++++++-------- drivers/media/video/omap3isp/isppreview.c | 94 +++++++++--------- drivers/media/video/omap3isp/ispresizer.c | 90 ++++++++--------- drivers/media/video/omap3isp/ispstat.c | 36 +++---- 6 files changed, 239 insertions(+), 239 deletions(-) diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 98804d5f89c2..c30cc59d7032 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -2152,6 +2152,37 @@ static const struct media_entity_operations ccdc_media_ops = { .link_setup = ccdc_link_setup, }; +void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) +{ + v4l2_device_unregister_subdev(&ccdc->subdev); + omap3isp_video_unregister(&ccdc->video_out); +} + +int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video node. */ + ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&ccdc->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_ccdc_unregister_entities(ccdc); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP CCDC initialisation and cleanup + */ + /* * ccdc_init_entities - Initialize V4L2 subdev and media entity * @ccdc: ISP CCDC module @@ -2204,37 +2235,6 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) return 0; } -void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) -{ - v4l2_device_unregister_subdev(&ccdc->subdev); - omap3isp_video_unregister(&ccdc->video_out); -} - -int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video node. */ - ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&ccdc->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_ccdc_unregister_entities(ccdc); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP CCDC initialisation and cleanup - */ - /* * omap3isp_ccdc_init - CCDC module initialization. * @dev: Device pointer specific to the OMAP3 ISP. diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index b8e0863b194c..883a2825cb41 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -1031,6 +1031,48 @@ static const struct media_entity_operations ccp2_media_ops = { .link_setup = ccp2_link_setup, }; +/* + * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev + * @ccp2: Pointer to ISP CCP2 device + */ +void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) +{ + v4l2_device_unregister_subdev(&ccp2->subdev); + omap3isp_video_unregister(&ccp2->video_in); +} + +/* + * omap3isp_ccp2_register_entities - Register the subdev media entity + * @ccp2: Pointer to ISP CCP2 device + * @vdev: Pointer to v4l device + * return negative error code or zero on success + */ + +int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&ccp2->video_in, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_ccp2_unregister_entities(ccp2); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP ccp2 initialisation and cleanup + */ + /* * ccp2_init_entities - Initialize ccp2 subdev and media entity. * @ccp2: Pointer to ISP CCP2 device @@ -1094,62 +1136,6 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) return 0; } -/* - * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev - * @ccp2: Pointer to ISP CCP2 device - */ -void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) -{ - v4l2_device_unregister_subdev(&ccp2->subdev); - omap3isp_video_unregister(&ccp2->video_in); -} - -/* - * omap3isp_ccp2_register_entities - Register the subdev media entity - * @ccp2: Pointer to ISP CCP2 device - * @vdev: Pointer to v4l device - * return negative error code or zero on success - */ - -int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&ccp2->video_in, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_ccp2_unregister_entities(ccp2); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP ccp2 initialisation and cleanup - */ - -/* - * omap3isp_ccp2_cleanup - CCP2 un-initialization - * @isp : Pointer to ISP device - */ -void omap3isp_ccp2_cleanup(struct isp_device *isp) -{ - struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; - - omap3isp_video_cleanup(&ccp2->video_in); - media_entity_cleanup(&ccp2->subdev.entity); - - regulator_put(ccp2->vdds_csib); -} - /* * omap3isp_ccp2_init - CCP2 initialization. * @isp : Pointer to ISP device @@ -1195,3 +1181,17 @@ out: return ret; } + +/* + * omap3isp_ccp2_cleanup - CCP2 un-initialization + * @isp : Pointer to ISP device + */ +void omap3isp_ccp2_cleanup(struct isp_device *isp) +{ + struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; + + omap3isp_video_cleanup(&ccp2->video_in); + media_entity_cleanup(&ccp2->subdev.entity); + + regulator_put(ccp2->vdds_csib); +} diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 5612e95ac0b8..2c9bffcdc5c9 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -1187,6 +1187,37 @@ static const struct media_entity_operations csi2_media_ops = { .link_setup = csi2_link_setup, }; +void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) +{ + v4l2_device_unregister_subdev(&csi2->subdev); + omap3isp_video_unregister(&csi2->video_out); +} + +int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &csi2->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&csi2->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_csi2_unregister_entities(csi2); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP CSI2 initialisation and cleanup + */ + /* * csi2_init_entities - Initialize subdev and media entity. * @csi2: Pointer to csi2 structure. @@ -1239,48 +1270,6 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) return 0; } -void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) -{ - v4l2_device_unregister_subdev(&csi2->subdev); - omap3isp_video_unregister(&csi2->video_out); -} - -int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &csi2->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&csi2->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_csi2_unregister_entities(csi2); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP CSI2 initialisation and cleanup - */ - -/* - * omap3isp_csi2_cleanup - Routine for module driver cleanup - */ -void omap3isp_csi2_cleanup(struct isp_device *isp) -{ - struct isp_csi2_device *csi2a = &isp->isp_csi2a; - - omap3isp_video_cleanup(&csi2a->video_out); - media_entity_cleanup(&csi2a->subdev.entity); -} - /* * omap3isp_csi2_init - Routine for module driver init */ @@ -1317,3 +1306,14 @@ fail: omap3isp_csi2_cleanup(isp); return ret; } + +/* + * omap3isp_csi2_cleanup - Routine for module driver cleanup + */ +void omap3isp_csi2_cleanup(struct isp_device *isp) +{ + struct isp_csi2_device *csi2a = &isp->isp_csi2a; + + omap3isp_video_cleanup(&csi2a->video_out); + media_entity_cleanup(&csi2a->subdev.entity); +} diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index 84a18b66b23c..b926ebbaca3a 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -1966,8 +1966,44 @@ static const struct media_entity_operations preview_media_ops = { .link_setup = preview_link_setup, }; +void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) +{ + v4l2_device_unregister_subdev(&prev->subdev); + omap3isp_video_unregister(&prev->video_in); + omap3isp_video_unregister(&prev->video_out); +} + +int omap3isp_preview_register_entities(struct isp_prev_device *prev, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &prev->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&prev->video_in, vdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&prev->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_preview_unregister_entities(prev); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP previewer initialisation and cleanup + */ + /* - * review_init_entities - Initialize subdev and media entity. + * preview_init_entities - Initialize subdev and media entity. * @prev : Pointer to preview structure * return -ENOMEM or zero on success */ @@ -2044,52 +2080,6 @@ static int preview_init_entities(struct isp_prev_device *prev) return 0; } -void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) -{ - v4l2_device_unregister_subdev(&prev->subdev); - omap3isp_video_unregister(&prev->video_in); - omap3isp_video_unregister(&prev->video_out); -} - -int omap3isp_preview_register_entities(struct isp_prev_device *prev, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &prev->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&prev->video_in, vdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&prev->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_preview_unregister_entities(prev); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP previewer initialisation and cleanup - */ - -void omap3isp_preview_cleanup(struct isp_device *isp) -{ - struct isp_prev_device *prev = &isp->isp_prev; - - v4l2_ctrl_handler_free(&prev->ctrls); - omap3isp_video_cleanup(&prev->video_in); - omap3isp_video_cleanup(&prev->video_out); - media_entity_cleanup(&prev->subdev.entity); -} - /* * isp_preview_init - Previewer initialization. * @dev : Pointer to ISP device @@ -2114,3 +2104,13 @@ out: return ret; } + +void omap3isp_preview_cleanup(struct isp_device *isp) +{ + struct isp_prev_device *prev = &isp->isp_prev; + + v4l2_ctrl_handler_free(&prev->ctrls); + omap3isp_video_cleanup(&prev->video_in); + omap3isp_video_cleanup(&prev->video_out); + media_entity_cleanup(&prev->subdev.entity); +} diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 78ce0406a232..224b0b90404d 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1608,6 +1608,42 @@ static const struct media_entity_operations resizer_media_ops = { .link_setup = resizer_link_setup, }; +void omap3isp_resizer_unregister_entities(struct isp_res_device *res) +{ + v4l2_device_unregister_subdev(&res->subdev); + omap3isp_video_unregister(&res->video_in); + omap3isp_video_unregister(&res->video_out); +} + +int omap3isp_resizer_register_entities(struct isp_res_device *res, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &res->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&res->video_in, vdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&res->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_resizer_unregister_entities(res); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP resizer initialization and cleanup + */ + /* * resizer_init_entities - Initialize resizer subdev and media entity. * @res : Pointer to resizer device structure @@ -1672,51 +1708,6 @@ static int resizer_init_entities(struct isp_res_device *res) return 0; } -void omap3isp_resizer_unregister_entities(struct isp_res_device *res) -{ - v4l2_device_unregister_subdev(&res->subdev); - omap3isp_video_unregister(&res->video_in); - omap3isp_video_unregister(&res->video_out); -} - -int omap3isp_resizer_register_entities(struct isp_res_device *res, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &res->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&res->video_in, vdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&res->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_resizer_unregister_entities(res); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP resizer initialization and cleanup - */ - -void omap3isp_resizer_cleanup(struct isp_device *isp) -{ - struct isp_res_device *res = &isp->isp_res; - - omap3isp_video_cleanup(&res->video_in); - omap3isp_video_cleanup(&res->video_out); - media_entity_cleanup(&res->subdev.entity); -} - /* * isp_resizer_init - Resizer initialization. * @isp : Pointer to ISP device @@ -1739,3 +1730,12 @@ out: return ret; } + +void omap3isp_resizer_cleanup(struct isp_device *isp) +{ + struct isp_res_device *res = &isp->isp_res; + + omap3isp_video_cleanup(&res->video_in); + omap3isp_video_cleanup(&res->video_out); + media_entity_cleanup(&res->subdev.entity); +} diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index bf0e5a771857..b124326d1e7f 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -1023,24 +1023,6 @@ void omap3isp_stat_dma_isr(struct ispstat *stat) __stat_isr(stat, 1); } -static int isp_stat_init_entities(struct ispstat *stat, const char *name, - const struct v4l2_subdev_ops *sd_ops) -{ - struct v4l2_subdev *subdev = &stat->subdev; - struct media_entity *me = &subdev->entity; - - v4l2_subdev_init(subdev, sd_ops); - snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); - subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ - subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - v4l2_set_subdevdata(subdev, stat); - - stat->pad.flags = MEDIA_PAD_FL_SINK; - me->ops = NULL; - - return media_entity_init(me, 1, &stat->pad, 0); -} - int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, struct v4l2_event_subscription *sub) @@ -1071,6 +1053,24 @@ int omap3isp_stat_register_entities(struct ispstat *stat, return v4l2_device_register_subdev(vdev, &stat->subdev); } +static int isp_stat_init_entities(struct ispstat *stat, const char *name, + const struct v4l2_subdev_ops *sd_ops) +{ + struct v4l2_subdev *subdev = &stat->subdev; + struct media_entity *me = &subdev->entity; + + v4l2_subdev_init(subdev, sd_ops); + snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); + subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ + subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; + v4l2_set_subdevdata(subdev, stat); + + stat->pad.flags = MEDIA_PAD_FL_SINK; + me->ops = NULL; + + return media_entity_init(me, 1, &stat->pad, 0); +} + int omap3isp_stat_init(struct ispstat *stat, const char *name, const struct v4l2_subdev_ops *sd_ops) { From ed33ac8e0876a3016511ea0aaf9af1d965ee2c44 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 22 Sep 2011 17:09:26 -0300 Subject: [PATCH 132/144] [media] omap3isp: Add missing mutex_destroy() calls Mutexes must be destroyed with mutex_destroy(). Add missing calls in the modules cleanup handlers. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 2 ++ drivers/media/video/omap3isp/ispccdc.c | 2 ++ drivers/media/video/omap3isp/ispstat.c | 1 + drivers/media/video/omap3isp/ispvideo.c | 2 ++ 4 files changed, 7 insertions(+) diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 678e1252047a..c8f147ef320d 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -2210,6 +2210,8 @@ error: regulator_put(isp->isp_csiphy2.vdd); regulator_put(isp->isp_csiphy1.vdd); platform_set_drvdata(pdev, NULL); + + mutex_destroy(&isp->isp_mutex); kfree(isp); return ret; diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index c30cc59d7032..3a43be2f5452 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -2297,4 +2297,6 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) if (ccdc->fpc.fpcaddr != 0) omap_iommu_vfree(isp->domain, isp->iommu, ccdc->fpc.fpcaddr); + + mutex_destroy(&ccdc->ioctl_lock); } diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index b124326d1e7f..28b7cc61cba6 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -1087,6 +1087,7 @@ int omap3isp_stat_init(struct ispstat *stat, const char *name, void omap3isp_stat_cleanup(struct ispstat *stat) { media_entity_cleanup(&stat->subdev.entity); + mutex_destroy(&stat->ioctl_lock); isp_stat_bufs_free(stat); kfree(stat->buf); } diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 7d74ebbdb63b..d1000723c5ae 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -1328,6 +1328,8 @@ int omap3isp_video_init(struct isp_video *video, const char *name) void omap3isp_video_cleanup(struct isp_video *video) { media_entity_cleanup(&video->video.entity); + mutex_destroy(&video->stream_lock); + mutex_destroy(&video->mutex); } int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) From 9b6390bd95c65ad4a6c650955fa1e3f18f8a540c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 22 Sep 2011 17:10:30 -0300 Subject: [PATCH 133/144] [media] omap3isp: Fix memory leaks in initialization error paths Make sure all modules init functions clean up after themselves in case of error. Signed-off-by: Laurent Pinchart Reported-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 19 +++++++++++++--- drivers/media/video/omap3isp/ispccp2.c | 22 ++++++++++-------- drivers/media/video/omap3isp/ispcsi2.c | 15 ++++++++----- drivers/media/video/omap3isp/isppreview.c | 27 +++++++++++------------ drivers/media/video/omap3isp/ispresizer.c | 27 +++++++++++------------ drivers/media/video/omap3isp/ispstat.c | 11 ++++++++- 6 files changed, 74 insertions(+), 47 deletions(-) diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 3a43be2f5452..6330b1d57b1e 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -2224,15 +2224,21 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); if (ret < 0) - return ret; + goto error_video; /* Connect the CCDC subdev to the video node. */ ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, &ccdc->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&ccdc->video_out); +error_video: + media_entity_cleanup(me); + return ret; } /* @@ -2246,6 +2252,7 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) int omap3isp_ccdc_init(struct isp_device *isp) { struct isp_ccdc_device *ccdc = &isp->isp_ccdc; + int ret; spin_lock_init(&ccdc->lock); init_waitqueue_head(&ccdc->wait); @@ -2274,7 +2281,13 @@ int omap3isp_ccdc_init(struct isp_device *isp) ccdc->update = OMAP3ISP_CCDC_BLCLAMP; ccdc_apply_controls(ccdc); - return ccdc_init_entities(ccdc); + ret = ccdc_init_entities(ccdc); + if (ret < 0) { + mutex_destroy(&ccdc->ioctl_lock); + return ret; + } + + return 0; } /* diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index 883a2825cb41..904ca8c8b17f 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -1125,15 +1125,21 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); if (ret < 0) - return ret; + goto error_video; /* Connect the video node to the ccp2 subdev. */ ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, &ccp2->subdev.entity, CCP2_PAD_SINK, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&ccp2->video_in); +error_video: + media_entity_cleanup(&ccp2->subdev.entity); + return ret; } /* @@ -1171,15 +1177,13 @@ int omap3isp_ccp2_init(struct isp_device *isp) } ret = ccp2_init_entities(ccp2); - if (ret < 0) - goto out; + if (ret < 0) { + regulator_put(ccp2->vdds_csib); + return ret; + } ccp2_reset(ccp2); -out: - if (ret) - omap3isp_ccp2_cleanup(isp); - - return ret; + return 0; } /* diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 2c9bffcdc5c9..0c5f1cb9d99d 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -1259,15 +1259,21 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); if (ret < 0) - return ret; + goto error_video; /* Connect the CSI2 subdev to the video node. */ ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, &csi2->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&csi2->video_out); +error_video: + media_entity_cleanup(&csi2->subdev.entity); + return ret; } /* @@ -1289,7 +1295,7 @@ int omap3isp_csi2_init(struct isp_device *isp) ret = csi2_init_entities(csi2a); if (ret < 0) - goto fail; + return ret; if (isp->revision == ISP_REVISION_15_0) { csi2c->isp = isp; @@ -1302,9 +1308,6 @@ int omap3isp_csi2_init(struct isp_device *isp) } return 0; -fail: - omap3isp_csi2_cleanup(isp); - return ret; } /* diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index b926ebbaca3a..b3818356b6f3 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -2060,24 +2060,32 @@ static int preview_init_entities(struct isp_prev_device *prev) ret = omap3isp_video_init(&prev->video_in, "preview"); if (ret < 0) - return ret; + goto error_video_in; ret = omap3isp_video_init(&prev->video_out, "preview"); if (ret < 0) - return ret; + goto error_video_out; /* Connect the video nodes to the previewer subdev. */ ret = media_entity_create_link(&prev->video_in.video.entity, 0, &prev->subdev.entity, PREV_PAD_SINK, 0); if (ret < 0) - return ret; + goto error_link; ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, &prev->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&prev->video_out); +error_video_out: + omap3isp_video_cleanup(&prev->video_in); +error_video_in: + media_entity_cleanup(&prev->subdev.entity); + return ret; } /* @@ -2088,21 +2096,12 @@ static int preview_init_entities(struct isp_prev_device *prev) int omap3isp_preview_init(struct isp_device *isp) { struct isp_prev_device *prev = &isp->isp_prev; - int ret; spin_lock_init(&prev->lock); init_waitqueue_head(&prev->wait); preview_init_params(prev); - ret = preview_init_entities(prev); - if (ret < 0) - goto out; - -out: - if (ret) - omap3isp_preview_cleanup(isp); - - return ret; + return preview_init_entities(prev); } void omap3isp_preview_cleanup(struct isp_device *isp) diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 224b0b90404d..50e593bfcfaf 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1688,24 +1688,32 @@ static int resizer_init_entities(struct isp_res_device *res) ret = omap3isp_video_init(&res->video_in, "resizer"); if (ret < 0) - return ret; + goto error_video_in; ret = omap3isp_video_init(&res->video_out, "resizer"); if (ret < 0) - return ret; + goto error_video_out; /* Connect the video nodes to the resizer subdev. */ ret = media_entity_create_link(&res->video_in.video.entity, 0, &res->subdev.entity, RESZ_PAD_SINK, 0); if (ret < 0) - return ret; + goto error_link; ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, &res->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&res->video_out); +error_video_out: + omap3isp_video_cleanup(&res->video_in); +error_video_in: + media_entity_cleanup(&res->subdev.entity); + return ret; } /* @@ -1716,19 +1724,10 @@ static int resizer_init_entities(struct isp_res_device *res) int omap3isp_resizer_init(struct isp_device *isp) { struct isp_res_device *res = &isp->isp_res; - int ret; init_waitqueue_head(&res->wait); atomic_set(&res->stopping, 0); - ret = resizer_init_entities(res); - if (ret < 0) - goto out; - -out: - if (ret) - omap3isp_resizer_cleanup(isp); - - return ret; + return resizer_init_entities(res); } void omap3isp_resizer_cleanup(struct isp_device *isp) diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index 28b7cc61cba6..68d539456c55 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -1074,14 +1074,23 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name, int omap3isp_stat_init(struct ispstat *stat, const char *name, const struct v4l2_subdev_ops *sd_ops) { + int ret; + stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL); if (!stat->buf) return -ENOMEM; + isp_stat_buf_clear(stat); mutex_init(&stat->ioctl_lock); atomic_set(&stat->buf_err, 0); - return isp_stat_init_entities(stat, name, sd_ops); + ret = isp_stat_init_entities(stat, name, sd_ops); + if (ret < 0) { + mutex_destroy(&stat->ioctl_lock); + kfree(stat->buf); + } + + return ret; } void omap3isp_stat_cleanup(struct ispstat *stat) From 882cc8539ee73e855a149f99e2166766ce5deb35 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 29 Sep 2011 07:57:00 -0300 Subject: [PATCH 134/144] [media] omap3isp: ccdc: remove redundant operation Trivial arithmetics clean up. Signed-off-by: Guennadi Liakhovetski Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 6330b1d57b1e..b0b0fa5a3572 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1836,7 +1836,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, * callers to request an output size bigger than the input size * up to the nearest multiple of 16. */ - fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); + fmt->width = clamp_t(u32, width, 32, fmt->width + 15); fmt->width &= ~15; fmt->height = clamp_t(u32, height, 32, fmt->height); break; From 083eb07854e128a0ed7d79390baae2439755ebdd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 11 Oct 2011 06:34:40 -0300 Subject: [PATCH 135/144] [media] omap3isp: Report the ISP revision through the media controller API Set the media_device::hw_revision field to the ISP revision number. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index c8f147ef320d..b818cacf420f 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -1704,6 +1704,7 @@ static int isp_register_entities(struct isp_device *isp) isp->media_dev.dev = isp->dev; strlcpy(isp->media_dev.model, "TI OMAP3 ISP", sizeof(isp->media_dev.model)); + isp->media_dev.hw_revision = isp->revision; isp->media_dev.link_notify = isp_pipeline_link_notify; ret = media_device_register(&isp->media_dev); if (ret < 0) { From e4bc6272ab3f7cb0b56705f78320e361880411e1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Sep 2011 07:54:44 -0300 Subject: [PATCH 136/144] [media] omap3isp: preview: Remove horizontal averager support The horizontal averager isn't used and will get in the way when implementing cropping support on the input pad. Remove it, it can be added back later if needed. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isppreview.c | 18 ++---------------- drivers/media/video/omap3isp/isppreview.h | 7 ------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index b3818356b6f3..c920c1e17ae9 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -1228,7 +1228,6 @@ static void preview_init_params(struct isp_prev_device *prev) /* Init values */ params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; - params->average = NO_AVE; params->cfa.format = OMAP3ISP_CFAFMT_BAYER; memcpy(params->cfa.table, cfa_coef_table, sizeof(params->cfa.table)); @@ -1297,7 +1296,6 @@ static void preview_configure(struct isp_prev_device *prev) struct isp_device *isp = to_isp_device(prev); struct v4l2_mbus_framefmt *format; unsigned int max_out_width; - unsigned int format_avg; preview_setup_hw(prev); @@ -1337,8 +1335,7 @@ static void preview_configure(struct isp_prev_device *prev) max_out_width = preview_max_out_width(prev); - format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1); - preview_config_averager(prev, format_avg); + preview_config_averager(prev, 0); preview_config_ycpos(prev, format->code); } @@ -1642,7 +1639,7 @@ static void preview_try_format(struct isp_prev_device *prev, */ if (prev->input == PREVIEW_INPUT_MEMORY) { fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, - max_out_width * 8); + max_out_width); fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, PREV_MAX_HEIGHT); } @@ -1689,17 +1686,6 @@ static void preview_try_format(struct isp_prev_device *prev, if (prev->input == PREVIEW_INPUT_CCDC) fmt->width -= 4; - /* The preview module can output a maximum of 3312 pixels - * horizontally due to fixed memory-line sizes. Compute the - * horizontal averaging factor accordingly. Note that the limit - * applies to the noise filter and CFA interpolation blocks, so - * it doesn't take cropping by further blocks into account. - * - * ES 1.0 hardware revision is limited to 1280 pixels - * horizontally. - */ - fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1); - /* Assume that all blocks are enabled and crop pixels and lines * accordingly. See preview_config_input_size() for more * information. diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index fa943bd05c7f..272a44a2b9bc 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h @@ -45,11 +45,6 @@ #define ISPPRV_CONTRAST_HIGH 0xFF #define ISPPRV_CONTRAST_UNITS 0x1 -#define NO_AVE 0x0 -#define AVE_2_PIX 0x1 -#define AVE_4_PIX 0x2 -#define AVE_8_PIX 0x3 - /* Features list */ #define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH #define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW @@ -106,7 +101,6 @@ enum preview_ycpos_mode { * @rgb2ycbcr: RGB to ycbcr parameters. * @hmed: Horizontal median filter. * @yclimit: YC limits parameters. - * @average: Downsampling rate for averager. * @contrast: Contrast. * @brightness: Brightness. */ @@ -124,7 +118,6 @@ struct prev_params { struct omap3isp_prev_csc rgb2ycbcr; struct omap3isp_prev_hmed hmed; struct omap3isp_prev_yclimit yclimit; - u8 average; u8 contrast; u8 brightness; }; From 059dc1d9841f061e5767b95822fb4035ad7559fc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 3 Oct 2011 07:56:15 -0300 Subject: [PATCH 137/144] [media] omap3isp: preview: Rename min/max input/output sizes defines The macros that define the minimum/maximum input and output sizes are defined in seperate files and have no consistent naming. In preparation for preview engine cropping support, move them all to isppreview.c and rename them to PREV_{MIN|MAX}_{IN|OUT}_{WIDTH|HEIGHT}*. Remove unused and/or unneeded local variables that store the maximum output width. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isppreview.c | 33 ++++++++++++----------- drivers/media/video/omap3isp/ispreg.h | 3 --- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index c920c1e17ae9..d5cce423283c 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -76,9 +76,15 @@ static struct omap3isp_prev_csc flr_prev_csc = { #define DEF_DETECT_CORRECT_VAL 0xe -#define PREV_MIN_WIDTH 64 -#define PREV_MIN_HEIGHT 8 -#define PREV_MAX_HEIGHT 16384 +#define PREV_MIN_IN_WIDTH 64 +#define PREV_MIN_IN_HEIGHT 8 +#define PREV_MAX_IN_HEIGHT 16384 + +#define PREV_MIN_OUT_WIDTH 0 +#define PREV_MIN_OUT_HEIGHT 0 +#define PREV_MAX_OUT_WIDTH 1280 +#define PREV_MAX_OUT_WIDTH_ES2 3300 +#define PREV_MAX_OUT_WIDTH_3630 4096 /* * Coeficient Tables for the submodules in Preview. @@ -1280,14 +1286,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev) switch (isp->revision) { case ISP_REVISION_1_0: - return ISPPRV_MAXOUTPUT_WIDTH; + return PREV_MAX_OUT_WIDTH; case ISP_REVISION_2_0: default: - return ISPPRV_MAXOUTPUT_WIDTH_ES2; + return PREV_MAX_OUT_WIDTH_ES2; case ISP_REVISION_15_0: - return ISPPRV_MAXOUTPUT_WIDTH_3630; + return PREV_MAX_OUT_WIDTH_3630; } } @@ -1295,7 +1301,6 @@ static void preview_configure(struct isp_prev_device *prev) { struct isp_device *isp = to_isp_device(prev); struct v4l2_mbus_framefmt *format; - unsigned int max_out_width; preview_setup_hw(prev); @@ -1333,8 +1338,6 @@ static void preview_configure(struct isp_prev_device *prev) preview_config_outlineoffset(prev, ALIGN(format->width, 0x10) * 2); - max_out_width = preview_max_out_width(prev); - preview_config_averager(prev, 0); preview_config_ycpos(prev, format->code); } @@ -1620,12 +1623,9 @@ static void preview_try_format(struct isp_prev_device *prev, enum v4l2_subdev_format_whence which) { struct v4l2_mbus_framefmt *format; - unsigned int max_out_width; enum v4l2_mbus_pixelcode pixelcode; unsigned int i; - max_out_width = preview_max_out_width(prev); - switch (pad) { case PREV_PAD_SINK: /* When reading data from the CCDC, the input size has already @@ -1638,10 +1638,11 @@ static void preview_try_format(struct isp_prev_device *prev, * filter array interpolation. */ if (prev->input == PREVIEW_INPUT_MEMORY) { - fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, - max_out_width); - fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, - PREV_MAX_HEIGHT); + fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH, + preview_max_out_width(prev)); + fmt->height = clamp_t(u32, fmt->height, + PREV_MIN_IN_HEIGHT, + PREV_MAX_IN_HEIGHT); } fmt->colorspace = V4L2_COLORSPACE_SRGB; diff --git a/drivers/media/video/omap3isp/ispreg.h b/drivers/media/video/omap3isp/ispreg.h index 69f6af6f6b9c..084ea77d65a7 100644 --- a/drivers/media/video/omap3isp/ispreg.h +++ b/drivers/media/video/omap3isp/ispreg.h @@ -402,9 +402,6 @@ #define ISPPRV_YENH_TABLE_ADDR 0x1000 #define ISPPRV_CFA_TABLE_ADDR 0x1400 -#define ISPPRV_MAXOUTPUT_WIDTH 1280 -#define ISPPRV_MAXOUTPUT_WIDTH_ES2 3300 -#define ISPPRV_MAXOUTPUT_WIDTH_3630 4096 #define ISPRSZ_MIN_OUTPUT 64 #define ISPRSZ_MAX_OUTPUT 3312 From 1f69fd970dfdd9872c83f62864b2557d686948cb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Sep 2011 20:05:45 -0300 Subject: [PATCH 138/144] [media] omap3isp: preview: Add crop support on the sink pad The crop rectangle takes the preview engine internal cropping requirements into account. The smallest allowable margins are 14 columns and 8 rows when reading from memory, and 18 columns and 8 rows when processing data on the fly from the CCDC. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isppreview.c | 260 ++++++++++++++++------ drivers/media/video/omap3isp/isppreview.h | 2 + 2 files changed, 197 insertions(+), 65 deletions(-) diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index d5cce423283c..ccb876fe023f 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -76,6 +76,42 @@ static struct omap3isp_prev_csc flr_prev_csc = { #define DEF_DETECT_CORRECT_VAL 0xe +/* + * Margins and image size limits. + * + * The preview engine crops several rows and columns internally depending on + * which filters are enabled. To avoid format changes when the filters are + * enabled or disabled (which would prevent them from being turned on or off + * during streaming), the driver assumes all the filters are enabled when + * computing sink crop and source format limits. + * + * If a filter is disabled, additional cropping is automatically added at the + * preview engine input by the driver to avoid overflow at line and frame end. + * This is completely transparent for applications. + * + * Median filter 4 pixels + * Noise filter, + * Faulty pixels correction 4 pixels, 4 lines + * CFA filter 4 pixels, 4 lines in Bayer mode + * 2 lines in other modes + * Color suppression 2 pixels + * or luma enhancement + * ------------------------------------------------------------- + * Maximum total 14 pixels, 8 lines + * + * The color suppression and luma enhancement filters are applied after bayer to + * YUV conversion. They thus can crop one pixel on the left and one pixel on the + * right side of the image without changing the color pattern. When both those + * filters are disabled, the driver must crop the two pixels on the same side of + * the image to avoid changing the bayer pattern. The left margin is thus set to + * 8 pixels and the right margin to 6 pixels. + */ + +#define PREV_MARGIN_LEFT 8 +#define PREV_MARGIN_RIGHT 6 +#define PREV_MARGIN_TOP 4 +#define PREV_MARGIN_BOTTOM 4 + #define PREV_MIN_IN_WIDTH 64 #define PREV_MIN_IN_HEIGHT 8 #define PREV_MAX_IN_HEIGHT 16384 @@ -985,52 +1021,36 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average) * enabled when reporting source pad formats to userspace. If this assumption is * not true, rows and columns must be manually cropped at the preview engine * input to avoid overflows at the end of lines and frames. + * + * See the explanation at the PREV_MARGIN_* definitions for more details. */ static void preview_config_input_size(struct isp_prev_device *prev) { struct isp_device *isp = to_isp_device(prev); struct prev_params *params = &prev->params; - struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; - unsigned int sph = 0; - unsigned int eph = format->width - 1; - unsigned int slv = 0; - unsigned int elv = format->height - 1; + unsigned int sph = prev->crop.left; + unsigned int eph = prev->crop.left + prev->crop.width - 1; + unsigned int slv = prev->crop.top; + unsigned int elv = prev->crop.top + prev->crop.height - 1; - if (prev->input == PREVIEW_INPUT_CCDC) { - sph += 2; - eph -= 2; + if (params->features & PREV_CFA) { + sph -= 2; + eph += 2; + slv -= 2; + elv += 2; } - - /* - * Median filter 4 pixels - * Noise filter 4 pixels, 4 lines - * or faulty pixels correction - * CFA filter 4 pixels, 4 lines in Bayer mode - * 2 lines in other modes - * Color suppression 2 pixels - * or luma enhancement - * ------------------------------------------------------------- - * Maximum total 14 pixels, 8 lines - */ - - if (!(params->features & PREV_CFA)) { - sph += 2; - eph -= 2; - slv += 2; - elv -= 2; + if (params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER)) { + sph -= 2; + eph += 2; + slv -= 2; + elv += 2; } - if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) { - sph += 2; - eph -= 2; - slv += 2; - elv -= 2; + if (params->features & PREV_HORZ_MEDIAN_FILTER) { + sph -= 2; + eph += 2; } - if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) { - sph += 2; - eph -= 2; - } - if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))) - sph += 2; + if (params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)) + sph -= 2; isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); @@ -1597,6 +1617,16 @@ __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, return &prev->formats[pad]; } +static struct v4l2_rect * +__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK); + else + return &prev->crop; +} + /* previewer format descriptions */ static const unsigned int preview_input_fmts[] = { V4L2_MBUS_FMT_SGRBG10_1X10, @@ -1611,19 +1641,23 @@ static const unsigned int preview_output_fmts[] = { }; /* - * preview_try_format - Handle try format by pad subdev method - * @prev: ISP preview device - * @fh : V4L2 subdev file handle - * @pad: pad num - * @fmt: pointer to v4l2 format structure + * preview_try_format - Validate a format + * @prev: ISP preview engine + * @fh: V4L2 subdev file handle + * @pad: pad number + * @fmt: format to be validated + * @which: try/active format selector + * + * Validate and adjust the given format for the given pad based on the preview + * engine limits and the format and crop rectangles on other pads. */ static void preview_try_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { - struct v4l2_mbus_framefmt *format; enum v4l2_mbus_pixelcode pixelcode; + struct v4l2_rect *crop; unsigned int i; switch (pad) { @@ -1659,15 +1693,8 @@ static void preview_try_format(struct isp_prev_device *prev, case PREV_PAD_SOURCE: pixelcode = fmt->code; - format = __preview_get_format(prev, fh, PREV_PAD_SINK, which); - memcpy(fmt, format, sizeof(*fmt)); + *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); - /* The preview module output size is configurable through the - * input interface (horizontal and vertical cropping) and the - * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In - * spite of this, hardcode the output size to the biggest - * possible value for simplicity reasons. - */ switch (pixelcode) { case V4L2_MBUS_FMT_YUYV8_1X16: case V4L2_MBUS_FMT_UYVY8_1X16: @@ -1679,20 +1706,14 @@ static void preview_try_format(struct isp_prev_device *prev, break; } - /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped - * from the left and right sides when the input source is the - * CCDC. This seems not to be needed in practice, investigation - * is required. + /* The preview module output size is configurable through the + * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This + * is not supported yet, hardcode the output size to the crop + * rectangle size. */ - if (prev->input == PREVIEW_INPUT_CCDC) - fmt->width -= 4; - - /* Assume that all blocks are enabled and crop pixels and lines - * accordingly. See preview_config_input_size() for more - * information. - */ - fmt->width -= 14; - fmt->height -= 8; + crop = __preview_get_crop(prev, fh, which); + fmt->width = crop->width; + fmt->height = crop->height; fmt->colorspace = V4L2_COLORSPACE_JPEG; break; @@ -1701,6 +1722,49 @@ static void preview_try_format(struct isp_prev_device *prev, fmt->field = V4L2_FIELD_NONE; } +/* + * preview_try_crop - Validate a crop rectangle + * @prev: ISP preview engine + * @sink: format on the sink pad + * @crop: crop rectangle to be validated + * + * The preview engine crops lines and columns for its internal operation, + * depending on which filters are enabled. Enforce minimum crop margins to + * handle that transparently for userspace. + * + * See the explanation at the PREV_MARGIN_* definitions for more details. + */ +static void preview_try_crop(struct isp_prev_device *prev, + const struct v4l2_mbus_framefmt *sink, + struct v4l2_rect *crop) +{ + unsigned int left = PREV_MARGIN_LEFT; + unsigned int right = sink->width - PREV_MARGIN_RIGHT; + unsigned int top = PREV_MARGIN_TOP; + unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM; + + /* When processing data on-the-fly from the CCDC, at least 2 pixels must + * be cropped from the left and right sides of the image. As we don't + * know which filters will be enabled, increase the left and right + * margins by two. + */ + if (prev->input == PREVIEW_INPUT_CCDC) { + left += 2; + right -= 2; + } + + /* Restrict left/top to even values to keep the Bayer pattern. */ + crop->left &= ~1; + crop->top &= ~1; + + crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH); + crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT); + crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH, + right - crop->left); + crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT, + bottom - crop->top); +} + /* * preview_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure @@ -1762,6 +1826,60 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, return 0; } +/* + * preview_get_crop - Retrieve the crop rectangle on a pad + * @sd: ISP preview V4L2 subdevice + * @fh: V4L2 subdev file handle + * @crop: crop rectangle + * + * Return 0 on success or a negative error code otherwise. + */ +static int preview_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + + /* Cropping is only supported on the sink pad. */ + if (crop->pad != PREV_PAD_SINK) + return -EINVAL; + + crop->rect = *__preview_get_crop(prev, fh, crop->which); + return 0; +} + +/* + * preview_set_crop - Retrieve the crop rectangle on a pad + * @sd: ISP preview V4L2 subdevice + * @fh: V4L2 subdev file handle + * @crop: crop rectangle + * + * Return 0 on success or a negative error code otherwise. + */ +static int preview_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + /* Cropping is only supported on the sink pad. */ + if (crop->pad != PREV_PAD_SINK) + return -EINVAL; + + /* The crop rectangle can't be changed while streaming. */ + if (prev->state != ISP_PIPELINE_STREAM_STOPPED) + return -EBUSY; + + format = __preview_get_format(prev, fh, PREV_PAD_SINK, crop->which); + preview_try_crop(prev, format, &crop->rect); + *__preview_get_crop(prev, fh, crop->which) = crop->rect; + + /* Update the source format. */ + format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, crop->which); + preview_try_format(prev, fh, PREV_PAD_SOURCE, format, crop->which); + + return 0; +} + /* * preview_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure @@ -1795,6 +1913,7 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; format = __preview_get_format(prev, fh, fmt->pad, fmt->which); if (format == NULL) @@ -1805,9 +1924,18 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* Propagate the format from sink to source */ if (fmt->pad == PREV_PAD_SINK) { + /* Reset the crop rectangle. */ + crop = __preview_get_crop(prev, fh, fmt->which); + crop->left = 0; + crop->top = 0; + crop->width = fmt->format.width; + crop->height = fmt->format.height; + + preview_try_crop(prev, &fmt->format, crop); + + /* Update the source format. */ format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, fmt->which); - *format = fmt->format; preview_try_format(prev, fh, PREV_PAD_SOURCE, format, fmt->which); } @@ -1856,6 +1984,8 @@ static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = { .enum_frame_size = preview_enum_frame_size, .get_fmt = preview_get_format, .set_fmt = preview_set_format, + .get_crop = preview_get_crop, + .set_crop = preview_set_crop, }; /* subdev operations */ diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index 272a44a2b9bc..f54e775c2df4 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h @@ -152,6 +152,7 @@ struct isptables_update { * @subdev: V4L2 subdevice * @pads: Media entity pads * @formats: Active formats at the subdev pad + * @crop: Active crop rectangle * @input: Module currently connected to the input pad * @output: Bitmask of the active output * @video_in: Input video entity @@ -170,6 +171,7 @@ struct isp_prev_device { struct v4l2_subdev subdev; struct media_pad pads[PREV_PADS_NUM]; struct v4l2_mbus_framefmt formats[PREV_PADS_NUM]; + struct v4l2_rect crop; struct v4l2_ctrl_handler ctrls; From 94f3f48f90f77e3bfcafce9b259086cfebcd166d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 20 Jan 2011 21:15:42 -0300 Subject: [PATCH 139/144] [media] omap_vout: Add poll() support Signed-off-by: Laurent Pinchart Acked-by: Vaibhav Hiremath Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap/omap_vout.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 30d8896bb710..9c5c19f142de 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -833,6 +833,15 @@ static void omap_vout_buffer_release(struct videobuf_queue *q, /* * File operations */ +static unsigned int omap_vout_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct omap_vout_device *vout = file->private_data; + struct videobuf_queue *q = &vout->vbq; + + return videobuf_poll_stream(file, q, wait); +} + static void omap_vout_vm_open(struct vm_area_struct *vma) { struct omap_vout_device *vout = vma->vm_private_data; @@ -1861,6 +1870,7 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = { static const struct v4l2_file_operations omap_vout_fops = { .owner = THIS_MODULE, + .poll = omap_vout_poll, .unlocked_ioctl = video_ioctl2, .mmap = omap_vout_mmap, .open = omap_vout_open, From 8c4343e5909f956140229b0d960dc7a9c4fd4bdd Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Wed, 12 Oct 2011 17:51:22 -0300 Subject: [PATCH 140/144] [media] media: tea5764: reconcile Kconfig symbol and macro The Kconfig symbol RADIO_TEA5764_XTAL is unused. The code does use a RADIO_TEA5764_XTAL macro, but does that rather peculiar. But there seems to be a way to keep both. (The easiest way out would be to rip out both the Kconfig symbol and the macro.) Note there's also a module parameter 'use_xtal' to influence all this. Signed-off-by: Paul Bolle Acked-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-tea5764.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 95ddcc4845d3..db20904d01f0 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -128,8 +128,10 @@ struct tea5764_write_regs { u16 rdsbbl; /* PAUSEDET & RDSBBL */ } __attribute__ ((packed)); -#ifndef RADIO_TEA5764_XTAL +#ifdef CONFIG_RADIO_TEA5764_XTAL #define RADIO_TEA5764_XTAL 1 +#else +#define RADIO_TEA5764_XTAL 0 #endif static int radio_nr = -1; From 567a23f4389f86c10355ae89909d6d87f312d1a0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Oct 2011 02:41:41 -0300 Subject: [PATCH 141/144] [media] cx25821: off by one in cx25821_vidioc_s_input() If "i" is 2 then when we call cx25821_video_mux() we'd end up going past the end of the cx25821_boards[dev->board]->input[]. The INPUT() macro obfuscates what's going on in that function so it's a bit hard to follow. And as Mauro points out the hard coded 2 is not very helpful. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25821/cx25821-video.c | 2 +- drivers/media/video/cx25821/cx25821.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c index 084fc0899e13..4d6907cda75b 100644 --- a/drivers/media/video/cx25821/cx25821-video.c +++ b/drivers/media/video/cx25821/cx25821-video.c @@ -1312,7 +1312,7 @@ int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) return err; } - if (i > 2) { + if (i >= CX25821_NR_INPUT) { dprintk(1, "%s(): -EINVAL\n", __func__); return -EINVAL; } diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h index db2615b2bac3..2d2d00932823 100644 --- a/drivers/media/video/cx25821/cx25821.h +++ b/drivers/media/video/cx25821/cx25821.h @@ -98,6 +98,7 @@ #define CX25821_BOARD_CONEXANT_ATHENA10 1 #define MAX_VID_CHANNEL_NUM 12 #define VID_CHANNEL_NUM 8 +#define CX25821_NR_INPUT 2 struct cx25821_fmt { char *name; @@ -196,7 +197,7 @@ struct cx25821_board { unsigned char radio_addr; u32 clk_freq; - struct cx25821_input input[2]; + struct cx25821_input input[CX25821_NR_INPUT]; }; struct cx25821_subid { From efabaaf38a6cac929650943151e679f2b5cdae8b Mon Sep 17 00:00:00 2001 From: Teka Date: Fri, 14 Oct 2011 05:40:29 -0300 Subject: [PATCH 142/144] [media] Support for Terratec G1 Hi, This is a little patch to support Terratec G1 (based on Terratec Grabby). It works perfectly on my pc (Ubuntu 11.04 / Kernel 2.6.38). Best regards, Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 4240f0b720fa..9b747c266afa 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1923,6 +1923,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2860_BOARD_TERRATEC_AV350 }, { USB_DEVICE(0x0ccd, 0x0096), .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, + { USB_DEVICE(0x0ccd, 0x10AF), + .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, { USB_DEVICE(0x0fd9, 0x0033), .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, { USB_DEVICE(0x185b, 0x2870), From bc54919f83df61860c7a183016bbced054f9e474 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Fri, 14 Oct 2011 19:54:11 -0300 Subject: [PATCH 143/144] [media] it913x [VER 1.07] Support for single ITE 9135 devices Support for single ITE 9135 device. Only single devices have been tested. Dual ITE 9135 devices should work, but have not been tested. TODOs support for ver 2 chip config for other tuner types. rework of firmware file. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 + drivers/media/dvb/dvb-usb/it913x.c | 109 +++++++++++++++++------- 2 files changed, 82 insertions(+), 29 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2ad33ba92ba2..2d08c9b5128a 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -37,6 +37,7 @@ #define USB_VID_HAUPPAUGE 0x2040 #define USB_VID_HYPER_PALTEK 0x1025 #define USB_VID_INTEL 0x8086 +#define USB_VID_ITETECH 0x048d #define USB_VID_KWORLD 0xeb2a #define USB_VID_KWORLD_2 0x1b80 #define USB_VID_KYE 0x0458 @@ -126,6 +127,7 @@ #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_INTEL_CE9500 0x9500 +#define USB_PID_ITETECH_IT9135 0x9135 #define USB_PID_KWORLD_399U 0xe399 #define USB_PID_KWORLD_399U_2 0xe400 #define USB_PID_KWORLD_395U 0xe396 diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index f027a2c1c3e8..c46226187143 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c @@ -60,6 +60,17 @@ struct it913x_state { u8 id; }; +struct ite_config { + u8 chip_ver; + u16 chip_type; + u32 firmware; + u8 tuner_id_0; + u8 tuner_id_1; + u8 dual_mode; +}; + +struct ite_config it913x_config; + static int it913x_bulk_write(struct usb_device *dev, u8 *snd, int len, u8 pipe) { @@ -191,18 +202,23 @@ static int it913x_read_reg(struct usb_device *udev, u32 reg) static u32 it913x_query(struct usb_device *udev, u8 pro) { int ret; - u32 res = 0; u8 data[4]; ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, - 0x1222, 0, &data[0], 1); - if (data[0] == 0x1) { - ret = it913x_io(udev, READ_SHORT, pro, - CMD_QUERYINFO, 0, 0x1, &data[0], 4); - res = (data[0] << 24) + (data[1] << 16) + - (data[2] << 8) + data[3]; - } + 0x1222, 0, &data[0], 3); - return (ret < 0) ? 0 : res; + it913x_config.chip_ver = data[0]; + it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; + + info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver, + it913x_config.chip_type); + + ret |= it913x_io(udev, READ_SHORT, pro, + CMD_QUERYINFO, 0, 0x1, &data[0], 4); + + it913x_config.firmware = (data[0] << 24) + (data[1] << 16) + + (data[2] << 8) + data[3]; + + return (ret < 0) ? 0 : it913x_config.firmware; } static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) @@ -336,26 +352,35 @@ static int it913x_identify_state(struct usb_device *udev, int *cold) { int ret = 0, firm_no; - u8 reg, adap, ep, tun0, tun1; + u8 reg, remote; firm_no = it913x_return_status(udev); - ep = it913x_read_reg(udev, 0x49ac); - adap = it913x_read_reg(udev, 0x49c5); - tun0 = it913x_read_reg(udev, 0x49d0); - info("No. Adapters=%x Endpoints=%x Tuner Type=%x", adap, ep, tun0); + /* checnk for dual mode */ + it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5); + + /* TODO different remotes */ + remote = it913x_read_reg(udev, 0x49ac); /* Remote */ + if (remote == 0) + props->rc.core.rc_codes = NULL; + + /* TODO at the moment tuner_id is always assigned to 0x38 */ + it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0); + + info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode + , remote, it913x_config.tuner_id_0); if (firm_no > 0) { *cold = 0; return 0; } - if (adap > 2) { - tun1 = it913x_read_reg(udev, 0x49e0); + if (it913x_config.dual_mode) { + it913x_config.tuner_id_1 = it913x_read_reg(udev, 0x49e0); ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1); ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1); ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1); - msleep(50); /* Delay noticed reset cycle ? */ + msleep(50); ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); msleep(50); reg = it913x_read_reg(udev, GPIOH1_O); @@ -366,14 +391,19 @@ static int it913x_identify_state(struct usb_device *udev, ret = it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); } + props->num_adapters = 2; } else props->num_adapters = 1; reg = it913x_read_reg(udev, IO_MUX_POWER_CLK); - ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); - - ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); + if (it913x_config.dual_mode) { + ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); + ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); + } else { + ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0); + ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0); + } *cold = 1; @@ -403,13 +433,11 @@ static int it913x_download_firmware(struct usb_device *udev, const struct firmware *fw) { int ret = 0, i; - u8 packet_size, dlen, tun1; + u8 packet_size, dlen; u8 *fw_data; packet_size = 0x29; - tun1 = it913x_read_reg(udev, 0x49e0); - ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100); info("FRM Starting Firmware Download"); @@ -444,11 +472,12 @@ static int it913x_download_firmware(struct usb_device *udev, ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); /* Tuner function */ - ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); + if (it913x_config.dual_mode) + ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); - if (tun1 > 0) { + if (it913x_config.dual_mode) { ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); } @@ -475,9 +504,28 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap) u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize; + u8 tuner_id, tuner_type; + + if (adap->id == 0) + tuner_id = it913x_config.tuner_id_0; + else + tuner_id = it913x_config.tuner_id_1; + + /* TODO we always use IT9137 possible references here*/ + /* Documentation suggests don't care */ + switch (tuner_id) { + case 0x51: + case 0x52: + case 0x60: + case 0x61: + case 0x62: + default: + case 0x38: + tuner_type = IT9137; + } adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach, - &adap->dev->i2c_adap, adap_addr, adf, IT9137); + &adap->dev->i2c_adap, adap_addr, adf, tuner_type); if (adap->id == 0 && adap->fe_adap[0].fe) { ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); @@ -533,6 +581,7 @@ static int it913x_probe(struct usb_interface *intf, static struct usb_device_id it913x_table[] = { { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) }, + { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) }, {} /* Terminating entry */ }; @@ -608,12 +657,14 @@ static struct dvb_usb_device_properties it913x_properties = { .rc_codes = RC_MAP_KWORLD_315U, }, .i2c_algo = &it913x_i2c_algo, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { { "Kworld UB499-2T T09(IT9137)", { &it913x_table[0], NULL }, }, - + { "ITE 9135 Generic", + { &it913x_table[1], NULL }, + }, } }; @@ -647,5 +698,5 @@ module_exit(it913x_module_exit); MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("it913x USB 2 Driver"); -MODULE_VERSION("1.06"); +MODULE_VERSION("1.07"); MODULE_LICENSE("GPL"); From b3f4e1eba45eda5d1213810ef3bc53e5247df2df Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Tue, 18 Oct 2011 15:37:36 -0300 Subject: [PATCH 144/144] [media] saa7134.h: Suppress compiler warnings when CONFIG_VIDEO_SAA7134_RC is not set If the said config optio is not set, the compiler will spill out many warnings about statements with no effect, such as: Casting the zero to void will cure the warning. Signed-off-by: Timo Kokkonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index bc8d6bba8ee5..9b550687213a 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -843,10 +843,10 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev); int saa7134_ir_start(struct saa7134_dev *dev); void saa7134_ir_stop(struct saa7134_dev *dev); #else -#define saa7134_input_init1(dev) (0) -#define saa7134_input_fini(dev) (0) -#define saa7134_input_irq(dev) (0) -#define saa7134_probe_i2c_ir(dev) (0) -#define saa7134_ir_start(dev) (0) -#define saa7134_ir_stop(dev) (0) +#define saa7134_input_init1(dev) ((void)0) +#define saa7134_input_fini(dev) ((void)0) +#define saa7134_input_irq(dev) ((void)0) +#define saa7134_probe_i2c_ir(dev) ((void)0) +#define saa7134_ir_start(dev) ((void)0) +#define saa7134_ir_stop(dev) ((void)0) #endif